-------------------------------------------------------------------------------
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 (such as specially setup Kiosk Terminals).
Other programs to generate 'hotkey' events also include:
xbindkeys
xhkeys
bbkeys
xhotkeys
xrebind
For a execute command when mouse is in a specific spot try:
xautolock
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)
"xmacroplay" (from the "xmacro" package)
"xvkbd" (virtual onscreen keyboard - no package known)
"cnee" (from "Xnee" source - not ferdora package)
Very low level (keys not strings) see "xnee.sh" for usage
-------------------------------------------------------------------------------
X Events...
The "xmodmap" program without arguments will list what keys are used as event
(key state) modifiers for example...
shift Shift_L (0x32), Shift_R (0x3e)
lock Caps_Lock (0x42)
control Control_L (0x25), Control_R (0x6d)
mod1 Alt_L (0x40), Mode_switch (0x71), Meta_L (0x9c)
mod2 Num_Lock (0x4d)
mod3
mod4 Super_L (0x7f), Hyper_L (0x80)
mod5 Mode_switch (0x5d), ISO_Level3_Shift (0x7c)
Shows 8 modifiers are possible (and any combination of modifier can be used)
Be warned however that events that have 'modifier' attached are the most
trouble. Many programs only 'bind' or use an event that has no modifiers.
That means if 'NumLock" is accidentally on some specific key may not actually
be reconised by an application!
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 keys
pressed as is.
Also you should note that keyboard presses are actually two separate events,
specifically KeyDown and KeyUp events. Whcih one an application uses is
again up to the application, but typicaly they perform actions on KeyDown.
This is much more important for modify keys where you get sequences like
Alt_L down A down A up Alt_L up
Note it is posible 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 situation, and I know of no application that does
this.
------------
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 movements from xev output.
More importantally this command will list the actual key names, and the
appropriate capitalizations used. For example these are specific 'keysym'
used for specific keys: "quotedbl", "Delete", "BackSpace"
WARNING: xev may not see (and thus not show) some event that some other
program has globally captured for some reason. Programs that can do this
include the window manager, Gnome keyboard shortcuts, or "xbindkeys".
As an alturnative you can also use "xbindkeys -k" to see what event various
key pressed will generate.
-------------------------------------------------------------------------------
Generating X Keyboard Events (Global Keyboard Macros).
You can for example create new X events (such as key strokes) by using a
program such as "xmacroplay" (xmacro package), "xte" (xautomation package)
or the "xdotool" program.
This works well from the command line. For example
xte 'str your.email.address@this.machine.com'
Will act as if the user typed that string (an email address). Of course
it doesn't work as a typed command, but what if this was run while the mouse
pointer was in a different window, such as a text editor, or some webpage form.
For example try this
sleep 5; xte 'str your.email.address@this.machine.com'
and quickly move your mouse pointer to some other window
(click to make it active if need be).
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 longer string will be immediatally typed in. And you can Atype it
into any input box. It does not matter if this inptu is a terminal, a mail
program or a web form! To the program the user typed it (very quickly).
In other words a Global Keyboard Macro.
---
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 marco from a general event
handler such as "xbindkeys".
First create a default ".xbindkeysrc" file in your home...
xbindkeys --defaults
Now edit the file ".xbindkeysrc", 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 50000' 'str email.address@machine.com'"
F3
#
"xte 'usleep 50000' '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
easilly 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 it is being 'actioned' while the "F2" key was will
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: programs can do this, and some like games do, but generally they don't.
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 in your key tap.
The delay (usleep) option causes the "xte" program to wait a moment before it
outputs the macro string. That gives the user 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 Keys
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 a binding to work
without delay.
The "openbox" window manager, for example, does this by default (no choice).
"Twm", "CTwm" and other old-style window managers can also specify 'release'
key binding events separateally 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 all
the letters capitalized. At least up until the '@' sign.
That is because even if you wait for the primary key to be released, users are
much slower in releasing modifiers like Shift, Control, Alt, Super, etc.. As
such the modifier will still be pressed when the macro is generated, producing
shifted or capitalized result.
If this was a Ctrl modifier you would generate control events, and that can be
VERY bad, not to mention DANGEROUS! Ctrl key macros are NOT recommended.
For a modifier like Mod4 (Super/Meta), 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 use it the most.
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 longer half second, now gives the user plenty of
time release both the primary key, and the 'Window' modifier key as well.
UPDATE: the "xdotool" has a --clearmodifiers option that will fix this
problem! You no longer need to delay to give the user time to release the
modifier!
xdotool type --clearmodifiers -delay 0 'A.Thyssen@griffith.edu.au'
The -delay in the above is to speed up 'typing' of the string.
WARNING: before version 2.20110530 the above are fairly slow, but
with that release typing is extremely quick.
Problem: Recursive Macros...
You should not try binding a keyboard macro to a normal alphabetic key,
and especially not without some sort of modifier.
For example try this key binding into an xterm window, but keep the 'Super' or
'Windows' key modifier pressed for a moment...
=======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.
The Ideal Solution...
Ideal solution would be to either wait for both the primary key and modifer to
be released before sending the event, OR somehow turn off the modifier while
the keyboard macro is being output.
Ideally you would combine a program like "xbindkeys" with "xte" so that while
a Keyboard Macro is being output, it can monitor the events (including the
macro events it is itself generating) and keep track of modifiers, and other
events, delaying or adjusting the modifier events, so while the macro was
being output, any existing modifiers do not effect the macro output.
That is if a keyboard macro was started using an event "Mod4 + a" with the
action taken on key release), then it turns off whatever key caused the 'Mod4'
and watches for other events from the user (such as other modifier changes).
When the macro has finally streamed passed, the other events can be forward as
if nothing had happened.
-------------------------------------------------------------------------------
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 (do dynamic libraries)
(from version 2010 10 )
However what makes the program specifically useful is
* a special --clearmodifiers option
This option ensures any and all user 'shift' keys are released before
you feed your own events. That way you don't 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
-------------------------------------------------------------------------------
Example... Keyboard Macro - Using OpenBox keyboard binding...
xte 'usleep 500000' \
'str A.Thyssen@griffith.edu.au'
With this, any time I press the Windows and F1 keys together
the marco will pause 1/2 second for me to release the Windows Key
then type into the current input box my password.
I use it all the time when writeing Emails, Gmails, Web Page Messages,
and even for login on some web sites. -- Very quick and easy.
xdotool example (no delay needed)
xdotool type --clearmodifiers -delay 0 'A.Thyssen@griffith.edu.au'
-------------------------------------------------------------------------------
Example... Generating Mouse Events
This is a little script that causes the mouse to 'double click' where ever
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)
Example: Send Ctrl-Alt-N to the currently active client
xte 'keydown Control_L' 'keydown Alt_L' \
'key n' \
'keyup Control_L' 'keyup Alt_L'
-------------------------------------------------------------------------------
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 Return key.
Here is a way for xdotool to do this. Essentually including the actual return
character in the argument that is given to xdotool itself
sleep 1; xdotool type "hello
world
"
or better still..
sleep 1; xdotool type "$(printf "hello\nworld\n")"
-------------------------------------------------------------------------------
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, 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 can not target the window manager, or something like
xbindkeys, only specific applications, though that will prevent posible 'event
loops'.
The BIG problem is that XSendEvents have a flag set in the event structure,
that will cause many applications to ignore the event. For example XTerm's
and the Firefox Browser will ignore XSendEvents.
This is its biggest drawback and why it is not used much.
---
Override the rejection of XSendEvent by application...
This lets you run a application so it never sees that 'send_event' flag.
See XSendEvent + LD_PRELOAD == win
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)
=======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
before running the application.
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: It may not be worth the trouble! Use Xtest events instead.
-------------------------------------------------------------------------------