Basically want to make a macro script

Adam D. Ruppe via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Thu Nov 13 14:33:42 PST 2014


All right, let's go through each line here too.

On Thursday, 13 November 2014 at 15:59:11 UTC, Adam D. Ruppe 
wrote:

> void sendString(wstring s) {

This function generates key press and key release events for each 
character in the string, making it a bit more convenient to use 
than the underlying OS function itself.

> 	INPUT[] inputs;
> 	inputs.reserve(s.length * 2);
>
> 	foreach(wchar c; s) {

We prepare the array of inputs which stores the information we 
pass to the operating system.


> 		INPUT input;
> 		input.type = INPUT_KEYBOARD;
> 		input.ki.wScan = c;
> 		input.ki.dwFlags = KEYEVENTF_UNICODE;
> 		inputs ~= input;

The exact values here come from the MSDN documentation, check the 
link I provided in a previous message.

Basically, we want an INPUT thing, type being the keyboard, and 
we tell the OS that it is a single Unicode character, value c. 
Add it to the list of events.

> 		input.ki.dwFlags |= KEYEVENTF_KEYUP; // released...
> 		inputs ~= input;

This modifies the event to add the key up flag then adds a copy 
of it to the list. So the key was pressed, then released.

> 	if(SendInput(inputs.length, inputs.ptr, INPUT.sizeof) != 
> inputs.length) {
> 		import std.stdio;
> 		writeln("SendInput failed");
> 	}

This function sends our data to Windows to forward to another 
program as keyboard events. The writeln in there is triggered if 
it doesn't work - for example, if permission is denied or the 
data is malformed.

> void main() {
>         // uses my simpledisplay.d to pop up a quick window
> 	import simpledisplay;

simpledisplay is a little file I wrote that handles a lot of 
other details involved in creating windows.

> 	enum hotkey_id = 1; // arbitrary unique ID for the program

When the operating system tells us that a hotkey was pressed, it 
sends an ID number to tell us which one. This can be almost any 
number, we just need to be consistent, so I set it to 1 here.

> 	auto window = new SimpleWindow(100, 50);

Creates a 100x50 pixel window using my simpledisplay library.

> 	window.handleNativeEvent = delegate int(HWND hwnd, UINT msg, 
> WPARAM wParam, LPARAM lParam) {

simpledisplay.d doesn't provide the specific functionality you 
need; it doesn't know how to register and react to hotkeys. So we 
have to extend it to handle those events. It uses delegate event 
handlers for that purpose.

> 		if(hwnd !is window.impl.hwnd)
> 			return 1; // we don't care...

just making sure the message is actually for our window, 
otherwise we ignore it and tell the library to take care of it by 
returning 1.

> 		switch(msg) {
> 			case WM_HOTKEY:

The operating system sends many, many different kinds of 
messages. The type is identified by the msg parameter. Using the 
switch statement in D, we can filter it do just the one we care 
about - a hotkey message - handle it, and ignore the rest.

> 				if(wParam == hotkey_id) {

Making sure the hotkey ID provided (in the wParam field - see the 
MSDN docs for this again. they have generic names because each 
message type has different meanings from these params) matches 
what we set.

> 					// MessageBoxA(window.impl.hwnd, "Hotkey", "Pressed!", 
> MB_OK);

This was just test code, it would pop up a message box saying a 
key was pressed. It is commented because we wanted to send a 
string instead.

> 					sendString("Hey, it worked!"w);
> 					return 0;

Which we do here, sending the string, then return 0 tells the 
library that we handled this message.

> 				}
> 			goto default;
> 			default: return 1; // not handled, pass it on
> 		}

Otherwise, our default behavior is to ignore all other messages 
and let the library handle them instead.

>
> 	string message = "Hotkey ready";

This message is displayed in the window when you run the program, 
to give some visual feedback that it is working.

> 	if(!RegisterHotKey(window.impl.hwnd, hotkey_id, 0, VK_F2)) {
> 		message = "RegisterHotKey failed";
> 	}

This informs the operating system that we want to register and 
reserve a hot key for our use. The params are first, our window 
which handles the message, the hotkey id used in the message 
above, then the key itself.

The third param is what modifiers need to be pressed. For 
example, the ctrl or alt keys. I didn't want to have to press 
those because it complicates things a bit, so I said 0 here - no 
modifiers required.

The fourth param is the key. I talked about this in my last 
email, VK_F2 is the F2 key. We could also use VK_F4 or even 'Z' 
to make it on the Z key. (Warning though, if you make it a 
letter, best to require ctrl or alt and then the sendString 
function needs to release that modifier then press it again so 
the program doesn't get confused. Otherwise, it would think the 
user is still holding ctrl or whatever, and when a 's' is passed 
along, it will try to save the file because it thought the user 
hit ctrl+s!)

> 	{
> 		auto painter = window.draw();
> 		painter.drawText(Point(0, 0), message);
> 	}

This little bit just draws the message on our window. The 
surrounding {} is a requirement from simpledisplay.d - it buffers 
all drawing actions until the next } (when the painter goes out 
of scope) and we want it to draw before entering the loop.

> 	window.eventLoop(0); // draw our window


And finally we go into the loop, where the window is actually 
drawn and we react to user actions. Most GUI programs have a line 
or lines similar to this. Internally it looks like

while(!window.closed) {
      window.handleNextMessage();
}

> // these are bindings to the necessary Windows API functions

And the rest of the file is just copy/pasting the function names 
and params, constant values, and struct layouts from MSDN, like i 
said before. Ideally, this would all just be in an imported file 
too, but D doesn't come with one for this purpose and it is 
easier to list them here than try searching the web and 
downloading one since we don't need that many.


More information about the Digitalmars-d-learn mailing list