aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Tay <nick@windblume.net>2022-05-07 23:00:13 +1000
committerNicholas Tay <nick@windblume.net>2022-05-07 23:00:13 +1000
commitecb4cff6f34783fd345419c0069c685793521e80 (patch)
tree2c21821cb000f86d72d7c8512ea27bdbe59bb5c3
parent740a0d2203a56033c630da2f11731f8f34df806d (diff)
downloadclak-ecb4cff6f34783fd345419c0069c685793521e80.tar.gz
clak-ecb4cff6f34783fd345419c0069c685793521e80.tar.bz2
clak-ecb4cff6f34783fd345419c0069c685793521e80.zip
Windows low-level hook working
Had to do some stuff with the previous VK tracking, just like what I had to do in C# with Meccha, since it keeps firing events. GetMessage part also just blocks to ensure we keep receiving Windows events, but not sure what to do otherwise.
-rw-r--r--clak.c90
1 files changed, 85 insertions, 5 deletions
diff --git a/clak.c b/clak.c
index 5203032..99b1482 100644
--- a/clak.c
+++ b/clak.c
@@ -1,6 +1,7 @@
#include <stdio.h>
#include <unistd.h>
#include <string.h>
+#include <signal.h>
#include <windows.h>
@@ -25,9 +26,9 @@ void sound_init(void)
waveOutSetVolume(NULL, (channel_volume << 16) | channel_volume);
}
-void sound_play(unsigned char* buffer)
+void sound_play(unsigned char *buffer)
{
- PlaySound((const char *) buffer, NULL, SND_MEMORY | SND_SYNC | SND_NODEFAULT);
+ PlaySound((const char *) buffer, NULL, SND_MEMORY | SND_ASYNC | SND_NODEFAULT);
}
Board *get_board(char *board_name)
@@ -39,9 +40,77 @@ Board *get_board(char *board_name)
return NULL;
}
+HHOOK keyboard_hook_windows;
+
+void keyboard_unhook(void)
+{
+ fprintf(stderr, "Cleaning up keyboard hook...\n");
+ if (!UnhookWindowsHookEx(keyboard_hook_windows))
+ printf("WARN: Windows keyboard hook could not be cleaned up! Error code: %lu\n", GetLastError());
+}
+
+void do_exit(int code)
+{
+ keyboard_unhook();
+ fprintf(stderr, "Goodbye.\n");
+ exit(code);
+}
+void on_clean_exit(void) { do_exit(0); }
+
+Board *board = NULL;
+
+void keyboard_on_down(void)
+{
+ if (board == NULL)
+ return;
+ sound_play(board->wav);
+}
+
+void keyboard_on_up(void)
+{
+ // if (board == NULL)
+ // return;
+}
+
+/* https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms644985(v=vs.85) */
+LRESULT CALLBACK keyboard_windows_callback(int nCode, WPARAM wParam, LPARAM lParam)
+{
+ /* Needed to prevent repeat fires */
+ static DWORD prev_vk = 0;
+
+ /* Do not handle unless nCode >= 0, pass to next hook right away */
+ if (nCode >= 0) {
+ BOOL down = wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN;
+ KBDLLHOOKSTRUCT *hook_struct = (KBDLLHOOKSTRUCT *) lParam;
+ DWORD vk = hook_struct->vkCode;
+ if (down && vk != prev_vk) {
+ keyboard_on_down();
+ prev_vk = vk;
+ } else {
+ keyboard_on_up();
+ /* Seems like repeat strokes are 0x0 or 0x1, and 'real' ones have 0x80 flag??
+ Not really sure how to handle this one, can't find many docs...
+ Saw this though: https://github.com/pyglet/pyglet/blob/838d004d68fcc5c3ce83b733e3d088fad0643859/pyglet/window/win32/__init__.py#L794= */
+ if (hook_struct->flags & 0x80)
+ prev_vk = 0;
+ }
+ }
+
+ return CallNextHookEx(NULL, nCode, wParam, lParam);
+}
+
+void keyboard_hook(void)
+{
+ fprintf(stderr, "Setting up keyboard hook...\n");
+ keyboard_hook_windows = SetWindowsHookEx(WH_KEYBOARD_LL, keyboard_windows_callback, NULL, 0);
+ if (keyboard_hook_windows == NULL) {
+ printf("ERROR: Could not set up Windows keyboard hook.\n");
+ do_exit(1);
+ }
+}
+
int main(int argc, char **argv)
{
- Board *board;
if (argc < 2 || (board = get_board(argv[1])) == NULL) {
printf("Please provide a valid board name.\n");
printf("Valid boards: ");
@@ -52,8 +121,19 @@ int main(int argc, char **argv)
}
sound_init();
- printf("name: %s\n", board->name);
- sound_play(board->wav);
+ keyboard_hook();
+ atexit(on_clean_exit);
+ fprintf(stderr, "Hooks set up, welcome to Clak!\n");
+
+ MSG msg;
+ BOOL status;
+ while ((status = GetMessage(&msg, NULL, 0, 0))) {
+ if (status == -1) {
+ // error case
+ printf("ERROR: Windows error, code %lu\n", GetLastError());
+ exit(1);
+ }
+ }
return 0;
} \ No newline at end of file