1 /** 2 * keybinder handles binding keys globally on X11 + GTK. 3 */ 4 module keybinder; 5 6 import keybinder_c; 7 8 /** 9 * Bind the key binding identified by $(D keys) to the given delegate. 10 * 11 * Only one callback per key sequence is supported. 12 * 13 * The callback will be called with a frequency according to the keyboard repeat settings. If a user 14 * holds down the relevant key sequence, the callback will be called once, then there will be a 15 * delay, then the callback will be called many times. 16 */ 17 void bindGlobal(string keys, void delegate() dg) 18 in 19 { 20 assert(keys !in dgs); 21 } 22 body 23 { 24 import std.string : toStringz; 25 dgs[keys] = dg; 26 keybinder_bind_full(keys.toStringz, &handleKeys, null, null); 27 } 28 29 /** 30 * Unbind everything on the given key combination. 31 */ 32 void unbindGlobal(string keys) 33 { 34 import std.string : toStringz; 35 keybinder_unbind_all(keys.toStringz); 36 dgs.remove(keys); 37 } 38 39 /** 40 * Initialize global keybinding support. 41 * 42 * libkeybinder requires you to be running with GTK+ and X11. This init function requires you to 43 * have initialized GTK+ yourself; you are responsible for maintaining a GTK+ main loop if you want 44 * to receive key events. 45 */ 46 void init() 47 { 48 keybinder_init(); 49 } 50 51 /** 52 * Initialize global keybinding support. 53 * 54 * libkeybinder requires you to be running with GTK+ and X11. This init function handles GTK+ 55 * initialization for you. In your program's main loop (or a frequent periodic callback), you must 56 * call the poll() function to check whether the key has been pressed. 57 */ 58 void initNoGTK() 59 { 60 import core.sys.posix.dlfcn; 61 auto d = dlopen("libgtk-3.so".ptr, RTLD_LAZY); 62 auto gtk_init = cast(void function())dlsym(d, "gtk_init".ptr); 63 gtk_init(); 64 keybinder_init(); 65 gtkMainIterationDo = cast(typeof(gtkMainIterationDo))dlsym(d, "gtk_main_iteration_do".ptr); 66 } 67 68 /** 69 * Check for new keypresses. 70 * 71 * If you already have a GTK+ main loop, you should not call this. 72 */ 73 void poll() 74 { 75 if (!gtkMainIterationDo) 76 { 77 throw new Exception( 78 "You must call initNoGTK() before calling poll().\n" ~ 79 "Note that if you have a GTK+ main loop, you don't need to call " ~ 80 "initNoGTK() or poll(); the GTK+ loop already handles this."); 81 } 82 gtkMainIterationDo(false); 83 } 84 85 private: 86 87 extern (C) bool function(bool) gtkMainIterationDo; 88 89 void delegate()[string] dgs; 90 91 private extern(C) void handleKeys(const char* keystring, void* data) 92 { 93 import std.string : fromStringz; 94 auto k = keystring.fromStringz; 95 auto v = k in dgs; 96 if (v is null) 97 { 98 // This shouldn't happen... 99 return; 100 } 101 (*v)(); 102 }