Chromium Code Reviews| Index: chrome/browser/extensions/global_shortcut_listener_win.cc |
| diff --git a/chrome/browser/extensions/global_shortcut_listener_win.cc b/chrome/browser/extensions/global_shortcut_listener_win.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..826cb2025705481e1a5eb42fd3e012f7423585a9 |
| --- /dev/null |
| +++ b/chrome/browser/extensions/global_shortcut_listener_win.cc |
| @@ -0,0 +1,119 @@ |
| +// Copyright (c) 2013 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 "chrome/browser/extensions/global_shortcut_listener_win.h" |
| + |
| +#include "base/win/win_util.h" |
| +#include "content/public/browser/browser_thread.h" |
| +#include "ui/base/accelerators/accelerator.h" |
| +#include "ui/events/event_constants.h" |
| +#include "ui/events/keycodes/keyboard_code_conversion_win.h" |
| + |
| +using content::BrowserThread; |
| + |
| +namespace { |
| + |
| +static base::LazyInstance<extensions::GlobalShortcutListenerWin> instance = |
| + LAZY_INSTANCE_INITIALIZER; |
| + |
| +} // namespace |
| + |
| +namespace extensions { |
| + |
| +// static |
| +GlobalShortcutListener* GlobalShortcutListener::GetInstance() { |
| + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + return instance.Pointer(); |
| +} |
| + |
| +GlobalShortcutListenerWin::GlobalShortcutListenerWin() |
| + : is_listening_(false) { |
| + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| +} |
| + |
| +GlobalShortcutListenerWin::~GlobalShortcutListenerWin() { |
| + if (is_listening_) |
| + StopListening(); |
| +} |
| + |
| +void GlobalShortcutListenerWin::StartListening() { |
| + DCHECK(!is_listening_); // Don't start twice. |
| + DCHECK(!hotkey_ids_.empty()); // Also don't start if no hotkey is registered. |
| + gfx::SingletonHwnd::GetInstance()->AddObserver(this); |
| + is_listening_ = true; |
| +} |
| + |
| +void GlobalShortcutListenerWin::StopListening() { |
| + DCHECK(is_listening_); // No point if we are not already listening. |
| + DCHECK(hotkey_ids_.empty()); // Make sure the map is clean before ending. |
| + gfx::SingletonHwnd::GetInstance()->RemoveObserver(this); |
| + is_listening_ = false; |
| +} |
| + |
| +void GlobalShortcutListenerWin::OnWndProc(HWND hwnd, |
| + UINT message, |
| + WPARAM wparam, |
| + LPARAM lparam) { |
| + if (message != WM_HOTKEY) |
| + return; |
| + |
| + int key_code = HIWORD(lparam); |
| + int modifiers = 0; |
| + modifiers |= (LOWORD(lparam) & MOD_SHIFT) ? ui::EF_SHIFT_DOWN : 0; |
| + modifiers |= (LOWORD(lparam) & MOD_ALT) ? ui::EF_ALT_DOWN : 0; |
| + modifiers |= (LOWORD(lparam) & MOD_CONTROL) ? ui::EF_CONTROL_DOWN : 0; |
| + ui::Accelerator accelerator( |
| + ui::KeyboardCodeForWindowsKeyCode(key_code), modifiers); |
| + |
| + instance.Get().NotifyKeyPressed(accelerator); |
| +} |
| + |
| +void GlobalShortcutListenerWin::RegisterAccelerator( |
| + const ui::Accelerator& accelerator, |
| + GlobalShortcutListener::Observer* observer) { |
| + int modifiers = 0; |
| + modifiers |= accelerator.IsShiftDown() ? MOD_SHIFT : 0; |
| + modifiers |= accelerator.IsCtrlDown() ? MOD_CONTROL : 0; |
| + modifiers |= accelerator.IsAltDown() ? MOD_ALT : 0; |
| + static int hotkey_id = 0; |
| + if (hotkey_id == 0) { |
| + // Ensure that the window has been created before calling RegisterHotKey |
|
Yoyo Zhou
2013/10/03 22:08:50
Which window is this?
Finnur
2013/10/04 17:57:02
The singleton-hwnd, but this code is now redundant
|
| + // because otherwise we'd be calling RegisterHotkey on a NULL window, which |
| + // causes problems when unregistering (after the window has been created). |
| + gfx::SingletonHwnd::GetInstance()->Init(); |
| + } |
| + |
| + bool success = !!RegisterHotKey( |
| + gfx::SingletonHwnd::GetInstance()->hwnd(), |
| + hotkey_id, |
| + modifiers, |
| + accelerator.key_code()); |
| + |
| + if (!success) { |
| + // Most likely error: 1409 (Hotkey already registered). |
| + LOG(ERROR) << "RegisterHotKey failed, error: " << GetLastError(); |
| + return; |
| + } |
| + |
| + hotkey_ids_[accelerator] = hotkey_id++; |
| + GlobalShortcutListener::RegisterAccelerator(accelerator, observer); |
| +} |
| + |
| +void GlobalShortcutListenerWin::UnregisterAccelerator( |
| + const ui::Accelerator& accelerator, |
| + GlobalShortcutListener::Observer* observer) { |
| + // We may get asked to unregister something that we couldn't register (for |
| + // example if the shortcut was already taken by another app), so we |
| + // need to handle that gracefully. |
| + HotkeyIdMap::iterator it = hotkey_ids_.find(accelerator); |
| + if (it == hotkey_ids_.end()) |
| + return; |
| + |
| + UnregisterHotKey(gfx::SingletonHwnd::GetInstance()->hwnd(), it->second); |
| + hotkey_ids_.erase(it); |
| + |
| + GlobalShortcutListener::UnregisterAccelerator(accelerator, observer); |
| +} |
| + |
| +} // namespace extensions |