------------------------------------------------------------------------------- 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 "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' 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) ------------------------------------------------------------------------------- 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. -------------------------------------------------------------------------------