# HG changeset patch # User Michael Pavone # Date 1448774841 28800 # Node ID b5d35222047e303ba93a48fd3e1b7694d82011d7 # Parent 8cf57c6558ed9ecaf1216ff66ab3848556753bfc Mega mouse support is mostly done diff -r 8cf57c6558ed -r b5d35222047e default.cfg --- a/default.cfg Sat Nov 28 20:05:15 2015 -0800 +++ b/default.cfg Sat Nov 28 21:27:21 2015 -0800 @@ -72,6 +72,28 @@ } } } + mice { + 0 { + motion mouse.1.motion + buttons { + 1 mouse.1.left + 2 mouse.1.middle + 3 mouse.1.right + 4 mouse.1.start + } + } + #having the second host mouse also mapped to the first emulated + #mouse is useful for laptop users with an external mouse + 1 { + motion mouse.1.motion + buttons { + 1 mouse.1.left + 2 mouse.1.middle + 3 mouse.1.right + 4 mouse.1.start + } + } + } } io { diff -r 8cf57c6558ed -r b5d35222047e io.c --- a/io.c Sat Nov 28 20:05:15 2015 -0800 +++ b/io.c Sat Nov 28 21:27:21 2015 -0800 @@ -44,7 +44,15 @@ BIND_GAMEPAD5, BIND_GAMEPAD6, BIND_GAMEPAD7, - BIND_GAMEPAD8 + BIND_GAMEPAD8, + BIND_MOUSE1, + BIND_MOUSE2, + BIND_MOUSE3, + BIND_MOUSE4, + BIND_MOUSE5, + BIND_MOUSE6, + BIND_MOUSE7, + BIND_MOUSE8 }; typedef enum { @@ -72,14 +80,16 @@ } joydpad; typedef struct { - io_port *port; - uint8_t mode; + io_port *motion_port; + keybinding buttons[MAX_MOUSE_BUTTONS]; + uint8_t bind_type; + uint8_t motion_mode; } mousebinding; keybinding * bindings[0x10000]; keybinding * joybindings[MAX_JOYSTICKS]; joydpad * joydpads[MAX_JOYSTICKS]; -mousebinding *mice[MAX_MICE]; +mousebinding mice[MAX_MICE]; const uint8_t dpadbits[] = {RENDER_DPAD_UP, RENDER_DPAD_DOWN, RENDER_DPAD_LEFT, RENDER_DPAD_RIGHT}; void bind_key(int keycode, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b, uint8_t value) @@ -154,6 +164,14 @@ #define BUTTON_START GAMEPAD_BUTTON(GAMEPAD_TH0, GAMEPAD_NONE, 0x20) #define BUTTON_C GAMEPAD_BUTTON(GAMEPAD_TH1, GAMEPAD_NONE, 0x20) +#define PSEUDO_BUTTON_MOTION 0xFFFF +#define MOUSE_LEFT 1 +#define MOUSE_RIGHT 2 +#define MOUSE_MIDDLE 4 +#define MOUSE_START 8 + + + void bind_gamepad(int keycode, int gamepadnum, int button) { @@ -199,7 +217,7 @@ void handle_binding_down(keybinding * binding) { - if (binding->bind_type >= BIND_GAMEPAD1) + if (binding->bind_type >= BIND_GAMEPAD1 && binding->bind_type <= BIND_GAMEPAD8) { if (binding->subtype_a <= GAMEPAD_EXTRA && binding->port) { binding->port->input[binding->subtype_a] |= binding->value; @@ -208,6 +226,12 @@ binding->port->input[binding->subtype_b] |= binding->value; } } + else if (binding->bind_type >= BIND_MOUSE1 && binding->bind_type <= BIND_MOUSE8) + { + if (binding->port) { + binding->port->input[0] |= binding->value; + } + } } void handle_keydown(int keycode) @@ -230,6 +254,15 @@ handle_binding_down(binding); } +void handle_mousedown(int mouse, int button) +{ + if (mouse >= MAX_MICE || button > MAX_MOUSE_BUTTONS || button <= 0) { + return; + } + keybinding * binding = mice[mouse].buttons + button - 1; + handle_binding_down(binding); +} + uint8_t ui_debug_mode = 0; uint8_t ui_debug_pal = 0; @@ -243,6 +276,12 @@ { case BIND_GAMEPAD1: case BIND_GAMEPAD2: + case BIND_GAMEPAD3: + case BIND_GAMEPAD4: + case BIND_GAMEPAD5: + case BIND_GAMEPAD6: + case BIND_GAMEPAD7: + case BIND_GAMEPAD8: if (binding->subtype_a <= GAMEPAD_EXTRA && binding->port) { binding->port->input[binding->subtype_a] &= ~binding->value; } @@ -250,6 +289,18 @@ binding->port->input[binding->subtype_b] &= ~binding->value; } break; + case BIND_MOUSE1: + case BIND_MOUSE2: + case BIND_MOUSE3: + case BIND_MOUSE4: + case BIND_MOUSE5: + case BIND_MOUSE6: + case BIND_MOUSE7: + case BIND_MOUSE8: + if (binding->port) { + binding->port->input[0] &= ~binding->value; + } + break; case BIND_UI: switch (binding->subtype_a) { @@ -344,18 +395,30 @@ } } -void handle_mouse_moved(int mouse, uint16_t x, uint16_t y) +void handle_mouseup(int mouse, int button) { - printf("mouse motion: %d - (%d, %d)\n", mouse, x, y); - if (mouse >= MAX_MICE || !mice[mouse]) { + if (mouse >= MAX_MICE || button > MAX_MOUSE_BUTTONS || button <= 0) { return; } - + keybinding * binding = mice[mouse].buttons + button - 1; + handle_binding_up(binding); } -int parse_binding_target(char * target, tern_node * padbuttons, int * ui_out, int * padnum_out, int * padbutton_out) +void handle_mouse_moved(int mouse, uint16_t x, uint16_t y) { - int gpadslen = strlen("gamepads."); + if (mouse >= MAX_MICE || !mice[mouse].motion_port) { + return; + } + //TODO: relative mode + //TODO: scale based on window size + mice[mouse].motion_port->device.mouse.cur_x = x; + mice[mouse].motion_port->device.mouse.cur_y = y; +} + +int parse_binding_target(char * target, tern_node * padbuttons, tern_node *mousebuttons, int * ui_out, int * padnum_out, int * padbutton_out) +{ + const int gpadslen = strlen("gamepads."); + const int mouselen = strlen("mouse."); if (!strncmp(target, "gamepads.", gpadslen)) { if (target[gpadslen] >= '1' && target[gpadslen] <= '8') { int padnum = target[gpadslen] - '0'; @@ -363,7 +426,7 @@ if (button) { *padnum_out = padnum; *padbutton_out = button; - return 1; + return BIND_GAMEPAD1; } else { if (target[gpadslen+1]) { warning("Gamepad mapping string '%s' refers to an invalid button '%s'\n", target, target + gpadslen + 1); @@ -374,6 +437,24 @@ } else { warning("Gamepad mapping string '%s' refers to an invalid gamepad number %c\n", target, target[gpadslen]); } + } else if(!strncmp(target, "mouse.", mouselen)) { + if (target[mouselen] >= '1' && target[mouselen] <= '8') { + int mousenum = target[mouselen] - '0'; + int button = tern_find_int(mousebuttons, target + mouselen + 1, 0); + if (button) { + *padnum_out = mousenum; + *padbutton_out = button; + return BIND_MOUSE1; + } else { + if (target[mouselen+1]) { + warning("Mouse mapping string '%s' refers to an invalid button '%s'\n", target, target + mouselen + 1); + } else { + warning("Mouse mapping string '%s' has no button component\n", target); + } + } + } else { + warning("Gamepad mapping string '%s' refers to an invalid mouse number %c\n", target, target[mouselen]); + } } else if(!strncmp(target, "ui.", strlen("ui."))) { *padbutton_out = 0; if (!strcmp(target + 3, "vdp_debug_mode")) { @@ -397,14 +478,14 @@ warning("Unreconized UI binding type %s\n", target); return 0; } - return 2; + return BIND_UI; } else { warning("Unrecognized binding type %s\n", target); } return 0; } -void process_keys(tern_node * cur, tern_node * special, tern_node * padbuttons, char * prefix) +void process_keys(tern_node * cur, tern_node * special, tern_node * padbuttons, tern_node *mousebuttons, char * prefix) { char * curstr = NULL; int len; @@ -423,7 +504,7 @@ curstr[len] = cur->el; curstr[len+1] = 0; if (cur->el) { - process_keys(cur->straight.next, special, padbuttons, curstr); + process_keys(cur->straight.next, special, padbuttons, mousebuttons, curstr); } else { int keycode = tern_find_int(special, curstr, 0); if (!keycode) { @@ -434,15 +515,15 @@ } char * target = cur->straight.value.ptrval; int ui_func, padnum, button; - int bindtype = parse_binding_target(target, padbuttons, &ui_func, &padnum, &button); - if (bindtype == 1) { + int bindtype = parse_binding_target(target, padbuttons, mousebuttons, &ui_func, &padnum, &button); + if (bindtype == BIND_GAMEPAD1) { bind_gamepad(keycode, padnum, button); - } else if(bindtype == 2) { + } else if(bindtype == BIND_UI) { bind_ui(keycode, ui_func, button); } } - process_keys(cur->left, special, padbuttons, prefix); - process_keys(cur->right, special, padbuttons, prefix); + process_keys(cur->left, special, padbuttons, mousebuttons, prefix); + process_keys(cur->right, special, padbuttons, mousebuttons, prefix); if (curstr && len) { free(curstr); } @@ -520,8 +601,13 @@ } port->device.pad.gamepad_num = device_type[gamepad_len+2] - '1'; } else if(!strncmp(device_type, "mouse", mouse_len)) { - //TODO: do something with mouse number port->device_type = IO_MOUSE; + port->device.mouse.mouse_num = device_type[mouse_len+1] - '1'; + port->device.mouse.last_read_x = 0; + port->device.mouse.last_read_y = 0; + port->device.mouse.cur_x = 0; + port->device.mouse.cur_y = 0; + port->device.mouse.tr_counter = 0; } else if(!strcmp(device_type, "sega_parallel")) { port->device_type = IO_SEGA_PARALLEL; port->device.stream.data_fd = -1; @@ -643,7 +729,7 @@ { for (int i = 0; i < numbindings; i++) { - if (bindings[i].bind_type >= BIND_GAMEPAD1) + if (bindings[i].bind_type >= BIND_GAMEPAD1 && bindings[i].bind_type <= BIND_GAMEPAD8) { int num = bindings[i].bind_type - BIND_GAMEPAD1; for (int j = 0; j < 3; j++) @@ -659,6 +745,93 @@ } } } + else if (bindings[i].bind_type >= BIND_MOUSE1 && bindings[i].bind_type <= BIND_MOUSE8) + { + int num = bindings[i].bind_type - BIND_MOUSE1; + for (int j = 0; j < 3; j++) + { + if (ports[j].device_type == IO_MOUSE && ports[j].device.mouse.mouse_num == num) + { + memset(ports[j].input, 0, sizeof(ports[j].input)); + bindings[i].port = ports + j; + break; + } + } + } + } +} + +typedef struct { + tern_node *padbuttons; + tern_node *mousebuttons; + int mouseidx; +} pmb_state; + +void process_mouse_button(char *buttonstr, tern_val value, void *data) +{ + pmb_state *state = data; + int buttonnum = atoi(buttonstr); + if (buttonnum < 1 || buttonnum > MAX_MOUSE_BUTTONS) { + warning("Mouse button %s is out of the supported range of 1-8\n", buttonstr); + return; + } + buttonnum--; + int ui_func, devicenum, button; + int bindtype = parse_binding_target(value.ptrval, state->padbuttons, state->mousebuttons, &ui_func, &devicenum, &button); + switch (bindtype) + { + case BIND_UI: + mice[state->mouseidx].buttons[buttonnum].subtype_a = ui_func; + break; + case BIND_GAMEPAD1: + mice[state->mouseidx].buttons[buttonnum].subtype_a = button >> 12; + mice[state->mouseidx].buttons[buttonnum].subtype_b = button >> 8 & 0xF; + mice[state->mouseidx].buttons[buttonnum].value = button & 0xFF; + break; + case BIND_MOUSE1: + mice[state->mouseidx].buttons[buttonnum].value = button & 0xFF; + break; + } + if (bindtype != BIND_UI) { + bindtype += devicenum-1; + } + mice[state->mouseidx].buttons[buttonnum].bind_type = bindtype; + +} + +void process_mouse(char *mousenum, tern_val value, void *data) +{ + tern_node **buttonmaps = data; + tern_node *mousedef = tern_get_node(value); + tern_node *padbuttons = buttonmaps[0]; + tern_node *mousebuttons = buttonmaps[1]; + + if (!mousedef) { + warning("Binding for mouse %s is a scalar!\n", mousenum); + return; + } + int mouseidx = atoi(mousenum); + if (mouseidx < 0 || mouseidx >= MAX_MICE) { + warning("Mouse numbers must be between 0 and %d, but %d is not\n", MAX_MICE, mouseidx); + return; + } + char *motion = tern_find_ptr(mousedef, "motion"); + if (motion) { + int ui_func,devicenum,button; + int bindtype = parse_binding_target(motion, padbuttons, mousebuttons, &ui_func, &devicenum, &button); + if (bindtype != BIND_UI) { + bindtype += devicenum-1; + } + if (button == PSEUDO_BUTTON_MOTION) { + mice[mouseidx].bind_type = bindtype; + } else { + warning("Mouse motion can't be bound to target %s\n", motion); + } + } + tern_node *buttons = tern_get_node(tern_find_path(mousedef, "buttons\0\0")); + if (buttons) { + pmb_state state = {padbuttons, mousebuttons, mouseidx}; + tern_foreach(buttons, process_mouse_button, &state); } } @@ -689,9 +862,15 @@ padbuttons = tern_insert_int(padbuttons, ".z", BUTTON_Z); padbuttons = tern_insert_int(padbuttons, ".start", BUTTON_START); padbuttons = tern_insert_int(padbuttons, ".mode", BUTTON_MODE); + + tern_node *mousebuttons = tern_insert_int(NULL, ".left", MOUSE_LEFT); + mousebuttons = tern_insert_int(mousebuttons, ".middle", MOUSE_MIDDLE); + mousebuttons = tern_insert_int(mousebuttons, ".right", MOUSE_RIGHT); + mousebuttons = tern_insert_int(mousebuttons, ".start", MOUSE_START); + mousebuttons = tern_insert_int(mousebuttons, ".motion", PSEUDO_BUTTON_MOTION); tern_node * keys = tern_get_node(tern_find_path(config, "bindings\0keys\0")); - process_keys(keys, special, padbuttons, NULL); + process_keys(keys, special, padbuttons, mousebuttons, NULL); char numstr[] = "00"; tern_node * pads = tern_get_node(tern_find_path(config, "bindings\0pads\0")); if (pads) { @@ -720,10 +899,10 @@ char * target = tern_find_ptr(pad_dpad, dirs[dir]); if (target) { int ui_func, padnum, button; - int bindtype = parse_binding_target(target, padbuttons, &ui_func, &padnum, &button); - if (bindtype == 1) { + int bindtype = parse_binding_target(target, padbuttons, mousebuttons, &ui_func, &padnum, &button); + if (bindtype == BIND_GAMEPAD1) { bind_dpad_gamepad(i, dpad, dirnums[dir], padnum, button); - } else if (bindtype == 2) { + } else if (bindtype == BIND_UI) { bind_dpad_ui(i, dpad, dirnums[dir], ui_func, button); } } @@ -744,10 +923,10 @@ char * target = tern_find_ptr(button_node, numstr); if (target) { int ui_func, padnum, button; - int bindtype = parse_binding_target(target, padbuttons, &ui_func, &padnum, &button); - if (bindtype == 1) { + int bindtype = parse_binding_target(target, padbuttons, mousebuttons, &ui_func, &padnum, &button); + if (bindtype == BIND_GAMEPAD1) { bind_button_gamepad(i, but, padnum, button); - } else if (bindtype == 2) { + } else if (bindtype == BIND_UI) { bind_button_ui(i, but, ui_func, button); } } @@ -756,6 +935,12 @@ } } } + memset(mice, 0, sizeof(mice)); + tern_node * mice = tern_get_node(tern_find_path(config, "bindings\0mice\0")); + if (mice) { + tern_node *buttonmaps[2] = {padbuttons, mousebuttons}; + tern_foreach(mice, process_mouse, buttonmaps); + } tern_node * speed_nodes = tern_get_node(tern_find_path(config, "clocks\0speeds\0")); speeds = malloc(sizeof(uint32_t)); speeds[0] = 100; @@ -791,6 +976,22 @@ map_bindings(ports, joydpads[stick]->bindings, 4); } } + for (int mouse = 0; mouse < MAX_MICE; mouse++) + { + if (mice[mouse].bind_type >= BIND_MOUSE1 && mice[mouse].bind_type <= BIND_MOUSE8) { + int num = mice[mouse].bind_type - BIND_MOUSE1; + for (int j = 0; j < 3; j++) + { + if (ports[j].device_type == IO_MOUSE && ports[j].device.mouse.mouse_num == num) + { + memset(ports[j].input, 0, sizeof(ports[j].input)); + mice[mouse].motion_port = ports + j; + break; + } + } + } + map_bindings(ports, mice[mouse].buttons, MAX_MOUSE_BUTTONS); + } } #define TH 0x40 @@ -1014,8 +1215,6 @@ input = 0; } } else { - int deltax = port->device.mouse.cur_x - port->device.mouse.last_read_x; - int deltay = port->device.mouse.cur_y - port->device.mouse.last_read_y; switch (port->device.mouse.tr_counter) { case 0: @@ -1027,16 +1226,20 @@ break; case 3: input = 0; - if (deltay > 255 || deltay < -255) { + //it would be unfortunate if our event handler updated cur_x or cur_y in the middle + //of the mouse poll sequence, so we save the delta here + port->device.mouse.delta_x = port->device.mouse.cur_x - port->device.mouse.last_read_x; + port->device.mouse.delta_y = port->device.mouse.cur_y - port->device.mouse.last_read_y; + if (port->device.mouse.delta_y > 255 || port->device.mouse.delta_y < -255) { input |= 8; } - if (deltax > 255 || deltax < -255) { + if (port->device.mouse.delta_x > 255 || port->device.mouse.delta_x < -255) { input |= 4; } - if (deltay < 0) { + if (port->device.mouse.delta_y < 0) { input |= 2; } - if (deltax < 0) { + if (port->device.mouse.delta_x < 0) { input |= 1; } break; @@ -1044,16 +1247,16 @@ input = port->input[0]; break; case 5: - input = abs(deltax) >> 4 & 0xF; + input = abs(port->device.mouse.delta_x) >> 4 & 0xF; break; case 6: - input = abs(deltax) & 0xF; + input = abs(port->device.mouse.delta_x) & 0xF; break; case 7: - input = abs(deltay) >> 4 & 0xF; + input = abs(port->device.mouse.delta_y) >> 4 & 0xF; break; case 8: - input = abs(deltay) & 0xF; + input = abs(port->device.mouse.delta_y) & 0xF; //need to figure out when this actually happens port->device.mouse.last_read_x = port->device.mouse.cur_x; port->device.mouse.last_read_y = port->device.mouse.cur_y; diff -r 8cf57c6558ed -r b5d35222047e io.h --- a/io.h Sat Nov 28 20:05:15 2015 -0800 +++ b/io.h Sat Nov 28 21:27:21 2015 -0800 @@ -38,8 +38,10 @@ uint16_t last_read_y; uint16_t cur_x; uint16_t cur_y; + int16_t delta_x; + int16_t delta_y; uint8_t tr_counter; - uint8_t state; + uint8_t mouse_num; } mouse; } device; uint8_t output; @@ -76,6 +78,8 @@ void handle_joyup(int joystick, int button); void handle_joy_dpad(int joystick, int dpad, uint8_t state); void handle_mouse_moved(int mouse, uint16_t x, uint16_t y); +void handle_mousedown(int mouse, int button); +void handle_mouseup(int mouse, int button); #endif //IO_H_ diff -r 8cf57c6558ed -r b5d35222047e render.h --- a/render.h Sat Nov 28 20:05:15 2015 -0800 +++ b/render.h Sat Nov 28 21:27:21 2015 -0800 @@ -26,6 +26,7 @@ #define MAX_JOYSTICKS 8 #define MAX_MICE 8 +#define MAX_MOUSE_BUTTONS 8 #include "vdp.h" #include "psg.h" diff -r 8cf57c6558ed -r b5d35222047e render_sdl.c --- a/render_sdl.c Sat Nov 28 20:05:15 2015 -0800 +++ b/render_sdl.c Sat Nov 28 21:27:21 2015 -0800 @@ -547,6 +547,12 @@ case SDL_MOUSEMOTION: handle_mouse_moved(event->motion.which, event->motion.x, event->motion.y); break; + case SDL_MOUSEBUTTONDOWN: + handle_mousedown(event->button.which, event->button.button); + break; + case SDL_MOUSEBUTTONUP: + handle_mouseup(event->button.which, event->button.button); + break; case SDL_QUIT: puts(""); exit(0);