aboutsummaryrefslogblamecommitdiff
path: root/platform/win32.c
blob: cf227180b681d860917fc3cc7d231553e882b116 (plain) (tree)
1
2
3
4
5
6
7



                    


                           










































































                                                                                                                                                                   


































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

#include "platform.h"
#include "../board/board.h"

/* 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);
		}
	}
}

bool load_board(char *board_name, fn_board_on_down *on_down, fn_board_on_down *on_up)
{
	char dll_name[100];
	int r = snprintf(dll_name, 100, "./board/%s.dll", board_name);
	if (r < 0 || r >= 100) {
		printf("ERROR: Invalid board name.\n");
		return false;
	}

	HMODULE board_module = LoadLibrary(dll_name);
	if (board_module == NULL) {
		printf("ERROR: Could not load board module.\n");
		return false;
	}
	fn_board_init board_init = (fn_board_init) (void (*)(void)) GetProcAddress(board_module, "board_init");
	if (board_init == NULL) {
		printf("ERROR: No board down function could be loaded.\n");
		return false;
	}
	board_init(&sound_play);

	*on_down = (fn_board_on_down) GetProcAddress(board_module, "board_on_down");
	if (on_down == NULL) {
		printf("ERROR: No board down function could be loaded.\n");
		return false;
	}
	*on_up = (fn_board_on_up) GetProcAddress(board_module, "board_on_up");
	if (on_up == NULL) {
		printf("ERROR: No board up function could be loaded.\n");
		return false;
	}

	return true;
}