diff options
Diffstat (limited to 'chromium/ui/gfx/win')
-rw-r--r-- | chromium/ui/gfx/win/singleton_hwnd_hot_key_observer.cc | 96 | ||||
-rw-r--r-- | chromium/ui/gfx/win/singleton_hwnd_hot_key_observer.h | 50 | ||||
-rw-r--r-- | chromium/ui/gfx/win/singleton_hwnd_observer.h | 2 |
3 files changed, 148 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 diff --git a/chromium/ui/gfx/win/singleton_hwnd_hot_key_observer.h b/chromium/ui/gfx/win/singleton_hwnd_hot_key_observer.h new file mode 100644 index 00000000000..bbc992b6199 --- /dev/null +++ b/chromium/ui/gfx/win/singleton_hwnd_hot_key_observer.h @@ -0,0 +1,50 @@ +// 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. + +#ifndef UI_GFX_WIN_SINGLETON_HWND_HOT_KEY_OBSERVER_H_ +#define UI_GFX_WIN_SINGLETON_HWND_HOT_KEY_OBSERVER_H_ + +#include "base/win/windows_types.h" +#include "ui/gfx/gfx_export.h" +#include "ui/gfx/win/singleton_hwnd_observer.h" + +namespace gfx { + +// We need to avoid duplicate hot key IDs for SingletonHwndObservers that call +// RegisterHotKey for SingletonHwnd. This class properly handles getting a +// unique hot key ID, registers the hotkey on construction, and unregisters the +// hot key on destruction. +// +// This class should always be used instead of directly registering hot keys on +// the SingletonHwnd with a SingletonHwndObserver in order to prevent duplicate +// hot key IDs. +class GFX_EXPORT SingletonHwndHotKeyObserver { + public: + // Registers a hot key with the given |key_code| and |modifiers| and returns + // a SingletonHwndHotKeyObserver if successful. Returns null if the hot key + // fails to register, which can happen if another application has already + // registered the hot key. + static std::unique_ptr<SingletonHwndHotKeyObserver> Create( + const SingletonHwndObserver::WndProc& wnd_proc, + UINT key_code, + int modifiers); + ~SingletonHwndHotKeyObserver(); + + private: + SingletonHwndHotKeyObserver(const SingletonHwndObserver::WndProc& wnd_proc, + int hot_key_id); + + // Called by SingletonHwndObserver. + void OnWndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); + + SingletonHwndObserver observer_; + SingletonHwndObserver::WndProc wnd_proc_; + const int hot_key_id_; + + DISALLOW_COPY_AND_ASSIGN(SingletonHwndHotKeyObserver); +}; + +} // namespace gfx + +#endif // UI_GFX_WIN_SINGLETON_HWND_HOT_KEY_OBSERVER_H_ diff --git a/chromium/ui/gfx/win/singleton_hwnd_observer.h b/chromium/ui/gfx/win/singleton_hwnd_observer.h index a1bd5244810..329a784c05a 100644 --- a/chromium/ui/gfx/win/singleton_hwnd_observer.h +++ b/chromium/ui/gfx/win/singleton_hwnd_observer.h @@ -17,6 +17,8 @@ class SingletonHwnd; // Singleton lifetime management is tricky. This observer handles the correct // cleanup if either the SingletonHwnd or forwarded object is destroyed first. +// Note that if you want to register a hot key on the SingletonHwnd, you need to +// use a SingletonHwndHotKeyObserver instead for each hot key. class GFX_EXPORT SingletonHwndObserver { public: typedef base::Callback<void(HWND, UINT, WPARAM, LPARAM)> WndProc; |