18bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved. 28bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 38bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// found in the LICENSE file. 48bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 58bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "chrome/browser/extensions/global_shortcut_listener.h" 65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/logging.h" 85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "content/public/browser/browser_thread.h" 98bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "ui/base/accelerators/accelerator.h" 108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using content::BrowserThread; 125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)namespace extensions { 148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 15effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochGlobalShortcutListener::GlobalShortcutListener() 16effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch : shortcut_handling_suspended_(false) { 175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)GlobalShortcutListener::~GlobalShortcutListener() { 215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) DCHECK(accelerator_map_.empty()); // Make sure we've cleaned up. 238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GlobalShortcutListener::RegisterAccelerator( 268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) const ui::Accelerator& accelerator, Observer* observer) { 275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 28effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (IsShortcutHandlingSuspended()) 29effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return false; 305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) AcceleratorMap::const_iterator it = accelerator_map_.find(accelerator); 325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (it != accelerator_map_.end()) { 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // The accelerator has been registered. 345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!RegisterAcceleratorImpl(accelerator)) { 385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // If the platform-specific registration fails, mostly likely the shortcut 395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // has been registered by other native applications. 405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (accelerator_map_.empty()) 445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) StartListening(); 455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) accelerator_map_[accelerator] = observer; 475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return true; 488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void GlobalShortcutListener::UnregisterAccelerator( 518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) const ui::Accelerator& accelerator, Observer* observer) { 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 53effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (IsShortcutHandlingSuspended()) 54effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return; 555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) AcceleratorMap::iterator it = accelerator_map_.find(accelerator); 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // We should never get asked to unregister something that we didn't register. 588bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) DCHECK(it != accelerator_map_.end()); 595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // The caller should call this function with the right observer. 605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(it->second == observer); 615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) UnregisterAcceleratorImpl(accelerator); 635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) accelerator_map_.erase(it); 645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (accelerator_map_.empty()) 655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) StopListening(); 668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GlobalShortcutListener::UnregisterAccelerators(Observer* observer) { 69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 70effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (IsShortcutHandlingSuspended()) 71effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return; 72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) AcceleratorMap::iterator it = accelerator_map_.begin(); 74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) while (it != accelerator_map_.end()) { 75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (it->second == observer) { 76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) AcceleratorMap::iterator to_remove = it++; 77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) UnregisterAccelerator(to_remove->first, observer); 78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } else { 79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ++it; 80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 84effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid GlobalShortcutListener::SetShortcutHandlingSuspended(bool suspended) { 85effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 86effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (shortcut_handling_suspended_ == suspended) 87effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return; 88effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 89effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch shortcut_handling_suspended_ = suspended; 90effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch for (AcceleratorMap::iterator it = accelerator_map_.begin(); 91effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch it != accelerator_map_.end(); 92effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch ++it) { 93effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // On Linux, when shortcut handling is suspended we cannot simply early 94effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // return in NotifyKeyPressed (similar to what we do for non-global 95effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // shortcuts) because we'd eat the keyboard event thereby preventing the 96effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // user from setting the shortcut. Therefore we must unregister while 97effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // handling is suspended and register when handling resumes. 98effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (shortcut_handling_suspended_) 99effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch UnregisterAcceleratorImpl(it->first); 100effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch else 101effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch RegisterAcceleratorImpl(it->first); 102effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 103effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 104effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 105effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochbool GlobalShortcutListener::IsShortcutHandlingSuspended() const { 106effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return shortcut_handling_suspended_; 107effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 108effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 1098bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void GlobalShortcutListener::NotifyKeyPressed( 1108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) const ui::Accelerator& accelerator) { 1118bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) AcceleratorMap::iterator iter = accelerator_map_.find(accelerator); 1128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (iter == accelerator_map_.end()) { 1138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // This should never occur, because if it does, we have failed to unregister 1148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // or failed to clean up the map after unregistering the shortcut. 1158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) NOTREACHED(); 1168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return; // No-one is listening to this key. 1178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 1188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) iter->second->OnKeyPressed(accelerator); 1208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 1218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} // namespace extensions 123