diff options
| -rw-r--r-- | backends/Makefile | 2 | ||||
| -rw-r--r-- | backends/wininput.c | 224 | ||||
| -rw-r--r-- | backends/wininput.h | 44 | ||||
| -rw-r--r-- | midimonster.h | 2 | 
4 files changed, 270 insertions, 2 deletions
| diff --git a/backends/Makefile b/backends/Makefile index 700c9b3..9b66728 100644 --- a/backends/Makefile +++ b/backends/Makefile @@ -1,6 +1,6 @@  .PHONY: all clean full  LINUX_BACKENDS = midi.so evdev.so -WINDOWS_BACKENDS = artnet.dll osc.dll loopback.dll sacn.dll maweb.dll winmidi.dll openpixelcontrol.dll rtpmidi.dll +WINDOWS_BACKENDS = artnet.dll osc.dll loopback.dll sacn.dll maweb.dll winmidi.dll openpixelcontrol.dll rtpmidi.dll wininput.dll  BACKENDS = artnet.so osc.so loopback.so sacn.so lua.so maweb.so jack.so openpixelcontrol.so python.so rtpmidi.so  OPTIONAL_BACKENDS = ola.so  BACKEND_LIB = libmmbackend.o diff --git a/backends/wininput.c b/backends/wininput.c new file mode 100644 index 0000000..352be66 --- /dev/null +++ b/backends/wininput.c @@ -0,0 +1,224 @@ +#define BACKEND_NAME "wininput" +#define DEBUG + +#include <string.h> +#include "wininput.h" + +MM_PLUGIN_API int init(){ +	backend wininput = { +		.name = BACKEND_NAME, +		.conf = wininput_configure, +		.create = wininput_instance, +		.conf_instance = wininput_configure_instance, +		.channel = wininput_channel, +		.handle = wininput_set, +		.process = wininput_handle, +		.start = wininput_start, +		.shutdown = wininput_shutdown +	}; + +	if(sizeof(wininput_channel_ident) != sizeof(uint64_t)){ +		LOG("Channel identification union out of bounds"); +		return 1; +	} + +	//register backend +	if(mm_backend_register(wininput)){ +		LOG("Failed to register backend"); +		return 1; +	} +	return 0; +} + +static int wininput_configure(char* option, char* value){ +	LOG("The backend does not take any global configuration"); +	return 1; +} + +static int wininput_configure_instance(instance* inst, char* option, char* value){ +	LOG("The backend does not take any instance configuration"); +	return 0; +} + +static int wininput_instance(instance* inst){ +	wininput_instance_data* data = calloc(1, sizeof(wininput_instance_data)); +	if(!data){ +		LOG("Failed to allocate memory"); +		return 1; +	} + +	inst->impl = data; +	return 0; +} + +static channel* wininput_channel(instance* inst, char* spec, uint8_t flags){ +	char* token = spec; +	wininput_channel_ident ident = { +		.label = 0 +	}; + +	if(!strncmp(spec, "mouse.", 6)){ +		//TODO wheel +		token += 6; +		ident.fields.type = mouse; +		if(!strcmp(token, "x")){ +			ident.fields.channel = position; +		} +		else if(!strcmp(token, "y")){ +			ident.fields.channel = position; +			ident.fields.control = 1; +		} +		else if(!strcmp(token, "lmb")){ +			ident.fields.channel = button; +		} +		else if(!strcmp(token, "rmb")){ +			ident.fields.channel = button; +			ident.fields.control = 1; +		} +		else if(!strcmp(token, "mmb")){ +			ident.fields.channel = button; +			ident.fields.control = 2; +		} +		else if(!strcmp(token, "xmb1")){ +			ident.fields.channel = button; +			ident.fields.control = 3; +		} +		else if(!strcmp(token, "xmb2")){ +			ident.fields.channel = button; +			ident.fields.control = 4; +		} +		else{ +			LOGPF("Unknown control %s", token); +			return NULL; +		} +	} +	else if(!strncmp(spec, "keyboard.", 9)){ +		token += 9; +		//TODO +	} +	else{ +		LOGPF("Unknown channel spec %s", spec); +	} + +	if(ident.label){ +		return mm_channel(inst, ident.label, 1); +	} +	return NULL; +} + +static INPUT wininput_event_mouse(wininput_instance_data* data, uint8_t channel, uint8_t control, double value){ +	DWORD flags_down = 0, flags_up = 0; +	INPUT ev = { +		.type = INPUT_MOUSE +	}; + +	if(channel == position){ +		if(control){ +			data->mouse.y = value * 0xFFFF; +		} +		else{ +			data->mouse.x = value * 0xFFFF; +		} + +		ev.mi.dwFlags |= MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; +		ev.mi.dx = data->mouse.x; +		ev.mi.dy = data->mouse.y; +	} +	if(channel == button){ +		switch(control){ +			case 0: +				flags_up |= MOUSEEVENTF_LEFTUP; +				flags_down |= MOUSEEVENTF_LEFTDOWN; +				break; +			case 1: +				flags_up |= MOUSEEVENTF_RIGHTUP; +				flags_down |= MOUSEEVENTF_RIGHTDOWN; +				break; +			case 2: +				flags_up |= MOUSEEVENTF_MIDDLEUP; +				flags_down |= MOUSEEVENTF_MIDDLEDOWN; +				break; +			case 3: +			case 4: +				ev.mi.mouseData = (control == 3) ? XBUTTON1 : XBUTTON2; +				flags_up |= MOUSEEVENTF_XUP; +				flags_down |= MOUSEEVENTF_XDOWN; +				break; +		} + +		if(value > 0.9){ +			ev.mi.dwFlags |= flags_down; +		} +		else{ +			ev.mi.dwFlags |= flags_up; +		} +	} + +	return ev; +} + +static INPUT wininput_event_keyboard(wininput_instance_data* data, uint8_t channel, uint8_t control, double value){ +	INPUT ev = { +		.type = INPUT_KEYBOARD +	}; + +	return ev; +} + +static int wininput_set(instance* inst, size_t num, channel** c, channel_value* v){ +	wininput_channel_ident ident = { +		.label = 0 +	}; +	wininput_instance_data* data = (wininput_instance_data*) inst->impl; +	size_t n = 0, offset = 0; +	INPUT events[500]; + +	//FIXME might want to coalesce mouse events +	if(num > sizeof(events) / sizeof(events[0])){ +		LOGPF("Truncating output on %s to the last %" PRIsize_t " events, please notify the developers", inst->name, sizeof(events) / sizeof(events[0])); +		offset = num - sizeof(events) / sizeof(events[0]); +	} + +	for(n = 0; n + offset < num; n++){ +		ident.label = c[n + offset]->ident; +		if(ident.fields.type == mouse){ +			events[n] = wininput_event_mouse(data, ident.fields.channel, ident.fields.control, v[n + offset].normalised); +		} +		else if(ident.fields.type == keyboard){ +			events[n] = wininput_event_keyboard(data, ident.fields.channel, ident.fields.control, v[n + offset].normalised); +		} +		else{ +			n--; +			offset++; +		} +	} + +	if(n){ +		offset = SendInput(n, events, sizeof(INPUT)); +		if(offset != n){ +			LOGPF("Output %" PRIsize_t " of %" PRIsize_t " events on %s", offset, n, inst->name); +		} +	} +	return 0; +} + +static int wininput_handle(size_t num, managed_fd* fds){ +	//TODO +	return 0; +} + +static int wininput_start(size_t n, instance** inst){ +	//TODO +	return 0; +} + +static int wininput_shutdown(size_t n, instance** inst){ +	size_t u; + +	for(u = 0; u < n; u++){ +		free(inst[u]->impl); +	} + +	LOG("Backend shut down"); +	return 0; +} diff --git a/backends/wininput.h b/backends/wininput.h new file mode 100644 index 0000000..240f1a6 --- /dev/null +++ b/backends/wininput.h @@ -0,0 +1,44 @@ +#include "midimonster.h" + +MM_PLUGIN_API int init(); +static int wininput_configure(char* option, char* value); +static int wininput_configure_instance(instance* inst, char* option, char* value); +static int wininput_instance(instance* inst); +static channel* wininput_channel(instance* inst, char* spec, uint8_t flags); +static int wininput_set(instance* inst, size_t num, channel** c, channel_value* v); +static int wininput_handle(size_t num, managed_fd* fds); +static int wininput_start(size_t n, instance** inst); +static int wininput_shutdown(size_t n, instance** inst); + +enum /*wininput_channel_type*/ { +	none = 0, +	mouse, +	keyboard, +	joystick +}; + +enum /*wininput_control_channel*/ { +	position, +	//wheel, /*relative*/ +	button, + +	keypress, +	key_unicode +}; + +typedef union { +	struct { +		uint8_t pad[4]; +		uint8_t type; +		uint8_t channel; +		uint16_t control; +	} fields; +	uint64_t label; +} wininput_channel_ident; + +typedef struct { +	struct { +		uint16_t x; +		uint16_t y; +	} mouse; +} wininput_instance_data; diff --git a/midimonster.h b/midimonster.h index 75eb30a..a5de60e 100644 --- a/midimonster.h +++ b/midimonster.h @@ -7,7 +7,7 @@  /* Core version unless set by the build process */  #ifndef MIDIMONSTER_VERSION -	#define MIDIMONSTER_VERSION "v0.5-dist" +	#define MIDIMONSTER_VERSION "v0.6-dist"  #endif  /* Set backend name if unset */ | 
