331 lines
9.9 KiB
C
331 lines
9.9 KiB
C
/* keysend.c
|
|
* Copyright (C) 2008 Alex Graveley
|
|
* Copyright (C) 2010 Ulrik Sverdrup <ulrik.sverdrup@gmail.com>
|
|
* Copyright (C) 2011 Olaf Schulz <schulz@math.hu-berlin.de> (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;
|
|
}
|
|
|