1 module xkeybind; 2 3 import x11.X; 4 import x11.keysym; 5 import x11.Xlib; 6 import std..string : toStringz; 7 import std.typecons : NotImplementedError; 8 9 /// 10 alias XKeybindHandler = void delegate(ModifierKey mods, int key); 11 12 private struct KeyHandlerEntry 13 { 14 ModifierKey mods; 15 int key; 16 XKeybindHandler handler; 17 } 18 19 /// Use Modifier for binding keys 20 enum ModifierKey : uint 21 { 22 /// 23 Shift = ShiftMask, 24 /// 25 Control = ControlMask, 26 /// 27 Mod1 = Mod1Mask, 28 /// 29 Mod2 = Mod2Mask, 30 /// 31 Mod3 = Mod3Mask, 32 /// 33 Mod4 = Mod4Mask, 34 /// 35 Mod5 = Mod5Mask, 36 /// 37 Any = AnyModifier 38 } 39 40 /// Modifier keys in this system (Get assigned after calling XKeyBind.load) 41 final struct Modifier 42 { 43 /// 44 static ModifierKey Shift = ModifierKey.Shift; 45 /// 46 static ModifierKey Control = ModifierKey.Control; 47 /// 48 static ModifierKey Alt; 49 /// 50 static ModifierKey AltR; 51 /// 52 static ModifierKey SuperR; 53 /// 54 static ModifierKey SuperL; 55 /// 56 static ModifierKey HyperR; 57 /// 58 static ModifierKey HyperL; 59 /// 60 static ModifierKey MetaR; 61 /// 62 static ModifierKey MetaL; 63 /// 64 static ModifierKey Any = ModifierKey.Any; 65 } 66 67 /// 68 bool parseKey(Display* display, string key, out ModifierKey mods, out int keycode) 69 { 70 import std..string : strip, split, toLower; 71 72 //dfmt off 73 ModifierKey[string] modName = [ 74 "shift" : Modifier.Shift, 75 "control" : Modifier.Control, 76 "ctrl" : Modifier.Control, 77 "alt" : Modifier.Alt, 78 "altl" : Modifier.Alt, 79 "altgr" : Modifier.AltR, 80 "altr" : Modifier.AltR, 81 "super" : Modifier.SuperL, 82 "superl" : Modifier.SuperL, 83 "superr" : Modifier.SuperR, 84 "hyper" : Modifier.HyperL, 85 "hyperl" : Modifier.HyperL, 86 "hyperr" : Modifier.HyperR, 87 "meta" : Modifier.MetaL, 88 "metal" : Modifier.MetaL, 89 "metar" : Modifier.MetaR, 90 ]; 91 //dfmt on 92 string[] parts = key.split('-'); 93 ModifierKey _mods; 94 if (parts.length > 1) 95 { 96 foreach (part; parts[0 .. $ - 1]) 97 { 98 if (part.strip.length == 0) 99 return false; // A--B 100 string mod = part.strip.toLower; 101 auto ptr = mod in modName; 102 if (!ptr) 103 return false; 104 _mods |= *ptr; 105 } 106 } 107 auto keysym = XStringToKeysym(cast(char*)(parts[$ - 1] ~ '\0').ptr); 108 if (keysym == NoSymbol) 109 return false; 110 keycode = XKeysymToKeycode(display, keysym); 111 mods = _mods; 112 return true; 113 } 114 115 /// 116 final class XKeyBind 117 { 118 public: 119 /// Creates a display and loads XKeyBind 120 static void load(string port = ":0") 121 { 122 load(XOpenDisplay(cast(char*) port.toStringz)); 123 } 124 125 /// Loads XKeyBind from an existing display 126 static void load(Display* displ) 127 { 128 display = displ; 129 root = DefaultRootWindow(displ); 130 131 XModifierKeymap* modmap = XGetModifierMapping(displ); 132 auto key_numlock = XKeysymToKeycode(displ, XK_Num_Lock); 133 auto key_alt = XKeysymToKeycode(displ, XK_Alt_L); 134 auto key_altr = XKeysymToKeycode(displ, XK_Alt_R); 135 auto key_superr = XKeysymToKeycode(displ, XK_Super_R); 136 auto key_superl = XKeysymToKeycode(displ, XK_Super_L); 137 auto key_hyperl = XKeysymToKeycode(displ, XK_Hyper_L); 138 auto key_hyperr = XKeysymToKeycode(displ, XK_Hyper_R); 139 auto key_metal = XKeysymToKeycode(displ, XK_Meta_L); 140 auto key_metar = XKeysymToKeycode(displ, XK_Meta_R); 141 142 for (int i = 3; i < 8; i++) 143 { 144 for (int j = 0; j < modmap.max_keypermod; j++) 145 { 146 auto ckey = modmap.modifiermap[i * modmap.max_keypermod + j]; 147 if (key_numlock && ckey == key_numlock) 148 Numlock = cast(ModifierKey) 1 << i; 149 if (key_alt && ckey == key_alt) 150 Modifier.Alt = cast(ModifierKey) 1 << i; 151 if (key_altr && ckey == key_altr) 152 Modifier.AltR = cast(ModifierKey) 1 << i; 153 if (key_superr && ckey == key_superr) 154 Modifier.SuperR = cast(ModifierKey) 1 << i; 155 if (key_superl && ckey == key_superl) 156 Modifier.SuperL = cast(ModifierKey) 1 << i; 157 if (key_hyperl && ckey == key_hyperl) 158 Modifier.HyperL = cast(ModifierKey) 1 << i; 159 if (key_hyperr && ckey == key_hyperr) 160 Modifier.HyperR = cast(ModifierKey) 1 << i; 161 if (key_metal && ckey == key_metal) 162 Modifier.MetaL = cast(ModifierKey) 1 << i; 163 if (key_metar && ckey == key_metar) 164 Modifier.MetaR = cast(ModifierKey) 1 << i; 165 } 166 } 167 168 ignoreMods = [Lock]; 169 ignoreMask = Lock; 170 if (Numlock) 171 { 172 ignoreMods = [Numlock, Lock, Numlock | Lock]; 173 ignoreMask = Numlock | Lock; 174 } 175 ignoreMask = ~ignoreMask; 176 } 177 178 /// Checks for key presses and calls handlers 179 static void update() 180 { 181 while (XCheckWindowEvent(display, root, KeyPressMask, &event)) 182 { 183 if (event.type == KeyPress) 184 { 185 int key = event.xkey.keycode; 186 ModifierKey mods = cast(ModifierKey)(event.xkey.state & ignoreMask); 187 foreach (KeyHandlerEntry bind; binds) 188 { 189 if (bind.key == key && bind.mods == mods) 190 bind.handler(mods, key); 191 } 192 } 193 } 194 } 195 196 /// Binds the key without binding keys when numlock or lock are active 197 static void bindExact(ModifierKey mods, int keycode, XKeybindHandler handler) 198 { 199 XGrabKey(display, keycode, cast(uint) mods, root, 0, GrabModeAsync, GrabModeAsync); 200 binds ~= KeyHandlerEntry(mods, keycode, handler); 201 } 202 203 /// 204 static void bind(ModifierKey mods, int keycode, XKeybindHandler handler) 205 { 206 bindExact(mods, keycode, handler); 207 foreach (mod; ignoreMods) 208 bindExact(mod | mods, keycode, handler); 209 } 210 211 /// 212 static void bind(string key, XKeybindHandler handler) 213 { 214 ModifierKey mods; 215 int code; 216 parseKey(display, key, mods, code); 217 bind(mods, code, handler); 218 } 219 220 /// 221 static void unbindExact(ModifierKey mods, int keycode) 222 { 223 XUngrabKey(display, keycode, cast(uint) mods, root); 224 } 225 226 /// 227 static void unbind(ModifierKey mods, int keycode) 228 { 229 unbindExact(mods, keycode); 230 foreach (mod; ignoreMods) 231 unbindExact(mod | mods, keycode); 232 } 233 234 /// 235 static void unbind(string key) 236 { 237 ModifierKey mods; 238 int code; 239 parseKey(display, key, mods, code); 240 unbind(mods, code); 241 } 242 243 private: 244 static ModifierKey Numlock; 245 static ModifierKey Lock = cast(ModifierKey) LockMask; 246 static ModifierKey[] ignoreMods; 247 static ModifierKey ignoreMask; 248 static KeyHandlerEntry[] binds; 249 static Display* display; 250 static Window root; 251 static XEvent event; 252 }