1 #include "xkeygrabber.h"
2
3 #include <X11/X.h>
4 #include <X11/XKBlib.h>
5 #include <X11/Xlib.h>
6 #include <X11/keysym.h>
7
8 #include "globals.h"
9
10 using std::vector;
11 using std::string;
12
XKeyGrabber()13 XKeyGrabber::XKeyGrabber() {
14 updateNumlockMask();
15 }
16
17 //! Obtains the current numlock mask value
updateNumlockMask()18 void XKeyGrabber::updateNumlockMask() {
19 XModifierKeymap *modmap;
20
21 numlockMask_ = 0;
22 modmap = XGetModifierMapping(g_display);
23 for (size_t i = 0; i < 8; i++) {
24 for (int j = 0; j < modmap->max_keypermod; j++) {
25 if (modmap->modifiermap[i * modmap->max_keypermod + j]
26 == XKeysymToKeycode(g_display, XK_Num_Lock)) {
27 numlockMask_ = (1 << i);
28 }
29 }
30 }
31 XFreeModifiermap(modmap);
32 }
33
34 /*!
35 * Derives a "normalized" KeyCombo from a given event.
36 *
37 * Normalization means stripping any ignored modifiers from the modifier mask
38 * (including the runtime-defined Numlock mask).
39 */
xEventToKeyCombo(XKeyEvent * ev) const40 KeyCombo XKeyGrabber::xEventToKeyCombo(XKeyEvent* ev) const {
41 KeyCombo combo = {};
42 combo.keysym = XkbKeycodeToKeysym(g_display, ev->keycode, 0, 0);
43 combo.modifiers_ = ev->state;
44
45 // Normalize
46 combo.modifiers_ &= ~(numlockMask_ | LockMask);
47
48 return combo;
49 }
50
51 //! Grabs the given key combo
grabKeyCombo(const KeyCombo & keyCombo)52 void XKeyGrabber::grabKeyCombo(const KeyCombo& keyCombo) {
53 changeGrabbedState(keyCombo, true);
54 }
55
56 //! Ungrabs the given key combo
ungrabKeyCombo(const KeyCombo & keyCombo)57 void XKeyGrabber::ungrabKeyCombo(const KeyCombo& keyCombo) {
58 changeGrabbedState(keyCombo, false);
59 }
60
61 //! Removes all grabbed keys (without knowing them)
ungrabAll()62 void XKeyGrabber::ungrabAll() {
63 XUngrabKey(g_display, AnyKey, AnyModifier, g_root);
64 }
65
66 //! Grabs/ungrabs a given key combo
changeGrabbedState(const KeyCombo & keyCombo,bool grabbed)67 void XKeyGrabber::changeGrabbedState(const KeyCombo& keyCombo, bool grabbed) {
68 // List of ignored modifiers (key combo will be grabbed for each of them):
69 const unsigned int ignModifiers[] = { 0, LockMask, numlockMask_, numlockMask_ | LockMask };
70
71 KeyCode keycode = XKeysymToKeycode(g_display, keyCombo.keysym);
72 if (!keycode) {
73 // Ignore unknown keysym
74 return;
75 }
76
77 // Grab/ungrab key for each modifier that is ignored (capslock, numlock)
78 for (auto& ignModifier : ignModifiers) {
79 if (grabbed) {
80 XGrabKey(g_display, keycode, ignModifier | keyCombo.modifiers_, g_root,
81 True, GrabModeAsync, GrabModeAsync);
82 } else {
83 XUngrabKey(g_display, keycode, ignModifier | keyCombo.modifiers_, g_root);
84 }
85 }
86 }
87
getPossibleKeySyms()88 vector<string> XKeyGrabber::getPossibleKeySyms() {
89 vector<string> ret;
90 int min, max;
91 XDisplayKeycodes(g_display, &min, &max);
92 int kc_count = max - min + 1;
93 int ks_per_kc; // count of keysysms per keycode
94 KeySym* keysyms;
95 keysyms = XGetKeyboardMapping(g_display, min, kc_count, &ks_per_kc);
96 // only symbols at a position i*ks_per_kc are symbols that are recieved in
97 // a keyevent, it should be the symbol for the keycode if no modifier is
98 // pressed
99 for (int i = 0; i < kc_count; i++) {
100 if (keysyms[i * ks_per_kc] != NoSymbol) {
101 char* str = XKeysymToString(keysyms[i * ks_per_kc]);
102 ret.push_back(str);
103 }
104 }
105 XFree(keysyms);
106
107 return ret;
108 }
109