Sunday, August 31, 2014

xmacro tutorial

UPDATE: xmacro is apparently working on Ubuntu 11.04 and subsequent releases now.

UPDATE2: added xmousepos instructions, some other changes.

I'm a huge fan of AutoHotkey. It's an open-source (GPL) program for automating repetitive keystroke and mouse functions. I use it at work for logging onto websites that have multiple login pages as well as data entry. Problem is, it's only written for Windows. There aren't many good Linux equivalents, but I've found one that works almost as well as AutoHotkey if you're willing to experiment with it. It's a series of several small programs collectively called xmacro.

It's a nifty little automation program, but it's all command-line and has some (to me) strange record and playback characteristics. I'd like to share my limited experience so that any other newbies with the same need might try to take the plunge. Please keep in mind, I just started fooling with this yesterday, so I'm no expert.

If you're using Linux, I'll assume you know how to install from source files or repositories. (If you have any questions, please feel free to write me. I installed the xmacro package using Synaptic from the Ubuntu universe repo, I think.)

The first thing to do is to either record a macro or write one from scratch.
To record the mouse movements and keystrokes on your current display, open a terminal window and enter the following:

~$ xmacrorec2 > testing.macro 

Server VendorRelease: 70101000 
XRecord for server ":0.0" is version 1.13. 
 
Press the key you want to use to end the application. This key can be any key, as long as you don't need it while working with the remote display. A good choice is Escape.
 
Humor it. Hit the Esc key. Just remember which key you pressed, because you'll need it!

The chosen quit-key has the keycode: 9 XQueryPointer returned: 1 
Got Start Of Data Skipping... - 
Skipping stale KeyRelease event. 1
 
Now it's recording. For this example, I used Ctrl+Alt+Right to switch workspaces, the mouse to open a terminal window, run pan, and download headers in subscribed groups (Ctrl+Shift+u). When I finished, I hit Escape to end the recording.

Got QuitKey, so exiting... ^[xmacrorec2: Exiting.
 
OK, testing.macro is recorded! Let's see what we got:

KeyStrPress Alt_L 
KeyStrPress Control_L 
KeyStrPress Right 
KeyStrRelease Right 
KeyStrRelease Alt_L 
KeyStrRelease Control_L 
MotionNotify 298 10 
ButtonPress 1 
ButtonRelease 1 
KeyStrPress p 
KeyStrRelease p 
KeyStrPress a 
KeyStrRelease a 
KeyStrPress n 
KeyStrRelease n 
KeyStrPress Return 
KeyStrRelease Return 
KeyStrPress Control_L 
KeyStrPress Shift_L 
KeyStrPress u 
KeyStrRelease u 
KeyStrRelease Shift_L 
KeyStrRelease Control_L 
 
It's pretty easy to see how it all works. Each key and mouse button in the sequence is pressed and released. The MotionNotify command tells the mouse where to move. (I'll discuss playback below, but because of the time it takes to open a window in Gnome, one must add some delays to a recorded macro. To pause playback for n seconds, insert the line "Delay n" where you need a pause.)

[Note: when I first tried recording a macro, I wound up with this error message:

~$ xmacrorec2 > testing.macro Server VendorRelease: 70101000 Xlib: extension "RECORD" missing on display ":0.0". xmacrorec2: XRecord extension not supported on server ":0.0"
 
The problem was with xorg.conf. If you get a similar error message, try the following:

sudo gedit /etc/X11/xorg.conf
 
Look for Section "Module" and add the following line:

Load "record"
 
Save and exit.]

A more complex macro should be recorded and edited, or better yet, written from scratch. Fortunately, this is not too difficult. The output above gives many useful hints about how xmacro records keystrokes and mouse actions. In fact, the xmacro documentation (such as it is) says the "standard KeySym names are obtained from [X11/keysymdef.h] by removing the XK_ prefix from each name." In my distro (Ubuntu), the file is located at /usr/include/X11/keysymdef.h (just type "locate keysymdef.h"). Examining the file reveals that the authors of xmacro weren't kidding, it's all there.

How do you determine where the mouse is supposed to click? I use xmousepos, part of the xautomation package. Install xautomation, open a terminal, type "xmousepos", place your cursor where you need the position and hit "Enter". The program will return four numbers. The first two are the mouse position in absolute coordinates (on the monitor) and the last two are the relative coordinates (in the window). I'd use the absolute coordinates.

So now that you've got a reference for the keystrokes and mouse movements, it's a good idea to decide what you want to accomplish and map out the macro from there.

For my first project, I wanted to copy text from a series of web pages and paste the text into another document. I quickly discovered that with no way (to my knowledge) of defining which window I wanted to make active, it was best to have the terminal open on the first workspace, the browser (with all of the pages open in separate tabs) on the second workspace, and the destination file (plain text) on the third workspace. I would then select the text I wanted to copy, switch to the first workspace, and run the macro. The macro would switch to the second workspace, copy the text, move to the third workspace, paste the text, add a return, switch back to the second workspace, close the tab, and position the mouse so I could select the next batch of text to copy.

Here's the macro (topten.macro) I wrote, with annotations in parens. It's a plain text file.

KeyStrPress Control_L (the first three entries are a Ctrl+Alt+Right, to switch to the second workspace)  
KeyStrPress Alt_L 
KeyStrPress Right 
KeyStrRelease Right (the next three release the keys in reverse order--important to release the keys!)  
KeyStrRelease Alt_L 
KeyStrRelease Control_L

KeyStrPress Control_L (these two simply do a Ctrl-c to copy the previously selected text)
KeyStrPress c 
KeyStrRelease c 
KeyStrRelease Control_L

KeyStrPress Control_L (now switch to the third workspace...)  
KeyStrPress Alt_L 
KeyStrPress Right 
KeyStrRelease Right 
KeyStrRelease Alt_L 
KeyStrRelease Control_L

KeyStrPress Control_L (and paste.)
KeyStrPress v 
KeyStrRelease v 
KeyStrRelease Control_L 
KeyStrPress KP_Enter ("Enter" would work just as well here)  
KeyStrRelease KP_Enter

KeyStrPress Control_L (now switch back to the second workspace...)
KeyStrPress Alt_L 
KeyStrPress Left 
KeyStrRelease Left 
KeyStrRelease Alt_L 
KeyStrRelease Control_L

KeyStrPress Control_L (and close the tab with Ctrl+w)  
KeyStrPress w 
KeyStrRelease w 
KeyStrRelease Control_L
MotionNotify 495 410 (move the mouse to where you want it for the next round)

Like I said, it's best if you know what you want to do and what keystrokes you need in advance.

So, how do you run a macro? It has to be read by the program, so enter the following on the open terminal:

cat test.macro | xmacroplay -d 100 :0
 
The "-d 100" is a delay in milliseconds between commands. The ":0" tells xmacro which display to run the macro on.

BTW, it worked exactly as designed, and I wound up with all of the text in one document. I did have to do some trial-and-error to get the pointer to end up where I wanted it, but that was just a matter of editing the macro file between runs.

I hope this was helpful. From the documentation, it looks like there are many ways to simplify the keystroke definitions in the macro, but this worked fine for my first attempt. Overall, I'm pleased!

No comments: