linux: Implement global keyboard shortcut API.
This commit is contained in:
parent
c2c5111d75
commit
a8034364ff
3 changed files with 226 additions and 0 deletions
2
atom.gyp
2
atom.gyp
|
@ -238,6 +238,8 @@
|
||||||
'chromium_src/chrome/browser/ui/shortcut/global_shortcut_listener.h',
|
'chromium_src/chrome/browser/ui/shortcut/global_shortcut_listener.h',
|
||||||
'chromium_src/chrome/browser/ui/shortcut/global_shortcut_listener_mac.mm',
|
'chromium_src/chrome/browser/ui/shortcut/global_shortcut_listener_mac.mm',
|
||||||
'chromium_src/chrome/browser/ui/shortcut/global_shortcut_listener_mac.h',
|
'chromium_src/chrome/browser/ui/shortcut/global_shortcut_listener_mac.h',
|
||||||
|
'chromium_src/chrome/browser/ui/shortcut/global_shortcut_listener_x11.cc',
|
||||||
|
'chromium_src/chrome/browser/ui/shortcut/global_shortcut_listener_x11.h',
|
||||||
'chromium_src/chrome/browser/ui/shortcut/global_shortcut_listener_win.cc',
|
'chromium_src/chrome/browser/ui/shortcut/global_shortcut_listener_win.cc',
|
||||||
'chromium_src/chrome/browser/ui/shortcut/global_shortcut_listener_win.h',
|
'chromium_src/chrome/browser/ui/shortcut/global_shortcut_listener_win.h',
|
||||||
'<@(native_mate_files)',
|
'<@(native_mate_files)',
|
||||||
|
|
160
chromium_src/chrome/browser/ui/shortcut/global_shortcut_listener_x11.cc
Executable file
160
chromium_src/chrome/browser/ui/shortcut/global_shortcut_listener_x11.cc
Executable file
|
@ -0,0 +1,160 @@
|
||||||
|
// Copyright 2014 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/ui/shortcut/global_shortcut_listener_x11.h"
|
||||||
|
|
||||||
|
#include "base/message_loop/message_pump_x11.h"
|
||||||
|
#include "content/public/browser/browser_thread.h"
|
||||||
|
#include "ui/base/accelerators/accelerator.h"
|
||||||
|
#include "ui/events/keycodes/keyboard_code_conversion_x.h"
|
||||||
|
#include "ui/gfx/x/x11_error_tracker.h"
|
||||||
|
#include "ui/gfx/x/x11_types.h"
|
||||||
|
|
||||||
|
using content::BrowserThread;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// The modifiers masks used for grabing keys. Due to XGrabKey only working on
|
||||||
|
// exact modifiers, we need to grab all key combination including zero or more
|
||||||
|
// of the following: Num lock, Caps lock and Scroll lock. So that we can make
|
||||||
|
// sure the behavior of global shortcuts is consistent on all platforms.
|
||||||
|
const unsigned int kModifiersMasks[] = {
|
||||||
|
0, // No additional modifier.
|
||||||
|
Mod2Mask, // Num lock
|
||||||
|
LockMask, // Caps lock
|
||||||
|
Mod5Mask, // Scroll lock
|
||||||
|
Mod2Mask | LockMask,
|
||||||
|
Mod2Mask | Mod5Mask,
|
||||||
|
LockMask | Mod5Mask,
|
||||||
|
Mod2Mask | LockMask | Mod5Mask
|
||||||
|
};
|
||||||
|
|
||||||
|
int GetNativeModifiers(const ui::Accelerator& accelerator) {
|
||||||
|
int modifiers = 0;
|
||||||
|
modifiers |= accelerator.IsShiftDown() ? ShiftMask : 0;
|
||||||
|
modifiers |= accelerator.IsCtrlDown() ? ControlMask : 0;
|
||||||
|
modifiers |= accelerator.IsAltDown() ? Mod1Mask : 0;
|
||||||
|
|
||||||
|
return modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
namespace api {
|
||||||
|
|
||||||
|
// static
|
||||||
|
GlobalShortcutListener* GlobalShortcutListener::GetInstance() {
|
||||||
|
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||||
|
static GlobalShortcutListenerX11* instance =
|
||||||
|
new GlobalShortcutListenerX11();
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalShortcutListenerX11::GlobalShortcutListenerX11()
|
||||||
|
: is_listening_(false),
|
||||||
|
x_display_(gfx::GetXDisplay()),
|
||||||
|
x_root_window_(DefaultRootWindow(x_display_)) {
|
||||||
|
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalShortcutListenerX11::~GlobalShortcutListenerX11() {
|
||||||
|
if (is_listening_)
|
||||||
|
StopListening();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GlobalShortcutListenerX11::IsAcceleratorRegistered(
|
||||||
|
const ui::Accelerator& accelerator) {
|
||||||
|
return registered_hot_keys_.find(accelerator) != registered_hot_keys_.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalShortcutListenerX11::StartListening() {
|
||||||
|
DCHECK(!is_listening_); // Don't start twice.
|
||||||
|
DCHECK(!registered_hot_keys_.empty()); // Also don't start if no hotkey is
|
||||||
|
// registered.
|
||||||
|
base::MessagePumpX11::Current()->AddDispatcherForRootWindow(this);
|
||||||
|
|
||||||
|
is_listening_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalShortcutListenerX11::StopListening() {
|
||||||
|
DCHECK(is_listening_); // No point if we are not already listening.
|
||||||
|
DCHECK(registered_hot_keys_.empty()); // Make sure the set is clean before
|
||||||
|
// ending.
|
||||||
|
|
||||||
|
base::MessagePumpX11::Current()->RemoveDispatcherForRootWindow(this);
|
||||||
|
|
||||||
|
is_listening_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t GlobalShortcutListenerX11::Dispatch(const base::NativeEvent& event) {
|
||||||
|
if (event->type == KeyPress)
|
||||||
|
OnXKeyPressEvent(event);
|
||||||
|
|
||||||
|
return POST_DISPATCH_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GlobalShortcutListenerX11::RegisterAcceleratorImpl(
|
||||||
|
const ui::Accelerator& accelerator) {
|
||||||
|
DCHECK(registered_hot_keys_.find(accelerator) == registered_hot_keys_.end());
|
||||||
|
|
||||||
|
int modifiers = GetNativeModifiers(accelerator);
|
||||||
|
KeyCode keycode = XKeysymToKeycode(x_display_,
|
||||||
|
XKeysymForWindowsKeyCode(accelerator.key_code(), false));
|
||||||
|
gfx::X11ErrorTracker err_tracker;
|
||||||
|
|
||||||
|
// Because XGrabKey only works on the exact modifiers mask, we should register
|
||||||
|
// our hot keys with modifiers that we want to ignore, including Num lock,
|
||||||
|
// Caps lock, Scroll lock. See comment about |kModifiersMasks|.
|
||||||
|
for (size_t i = 0; i < arraysize(kModifiersMasks); ++i) {
|
||||||
|
XGrabKey(x_display_, keycode, modifiers | kModifiersMasks[i],
|
||||||
|
x_root_window_, False, GrabModeAsync, GrabModeAsync);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err_tracker.FoundNewError()) {
|
||||||
|
// We may have part of the hotkeys registered, clean up.
|
||||||
|
for (size_t i = 0; i < arraysize(kModifiersMasks); ++i) {
|
||||||
|
XUngrabKey(x_display_, keycode, modifiers | kModifiersMasks[i],
|
||||||
|
x_root_window_);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
registered_hot_keys_.insert(accelerator);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalShortcutListenerX11::UnregisterAcceleratorImpl(
|
||||||
|
const ui::Accelerator& accelerator) {
|
||||||
|
DCHECK(registered_hot_keys_.find(accelerator) != registered_hot_keys_.end());
|
||||||
|
|
||||||
|
int modifiers = GetNativeModifiers(accelerator);
|
||||||
|
KeyCode keycode = XKeysymToKeycode(x_display_,
|
||||||
|
XKeysymForWindowsKeyCode(accelerator.key_code(), false));
|
||||||
|
|
||||||
|
for (size_t i = 0; i < arraysize(kModifiersMasks); ++i) {
|
||||||
|
XUngrabKey(x_display_, keycode, modifiers | kModifiersMasks[i],
|
||||||
|
x_root_window_);
|
||||||
|
}
|
||||||
|
registered_hot_keys_.erase(accelerator);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalShortcutListenerX11::OnXKeyPressEvent(::XEvent* x_event) {
|
||||||
|
DCHECK(x_event->type == KeyPress);
|
||||||
|
int modifiers = 0;
|
||||||
|
modifiers |= (x_event->xkey.state & ShiftMask) ? ui::EF_SHIFT_DOWN : 0;
|
||||||
|
modifiers |= (x_event->xkey.state & ControlMask) ? ui::EF_CONTROL_DOWN : 0;
|
||||||
|
modifiers |= (x_event->xkey.state & Mod1Mask) ? ui::EF_ALT_DOWN : 0;
|
||||||
|
|
||||||
|
ui::Accelerator accelerator(
|
||||||
|
ui::KeyboardCodeFromXKeyEvent(x_event), modifiers);
|
||||||
|
if (registered_hot_keys_.find(accelerator) != registered_hot_keys_.end())
|
||||||
|
NotifyKeyPressed(accelerator);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace api
|
||||||
|
|
||||||
|
} // namespace atom
|
64
chromium_src/chrome/browser/ui/shortcut/global_shortcut_listener_x11.h
Executable file
64
chromium_src/chrome/browser/ui/shortcut/global_shortcut_listener_x11.h
Executable file
|
@ -0,0 +1,64 @@
|
||||||
|
// Copyright 2014 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 CHROME_BROWSER_UI_SHORTCUT_GLOBAL_SHORTCUT_LISTENER_X11_H_
|
||||||
|
#define CHROME_BROWSER_UI_SHORTCUT_GLOBAL_SHORTCUT_LISTENER_X11_H_
|
||||||
|
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include "base/message_loop/message_pump_dispatcher.h"
|
||||||
|
#include "chrome/browser/ui/shortcut/global_shortcut_listener.h"
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
namespace api {
|
||||||
|
|
||||||
|
// X11-specific implementation of the GlobalShortcutListener class that
|
||||||
|
// listens for global shortcuts. Handles basic keyboard intercepting and
|
||||||
|
// forwards its output to the base class for processing.
|
||||||
|
class GlobalShortcutListenerX11
|
||||||
|
: public base::MessagePumpDispatcher,
|
||||||
|
public GlobalShortcutListener {
|
||||||
|
public:
|
||||||
|
GlobalShortcutListenerX11();
|
||||||
|
virtual ~GlobalShortcutListenerX11();
|
||||||
|
|
||||||
|
// base::MessagePumpDispatcher implementation.
|
||||||
|
virtual uint32_t Dispatch(const base::NativeEvent& event) OVERRIDE;
|
||||||
|
|
||||||
|
virtual bool IsAcceleratorRegistered(
|
||||||
|
const ui::Accelerator& accelerator) OVERRIDE;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// GlobalShortcutListener implementation.
|
||||||
|
virtual void StartListening() OVERRIDE;
|
||||||
|
virtual void StopListening() OVERRIDE;
|
||||||
|
virtual bool RegisterAcceleratorImpl(
|
||||||
|
const ui::Accelerator& accelerator) OVERRIDE;
|
||||||
|
virtual void UnregisterAcceleratorImpl(
|
||||||
|
const ui::Accelerator& accelerator) OVERRIDE;
|
||||||
|
|
||||||
|
// Invoked when a global shortcut is pressed.
|
||||||
|
void OnXKeyPressEvent(::XEvent* x_event);
|
||||||
|
|
||||||
|
// Whether this object is listening for global shortcuts.
|
||||||
|
bool is_listening_;
|
||||||
|
|
||||||
|
// The x11 default display and the native root window.
|
||||||
|
::Display* x_display_;
|
||||||
|
::Window x_root_window_;
|
||||||
|
|
||||||
|
// A set of registered accelerators.
|
||||||
|
typedef std::set<ui::Accelerator> RegisteredHotKeys;
|
||||||
|
RegisteredHotKeys registered_hot_keys_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(GlobalShortcutListenerX11);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace api
|
||||||
|
|
||||||
|
} // namespace atom
|
||||||
|
|
||||||
|
#endif // CHROME_BROWSER_UI_SHORTCUT_GLOBAL_SHORTCUT_LISTENER_X11_H_
|
Loading…
Add table
Add a link
Reference in a new issue