Keyboard event generation in EventGhost

Was recently doing some program automation work in EventGhost (http://www.eventghost.org) for a client. Initially started out using the GUI actions such as SendKeys but it very quickly bogged down: application windows would miss key presses or the wrong window would get the key presses, sometimes it would act like I'd never even sent the key presses. After some pain I figured out that for some windows generated in certain programming environments (I'm looking at you, .Net) I simply couldn't use the SendKeys action. Enter Python.

I was quite pleased to discover that EventGhost has extensive Python integration: over the course of 2 weeks I basically reduced my entire EventGhost action tree from 20 actions to 3 comparatively complex Python scripts, which included robust error detection and integration hooks to support calling back to the client that generated the event to indicate the progress of the EventGhost macros. However, that's another longer story. Today's story is limited to key event generation.

EventGhost makes the Win32 keybd_event function available: this lets you generate low-level keyboard events that are much more reliable than the EventGhost SendKeys action. As with much of the Python package functions, it took me a good little while to track down the implementation details, but once I did I was able to implement the two functions below:

KEYEVENT_KEYDN = 0x0
KEYEVENT_KEYUP = 0x2
VK_SHIFT = 0x10
VK_CTRL = 0x11
VK_ALT = 0x12
VK_UP = 0x26
VK_DOWN = 0x28
VK_TAB = 0x09
VK_OEM_COMMA = 0xBC
VK_OEM_1 = 0xBA
VK_ESCAPE = 0x1B
VK_OEM_PLUS = 0xBB
VK_OEM_MINUS = 0xBD
VK_OEM_PERIOD = 0xBE
VK_SPACE = 0x20

def outputtext(text):
for c in text:
    outputkey(c)

def outputkey(src, ctrl = False, shift = False, alt = False):
if ctrl: eg.win32api.keybd_event(VK_CTRL, 0, 0, 0)
if alt: eg.win32api.keybd_event(VK_ALT, 0, 0, 0)
if src == u',':
    if shift: eg.win32api.keybd_event(VK_SHIFT, 0, 0, 0)
    eg.win32api.keybd_event(VK_OEM_COMMA, 0, 0, 0)
    eg.win32api.keybd_event(VK_OEM_COMMA, 0, KEYEVENT_KEYUP, 0)
elif src == u'+':
    shift = True
    eg.win32api.keybd_event(VK_SHIFT, 0, 0, 0)
    eg.win32api.keybd_event(VK_OEM_PLUS, 0, 0, 0)
    eg.win32api.keybd_event(VK_OEM_PLUS, 0, KEYEVENT_KEYUP, 0)
elif src == u'=':
    eg.win32api.keybd_event(VK_OEM_PLUS, 0, 0, 0)
    eg.win32api.keybd_event(VK_OEM_PLUS, 0, KEYEVENT_KEYUP, 0)
elif src == u'-':
    if shift: eg.win32api.keybd_event(VK_SHIFT, 0, 0, 0)
    eg.win32api.keybd_event(VK_OEM_MINUS, 0, 0, 0)
    eg.win32api.keybd_event(VK_OEM_MINUS, 0, KEYEVENT_KEYUP, 0)
elif src == u'_':
    shift = True
    if shift: eg.win32api.keybd_event(VK_SHIFT, 0, 0, 0)
    eg.win32api.keybd_event(VK_OEM_MINUS, 0, 0, 0)
    eg.win32api.keybd_event(VK_OEM_MINUS, 0, KEYEVENT_KEYUP, 0)
elif src == u' ':
    if shift: eg.win32api.keybd_event(VK_SHIFT, 0, 0, 0)
    eg.win32api.keybd_event(VK_SPACE, 0, 0, 0)
    eg.win32api.keybd_event(VK_SPACE, 0, KEYEVENT_KEYUP, 0)
elif src == u'.':
    if shift: eg.win32api.keybd_event(VK_SHIFT, 0, 0, 0)
    eg.win32api.keybd_event(VK_OEM_PERIOD, 0, 0, 0)
    eg.win32api.keybd_event(VK_OEM_PERIOD, 0, KEYEVENT_KEYUP, 0)
elif src.isdigit():
    eg.win32api.keybd_event(chr, chr, 0, 0)
    eg.win32api.keybd_event(chr, chr, KEYEVENT_KEYUP, 0)
else:
    chr = ord(src.upper())
    if src.isupper(): shift = True
    if shift: eg.win32api.keybd_event(VK_SHIFT, 0, 0, 0)
    eg.win32api.keybd_event(chr, eg.WinApi.Dynamic.MapVirtualKeyW(chr,0), 0, 0)
    eg.win32api.keybd_event(chr, eg.WinApi.Dynamic.MapVirtualKeyW(chr,0), KEYEVENT_KEYUP, 0)

if shift: eg.win32api.keybd_event(VK_SHIFT,0, KEYEVENT_KEYUP, 0)
if alt: eg.win32api.keybd_event(VK_ALT,0, KEYEVENT_KEYUP, 0)
if ctrl: eg.win32api.keybd_event(VK_CTRL,0, KEYEVENT_KEYUP, 0)

You can simply copy and paste the above functions into any PythonScript node: once that's done you can generate the keyboard events for any text string using the single call

outputtext(<string>)

This will work reliably independent of the programming environment of the target program, and will also trigger keyboard hooks or other such things.

Note: this is currently limited to standard letters (A to Z and a to z), digits (0 to 9), the plus (+), minus (-), comma (,), space ( ), equals (=), underscore (_) and period (.) characters (as that's all I had to support). At some point in the distant future I may expand the range of supported characters and figure out how to package this nicely so it can be imported rather than being copied/pasted into place, but for now it serves.

P.S. If you're looking to use your Android phone as a Bluetooth GPS device, checkout SolidSync Network/Bluetooth GPS in the Google Play Store or on the web at http://solidsync.com/networkbluetooth-gps.

Image

Need to send mail in a hurry?

Try Send Overnight Mail for your FedEx Overnight, USPS Priority Express or USPS Priority mailing needs. Send Overnight Mail is the easiest way to send overnight mail, online or offline: early-morning orders can even be sent same day!