Pages

8/20/2012

How to Sending Keystrokes Using Ruby

Sending keystrokes requires heavily on interfacing with operating system. Therefore, the solution for Ruby to do this is different for each operating system.

For me, I'm using Ubuntu, and I found couple of tools to use purely out-of-the-box (I mean as a command-line.) These tools are:

Xautomation
My opinion, this is quite useful if you want to send a string, some characters, or single keystroke. But sending combined keystroke is a bit harder and longer to do as demonstrated in the picture below. Another point is, this tool does not have a feature to send keystrokes to a specific a application window. It only can accepts "xwindow" parameter which allows us to send a keystroke to a specific Xwindow(e.g. :0), but cannot specify which application (in that xwindow) it sends to. My guess, it only send to an active application's window only.

To install on Ubuntu:
sudo apt-get install xautomation

After installation, the command that comes with this package is not actually same as package's name, it's "xte". This tool allows you to send commands, such as "str", "key", "keyup", "keydown", "mouseclick", "mouseup", "mousedown", "mousemove", and also delay commands, such as "sleep".

Usage:
xte command param


Xdotool
I found this tool because I wanted to use a Ruby gem package called "xdo" and it requires this command line tool. It turns out this "xdotool" is a powerful tool by itself, and the ruby package("xdo") is just a ruby interface of this tool. Here are reason why I think it's more powerful than Xautomation:
  • it can send keystrokes easier, e.g. xdotool key "ctrl+c"
  • it can specified application's window it sends the keystrokes to
  • it can be set to have delay between keystrokes (default = 12ms)
  • since it allows to send keystrokes to a target window, it has its own window manipulation module built-in, which allows us to:
    • search for a window using window's title name, xwindow, desktop, pid
    • set focus/unfocus the window
    • bind window event, such as mouse-enter, mouse-leave, mouse-click, focus, etc. to an xdotool's command or external command
    • resize, minimize, , close, move window

To installation on Ubuntu:
sudo apt-get install xdotool

Usage:
xdotool command param



** I also found another tool, called "X11-guitest" which seems to be a tool/library in Perl language. Since it's in Perl, not Ruby, so I don't include it here :P

Now, It's time to write code on Ruby
As I have explain above, I am using "xdo" package on Ruby which is an interface to Xdotool. So the process of using Xdo is very similar to Xdotool on command line.

First, get started by install "xdo" gem package
sudo gem install xdo

Then, write code to use Xdo.

Here's my code to cheat on Google's doodle game, "Slalom Canoe 2012"
This game needs a player to press Left and Right alternatively, and repeatedly, as fast as possible.
So why not write a script to do it.
This should work the same way as AutoIt does on Windows, or way better because it is Ruby :)

#!/usr/bin/env ruby

# includes Xdo package
require 'xdo/keyboard'
require 'xdo/mouse'
require 'xdo/xwindow'

# search for window id using title name
win_id = XDo::XWindow.search("Slalom Canoe 2012").last 

# Uncomment to bring the window up (I don't need to bring it up)
# window = XDo::XWindow.new(win_id) # create window object (this does not create an actual new window)
# window.unfocus  #make sure the window is not focus before call .activate
# window.activate #bring the window up

# loop 1000 times to send left and right to the window
1000.times do
 XDo::Keyboard.char("Left",win_id);
 XDo::Keyboard.char("Right",win_id);
end


One thing to point out in the VDO, this code does not require the window to be focused before sending the keystrokes. It can send to any unfocused or minimized window. This could turn into a malicious annoying keystroke bastard program. LOL.

For those who live on Windows
You can try AutoIt , so you don't have to write ruby code like this.
Just in case, you want to try writing Ruby code to sending keystrokes, I found two projects that can do this.

Au3 
This is a Ruby package acting as an interface to AutoIt library. That's why its requirement is "AutoItX3.dll" which you need to install AutoIt first, then copy the file from it. Au3 also created from the same team (Automations) who created Xdo.

FFI
This is totally different from the above packages. While it still acts as a proxy between Ruby code and native libraries, it does not specified the native library nor function to bind with. Therefore, you can bind it with LibC (on linux), user32.dll(on Windows), kernel32.dll(on Windows).
To send a keystroke on Windows, you need to call "kbd_event" function, on "user32.dll".

I have not yet tried these two out. So I don't know what to say on this. If anyone has tried it, please let me know on the comment below.

References:

No comments:

Post a Comment