This source file includes following definitions.
- GetNativeModifiers
- GetInstance
- x_root_window_
- StartListening
- StopListening
- Dispatch
- RegisterAcceleratorImpl
- UnregisterAcceleratorImpl
- OnXEvent
- OnXKeyPressEvent
#include "chrome/browser/extensions/global_shortcut_listener_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"
#if defined(TOOLKIT_GTK)
#include <gdk/gdkx.h>
#else
#include "base/message_loop/message_pump_x11.h"
#endif
using content::BrowserThread;
namespace {
const unsigned int kModifiersMasks[] = {
0,
Mod2Mask,
LockMask,
Mod5Mask,
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 extensions {
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();
}
void GlobalShortcutListenerX11::StartListening() {
DCHECK(!is_listening_);
DCHECK(!registered_hot_keys_.empty());
#if defined(TOOLKIT_GTK)
gdk_window_add_filter(gdk_get_default_root_window(),
&GlobalShortcutListenerX11::OnXEventThunk,
this);
#else
base::MessagePumpX11::Current()->AddDispatcherForRootWindow(this);
#endif
is_listening_ = true;
}
void GlobalShortcutListenerX11::StopListening() {
DCHECK(is_listening_);
DCHECK(registered_hot_keys_.empty());
#if defined(TOOLKIT_GTK)
gdk_window_remove_filter(NULL,
&GlobalShortcutListenerX11::OnXEventThunk,
this);
#else
base::MessagePumpX11::Current()->RemoveDispatcherForRootWindow(this);
#endif
is_listening_ = false;
}
#if !defined(TOOLKIT_GTK)
uint32_t GlobalShortcutListenerX11::Dispatch(const base::NativeEvent& event) {
if (event->type == KeyPress)
OnXKeyPressEvent(event);
return POST_DISPATCH_NONE;
}
#endif
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;
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()) {
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);
}
#if defined(TOOLKIT_GTK)
GdkFilterReturn GlobalShortcutListenerX11::OnXEvent(GdkXEvent* gdk_x_event,
GdkEvent* gdk_event) {
XEvent* x_event = static_cast<XEvent*>(gdk_x_event);
if (x_event->type == KeyPress)
OnXKeyPressEvent(x_event);
return GDK_FILTER_CONTINUE;
}
#endif
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);
}
}