• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.h"
6 
7 #include "base/logging.h"
8 #include "content/public/browser/browser_thread.h"
9 #include "ui/base/accelerators/accelerator.h"
10 
11 using content::BrowserThread;
12 
13 namespace extensions {
14 
GlobalShortcutListener()15 GlobalShortcutListener::GlobalShortcutListener()
16     : shortcut_handling_suspended_(false) {
17   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
18 }
19 
~GlobalShortcutListener()20 GlobalShortcutListener::~GlobalShortcutListener() {
21   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
22   DCHECK(accelerator_map_.empty());  // Make sure we've cleaned up.
23 }
24 
RegisterAccelerator(const ui::Accelerator & accelerator,Observer * observer)25 bool GlobalShortcutListener::RegisterAccelerator(
26     const ui::Accelerator& accelerator, Observer* observer) {
27   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
28   if (IsShortcutHandlingSuspended())
29     return false;
30 
31   AcceleratorMap::const_iterator it = accelerator_map_.find(accelerator);
32   if (it != accelerator_map_.end()) {
33     // The accelerator has been registered.
34     return false;
35   }
36 
37   if (!RegisterAcceleratorImpl(accelerator)) {
38     // If the platform-specific registration fails, mostly likely the shortcut
39     // has been registered by other native applications.
40     return false;
41   }
42 
43   if (accelerator_map_.empty())
44     StartListening();
45 
46   accelerator_map_[accelerator] = observer;
47   return true;
48 }
49 
UnregisterAccelerator(const ui::Accelerator & accelerator,Observer * observer)50 void GlobalShortcutListener::UnregisterAccelerator(
51     const ui::Accelerator& accelerator, Observer* observer) {
52   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
53   if (IsShortcutHandlingSuspended())
54     return;
55 
56   AcceleratorMap::iterator it = accelerator_map_.find(accelerator);
57   // We should never get asked to unregister something that we didn't register.
58   DCHECK(it != accelerator_map_.end());
59   // The caller should call this function with the right observer.
60   DCHECK(it->second == observer);
61 
62   UnregisterAcceleratorImpl(accelerator);
63   accelerator_map_.erase(it);
64   if (accelerator_map_.empty())
65     StopListening();
66 }
67 
UnregisterAccelerators(Observer * observer)68 void GlobalShortcutListener::UnregisterAccelerators(Observer* observer) {
69   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
70   if (IsShortcutHandlingSuspended())
71     return;
72 
73   AcceleratorMap::iterator it = accelerator_map_.begin();
74   while (it != accelerator_map_.end()) {
75     if (it->second == observer) {
76       AcceleratorMap::iterator to_remove = it++;
77       UnregisterAccelerator(to_remove->first, observer);
78     } else {
79       ++it;
80     }
81   }
82 }
83 
SetShortcutHandlingSuspended(bool suspended)84 void GlobalShortcutListener::SetShortcutHandlingSuspended(bool suspended) {
85   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
86   if (shortcut_handling_suspended_ == suspended)
87     return;
88 
89   shortcut_handling_suspended_ = suspended;
90   for (AcceleratorMap::iterator it = accelerator_map_.begin();
91        it != accelerator_map_.end();
92        ++it) {
93     // On Linux, when shortcut handling is suspended we cannot simply early
94     // return in NotifyKeyPressed (similar to what we do for non-global
95     // shortcuts) because we'd eat the keyboard event thereby preventing the
96     // user from setting the shortcut. Therefore we must unregister while
97     // handling is suspended and register when handling resumes.
98     if (shortcut_handling_suspended_)
99       UnregisterAcceleratorImpl(it->first);
100     else
101       RegisterAcceleratorImpl(it->first);
102   }
103 }
104 
IsShortcutHandlingSuspended() const105 bool GlobalShortcutListener::IsShortcutHandlingSuspended() const {
106   return shortcut_handling_suspended_;
107 }
108 
NotifyKeyPressed(const ui::Accelerator & accelerator)109 void GlobalShortcutListener::NotifyKeyPressed(
110     const ui::Accelerator& accelerator) {
111   AcceleratorMap::iterator iter = accelerator_map_.find(accelerator);
112   if (iter == accelerator_map_.end()) {
113     // This should never occur, because if it does, we have failed to unregister
114     // or failed to clean up the map after unregistering the shortcut.
115     NOTREACHED();
116     return;  // No-one is listening to this key.
117   }
118 
119   iter->second->OnKeyPressed(accelerator);
120 }
121 
122 }  // namespace extensions
123