diff options
Diffstat (limited to '')
| -rw-r--r-- | .gitignore | 3 | ||||
| -rw-r--r-- | Makefile | 5 | ||||
| -rw-r--r-- | board/Makefile | 8 | ||||
| -rw-r--r-- | platform/darwin.c | 167 | 
4 files changed, 180 insertions, 3 deletions
| @@ -3,4 +3,5 @@ clak.exe  board/boards.h  board/*/sound.h  board/*.dll -board/*.so
\ No newline at end of file +board/*.so +board/*.dylib @@ -1,7 +1,7 @@  NAME = clak  PREFIX = $(HOME)/.local -CC = gcc +CC = clang  CFLAGS += -std=c99 -Wall -Wextra -Wshadow -Werror  ifeq ($(OS),Windows_NT) @@ -14,6 +14,9 @@ else  		PKG_CONF_LIBS = sdl2 SDL2_mixer x11 xi  		CFLAGS += `pkg-config --cflags $(PKG_CONF_LIBS)`  		LDLIBS += `pkg-config --libs $(PKG_CONF_LIBS)` +	else ifeq ($(UNAME_S),Darwin) +		PLATFORM = darwin +		CFLAGS += -framework CoreFoundation -framework IOKit -framework AppKit  	endif  endif diff --git a/board/Makefile b/board/Makefile index ae3d691..ba53910 100644 --- a/board/Makefile +++ b/board/Makefile @@ -6,8 +6,14 @@ CFLAGS += -std=c99 -Wall -Wextra -Wshadow -Werror -pedantic -shared  ifeq ($(OS),Windows_NT)  	OUTEXT = dll  else -	OUTEXT = so  	CFLAGS += -fPIC + +	UNAME_S := $(shell uname) +	ifeq ($(UNAME_S),Linux) +		OUTEXT = so +	else ifeq ($(UNAME_S),Darwin) +		OUTEXT = dylib +	endif  endif  default: all diff --git a/platform/darwin.c b/platform/darwin.c new file mode 100644 index 0000000..820c012 --- /dev/null +++ b/platform/darwin.c @@ -0,0 +1,167 @@ +#include <stdio.h> +#include <stdbool.h> +#include <dlfcn.h> +#include <IOKit/hid/IOHIDManager.h> + +#include "platform.h" +#include "../board/board.h" + +/* TODO: Try out objc_msgsend for fun in future to not even have Obj-C! */ + +extern void keyboard_on_down(void); +extern void keyboard_on_up(void); + +static float volume = 0; +static IOHIDManagerRef hid_manager = NULL; + +bool sound_init(float _volume) +{ +	volume = _volume; + +	/* TODO: Init sound, NSCache probably too via bridge? */ + +	return true; +} + +void sound_play(unsigned char *buffer, unsigned int buffer_len) +{ +	(void) buffer; +	(void) buffer_len; + +	/* TODO: Play the sound via obj-c for now */ +} + +/* TODO: Maybe merge some of this stuff with linux, lots of overlap */ +void handle_signal(int signal) +{ +	(void) signal; + +	/* Terminate the runloop, which will kick out of enter_idle */ +	CFRunLoopStop(CFRunLoopGetMain()); +} +void enter_idle(void) +{ +	/* Setup quit handling */ +	struct sigaction sa = { .sa_handler = handle_signal }; +	sigaction(SIGINT, &sa, NULL); + +	/* Enter the CoreFoundation run loop and it will pump events for our callback */ +	CFRunLoopRun(); +} + +/* TODO: probably also merge into a *nix module */ +struct board *load_board(char *board_name) +{ +	char so_name[100]; +	int r = snprintf(so_name, 100, "./board/%s.dylib", board_name); +	if (r < 0 || r >= 100) { +		printf("ERROR: Invalid board name.\n"); +		return false; +	} + +	void *board_module = dlopen(so_name, RTLD_LAZY); +	if (board_module == NULL) { +		printf("ERROR: Could not load board module.\n"); +		return false; +	} + +	fn_board_init board_init = dlsym(board_module, "board_init"); +	if (board_init == NULL) { +		printf("ERROR: No board initialisation function could be loaded.\n"); +		return false; +	} + +	struct board_data data = { +		.sound_play = &sound_play +	}; +	return board_init(data); +} + +/* https://developer.apple.com/documentation/iokit/iohidvaluecallback */ +void hid_callback(void *context, IOReturn result, void *sender, IOHIDValueRef value) +{ +	(void) context; +	(void) result; +	(void) sender; + +	IOHIDElementRef elem = IOHIDValueGetElement(value); + +	/* seems like 'usage' is the scancode */ +	int32_t scancode = IOHIDElementGetUsage(elem); +	/* someething < 4 (usually -1) is emitted on every press, not sure what it really means. +	 * But it doesn't seem to be a valid scancode regardless... +	 * https://www.win.tue.nl/~aeb/linux/kbd/scancodes-14.html */ +	if (scancode < 4) +		return; + +	/* seems like getting 'int value' is if it is key up or down +	 * true(1) = down */ +	bool key_down = IOHIDValueGetIntegerValue(value) == 1; +	printf(">>> value: %d, down: %d\n", scancode, key_down); +	if (key_down) +		keyboard_on_down(); +	else +		keyboard_on_up(); +} + +bool keyboard_hook(void) +{ +	fprintf(stderr, "Setting up keyboard manager...\n"); +	hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); +	if (hid_manager == NULL) { +		printf("ERROR: IOKit HID manager failed to initialise.\n"); +		return false; +	} + +	/* TODO: handle errors on allocs below? */ + +	/* We want to hook keyboard, so setup the filter to match the device for IOKit. +	 * It wants a CFArray of CFDictionary, so we set that up */ +	fprintf(stderr, "Setting up IOKit hook...\n"); +	const void *keyboard_keys[] = { +		CFSTR(kIOHIDDeviceUsagePageKey), +		CFSTR(kIOHIDDeviceUsageKey) +	}; +	int gd = kHIDPage_GenericDesktop; +	int gdk = kHIDUsage_GD_Keyboard; +	const void *keyboard_values[] = {  +		CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &gd), +		CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &gdk) +	}; +	/* Usage Page = Generic Desktop, Usage = Keyboard */ +	CFDictionaryRef keyboard_dict = CFDictionaryCreate( +		kCFAllocatorDefault, +		keyboard_keys, +		keyboard_values, +		2, +		&kCFTypeDictionaryKeyCallBacks, +		&kCFTypeDictionaryValueCallBacks +	); +	const void *match_values[] = { keyboard_dict }; +	/* 1 element, the keyboard filter dict */ +	CFArrayRef device_matches = CFArrayCreate( +		kCFAllocatorDefault, +		match_values, +		1, +		&kCFTypeArrayCallBacks +	); + +	IOHIDManagerSetDeviceMatchingMultiple(hid_manager, device_matches); +	CFRelease(keyboard_dict); +	CFRelease(device_matches); + +	IOHIDManagerRegisterInputValueCallback(hid_manager, hid_callback, NULL); +	IOHIDManagerOpen(hid_manager, kIOHIDOptionsTypeNone); + +	/* Schedule the HID manager for run loop later */ +	IOHIDManagerScheduleWithRunLoop(hid_manager, CFRunLoopGetMain(), kCFRunLoopDefaultMode); + +	return true; +} + +void keyboard_unhook(void) +{ +	fprintf(stderr, "Cleaning up keyboard hooks...\n"); +	IOHIDManagerClose(hid_manager, kIOHIDOptionsTypeNone); +	/* TODO: Cleanup sound system */ +} | 
