1
\$\begingroup\$

I am using the Windows API to register system-wide hotkeys. This requires a message loop to be created, and a handler to handle the hotkey messages. I have written two pieces of functioning code. The definitions of some functions have been redacted because they are unnecessary for the example. You just need to know that readConfig(), registerAllHotKeys(), and messageLoop() are functions that I wrote.

The design of messageLoop() is in question. I can either make it take one function to which the hotkey message will be passed, or I can pass an array of void function()[HotKeyID] handlers to call from.

Here is the source of messageLoop() when handling the arrays.

void messageLoop(void function()[HotKeyID] handlers) {
    MSG message;

    while (GetMessage(&message, null, 0, 0) > 0) {
        HotKeyID hkID = to!HotKeyID(message.wParam);

        if (hkID in handlers)
            handlers[hkID]();
    }
}

This is the code to handle messages by calling functions defined in the array, if present.

void main() {
    string[string] hkConfig = readConfig("hotkeys.conf");

    registerAllHotKeys(hkConfig);

    messageLoop([
        HotKeyID.TOGGLETILING: &toggleTiling,

        HotKeyID.FOCUSUP: &focusUp,
        HotKeyID.FOCUSDOWN: &focusDown,
        HotKeyID.FOCUSLEFT: &focusLeft,
        HotKeyID.FOCUSRIGHT: &focusRight,

        HotKeyID.SELECTUP: &selectUp,
        HotKeyID.SELECTDOWN: &selectDown,
        HotKeyID.SELECTLEFT: &selectLeft,
        HotKeyID.SELECTRIGHT: &selectRight,

        HotKeyID.SWAPUP: &swapUp,
        HotKeyID.SWAPDOWN: &swapDown,
        HotKeyID.SWAPLEFT: &swapLeft,
        HotKeyID.SWAPRIGHT: &swapRight,

        HotKeyID.MINIMIZE: &minimize,
        HotKeyID.MAXIMIZE: &maximize,

        HotKeyID.TERMINATE: &terminate,
        HotKeyID.FORCEKILL: &forcekill,

        HotKeyID.POPOUT: &popout,
        HotKeyID.POPIN: &popin,

        HotKeyID.MOVEUP: &moveUp,
        HotKeyID.MOVEDOWN: &moveDown,
        HotKeyID.MOVELEFT: &moveLeft,
        HotKeyID.MOVERIGHT: &moveRight,

        HotKeyID.INCREASESIZE: &increaseSize,
        HotKeyID.DECREASESIZE: &decreaseSize,

        HotKeyID.INCREASEGAP: &increaseGap,
        HotKeyID.DECREASEGAP: &decreaseGap
    ]);
}

Versus the code to handle the message ID directly.

void handleMessage(HotKeyID hkID) {
    switch (hkID) {
    case HotKeyID.TOGGLETILING:
        toggleTiling();
        break;

    case HotKeyID.FOCUSUP:
        focusUp();
        break;
    case HotKeyID.FOCUSDOWN:
        focusDown();
        break;
    case HotKeyID.FOCUSLEFT:
        focusLeft();
        break;
    case HotKeyID.FOCUSRIGHT:
        focusRight();
        break;

    case HotKeyID.SELECTUP:
        selectUp();
        break;
    case HotKeyID.SELECTDOWN:
        selectDown();
        break;
    case HotKeyID.SELECTLEFT:
        selectLeft();
        break;
    case HotKeyID.SELECTRIGHT:
        selectRight();
        break;

    case HotKeyID.SWAPUP:
        swapUp();
        break;
    case HotKeyID.SWAPDOWN:
        swapDown();
        break;
    case HotKeyID.SWAPLEFT:
        swapLeft();
        break;
    case HotKeyID.SWAPRIGHT:
        swapRight();
        break;

    case HotKeyID.MINIMIZE:
        minimize();
        break;
    case HotKeyID.MAXIMIZE:
        maximize();
        break;

    case HotKeyID.TERMINATE:
        terminate();
        break;
    case HotKeyID.FORCEKILL:
        forcekill();
        break;

    case HotKeyID.POPOUT:
        popout();
        break;
    case HotKeyID.POPIN:
        popin();
        break;

    case HotKeyID.MOVEUP:
        moveUp();
        break;
    case HotKeyID.MOVEDOWN:
        moveDown();
        break;
    case HotKeyID.MOVELEFT:
        moveLeft();
        break;
    case HotKeyID.MOVERIGHT:
        moveRight();
        break;

    case HotKeyID.INCREASESIZE:
        increaseSize();
        break;
    case HotKeyID.DECREASESIZE:
        decreaseSize();
        break;

    case HotKeyID.INCREASEGAP:
        increaseGap();
        break;
    case HotKeyID.DECREASEGAP:
        decreaseGap();
        break;
    default:
        break;
    }
}

void main() {
    string[string] hkConfig = readConfig("hotkeys.conf");

    registerAllHotKeys(hkConfig);

    messageLoop(&handleMessage);
}

Which one?

The disadvantage of the array being passed to messageLoop() is that I can't control the arguments of the functions it calls from the pointers. An advantage is that I can programatically modify the array if I need to. Since these functions effectively modify a state machine, I don't need arguments.

An advantage of the switch is that I can control the arguments, however I cannot change the handlers once the messageLoop() has been instantiated. It is also longer, and more breakable. However it does offer more control, as all of the functions could be inline lambdas to the switch.

If I am correct, performance difference between the two should be negligible.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.