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.

Reply via email to