This module contains useful procs that can be used to automate boring GUI tasks.
Concept: contexts
The autome namespace contains several variables available for you: mouse and keyboard. They are called mouse context and keyboard context correspondingly. To use mouse or keyboard procs, you must pass these variables in them or create your own context.
move(mouse, 640, 480) # move mouse to 640, 480 # .. or .. mouse.move(640, 480)
All of mouse or keyboard procs returns same context they have received, so you can chain procs of same context:
mouse .move(640, 480) .click() .move(123, 321)
There are methods that are not bound to specific context, but accept them to not break proc chaining (wait proc for example).
Types
KeyboardCtx = ref object
- represents keyboard context.
MouseCtx = ref object perActionWaitTime: int32
- represents mouse context.
Window = distinct Handle
- represents window handle.
Point = tuple[x: int32, y: int32]
- represents point on the screen.
KeyboardModifier = enum modAlt = 0, modControl = 1, modShift = 2, modNoRepeat = 14
- represents various keyboard modifiers.
KeyboardModifiers = set[KeyboardModifier]
- represents set of keyboard modifiers that can be combined.
Hotkey = distinct int
- represents hotkey registered with registerHotkey proc.
WinString = WideCString
- cstring when useWinAnsi defined, WideCString otherwise.
MouseButton = enum mLeft, mRight, mMiddle
- represents mouse button
MouseState = enum msDown, msUp
- represents mouse button click state: pressed or released
Procs
proc `==`(a, b: Window): bool {.borrow.}
- proc to enable comparison of two windows.
proc `==`(a, b: Hotkey): bool {.borrow.}
- proc to enable comparison of two hotkey handles.
proc `!=`(a, b: Hotkey): bool {.raises: [], tags: [].}
- proc to enable comparisson of two hotkey handles.
proc wait(ms: int32): void {.inline, sideEffect, raises: [], tags: [].}
- suspends the execution of current thread until the time-out interval elapses. Time is in milliseconds.
proc getPixel(x, y: int): int32 {.raises: [OSError], tags: [].}
returns pixel color at x and y. High-order byte is always 0, next bytes are blue, green, and low-order byte is red (aka 0x00BBGGRR). If x or y are out of bounds, OSError raised.
You can use unpackColor() proc to get tuple containing red, green and blue values in their respective bytes.
proc unpackColor(color: int32): tuple[r, g, b: byte] {.raises: [], tags: [].}
- unpacks color, encoded as int32, to tuple. 0x00BBGGRR
proc desktopSize(): tuple[width, height: int] {.raises: [], tags: [].}
- returns desktop size. This is not same as monitor size: if Windows runs in 640x480, but monitor is 1920x1080, returned value will be 640x480.
proc minimized(h: Window): bool {.raises: [], tags: [].}
- determines whether a window is minimized.
proc maximized(h: Window): bool {.raises: [], tags: [].}
- determines whether a window is maximized.
proc restore(h: Window): Window {.sideEffect, discardable, raises: [], tags: [].}
restores window from minimized or maximized state or both. As result window is getting ## unminimized and unmaximized, its previous position before minimization or maximization gets restored. If window is not minimized or maximized, nothing will happen.
When window gets restores from minimized state, it will gain focus, but restoring from maximized state doesn't give focus. Already showing window also does not receive focus.
proc unminimize(h: Window): Window {.inline, sideEffect, discardable, raises: [], tags: [].}
- unminimizes window if it is minimized. Does nothing otherwise.
proc unmaximize(h: Window): Window {.inline, sideEffect, discardable, raises: [], tags: [].}
- unmaximizes window if it is maximized. Does nothing otherwise.
proc title(window: Window; cap: int = 96): string {.raises: [], tags: [].}
- returns title of the window. Variable cap specifies how much bytes will be allocated for title string. If window title has length >= cap, returned window title will be trimmed to cap - 1 characters.
proc findWindow(search: string): Window {.raises: [Exception], tags: [RootEffect].}
- returns first window which contains following string. Returns Window(0) if not found.
proc waitForWindow(search: string; timeout: int; pollDelay: int32 = 100): Window {. sideEffect, raises: [Exception], tags: [RootEffect].}
- blocks current thread until window containing string search has been found or until timeout (milliseconds) elapses, polling for window each pollDelay milliseconds. Returns Window(0) if timeout has elapsed and no window was found.
proc waitForWindowDestroy(window: Window; timeout: int; pollDelay: int32 = 100): bool {. sideEffect, raises: [], tags: [].}
- blocks current thread until window gets destroyed. This proc may not catch destroy event because window handles are recycled and thus old window handle may point to the new window handle. Returns true when window has been destroyed and false when timeout elapsed.
proc windowAt(pos: Point): Window {.raises: [OSError], tags: [].}
- returns window at pixel pos. If there are no window at pos, OSError is raised.
proc enumWindows(): seq[Window] {.raises: [Exception], tags: [RootEffect].}
- enumerates all opened windows, including hidden system windows.
proc pos(h: Window): Point {.raises: [OSError], tags: [].}
- returns window position relative to upper-left corner. If window is minimized or proc fails, OSError is raised.
proc size(h: Window): tuple[w: int32, h: int32] {.raises: [OSError], tags: [].}
- returns width and height of the window including window borders. If proc fails, OSError raised. May report wrong values.
proc clientsize(h: Window): tuple[w: int32, h: int32] {.raises: [OSError], tags: [].}
- returns width and height of the window without window borders aka actual window size. If proc fails, OSError raised. May report wrong values.
proc move(window: Window; x, y: int): Window {.sideEffect, discardable, raises: [OSError], tags: [].}
- moves window to new position. If proc fails, OSError raised.
proc resize(window: Window; w, h: int): Window {.sideEffect, discardable, raises: [OSError], tags: [].}
- resizes window. If proc fails, OSError raised.
proc attach(h: Window): Window {.sideEffect, discardable, raises: [OSError], tags: [].}
- attaches current thread to window thread so show() and focus() procs can be used with window.
proc detach(h: Window): Window {.sideEffect, discardable, raises: [OSError], tags: [].}
- detaches current thread from window.
proc tofront(window: Window): Window {.sideEffect, discardable, raises: [OSError], tags: [].}
- puts window on top of Z-order. If proc fails, OSError raised.
proc focus(window: Window): Window {.sideEffect, discardable, raises: [OSError], tags: [].}
- gains focus to the window. If proc fails or current thread is not attached to thread of window, OSError raised.
proc show(window: Window): Window {.sideEffect, discardable, raises: [OSError], tags: [].}
- unminimizes window if it is not in normal state, brings it to front and focuses on it, basically, window is now on top above all other windows, howerer, it still may be covered by topmost windows.
proc tobottom(window: Window): Window {.sideEffect, discardable, raises: [OSError], tags: [].}
- puts the window on the bottom of Z-order. Window will lose it's topmost status. If proc fails, OSError raised.
proc topmost(window: Window; topmost: bool = true): Window {.sideEffect, discardable, raises: [OSError], tags: [].}
- enables or disables topmost status of the window. When topmost status disabled, window will be placed on top of Z-order before topmost windows. If proc fails, OSError raised.
proc setActionWaitTime(mouse: MouseCtx; ms: int32; waitToo: bool = true): MouseCtx {. inline, raises: [], tags: [].}
- change action wait time of mouse. This proc specifies for how much this application thread should sleep before continuing execution after each MouseCtx action like move() or click(). Change to 0 to disable waiting after each action. If waitToo is true, this proc will wait ms milliseconds before executing.
proc pos(m: MouseCtx): Point {.raises: [], tags: [].}
- returns current position of the cursor.
proc click(m: MouseCtx; button: MouseButton; x, y: int32): MouseCtx {.sideEffect, discardable, raises: [], tags: [].}
- emulates mouse press and release event.
proc click(m: MouseCtx; x, y: int32): MouseCtx {.sideEffect, discardable, raises: [], tags: [].}
- emulates mouse press with left mouse button at position x, y.
proc click(m: MouseCtx): MouseCtx {.sideEffect, discardable, raises: [], tags: [].}
- enumates mouse press with left mouse button at current mouse position.
proc doubleclick(m: MouseCtx): MouseCtx {.sideEffect, discardable, raises: [], tags: [].}
- emulates double mouse press and one release event.
proc emit(m: MouseCtx; button: MouseButton; events: varargs[MouseState]): MouseCtx {. sideEffect, discardable, raises: [Exception], tags: [].}
- emits mouse press/release events at current mouse position.
mouse.emit(mLeft, msDown, msDown, msDown, msUp) # emulate tripleclick
proc move(m: MouseCtx; x, y: int): MouseCtx {.sideEffect, discardable, raises: [], tags: [].}
- sets mouse position to x and y.
proc movedelta(m: MouseCtx; dx, dy: int): MouseCtx {.sideEffect, discardable, raises: [], tags: [].}
- moves mouse by dx and dy pixels. This proc may be useful to interface with window menu bar items, which are not receiving "hover" event when using move proc.
proc x(m: MouseCtx): int {.inline, raises: [], tags: [].}
- returns mouse x position.
proc y(m: MouseCtx): int {.inline, raises: [], tags: [].}
- returns mouse y position.
proc x(m: MouseCtx; pos: int): MouseCtx {.inline, sideEffect, discardable, raises: [], tags: [].}
- sets mouse x position.
proc y(m: MouseCtx; pos: int): MouseCtx {.inline, sideEffect, discardable, raises: [], tags: [].}
- sets mouse y position.
proc x=(m: MouseCtx; pos: int) {.inline, sideEffect, raises: [], tags: [].}
- sets mouse x position.
proc y=(m: MouseCtx; pos: int) {.inline, sideEffect, raises: [], tags: [].}
- sets mouse y position.
proc wait(m: MouseCtx; ms: int32): MouseCtx {.inline, sideEffect, discardable, raises: [], tags: [].}
- stops execution for ms milliseconds.
proc send(kb: KeyboardCtx; keys: string): KeyboardCtx {.sideEffect, discardable, raises: [], tags: [].}
- emulates character key presses with characters in keys string. Make sure you have right keyboard layout set up, because this proc does not send actual characters, but underlying ASCII key codes associated with characters.
proc wait(kb: KeyboardCtx; ms: int32): KeyboardCtx {.sideEffect, discardable, raises: [], tags: [].}
- stops execution for ms milliseconds.
proc registerHotkey(key: uint32; mods: KeyboardModifiers = {}): Hotkey {.sideEffect, raises: [OSError], tags: [].}
registers hotkey that can be invoked globally. Use waitForHotkey proc to wait until hotkey is pressed. key is virtual-key code, which is unfortunately does not match ASCII key codes. List of virtual-key codes is available on MSDN. mods can be combined with or operator. Use modNoRepeat, so that keyboard auto-repeat does not yield multiple events.
If there are global hotkey with same signature already registered in system by any another application, this proc will raise OSError.
let hk = registerHotkey(0x42, {modShift}) # 0x42 - virtual-key of `b` waitForHotkey(hk) echo "hotkey SHIFT+b invoked"
Do not register hotkeys without modifiers because that will effectively block any key presses of button that specified as hotkey, for example, in Notepad.
proc unregisterHotkey(hotkey: Hotkey) {.sideEffect, raises: [], tags: [].}
- unregisters hotkey that was registered using registerHotkey proc.
proc waitForHotkeys(hotkeys: openArray[Hotkey]; timeout: uint32 = 0): Hotkey {. sideEffect, raises: [OSError], tags: [].}
- blocks current thread until any hotkey in openArray[Hotkey] invoked. If timeout is more than 0, then this proc will return after hotkey invoked or until timeout in milliseconds has elapsed. This proc returns handle of hotkey that was invoked or Hotkey(-1) if timeout elapsed.
proc waitForHotkey(hotkey: Hotkey; timeout: uint32 = 0): bool {.sideEffect, discardable, raises: [OSError], tags: [].}
- blocks current thread until hotkey is invoked. If timeout is 0, then this proc has no timeout. If timeout has elapsed, false returned, true otherwise. Note that registering Ctrl+C hotkey will shadow console Ctrl+C interrupt.
proc registerForNotify(): bool {.raises: [], tags: [].}
- registers dummy tray icon to status bar so you can send notifications to Windows. If this proc returns true, you can use notify proc to send notifications. If you don't unregister tray icon with unregisterNotify(), you will not able to register it again in when program launches next time.
proc notify(msg: string; title, tip: string = nil): bool {.discardable, raises: [], tags: [].}
- sends notification to Windows desktop notification area. Maximum size for msg is 255, for title - 64, for tip - 128. Before calling this proc you should call registerForNotify(). Returns false if length of msg, title or tip is more than allowed or when unable to send a notification.
proc unregisterNotify(): bool {.raises: [], tags: [].}
- unregisters tray icon from status bar that was registered by registerForNotify proc.