I'm starting a thread for my macro programming tools project here, and I'll keep it up to date as progress is made, with source code postings and such things, along the way.
The basic idea for this project is to create an open-source software library that makes creating macros for various input devices a lot easier.
Built on top of this open-source library will be a custom-developed, user-friendly scripting language (somewhat akin to the Cougar macro language), a compiler, and a runtime that can execute user-defined scripts. Later, there may be a visual development environment as well.
To give you an idea of some of the "primitives" that make up the underlying library, here's an incomplete list:
AnalogSignal Represents a 64-bit integer value, and provides notifications to registered "listeners" whenever this value changes.
Counter Takes a
DigitalSignal called
In, and produces an
AnalogSignal that represents the number of times the
DigitalSignal's value has been set High (
true). Also provides a
Reset line, and can be initialized to start at any number, and increment by any number.
Delay Allows adding user-defined delay to a macro chain. When
Delay's
In signal is set High (
true), it's
Out signal will come on a user-specified time period later.
DigitalSignal Represents a Boolean value (
true or
false), and provides notifications to registerd "listeners" whenever this value changes.
ExecuteCommand When its
In line is set High (
true),
ExecuteCommand runs a user-specified program, optionally supplying user-specified parameters to the program.
FlipFlop Each time its
In line is set High (
true), a
FlipFlop's
Out value toggles between
true and
falseForcedPriorityTask When its
In line is set High (
true), a
ForcedPriorityTask will cause any other I/O macros to queue up. When the
ForcedPriorityTask completes, those other macros can then be completed in the order they were queued.
IntegerOperation Provides basic math operations on
AnalogSignals. Available operators include:
AbsoluteValue,
Multiply,
Divide,
Add,
Subtract,
DivRem (modulo division),
Min,
Max,
Power,
Sign,
LeftShift,
RightShift, and
Negate, among potentially many others.
Takes any number of
AnalogSignals and applies the given operator to them, in order, producing another
AnalogSignal as the output carrying the result of the operation.
Inverter Flips a
DigitalSignal to its opposite value. An
Inverter's
Out line is set High (
true) whenever its
In line is set Low (
false).
Join Waits for two or more
DigitalSignals to be set High (
true), at which point its
Out line is set High (
true).
KeyPress Generates a user-specified key press (down, up, or both in sequence) one time, when its
In line is set High (
true). Upon completion, it raises its
Out line.
LogicGate Provides basic logical operators on
DigitalSignals. Operators include
Not (output is the opposite of the input),
And,
Or,
Nand,
Nor,
Xor,
XNor,
False (output is True when both inputs are False),and
True (output is True when both inputs are True)
Macro Provides a wrapper that allows waiting for multiple, chained "primitives" to finish. A
Macro has an
In line that will start the macro chain when it is raised. It also requires a
ToStart line indicating the input signal at the front of the macro chain that will be started, and a
WaitFor line that represents the output from the last macro in the chain. A
Macro's
Out line will be set High (
true) when all of the macros contained in the chain have completed.
MouseClick Generates a mouse button click (or a simple independent button-down or button-up event) on the user-specified mouse button, when its
In line is set High (
true). Upon completion, its
Out line will be set High (
true).
MouseDoubleClick Same as
MouseClick except generates a double click on the specified mouse button.
MouseMovement Moves the mouse cursor to the specified absolute or relative coordinates when its
In line is set High (
true). Upon completion, its
Out line will be set High (
true).
MouseRotator Similar to the Cougar's MOUSEROTATE command. Rotates the mouse cursor around a user-specified circle, optionally executing a
Macro at user-defined spots along the circle or along the entire path. Upon completion, its
Out line will be set High (
true).
MouseWheelMovement Simulates movement of the mouse wheel by a user-specified amount (specified in multiples of
WheelDelta). Upon completion, its
Out line will be set High (
true).
Pulser A
Pulser toggles a
Macro on and off, at user-specified intervals.
Range Represents a pair of user-specified analog values to which an
AnalogSignal can be compared.
RangeEvaluator Compares an
AnalogSignal to a
Range. The
RangeEvaluator's
Out line will be set to High (
true) when the
AnalogSignal's value is within the specified
Range.
Repeater Repeats a
Macro a user-specified number of times.
Split Splits a
DigitalSignal into two or more
DigitalSignals that all derive their values from same source
DigitalSignal. Allows for macro chains to execute in parallel.
Timeout Executes a
Macro and forcibly aborts the
Macro if the
Macro does not complete within a user-specified time period.
Timer Executes a
Macro only for a user-specified time period.
Toggle Each time its
In line is set High (
true), a
Toggle will set the next
DigitalSignal in its
Outs collection to High (
true), and will set all other output lines Low (
false). A
Toggle also provides reset and reverse lines. Acts as a switch for selecting between alternate signal paths, in sequence.
You can combine these programmatic "primitives" to produce a full-fledged macro program. The "compiler" itself, generates a program built entirely from these and other such primitives.
An example C# code snippet, showing a tiny program built using some of the above primitives, is shown below:
ExecuteCommand notepad = new ExecuteCommand("notepad.exe");
Delay waitForNotepad = new Delay(new TimeSpan(0, 0, 4), notepad.Out);
KeyPress key1 = new KeyPress(Keys.H);
KeyPress key2 = new KeyPress(Keys.E, key1.Out);
KeyPress key3 = new KeyPress(Keys.L, key2.Out);
KeyPress key4 = new KeyPress(Keys.L, key3.Out);
KeyPress key5 = new KeyPress(Keys.O, key4.Out);
KeyPress key6 = new KeyPress(Keys.Oemcomma, key5.Out);
KeyPress key7 = new KeyPress(Keys.Space, key6.Out);
KeyPress key8 = new KeyPress(Keys.W, key7.Out);
KeyPress key9 = new KeyPress(Keys.O, key8.Out);
KeyPress key10 = new KeyPress(Keys.R, key9.Out);
KeyPress key11 = new KeyPress(Keys.L, key10.Out);
KeyPress key12 = new KeyPress(Keys.D,key11.Out);
KeyPress key13 = new KeyPress(Keys.OemPeriod, key12.Out);
KeyPress key14 = new KeyPress(Keys.Return, key13.Out);
Delay d = new Delay(new TimeSpan(0, 0, 0, 1));
d.In = key14.Out;
Pulser p = new Pulser(new TimeSpan(0,0,0,0,1));
p.Macro.ToStart = key1.In;
p.Macro.WaitFor = d.Out;
Timer t = new Timer(new TimeSpan(0, 0,1));
t.Macro.ToStart = p.In;
t.Macro.WaitFor = p.Out;
Macro start = new Macro();
start.In = waitForNotepad.Out; //this macro will start after notepad launches
start.ToStart = t.In;
start.WaitFor = t.Out;
notepad.In.State = true; //start the notepad macro which will in turn launch our other stuff
I leave it as an exercise for the reader to figure out just what this simple program might be outputting.
I will be uploading the primitives library to this thread in a few weeks, and I'll get more work done on the scripting language and compiler after that.
edit:the current work on this macro tools project can be found in my
Subversion repository, for now; NOT on the main page of my
Assembla workspace, yet, since it has not been officially released yet...)