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