1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/extensions/global_shortcut_listener_win.h" 6 7 #include "base/win/win_util.h" 8 #include "content/public/browser/browser_thread.h" 9 #include "ui/base/accelerators/accelerator.h" 10 #include "ui/events/event_constants.h" 11 #include "ui/events/keycodes/keyboard_code_conversion_win.h" 12 13 using content::BrowserThread; 14 15 namespace extensions { 16 17 // static 18 GlobalShortcutListener* GlobalShortcutListener::GetInstance() { 19 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 20 static GlobalShortcutListenerWin* instance = 21 new GlobalShortcutListenerWin(); 22 return instance; 23 } 24 25 GlobalShortcutListenerWin::GlobalShortcutListenerWin() 26 : is_listening_(false) { 27 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 28 } 29 30 GlobalShortcutListenerWin::~GlobalShortcutListenerWin() { 31 if (is_listening_) 32 StopListening(); 33 } 34 35 void GlobalShortcutListenerWin::StartListening() { 36 DCHECK(!is_listening_); // Don't start twice. 37 DCHECK(!hotkey_ids_.empty()); // Also don't start if no hotkey is registered. 38 gfx::SingletonHwnd::GetInstance()->AddObserver(this); 39 is_listening_ = true; 40 } 41 42 void GlobalShortcutListenerWin::StopListening() { 43 DCHECK(is_listening_); // No point if we are not already listening. 44 DCHECK(hotkey_ids_.empty()); // Make sure the map is clean before ending. 45 gfx::SingletonHwnd::GetInstance()->RemoveObserver(this); 46 is_listening_ = false; 47 } 48 49 void GlobalShortcutListenerWin::OnWndProc(HWND hwnd, 50 UINT message, 51 WPARAM wparam, 52 LPARAM lparam) { 53 if (message != WM_HOTKEY) 54 return; 55 56 int key_code = HIWORD(lparam); 57 int modifiers = 0; 58 modifiers |= (LOWORD(lparam) & MOD_SHIFT) ? ui::EF_SHIFT_DOWN : 0; 59 modifiers |= (LOWORD(lparam) & MOD_ALT) ? ui::EF_ALT_DOWN : 0; 60 modifiers |= (LOWORD(lparam) & MOD_CONTROL) ? ui::EF_CONTROL_DOWN : 0; 61 ui::Accelerator accelerator( 62 ui::KeyboardCodeForWindowsKeyCode(key_code), modifiers); 63 64 NotifyKeyPressed(accelerator); 65 } 66 67 bool GlobalShortcutListenerWin::RegisterAcceleratorImpl( 68 const ui::Accelerator& accelerator) { 69 DCHECK(hotkey_ids_.find(accelerator) == hotkey_ids_.end()); 70 71 int modifiers = 0; 72 modifiers |= accelerator.IsShiftDown() ? MOD_SHIFT : 0; 73 modifiers |= accelerator.IsCtrlDown() ? MOD_CONTROL : 0; 74 modifiers |= accelerator.IsAltDown() ? MOD_ALT : 0; 75 static int hotkey_id = 0; 76 bool success = !!RegisterHotKey( 77 gfx::SingletonHwnd::GetInstance()->hwnd(), 78 hotkey_id, 79 modifiers, 80 accelerator.key_code()); 81 82 if (!success) { 83 // Most likely error: 1409 (Hotkey already registered). 84 return false; 85 } 86 87 hotkey_ids_[accelerator] = hotkey_id++; 88 return true; 89 } 90 91 void GlobalShortcutListenerWin::UnregisterAcceleratorImpl( 92 const ui::Accelerator& accelerator) { 93 HotkeyIdMap::iterator it = hotkey_ids_.find(accelerator); 94 DCHECK(it != hotkey_ids_.end()); 95 96 bool success = !!UnregisterHotKey( 97 gfx::SingletonHwnd::GetInstance()->hwnd(), it->second); 98 // This call should always succeed, as long as we pass in the right HWND and 99 // an id we've used to register before. 100 DCHECK(success); 101 102 hotkey_ids_.erase(it); 103 } 104 105 } // namespace extensions 106