From 047544a5af9100ec269e9222213385bc7794f619 Mon Sep 17 00:00:00 2001 From: Nicholas Tay Date: Sat, 7 May 2022 23:26:27 +1000 Subject: Split out platform-specific code for Windows Not sure if I'm really doing it in the best way possible. Feels a bit weird that some place assumes the existence of other functions. --- Makefile | 15 ++++++++-- clak.c | 86 +++++++++-------------------------------------------- platform/platform.h | 10 +++++++ platform/win32.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 116 insertions(+), 75 deletions(-) create mode 100644 platform/platform.h create mode 100644 platform/win32.c diff --git a/Makefile b/Makefile index c2a94a6..bd016b7 100644 --- a/Makefile +++ b/Makefile @@ -5,14 +5,23 @@ BOARDS = mxblue quack CC = gcc CFLAGS += -std=c99 -Wall -Wextra -Wshadow -Werror -pedantic -LDLIBS = -lWinmm BOARD_FILES = $(addsuffix /board.h,$(addprefix board/,$(BOARDS))) +ifeq ($(OS),Windows_NT) + LDLIBS = -lWinmm + PLATFORM = win32 +else + UNAME_S := $(shell uname) + ifeq ($(UNAME_S),Linux) + PLATFORM = linux + endif +endif + default: $(NAME) -$(NAME): $(NAME).c $(BOARD_FILES) board/boards.h - $(CC) $(CFLAGS) $(NAME).c $(LDLIBS) -o $(NAME) +$(NAME): $(NAME).c platform/$(PLATFORM).c $(BOARD_FILES) board/boards.h + $(CC) $(CFLAGS) $(NAME).c platform/$(PLATFORM).c $(LDLIBS) -o $(NAME) board/boards.h: printf "#ifndef BOARD_DEFAULTS_H\n#define BOARD_DEFAULTS_H\n\n" > board/boards.h diff --git a/clak.c b/clak.c index 99b1482..eace40d 100644 --- a/clak.c +++ b/clak.c @@ -1,15 +1,16 @@ #include #include #include -#include - -#include +#include +#include #define VOLUME 0.15 #include "board/boards.h" #define BOARD(str, buf) { .name = str, .wav = buf }, +#include "platform/platform.h" + typedef struct { char *name; unsigned char* wav; @@ -20,16 +21,7 @@ Board boards[] = { }; int const boards_n = sizeof(boards) / sizeof(boards[0]); -void sound_init(void) -{ - DWORD channel_volume = VOLUME * 0xFFFF; - waveOutSetVolume(NULL, (channel_volume << 16) | channel_volume); -} - -void sound_play(unsigned char *buffer) -{ - PlaySound((const char *) buffer, NULL, SND_MEMORY | SND_ASYNC | SND_NODEFAULT); -} +Board *board = NULL; Board *get_board(char *board_name) { @@ -40,15 +32,6 @@ 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(); @@ -57,8 +40,6 @@ void do_exit(int code) } void on_clean_exit(void) { do_exit(0); } -Board *board = NULL; - void keyboard_on_down(void) { if (board == NULL) @@ -72,43 +53,6 @@ void keyboard_on_up(void) // 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) { if (argc < 2 || (board = get_board(argv[1])) == NULL) { @@ -120,20 +64,18 @@ int main(int argc, char **argv) return 1; } - sound_init(); - keyboard_hook(); + if (!sound_init(VOLUME)) { + printf("ERROR: Could not initialise sound system.\n"); + return 1; + } + if (!keyboard_hook()) { + printf("ERROR: Could not set up keyboard hooks.\n"); + return 1; + } 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); - } - } + enter_idle(); return 0; } \ No newline at end of file diff --git a/platform/platform.h b/platform/platform.h new file mode 100644 index 0000000..da1efa6 --- /dev/null +++ b/platform/platform.h @@ -0,0 +1,10 @@ +#ifndef CLAK_PLATFORM_H_ +#define CLAK_PLATFORM_H_ + +bool sound_init(float volume); +void sound_play(unsigned char *buffer); +void keyboard_unhook(void); +bool keyboard_hook(void); +void enter_idle(void); + +#endif /* CLAK_PLATFORM_H_ */ \ No newline at end of file diff --git a/platform/win32.c b/platform/win32.c new file mode 100644 index 0000000..90cd37c --- /dev/null +++ b/platform/win32.c @@ -0,0 +1,80 @@ +#include +#include +#include + +/* Required callbacks */ +extern void keyboard_on_down(void); +extern void keyboard_on_up(void); + +static HHOOK keyboard_hook_windows; + +bool sound_init(float volume) +{ + DWORD channel_volume = volume * 0xFFFF; + if (waveOutSetVolume(NULL, (channel_volume << 16) | channel_volume) != MMSYSERR_NOERROR) + return false; + return true; +} + +void sound_play(unsigned char *buffer) +{ + PlaySound((const char *) buffer, NULL, SND_MEMORY | SND_ASYNC | SND_NODEFAULT); +} + +/* https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms644985(v=vs.85) */ +static 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); +} + +bool 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) { + return false; + } + return true; +} + +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 enter_idle(void) +{ + MSG msg; + BOOL status; + while ((status = GetMessage(&msg, NULL, 0, 0))) { + if (status == -1) { + // error case + printf("ERROR: Windows error, code %lu\n", GetLastError()); + keyboard_unhook(); + exit(1); + } + } +} \ No newline at end of file -- cgit