* Copyright (C) 2005 Evgeniy <dushistov@mail.ru>
* Copyright 2011 kubtek <kubtek@mail.com>
*
* This file is part of StarDict.
*
* StarDict is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* StarDict is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with StarDict. If not, see <http://www.gnu.org/licenses/>.
*/
* goal: react on key press even if there are window
* have no focus in XWindows. This code based on xbindkeys.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "gtk_iskeyspressed.h"
#include "x11_iskeyspressed.h"
#include <X11/XKBlib.h>
unsigned int x11_hotkeys::numlock_mask, x11_hotkeys::scrolllock_mask,
x11_hotkeys::capslock_mask;
void x11_hotkeys::get_offending_modifiers(Display * dpy)
{
int i;
XModifierKeymap *modmap;
KeyCode nlock, slock;
static int mask_table[8] = {
ShiftMask, LockMask, ControlMask, Mod1Mask,
Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
};
nlock = XKeysymToKeycode (dpy, XK_Num_Lock);
slock = XKeysymToKeycode (dpy, XK_Scroll_Lock);
* Find out the masks for the NumLock and ScrollLock modifiers,
* so that we can bind the grabs for when they are enabled too.
*/
modmap = XGetModifierMapping (dpy);
if (modmap != NULL && modmap->max_keypermod > 0) {
for (i = 0; i < 8 * modmap->max_keypermod; i++) {
if (modmap->modifiermap[i] == nlock && nlock != 0)
numlock_mask = mask_table[i / modmap->max_keypermod];
else if (modmap->modifiermap[i] == slock && slock != 0)
scrolllock_mask = mask_table[i / modmap->max_keypermod];
}
}
capslock_mask = LockMask;
if (modmap)
XFreeModifiermap (modmap);
}
void x11_hotkeys::my_grab_key(Display * dpy, KeyCode keycode,
unsigned int modifier, Window win)
{
modifier &= ~(numlock_mask | capslock_mask | scrolllock_mask);
XGrabKey(dpy, keycode, modifier, (win ? win : DefaultRootWindow(dpy)),
False, GrabModeAsync, GrabModeAsync);
if (modifier == AnyModifier)
return;
if (numlock_mask)
XGrabKey (dpy, keycode, modifier | numlock_mask,
(win ? win : DefaultRootWindow (dpy)),
False, GrabModeAsync, GrabModeAsync);
if (capslock_mask)
XGrabKey (dpy, keycode, modifier | capslock_mask,
(win ? win : DefaultRootWindow (dpy)),
False, GrabModeAsync, GrabModeAsync);
if (scrolllock_mask)
XGrabKey (dpy, keycode, modifier | scrolllock_mask,
(win ? win : DefaultRootWindow (dpy)),
False, GrabModeAsync, GrabModeAsync);
if (numlock_mask && capslock_mask)
XGrabKey (dpy, keycode, modifier | numlock_mask | capslock_mask,
(win ? win : DefaultRootWindow (dpy)),
False, GrabModeAsync, GrabModeAsync);
if (numlock_mask && scrolllock_mask)
XGrabKey (dpy, keycode, modifier | numlock_mask | scrolllock_mask,
(win ? win : DefaultRootWindow (dpy)),
False, GrabModeAsync, GrabModeAsync);
if (capslock_mask && scrolllock_mask)
XGrabKey (dpy, keycode, modifier | capslock_mask | scrolllock_mask,
(win ? win : DefaultRootWindow (dpy)),
False, GrabModeAsync, GrabModeAsync);
if (numlock_mask && capslock_mask && scrolllock_mask)
XGrabKey (dpy, keycode,
modifier | numlock_mask | capslock_mask | scrolllock_mask,
(win ? win : DefaultRootWindow (dpy)), False, GrabModeAsync,
GrabModeAsync);
}
void x11_hotkeys::my_grab_button(Display * dpy, unsigned int button,
unsigned int modifier, Window win)
{
modifier &= ~(numlock_mask | capslock_mask | scrolllock_mask);
XGrabButton (dpy, button, modifier, (win ? win : DefaultRootWindow (dpy)),
False, ButtonPressMask | ButtonReleaseMask,
GrabModeAsync, GrabModeAsync, None, None);
if (modifier == AnyModifier)
return;
if (numlock_mask)
XGrabButton (dpy, button, modifier | numlock_mask,
(win ? win : DefaultRootWindow (dpy)),
False, ButtonPressMask | ButtonReleaseMask,
GrabModeAsync, GrabModeAsync, None, None);
if (capslock_mask)
XGrabButton (dpy, button, modifier | capslock_mask,
(win ? win : DefaultRootWindow (dpy)),
False, ButtonPressMask | ButtonReleaseMask,
GrabModeAsync, GrabModeAsync, None, None);
if (scrolllock_mask)
XGrabButton (dpy, button, modifier | scrolllock_mask,
(win ? win : DefaultRootWindow (dpy)),
False, ButtonPressMask | ButtonReleaseMask,
GrabModeAsync, GrabModeAsync, None, None);
if (numlock_mask && capslock_mask)
XGrabButton (dpy, button, modifier | numlock_mask | capslock_mask,
(win ? win : DefaultRootWindow (dpy)),
False, ButtonPressMask | ButtonReleaseMask,
GrabModeAsync, GrabModeAsync, None, None);
if (numlock_mask && scrolllock_mask)
XGrabButton (dpy, button, modifier | numlock_mask | scrolllock_mask,
(win ? win : DefaultRootWindow (dpy)),
False, ButtonPressMask | ButtonReleaseMask,
GrabModeAsync, GrabModeAsync, None, None);
if (capslock_mask && scrolllock_mask)
XGrabButton (dpy, button, modifier | capslock_mask | scrolllock_mask,
(win ? win : DefaultRootWindow (dpy)),
False, ButtonPressMask | ButtonReleaseMask,
GrabModeAsync, GrabModeAsync, None, None);
if (numlock_mask && capslock_mask && scrolllock_mask)
XGrabButton (dpy, button,
modifier | numlock_mask | capslock_mask | scrolllock_mask,
(win ? win : DefaultRootWindow (dpy)), False,
ButtonPressMask | ButtonReleaseMask, GrabModeAsync,
GrabModeAsync, None, None);
}
bool x11_hotkeys::grab_keys(Display *dpy, Keys_t keys[], int nb_keys)
{
int i;
int min, max;
int screen;
XDisplayKeycodes(dpy, &min, &max);
#ifdef DEBUG
printf("\n");
printf("min_keycode=%d max_keycode=%d (ie: know keycodes)\n",
min, max);
#endif
for (i = 0; i < nb_keys; i++) {
#ifdef DEBUG
print_key(dpy, &keys[i]);
#endif
if (keys[i].type == SYM) {
for (screen = 0; screen < ScreenCount (dpy); screen++) {
my_grab_key(dpy, XKeysymToKeycode(dpy, keys[i].key.sym),
keys[i].modifier, RootWindow(dpy, screen));
}
} else if (keys[i].type == BUTTON) {
for (screen = 0; screen < ScreenCount (dpy); screen++) {
my_grab_button(dpy, keys[i].key.button, keys[i].modifier,
RootWindow (dpy, screen));
}
} else {
if (keys[i].key.code >= min && keys[i].key.code <= max) {
for (screen = 0; screen < ScreenCount (dpy); screen++) {
my_grab_key (dpy, keys[i].key.code, keys[i].modifier,
RootWindow (dpy, screen));
}
} else {
#ifdef DEBUG
print_key (dpy, &keys[i]);
fprintf (stderr,
" The keycode %d cannot be used, as it's not between the\n"
" min(%d) and max(%d) keycode of your keyboard.\n"
" Please increase the 'maximum' value in\n"
" /usr/X11R6/lib/X11/xkb/keycodes/xfree86,\n"
" then restart X.\n", keys[i].key.code, min, max);
#endif
return false;
}
}
}
return true;
}
x11_hotkeys::x11_hotkeys(GtkWindow *win_) :
win(win_),
pressed(false),
def_hot_keys(new gtk_hotkeys(win_))
{
possb_combs=def_hot_keys->possible_combs();
possb_combs.push_back("Ctrl+e");
possb_combs.push_back("Win+d");
possb_combs.push_back("F1");
possb_combs.push_back("F2");
possb_combs.push_back("F3");
possb_combs.push_back("F4");
display=gdk_x11_display_get_xdisplay(gdk_screen_get_display(gtk_window_get_screen(win)));
get_offending_modifiers(display);
gdk_window_add_filter(NULL, GdkFilterFunc(key_filter), this);
}
x11_hotkeys::~x11_hotkeys()
{
ungrabkeys();
}
const std::list<std::string>& x11_hotkeys::possible_combs()
{
return possb_combs;
}
void x11_hotkeys::set_comb(const std::string& val)
{
if (comb==val)
return;
unsigned int modifier=0;
KeySym key=0;
std::string::size_type pos=std::string::npos;
do {
std::string::size_type prev_pos=pos;
pos=val.find('+', pos+1);
std::string cur;
if (pos!=std::string::npos)
cur.assign(val, prev_pos+1, pos-prev_pos-1);
else
cur.assign(val, prev_pos+1, val.length()-prev_pos-1);
if (cur=="Ctrl") {
modifier|=ControlMask;
} else if (cur=="Alt") {
modifier|=Mod1Mask;
} else if (cur=="Shift") {
modifier|=ShiftMask;
} else if (cur=="Win") {
modifier|=Mod4Mask;
} else {
key=XStringToKeysym(cur.c_str());
}
} while (pos!=std::string::npos);
comb=val;
pressed=false;
grab_key.key.sym=0;
if (key!=0) {
ungrabkeys();
grab_key.type=SYM;
grab_key.event_type=PRESS;
grab_key.key.sym=key;
grab_key.modifier=modifier;
grab_keys(display, &grab_key, 1);
} else
def_hot_keys->set_comb(val);
}
bool x11_hotkeys::is_pressed()
{
if (grab_key.key.sym!=0)
return pressed;
return def_hot_keys->is_pressed();
}
void x11_hotkeys::ungrabkeys()
{
if (grab_key.key.sym==0)
return;
Display *d=display;
for (int screen = 0; screen<ScreenCount(d); screen++) {
XUngrabKey(d, AnyKey, AnyModifier, RootWindow (d, screen));
XUngrabButton(d, AnyButton, AnyModifier, RootWindow (d, screen));
}
}
GdkFilterReturn x11_hotkeys::key_filter(GdkXEvent *gdk_xevent,
GdkEvent *event,
x11_hotkeys *th)
{
int type;
XKeyEvent *xevent;
xevent = (XKeyEvent *)gdk_xevent;
type = xevent->type;
KeySym keysym = XkbKeycodeToKeysym(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), ((XKeyEvent *)xevent)->keycode, 0, 0);
unsigned int state=xevent->state;
state &= ~(numlock_mask | capslock_mask | scrolllock_mask);
if (type == KeyPress) {
if (keysym==th->grab_key.key.sym && state==th->grab_key.modifier) {
th->pressed=true;
}
} else if (type==KeyRelease) {
if (keysym==th->grab_key.key.sym) {
th->pressed=false;
}
}
return GDK_FILTER_CONTINUE;
}