You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

330 lines
9.9 KiB

/* 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;
}