-------------------------------------------------------------------------------
X Window Event Handling
There are many programs which allow you to launch applications or do
certain actions based on X events they receive (hotkeys). This is
especially the case with Window Managers.
Basically they grab events to perform the action requested, then either
allow the event to pass on to other clients... Or not!
This includes, Twm, CTwm, Openbox, Gnome 2 Session, etc, etc....
If you do have a window manager with good event handler configuration
(Not Gnome) then that is typically the best place to add your hotkeys.
But sometimes you don't have that option, or you are running clients
without any window manager (For example creating a special Kiosk
Terminal), in which case you may need a special program to handle the
events...
xbindkeys
xhkeys
bbkeys
xhotkeys
xrebind
For way to execute command when mouse is in a specific spot try:
xautolock when putting the cursor in a corner
xdotool For example hitting an edge
To run commands or send events on mouse gestures
easystroke specific mouse movements generates specific events
for example: control windows, send keys, run program, etc
Applications dependant actions, with good grouping.
For example controling tabbed applications like browsers
using specific mouse gestures
For Sending or injecting events into the X window system you programs such as
"xdotool" One of the best tools.
With many user requested features, and active development.
"xte" From the "xautomation" package. See below
The "xautomation" package also provides "visgrep"
"xmacroplay" from the "xmacro" package
"cnee" from "Xnee" package
Very low level, outputing individual keys, not strings
See "xnee.sh" in the source package for usage
Specific Purpose Event injectors
"xvkbd" virtual onscreen keyboard
Programming language modules that may be useful
X11-GUITest (perl)
AutoKey (python) https://code.google.com/p/autokey/
-------------------------------------------------------------------------------
X Events...
The "xmodmap" program without arguments will list what keys are used as event
(key state) modifiers. For example I get this...
shift Shift_L (0x32), Shift_R (0x3e)
lock Caps_Lock (0x42)
control Control_L (0x25), Control_R (0x69)
mod1 Alt_L (0x40), Alt_R (0x6c), Meta_L (0xcd)
mod2 Num_Lock (0x4d)
mod3
mod4 Super_L (0x85), Super_R (0x86), Super_L (0xce), Hyper_L (0xcf)
mod5 ISO_Level3_Shift (0x5c), Mode_switch (0xcb)
This shows 8 modifiers or combination of modifiers, can be used with any key
from the keyboard.
Be warned however that events that have a 'modifier' attached can be a lot of
trouble. Many programs only 'bind' or use an event that has no modifiers.
That means if 'NumLock' is accidentally activated, many applications will
ignore all your key strokes!
Typically programs either ignore all modifiers, or ignore/handle specific ones
globally. For example, ignore "mod2" (numLock), or merge "lock" and "shift"
modifiers to mean the same thing. But each program does this in its own way.
For example "FireFox" web browser will ignore key stroke events that happen
while "mod4" (typically the Super or Windows key) is pressed. On the other
hand a normal "XTerm" will just ignore the "mod4" modifier and use the key
presses regardless of the modifer being present or not.
Also you should note that keyboard presses are actually two separate events,
specifically KeyDown and KeyUp events. Which event an application uses is
again up to the application, but typically most applications perform actions on
KeyDown.
Handling Up-Down Key events are typically more important for modify an
application behaviour. For example for a Alt-A key press an application will
typically receive 4 events in a sequence like this...
Alt_L-down A-down A-up Alt_L-up
Note it is possible for an application to treat ANY key as a modifier. EG: Do
something only if all the keys A, S and D are down. Though not all physical
keyboards can generate these events, and the only applications I know of that
does this are games.
------------
Watching Events...
You can see what xevents are being generated by looking at the output of
the "xev" program. However I find you get swamped in Mouse movement events
so I tend to use this command instead...
xterm -g 80x30+60+10 -e \
sh -c 'xev -g +730+10 | sed "/^MotionNotify/,/^$/d"'
The "sed" removes the mouse movement events from the "xev" output.
which is usually far more verbose than any other event.
You will however still get window entry, exit and focus events,
as well as keyboard and mouse button events.
More importantly this command will give details of the events, including
list the actual key names, and the appropriate capitalizations.
For example these are the specific 'keysym' names used for specific keys:
"quotedbl", "Delete", "BackSpace"
WARNING: "xev" may not see (and thus not show) event that some other program
has globally captured for some reason. Window Managers often do this, also
programs like Gnome keyboard shortcuts, or "xbindkeys" may capture such events.
So you may need to any remove 'hotkeys' or other 'key bindings' that is defined
before you can see those events.
As an alternative you can also use "xbindkeys -k" to see what event various
key pressed will generate. Though with the same warning as for "xev".
-------------------------------------------------------------------------------
Generating or Injecting, X Keyboard Events (Global Keyboard Macros).
The following are notes I made during the development of a small simple
"keyboard_macro" script to type strings.
https://antofthy.gitlab.io/software#keyboard_macro
You can create new X events (such as key strokes) by using a program such as
"xmacroplay" (xmacro package), "xte" (xautomation package) or the "xdotool"
program.
For example from the command line you can type...
xte 'str your.email.address@this.machine.com'
Will act as if the user typed that string, and will appear on the next command
line.
Of course it doesn't work as a typed command, as the computer thinks you
actually typed that text for the next shell prompt. But what if this was run
while the mouse pointer was in a different window, such as a text editor, or
some webpage form, the text will be typed in there.
For example try this
sleep 5; xte 'str your.email.address@this.machine.com'
and quickly move your mouse pointer to some other window that accepts text
input. Click to make that window active if you need to.
When the sleep finished suddenly the string would have appeared in the other
window as if you typed it yourself. It does not matter what input box it is,
or whether it was designed to allow "CUT 'n' PASTE" or anything. The
application will just accept the input as if the string was typed at the
keyboard.
Now if you can arrange for it to execute this command when you press a certain
key, the string will be immediately typed into whatever input box to are
currently using. It does not matter if this input is a terminal, a mail
program, web form, or even hidden password input box! The application just
receives it as if the user actually typed it in (very quickly).
---
Problems to Macros...
This is good in theory, but some tricky and confusing problems pop up when you
try to put the above into practice, causing it to either not work, work
intermittently, or with the letters becoming shifted, or as control characters.
To demonstrate the problems, lets call our keyboard macro from a general
event handler such as "xbindkeys".
First create a default ".xbindkeysrc" file in your home...
xbindkeys --defaults > $HOME/.xbindkeysrc
Now edit the file ".xbindkeysrc" in your home directory, and add the following
test bindings...
=======8<--------CUT HERE----------
# TESTING
#
"zenity --info --text 'email.address@machine.com'"
F1
#
"xte 'str email.address@machine.com'"
F2
#
"xte 'usleep 500000' 'str email.address@machine.com'"
F3
#
"xte 'usleep 500000' 'str email.address@machine.com'"
Shift + F4
#
"xte 'usleep 500000' 'str email.address@machine.com'"
Mod4 + F5
#
=======8<--------CUT HERE----------
Now run "xbindkeys", but lets turn off its background daemon mode so we can
easily stop it using Ctrl-C.
xbindkeys -n
Now if you press 'F1' anywhere on your display, it should run the 'zenity'
program to pop up a window containing the email address.. That shows
"xbindkeys" is working, and it has bound an action to 'F1'. (xbindkeys will
ignore CapsLock and NumLock modifiers by default)
But when you press 'F2' with the input directed to a XTerm window, nothing
happens. -- WHY?
Well that is because you are using xte to send more events while F2 is still
being held down! That means in reality you are sending the events...
F2-down e-down e-release m-down m-release....
That is 'F2' and 'e' keys are BOTH pressed together, and very few X window
programs, will handle multiple key combinations such as this.
ASIDE: Some programs can do this, and some games require it, but generally most
programs will ignore multi-key presses as being non-sensible.
Simple Solution: Delay the Macro Output
Now try giving a quick tap of 'F3' in an xterm window, and suddenly the string
will appear, or at least the last part of the string will appear if you were a
little slow on your key tap.
The xte delay option (usleep 500000) causes the "xte" program to wait 1/2
second before it outputs the macro string. That gives the user time plenty of
time to release the 'F3' key, so the later key events will be clear of multiple
key presses and come out correctly. The sleep makes the difference.
Solution: Bind to the Release of the Function Key
Some event binding software, can be set do the requested action when the key is
released, rather than pressed. That means the events will not be generated
until after the 'F3' (or whatever) was released by the user. This will avoid
any 'multi-key' event generation problems, and allow a binding to work without
delay.
Since writing this, the newer "xbindkeys" now provides a 'release key'
function.
=======8<--------CUT HERE----------
"xte 'str email.address@machine.com'"
F2 + Release
=======8<--------CUT HERE----------
The "openbox" window manager, for example, does this by default, but will not
give you the choice.
"Twm", "CTwm" and other old-style window managers can also specify 'release'
key binding events separately to 'press' events.
Do you know any other key binding programs that lets you do this?
The Bigger Problem: Modifiers...
Unfortunately that does NOT help when event 'modifiers' become involved. For
example try playing with the Shift-F4 combination in an XTerm window. If you
try this you will probably find the email address will appear, but with some of
the letters capitalized.
Note however that the capitals actually stop at the '@' sign. The reason is
that for "xte" (or any other key typing command) to send a '@' it actually
would also send, and more importantly release the SHIFT modifier key. As such
after the '@' the shift modifier is no longer in effect.
Even if you use a 'sleep' to wait for the primary key to be released, users are
generally much slower in releasing modifiers like Shift, Control, Alt, Super,
etc.. As such often the time modifiers will still be pressed when the macro is
generated, producing shifted or capitalized result.
If this was a Ctrl modifier you would generate control key events, and that can
be VERY bad, not to mention DANGEROUS! Ctrl key macros are NOT recommended.
For a modifier like Mod4 (Super/Meta/Window Key), some applications may ignore
the modifier, while other applications may not. A terminal for example will
typically ignore the 'Super' or 'mod4' modifier and you will get the email
address printed, but other applications like "FireFox" completely ignore
keyboard events that have a 'mod4' modifier, so nothing gets 'typed' into web
forms, where you could really use keyboard macros.
Try it again with the next keyboard binding that was setup above. The
'Windows-F5' or 'Super-F5' key-binding (the "Mod4" modifier in the binding)
will work with "firefox", but only if you release the modifier key quickly.
That is because by delaying a long half second, gives the user plenty of time
release both the primary key, and the 'Window' modifier key as well.
Clear modifiers
You can use "xte" (or other event generator) to send release events for the key
and the modifier keys before sending the macro string. However I have not got
this to work with "xbindkeys".
With a suggestion from me, the author of "xdotool" added a "--clearmodifiers"
option. It notes what modifiers are present and sends the appropriate release
events to clear them. (See below)
For example from "openbox" (which waits for key releases, not key presses),
I can set up a binding like this (attached to the 'Window' mod4 modifier key)
=======8<--------CUT HERE----------
xdotool type --clearmodifiers -delay 0 'Email.Address@example.com'
=======8<--------CUT HERE----------
Note the -delay in the above is to speed up 'typing' of the string (delay
between key strokes, not a wait for the modifier.
That is if a keyboard macro was started using an event "Mod4 + a" with the
action taken on the release of 'a' as it is with "openbox"), then it sends
a release event for the modifier key. For example it sends a Super_L release
event to clear any 'Mod4' modifier that may still be present.
Recursive Macros
You should not try binding a keyboard macro to a normal alphanumeric keys, and
especially not without some sort of clear modifier.
For example try out this key binding into an xterm window, but keep the 'Super'
or 'Windows' key modifier pressed for a long time...
=======8<--------CUT HERE----------
"xte 'usleep 500000' 'str email.address@machine.com'"
Mod4 + a
=======8<--------CUT HERE----------
What will happen is that it will continually repeat the macro over and
over and over until you release the 'Super/Windows' modifier.
What happens is that "xte" injects the X Window Events as if it is from
the keyboard. As such "xbindkeys" (or any such event binding program)
will see all the keyboard events that the macro itself produces! As
such the "xbindkeys" will see the 'a' in the macro, and if the user is
still pressing the 'mod4' modifier, then it will expand the macro again!
Basically it will loop continuously, until you release the modifier.
Now imagine what would have happen if you did not have that modifier!!!!
It is fine to bind other actions to normal alphanumeric keys (such as
launch specific applications) as that will not cause an event loop.
-------------------------------------------------------------------------------
xte faults...
v1.02 seems to have a 255 character limit for sending strings
(confirmed as a built in buffer limitation by author, Steve Slaven)
v1.07 seems to ignore all newlines in strings to be sent
Solution from the author of xte is a small perl script "xte_strfile"
to recode input strings into multiple events. Just a shame it doesn't
do this automatically.
=======8<--------
#!/usr/bin/perl -w
#
# Convert a string read from stdin (a selection), into a set of X window
# events that you can have "xte" 'type'. For example, type the current
# X Windows "clipboard" into the current text window. (Very useful)
#
# xsel -b | /path/to/xte_strfile | xte
#
# This is to get around limitations in "xte" involving
# newline not being sent, and a 255 string size limit.
#
# Steve Slaven -- 19 Dec 2014
#
use strict;
print "str ";
my $c = 0;
while( <> ) {
for my $char ( split( // ) ) {
if ( $char eq "\n" ) {
print "\nkey Return\nstr ";
$c = 0;
}else{
print $char;
if ( $c++ > 200 ) {
print "\nstr ";
$c = 0;
}
}
}
}
=======8<--------
Example of using "xte"
Send Ctrl-Alt-N to the currently active client
xte 'keydown Control_L' 'keydown Alt_L' \
'key n' \
'keyup Control_L' 'keyup Alt_L'
-------------------------------------------------------------------------------
XDoTool -- Event handler.
As mentioned above "xdotool" has added features that make it ideal
for generating keyboard macros.
As a bonus it also has
* Window Manager controls (similar to those provided by "xwit")
* It also has built-in "xwininfo" search support
* Mouse Input Controls (movements, clicks, warps)
* Each key press can be delayed as if you were typing (default) or not!
* Build a single free standing 'static' version (no dynamic libraries)
(from version 2010 10 )
* It will switch keyboards to general unicode keys like 'ยง'
However what makes the program specifically useful is
* a special '--clearmodifiers' option
This option ensures any and all modifier keys are released before it types
your own events. That way you don't accidentally generate strings with all
the characters 'Ctrl' or 'Alt' shifted! (from version 2010-08 )
You can Download the latest it from
http://www.semicomplete.com/projects/xdotool/
or a beta release (zip) from GitHub
https://github.com/jordansissel/xdotool
You may like to browse the "xdotool-users" google group mailing list
-------------------------------------------------------------------------------
OpenBox Keyboard Macros
=======8<--------CUT HERE----------
xte 'usleep 500000' \
'str Anthony.Thyssen@gmail.com'
=======8<--------CUT HERE----------
With this, any time I press the Windows and F1 keys together the macro will
pause 1/2 second for me to release the Windows Key then type into the current
input box my password.
Same thing using xdotool (no delay needed)
=======8<--------CUT HERE----------
xdotool type --clearmodifiers -delay 0 'Anthony.Thyssen@gmail.com'
=======8<--------CUT HERE----------
Currently I use "xte", via a script "keyboard_macro" that is almost identical
to the "xte_strfile" script supplied by the programmer of "xte". For
example...
=======8<--------CUT HERE----------
keyboard_macro 'Anthony.Thyssen@gmail.com'
sh -c 'xsel -p | keyboard_macro -'
=======8<--------CUT HERE----------
-------------------------------------------------------------------------------
Typing Strings with Return Keys
Often when typing a string to use as an event sequence you can't specify
'Return Key' in the string. After all how does the application knows
if "\n" means '\' and 'n' or just a Newline key.
Here is a way for xdotool to do this. Essentually including the actual return
character in the quoted argument that is given to xdotool itself
sleep 1; xdotool type "hello
world
"
or better still..
sleep 1; xdotool type "$(printf "hello\nworld\n")"
WARNING: While many applications accept a 'newline' to mean return
many do not, and expect an actual carrage return ("\r" in printf).
-------------------------------------------------------------------------------
Double Clicking copy-n-paste Events
This is a little script that causes the mouse to 'double click' whereever
it is to select and then grab the selected word for further processing.
=======8<--------
#!/bin/bash
# getdclick: simulate double-click and get selected word
# Time to wait between clicks (test what works for you)
DCLICK_WAIT=0.1
# Before double-click, simulate a Release of all buttons
# then simulate double click
xte "mouseup 1" "mouseup 2" "mouseup 3" "mouseup 4" "mouseup 5" \
"mouseclick 1" "sleep $DCLICK_WAIT" "mouseclick 1"
# Get selection first word from primary X clipbloard
SELECTION=$(xsel -p | awk '{print $1}')
echo $SELECTION
exit 0
=======8<--------
You can use this in a event action, for example dictionary lookup
gnome-dictionary $(getdclick)
-------------------------------------------------------------------------------
Mouse Moves
"xwit -warp" will move the mouse by default relative to the current window
(equivelent to -current option). But does not let you 'click'.
xwit -warp +20+20 -id $window_id
or using xdotool...
mousemove -window $id 500 100
For example... Microsoft Outlook only shows 75 results from a search,
and the delete button only deleted those 75. To delete ALL mail matching
the current search term, I have to repeat the search multiple times.
That can be very annoying when you have thousands of such mails!
but you do not want to empty the whole folders.
This script will...
* Press 'return' in a search window, and wait for results to appear.
* Moves mouse to the 'delete' button, and clicks that,
* Then presses retunt for the popup window, to confirm 'DO IT'
* Then a large pause, before repeating....
=======8<--------CUT HERE----------
id=$(xwin_find 'Mail - .*') && echo "Window at $id"
repeat 100 xdotool \
mousemove -window $id 500 100 click 1 sleep 0.1 key Return \
sleep 2 \
mousemove -window $id 250 170 click 1 sleep 0.3 key Return \
sleep 3
=======8<--------CUT HERE----------
The large pause allows me to move the mouse and 'ctrl-C' the script, when
I come back and see no more matching mail to delete.
I have done simular scripts for other 'grind's such as in games,
For example, auto-fishing or auto-crafting in minecraft.
-------------------------------------------------------------------------------
Firefox problems...
"Firefox" just ignores ALL input events if it does not have focus.
So you need to 'activate' the firefox window to send it say a Crtl-R...
xdotool search firefox windowfocus key ctrl+r
If you want to preserve the current focus, then grab what it is
swicth focus, send key, switch back...
focused="$(xdotool getactivewindow)";
xdotool search firefox windowfocus key ctrl+r windowfocus $focused
-------------------------------------------------------------------------------
XSendEvents vs XTest Events
XTest events is a additional module to the X Server. It is usually present but
not always. It is untargeted, and as such follows focus sending the fake event
to the currently active window. It basically means that if the focus changes
while events are being sent (user moves mouse), the events may not reach its
intended target.
XSendEvents is older and has always been present in X windows. It will only
target a specific window, and not the general 'current focus'. Of course that
means XSendEvents cannot target the window manager, or something like
xbindkeys, only specific applications, which can be a good thing!
The BIG problem is that XSendEvents have a flag set in the event structure,
that will cause many applications to ignore the event.
This is its biggest drawback and why it is not used much.
"xdotool" will use XSendEvents when a specific window is targeted.
This may mean the application might reject the events it generates.
But if window is set to "--window 0" (the root window) it uses XTest.
You may need to ensure the window is focused (mouse clicked in the window).
Also see...
https://xdotool-users.narkive.com/00wVwAS0/xtest-versus-xsendevent
"XTerms" generally ignore SendEvents, but you can enable it in the
"ctrl-leftclick" menu
---
Override the rejection of XSendEvent by application...
This lets you run a application so it never sees that 'send_event' flag,
and thus stop it ignoring such events.
See "XSendEvent + LD_PRELOAD == win"
https://web.archive.org/web/20160623141620/http://www.semicomplete.com/blog/geekery/xsendevent-xdotool-and-ld_preload.html
Basically create a custom library that will overrides the XNextEvent() and
XPeekEvent() functions used by an application, forcably setting the
'send_event' to always be false. (Using LD_PRELOAD library functions)
=======8<--------
#include
#include
void hack_send_event(XEvent *ev) {
switch (ev->type) {
case KeyPress:
case KeyRelease:
case ButtonPress:
case ButtonRelease:
ev->xany.send_event = False;
break;
}
}
override('XNextEvent', '
{ real_func(display, event_return);
hack_send_event(event_return);
return;
}
')
=======8<--------
Compile this into a shared library and set the LD_PRELOAD environment variable
to use this library, before running the application.
See my seperate notes in "store/c/override_libraries/liboverride"
WARNING: Firefox will ignore all events when it does not have focus.
As such you still have to give focus to firefox before sending it events,
just like you would do for a X Test Events.
In Summery: In the end it still may still not work! Use Xtest events instead.
-------------------------------------------------------------------------------