0

I am trying to write a macro program in C and I have managed to get the keys with the following code:

#include <windows.h>
#include <stdio.h>

HHOOK _hook;

KBDLLHOOKSTRUCT kbdStruct;

LRESULT __stdcall HookCallback(int nCode, WPARAM wParam, LPARAM lParam) {
    if (nCode >= 0) {
        kbdStruct = *((KBDLLHOOKSTRUCT*)lParam);
        if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) {
            printf("Key %lu pressed.\n", kbdStruct.vkCode);
        } else if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP) {
            printf("Key %lu released.\n", kbdStruct.vkCode);
        }
    }

    return CallNextHookEx(_hook, nCode, wParam, lParam);
}

void main() {
    if (!(_hook = SetWindowsHookEx(WH_KEYBOARD_LL, HookCallback, NULL, 0))) {
        MessageBox(NULL, "Failed to install hook!", "Error", MB_ICONERROR);
    }

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {}
}

I want the program to press a sequence of keys on specific times with SendInput() function when a specific key is pressed. The WH_KEYBOARD_LL hook is not called anymore when the while loop is set to infinite. Also using GetMessage(&msg, NULL, 0, 0) does not seem to be clean to me.

I have searched for a hook method to call a function on a given interval but without success.

I use the GNU GCC compiler.

I have almost no experience in programming in C on the computer but I do have experience in programming in C for microcontrollers.

Edit:

I have tried the method with SetTimer() but it does not get called. I have used the example from this page: http://www.equestionanswers.com/vcpp/set-timer.php

#include <windows.h>
#include <stdio.h>

#define TimerID 85

HHOOK _hook;

KBDLLHOOKSTRUCT kbdStruct;

VOID __stdcall MyTimerProc(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime) {
    printf("Timer call\n");
}

LRESULT __stdcall HookCallback(int nCode, WPARAM wParam, LPARAM lParam) {
    if (nCode >= 0) {
        kbdStruct = *((KBDLLHOOKSTRUCT*)lParam);
        if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) {
            printf("Key %lu pressed.\n", kbdStruct.vkCode);
        } else if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP) {
            printf("Key %lu released.\n", kbdStruct.vkCode);
        }
    }

    return CallNextHookEx(_hook, nCode, wParam, lParam);
}

void main() {
    if (!(_hook = SetWindowsHookEx(WH_KEYBOARD_LL, HookCallback, NULL, 0))) {
        MessageBox(NULL, "Failed to install hook!", "Error", MB_ICONERROR);
    }

    SetTimer(NULL, TimerID, 1000, MyTimerProc);

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {}
}

Tigris
  • 1
  • 2
  • I’m not familiar with Windows but looked up “winapi timers using messages” and found https://learn.microsoft.com/en-us/windows/win32/winmsg/using-timers, which looks like it might be right. – Ry- Aug 24 '20 at 00:30
  • You want to use `SetTimer()` like @Ry- posted above, but you want to use it with the 4th parameter (`TIMERPROC`) filled in. That would be a callback to a method with this signature: https://learn.microsoft.com/en-us/windows/win32/api/winuser/nc-winuser-timerproc – Andy Aug 24 '20 at 01:43
  • Is `SetTimer` failing? Can you call `GetLastError()` after you call `SetTimer`? What does `SetTimer` return? – Andy Aug 24 '20 at 03:32
  • With `DWORD dw = GetLastError(); printf("Error code is %X", dw);` I get 7E wich is the same as when I remove `SetTimer`. – Tigris Aug 24 '20 at 05:35

1 Answers1

0

I haven't used it ages, but from what I remember SetTimer relies on a Wndproc or Timerproc callback that looks for WM_TIMER messages. "Windows timers" are pretty crude overall though, so I would stay away from them.

What you should do instead is to create a thread which does the job. You can have it effectively asleep most of the time with WaitForMultipleObjects that allows you to define a timeout. When it times out, perform the task that should repeated cyclically. You should also create two custom events (CreateEvent etc), one that is sent from the hook callback informing the thread of an update ("next time you work, do work x instead"), and another that tells the threat to gracefully shut itself down (end of program etc). With this design you don't have to worry about re-entrancy either.

Lundin
  • 195,001
  • 40
  • 254
  • 396