/* keysend.c * Copyright (C) 2008 Alex Graveley * Copyright (C) 2010 Ulrik Sverdrup * Copyright (C) 2011 Olaf Schulz (modified bind.c) * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "keysend.h" /* Uncomment the next line to print a debug trace. */ /* #define DEBUG */ #ifdef DEBUG # define TRACE(x) x #else # define TRACE(x) do {} while (FALSE); #endif #define MODIFIERS_ERROR ((GdkModifierType)(-1)) #define MODIFIERS_NONE 0 /* Group to use: Which of configured keyboard Layouts * Since grabbing a key blocks its use, we can't grab the corresponding * (physical) keys for alternative layouts. * * Because of this, we interpret all keys relative to the default * keyboard layout. * * For example, if you bind "w", the physical W key will respond to * the bound key, even if you switch to a keyboard layout where the W key * types a different letter. */ #define WE_ONLY_USE_ONE_GROUP 0 // The key code to be sent. // A full list of available codes can be found in /usr/include/X11/keysymdef.h //#define KEYCODE XK_Down //#define KEYCODE XK_a /* Return the modifier mask that needs to be pressed to produce key in the * given group (keyboard layout) and level ("shift level"). */ static GdkModifierType FinallyGetModifiersForKeycode (XkbDescPtr xkb, KeyCode key, uint group, uint level) { int nKeyGroups; int effectiveGroup; XkbKeyTypeRec *type; int k; nKeyGroups = XkbKeyNumGroups(xkb, key); if ((!XkbKeycodeInRange(xkb, key)) || (nKeyGroups == 0)) { return MODIFIERS_ERROR; } /* Taken from GDK's MyEnhancedXkbTranslateKeyCode */ /* find the offset of the effective group */ effectiveGroup = group; if (effectiveGroup >= nKeyGroups) { unsigned groupInfo = XkbKeyGroupInfo(xkb,key); switch (XkbOutOfRangeGroupAction(groupInfo)) { default: effectiveGroup %= nKeyGroups; break; case XkbClampIntoRange: effectiveGroup = nKeyGroups-1; break; case XkbRedirectIntoRange: effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo); if (effectiveGroup >= nKeyGroups) effectiveGroup = 0; break; } } type = XkbKeyKeyType(xkb, key, effectiveGroup); for (k = 0; k < type->map_count; k++) { if (type->map[k].active && type->map[k].level == level) { if (type->preserve) { return (type->map[k].mods.mask & ~type->preserve[k].mask); } else { return type->map[k].mods.mask; } } } return MODIFIERS_NONE; } //++++++++++++++++++++++++++++++ Olaf static KeyMod getKeyModCodes (GdkWindow *rootwin, uint keyval, int modifiers) { int k; GdkKeymap *map; GdkKeymapKey *keys; gint n_keys; GdkModifierType add_modifiers; XkbDescPtr xmap; // gboolean success = FALSE; KeyMod keymod; xmap = XkbGetMap(GDK_WINDOW_XDISPLAY(rootwin), XkbAllClientInfoMask, XkbUseCoreKbd); map = gdk_keymap_get_default(); gdk_keymap_get_entries_for_keyval(map, keyval, &keys, &n_keys); if (n_keys == 0){ // return FALSE; keymod.keyval = -1; keymod.modifiers = 0; return keymod; } for (k = 0; k < n_keys; k++) { /* NOTE: We only bind for the first group, * so regardless of current keyboard layout, it will * grab the key from the default Layout. */ if (keys[k].group != WE_ONLY_USE_ONE_GROUP) { continue; } add_modifiers = FinallyGetModifiersForKeycode(xmap, keys[k].keycode, keys[k].group, keys[k].level); if (add_modifiers == MODIFIERS_ERROR) { continue; } // TRACE (g_print("grab/ungrab keycode: %d, lev: %d, grp: %d, ", keys[k].keycode, keys[k].level, keys[k].group)); // TRACE (g_print("modifiers: 0x%x (consumed: 0x%x)\n", add_modifiers | modifiers, add_modifiers)); // zu wählen ist 'add_modifiers | modifiers' keymod.keyval = keys[k].keycode; keymod.modifiers = add_modifiers | modifiers; //printf(" Foo %u %u\n", keymod.keyval, keymod.modifiers); break; } g_free(keys); XkbFreeClientMap(xmap, 0, True); return keymod; //return success; } // Function to create a keyboard event static XKeyEvent createKeyEvent(Display *display, Window win, Window winRoot, int press, int keycode, int modifiers) { XKeyEvent event; event.display = display; event.window = win; event.root = winRoot; event.subwindow = None; event.time = CurrentTime; event.x = 1; event.y = 1; event.x_root = 1; event.y_root = 1; event.same_screen = True; event.keycode = keycode; event.state = modifiers; if(press) event.type = KeyPress; else event.type = KeyRelease; //test, bringen keine Verschlechterung... //event.send_event=true; //event.serial = 0; return event; } int keysend(uint keysym, int modifiers){ //int keysym; KeyMod keymod; // Obtain the X11 display. Display *display = XOpenDisplay(0); if(display == NULL) return -1; //von bind.c // gdk_init (&argc, &argv);//call this in main routine GdkWindow *rootwin = gdk_get_default_root_window (); // Get the root window for the current display. Window winRoot = XDefaultRootWindow(display); // Find the window which has the current keyboard focus. Window winFocus; int revert; XGetInputFocus(display, &winFocus, &revert); keymod = getKeyModCodes(rootwin, keysym, modifiers); /* Bugfix?! * for the first layer (=no modifier is pressed) the above fuction * returns 33 for the modifier, if the neo layer is activated. * This will be corrected to 0. * * 33 = Mod4+Shift */ //if( keymod.modifiers == 33 ) keymod.modifiers = 0; XKeyEvent event; //printf("Send key %u %i %u %u\n", keysym, modifiers, keymod.keyval, keymod.modifiers); // Send a fake key press event to the focused window. event = createKeyEvent(display, winFocus, winRoot, True, keymod.keyval, keymod.modifiers); XSendEvent(event.display, event.window, True, KeyPressMask, (XEvent *)&event); // Send a fake key press event to root window. event = createKeyEvent(display, winRoot, winRoot, True, keymod.keyval, keymod.modifiers); XSendEvent(event.display, event.window, True, KeyPressMask, (XEvent *)&event); // Send a fake key release event to root window. event = createKeyEvent(display, winRoot, winRoot, False, keymod.keyval, keymod.modifiers); XSendEvent(event.display, event.window, True, KeyReleaseMask, (XEvent *)&event); // Send a fake key release event to the focused window. event = createKeyEvent(display, winFocus, winRoot, False, keymod.keyval, keymod.modifiers); XSendEvent(event.display, event.window, True, KeyReleaseMask, (XEvent *)&event); // Present active window. Usefull, if alt+F1 oder alt+d clicked. //XRaiseWindow(display, winFocus); //XLowerWindow(display, winFocus); // Done. XCloseDisplay(display); return 0; } int keysend2(uint keysym, uint modsym1, uint modsym2) { KeyMod keymod; // Obtain the X11 display. Display *display = XOpenDisplay(0); if(display == NULL) return -1; //von bind.c // gdk_init (&argc, &argv);//call this in main routine GdkWindow *rootwin = gdk_get_default_root_window (); // Get the root window for the current display. Window winRoot = XDefaultRootWindow(display); // Find the window which has the current keyboard focus. Window winFocus; int revert; XGetInputFocus(display, &winFocus, &revert); int xkeycode = -1; int xmodcode1 = -1; int xmodcode2 = -1; XKeyEvent event; xkeycode = XKeysymToKeycode(display, keysym); if( modsym2 != 0 ){ xmodcode2 = XKeysymToKeycode(display, modsym2); event = createKeyEvent(display, winFocus, winRoot, True, xmodcode2, 0); XSendEvent(event.display, event.window, True, KeyPressMask, (XEvent *)&event); } if( modsym1 != 0 ){ xmodcode1 = XKeysymToKeycode(display, modsym1); event = createKeyEvent(display, winFocus, winRoot, True, xmodcode1, 0); XSendEvent(event.display, event.window, True, KeyPressMask, (XEvent *)&event); } // Send a fake key press event to the window. event = createKeyEvent(display, winFocus, winRoot, True, xkeycode, 0); XSendEvent(event.display, event.window, True, KeyPressMask, (XEvent *)&event); // Send a fake key release event to the window. event = createKeyEvent(display, winFocus, winRoot, False, xkeycode, 0); XSendEvent(event.display, event.window, True, KeyReleaseMask, (XEvent *)&event); if( modsym1 != 0 ){ event = createKeyEvent(display, winFocus, winRoot, False, xmodcode1, 0); XSendEvent(event.display, event.window, True, KeyReleaseMask, (XEvent *)&event); } if( modsym2 != 0 ){ event = createKeyEvent(display, winFocus, winRoot, False, xmodcode2, 0); XSendEvent(event.display, event.window, True, KeyReleaseMask, (XEvent *)&event); } // Done. XCloseDisplay(display); return 0; }