diff options
Diffstat (limited to 'chromium/ui/gfx/win/singleton_hwnd_hot_key_observer.cc')
-rw-r--r-- | chromium/ui/gfx/win/singleton_hwnd_hot_key_observer.cc | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/chromium/ui/gfx/win/singleton_hwnd_hot_key_observer.cc b/chromium/ui/gfx/win/singleton_hwnd_hot_key_observer.cc new file mode 100644 index 00000000000..2d2363477b2 --- /dev/null +++ b/chromium/ui/gfx/win/singleton_hwnd_hot_key_observer.cc @@ -0,0 +1,96 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/gfx/win/singleton_hwnd_hot_key_observer.h" + +#include "base/bind.h" +#include "base/containers/flat_set.h" +#include "base/memory/ptr_util.h" +#include "base/no_destructor.h" +#include "base/optional.h" +#include "ui/gfx/win/singleton_hwnd.h" + +namespace gfx { + +namespace { + +base::flat_set<int>& GetUsedHotKeyIDs() { + static base::NoDestructor<base::flat_set<int>> used_hot_key_ids; + return *used_hot_key_ids; +} + +base::Optional<int> GetAvailableHotKeyID() { + // Valid hot key IDs are in the range 0x0000 to 0xBFFF. See + // https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-registerhotkey + for (int i = 0x0000; i < 0xBFFF; i++) { + if (!GetUsedHotKeyIDs().contains(i)) + return i; + } + return base::nullopt; +} + +void SetHotKeyIDUsed(int id) { + DCHECK(!GetUsedHotKeyIDs().contains(id)); + GetUsedHotKeyIDs().insert(id); +} + +void SetHotKeyIDAvailable(int id) { + DCHECK(GetUsedHotKeyIDs().contains(id)); + GetUsedHotKeyIDs().erase(id); +} + +} // anonymous namespace + +std::unique_ptr<SingletonHwndHotKeyObserver> +SingletonHwndHotKeyObserver::Create( + const SingletonHwndObserver::WndProc& wnd_proc, + UINT key_code, + int modifiers) { + base::Optional<int> hot_key_id = GetAvailableHotKeyID(); + + // If there are no available hot key IDs, return null. + if (!hot_key_id.has_value()) + return nullptr; + + // If we fail to register the hot key, return null. Most likely reason for + // failure is that another application has already registered the hot key. + if (!RegisterHotKey(gfx::SingletonHwnd::GetInstance()->hwnd(), *hot_key_id, + modifiers, key_code)) { + return nullptr; + } + + return base::WrapUnique( + new SingletonHwndHotKeyObserver(wnd_proc, *hot_key_id)); +} + +SingletonHwndHotKeyObserver::SingletonHwndHotKeyObserver( + const SingletonHwndObserver::WndProc& wnd_proc, + int hot_key_id) + : observer_(base::BindRepeating(&SingletonHwndHotKeyObserver::OnWndProc, + base::Unretained(this))), + wnd_proc_(wnd_proc), + hot_key_id_(hot_key_id) { + SetHotKeyIDUsed(hot_key_id); +} + +SingletonHwndHotKeyObserver::~SingletonHwndHotKeyObserver() { + bool success = !!UnregisterHotKey(gfx::SingletonHwnd::GetInstance()->hwnd(), + hot_key_id_); + // This call should always succeed, as long as we pass in the right HWND and + // an id we've used to register before. + DCHECK(success); + SetHotKeyIDAvailable(hot_key_id_); +} + +void SingletonHwndHotKeyObserver::OnWndProc(HWND hwnd, + UINT message, + WPARAM wparam, + LPARAM lparam) { + // Only propagate WM_HOTKEY messages for this particular hot key to the owner + // of this observer. + if (message == WM_HOTKEY && static_cast<int>(wparam) == hot_key_id_) + wnd_proc_.Run(hwnd, message, wparam, lparam); +} + +} // namespace gfx |