aboutsummaryrefslogblamecommitdiff
path: root/clak.c
blob: 99b14829fb520f826e2e294557a23d897c288e14 (plain) (tree)
1
2
3
4
5
6
7
8
9
                  
                   
                   
                   


                    
                   
 
                         










                                                        
 
                     
 
                                               
                                                                        

 
                                      
 
                                                                                       

 
                                  
 
                                            





                                                            




































































                                                                                                                                                                   

                               






                                                                                          
         
 
                     












                                                                                   
 

                 
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>

#include <windows.h>

#define VOLUME 0.15

#include "board/boards.h"
#define BOARD(str, buf) { .name = str, .wav = buf },

typedef struct {
	char *name;
	unsigned char* wav;
} Board;

Board boards[] = {
	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 *get_board(char *board_name)
{
	for (int i = 0; i < boards_n; ++i) {
		if (strcmp(boards[i].name, board_name) == 0)
			return &boards[i];
	}
	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)
{
	if (argc < 2 || (board = get_board(argv[1])) == NULL) {
		printf("Please provide a valid board name.\n");
		printf("Valid boards: ");
		for (int i = 0; i < boards_n; ++i) {
			printf("%s%s", boards[i].name, (i == boards_n - 1) ? "\n" : ", ");
		}
		return 1;
	}

	sound_init();
	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;
}