Please accept my apologies for the mess — the site is under construction.


about / contact

the site
the webmaster

full cv (pdf)



the Lorentz boost (coming soon)

Windows Macro (v2)
19:40 10-Dec-13

As it turns out, necessity coupled with laziness the desire to be efficient is a powerful motivator. One of my laboratory experimental procedures included clicking in a series of set places every 3 minutes to record measurements. Rather than do this manually, I settled on automation. The product is "macro_win", an extensive upgrade/rewrite of the perviously published Auto Clicker Mouse Utility.

(I'll admit I originally planned on writing the code in Java, but decided to switch to C++ because I had already developed the mouse library—and hey, C++ is more fun anyway.)

The idea behind the program is to allow the user to easily define a custom macro and then automatically execute this macro any number of times.

Upon execution, the program looks for a custom macro name (passed as a command line argument after a -m flag). If it does not find one, it continues with the macro named default.macro. The steps of the macro are loaded into memory making use of the custom defined MStep (macro step) class. To be honest, all this structure was a bit overkill and likely could've been handled with enums and pairs just as well—but classes are fun!

Full source may be found here.

how to write the macro file (quickstart)
The macro file consists of two parts, the configuration section and the macro defintion section.

The configuration consists of 3 lines. The first is a comment, the next two specify the number of times the macro should be repeated and the third specificies how long to wait (in seconds) before executing the macro. The wait time can be useful in switching windows/ensuring everything is in the right place.

# Number of repeats

The macro definition section begins with two comment lines and then lists each macro step.

# Commands in form:
# OPR (ARG1) (ARG2) [trailing space]
PAU 0.2 
CLK 0 
MOV 10 20 
TYP hello world 
POS 0 

  • PAU followed by a double-type argument (i.e. decimals allowed) instructs the program to sleep for the given number of seconds
  • CLK instructs the program to click using either the left or right (0 or 1 repsectively) mouse button
  • MOV followed by two integer-type arguments instructs the program to move the cursor to the absolute screne position as given by the arguments
  • TYP followed by any string of characters will simulate typing the string
  • POS requests the program print out the current position (in pixels) of the mouse pointer. If the argument is greater than 0, the program will print the cursor's position as often as the given argument. This function can be useful for debugging/determining the arguments for MOV steps.

Save your macro file with any desired filename and extension and tell main.exe to use it by running the program with the -m myMacroName.ext flag.

source review
The source for Macro Win includes two libraries I've written for generating I/O events in windows: keyboard_w32.hpp and mouse_w32.hpp.

keyboard interface
Functions related to keyboard events are defined within the KEYBOARD namespace, for the purpose of keeping a relatively muddle-free code. Keyboard events act exactly as if someone were physically pushing down the appropriate character(s) on their keyboard.

Skipping over helper function, the following are functions are useful:
int num_press (uint32_t n)
int any_char_press (const char c)
int space_press ()
... and of course is the amalgamated function
int string_write (std::string s).

Ideally, each action key should have a simple way to be called. I've written the following
int shift_down ()
int shift_up ()
int gen_press (uint32_t n, bool shift)

While each of the above functions is safe enough—especially for their intended uses—I highly suggest simply using string_write( ), unless you particularly need speed and/or memory efficiency.

mouse interface
As keyboard events live in the KEYBOARD namespace, mouse events live in the MOUSE namespace. All functions are relevant and are named as follows:

int moveTo (x, y)
int position (x, y)
int rightClick ()
int leftClick ()

int rightDown ()
int rightUp ()
int leftDown ()
int leftUp ()

The last four might be useful for dragging/box selection. Both moveTo and position take normal int variables. position updates the values for both x and y in the calling function (one step up).

miscellaneous code
The MStep class (named after Macro Step) is defined within. Basically, mstep provides a general structure within which to store instructions and their associated arguments. The four instance fields are defined: size, INS, ARG1, and ARG2.

INS, ARG1, and ARG2 are all strings; size is a number corresponding to the number of arguments + 1 (or equivalently the number of "arguments + one instruction").

Three constructors are provided (these are what are called when you first instantiate an MStep object), one for each allowed number of arguments. If an argument is not provided, the corresponding string is initialized to an empty string std::string("").

The ins_t function returns a number corresponding to the instruction type. The number-type relations are given below:
0 -> null
1 -> MOV
2 -> CLK
3 -> TYP
4 -> PAU
5 -> POS

Arguments can be returned in various forms by using arg_s, arg_ui, or arg_d to return a std::string, an unsigned 32-bit integer, or a double (respectively).

The two functions print and print_short may be used to print out the information stored in the MStep, as during debugging.

I wrote the one I/O function (reading the macro file into memory) into the IO namespace for no particular reason. It's not particularly engaging stuff, unless you're not familiar with file I/O, I suppose?

load_macro (this namespace's singular function) updates the *repeats, steps, wait, and MStep list passed to it according to information in the file with filename fname.
The main file, (which defines our program's entry point) is utterly uninteresting. It prints information to the user about the functionality of the program, parses the commandline input, and provides a help (man) page if prompted. After loading the definitions within the macro file, it executes the macro in a for loop for the given number of requested runs.

And that more or less wraps up everything you could possibly want to know about this program. Feel free to make use of any of my code (just leave my name somewhere in the comments, please!).

For the interested persons reading this, I used this program to automate the data collection process for a Mössbauer spectroscopy experiment. The two graphs generated from the data taken are provided below. The full report can be found here.

This website is run and maintained by George Wong. This webpage was last modified 19:40 10-Dec-13 est.
You opened this page on and its subsidiaries are copyright 2003-2014.