George Wong
( ./gnw )
Computer Science

most recent



Various (resources)

aim -
email -
form - here
linkedin - here
youtube - here

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.

MATLAB | findCalibrationValues.m
01:17 01-Sep-12

A somewhat well-documented matlab code that will read the PDP calibration files, allow the user to find the linear range, show some statistics, then save a .mat file with relevant information.

I won't really go into the specifics of how calibration works, or how the code works, as I think it is sufficiently explained in the code file itself. Rather, I'll talk briefly about how the directory should be organized, and what will be encountered on the user-end when running the code.

[This code was published 1 September 2012, GW]

directory structure:
The findCalibrationValues.m file should be placed in whatever RX folder the calibration data exists in, in the uppermost directory. Within that directory, the calibration data should be in a folder named "Folder Number #" where # is defaulted to 1 in the program, however can be changed to whatever number is appropriate.

Within this folder should be new folders, one corresponding to each different measurement taken at a certain RX attenuation level. The folders should be named "# dB" where # corresponds to the RX attenuator level. Within these folders should be text files, names starting with "PDP".

The files themselves should be comma separated, with two columns, the first corresponding to time, the second to voltage-squared values (unscaled power). For this part of post-processing, the time column is not necessary; however, in its current form, the program will only look for power levels in the second column.

running the code:
Assuming that all of the files and folders are in their proper places, running the code is easy! The program displays an image similar to the one below and prints the following
Please enter extrema of linear range.
Min (dB): 20
Max (dB): 50

The user identifies the linear range of the graph and enters the minimum and maximum x-axis values. The code then replots the graph (reproduced below) and asks the user if the new line is a good fit (for the linear range). In this example, the linear range extends from about 20dB to 50dB. The new line, shown in green, should run with the data in the linear range specified before. The program asks if the line is good enough, if so, requesting the user enter the number "1".

Please enter extrema of linear range.
Min (dB): 20
Max (dB): 50
If new line fits, enter 1: 1

The graph closes and statistics are printed.

This section is meant to provide numerical confirmation that
the numbers entered are correct.
For the linear range that you entered, the path
loss(es) calculated follow(s):
20 dB ~ 0.16746
30 dB ~ -0.28775
40 dB ~ 0.073125
50 dB ~ 0.047166
The above numbers are in dB and should be close
to zero, whereas the following number (ratio) is
in linear and should be close to 1: 1.0008
If the above values are not satisfactory, rerun the program!

The first four numbers are the literal difference between the slope/intercept-calculated points for corresponding attenuations (points on the green line). The last number that is printed is the mean of the dB offsets represented in linear (i.e. ratios). The closer the first numbers are to zero, the better (0dB means no variance); the closer the last number is to one, the better (1:1 ratio).

The full program code can be found here.

This website is run and maintained by George Wong. This webpage was last modified 01:17 01-Sep-12 est.
You opened this page on and its subsidiaries are copyright 2003-2014.