typedef enum { CONTROL_CONTROLLER, CONTROL_MOUSE, CONTROL_KEYBOARD, } ControlMethod; const ControlMethod ctrl_methods[] = { CONTROL_METHODS }; static ControlMethod ctrl_idx = 0; #define MOUSE_DELTA 1 typedef struct Mouse { int x; int y; } Mouse; static Mouse mouse = {SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2}; void handle_input() { poll_keys(); if (key_tap(KEY_L) || key_tap(KEY_R)) { // Reset control variables on method switch. switch (ctrl_methods[ctrl_idx]) { case CONTROL_CONTROLLER: { u8 *d = &device_data[0x80]; d[2] = 0; uxn_eval_asm(PEEK2(d)); d[3] = 0; } break; case CONTROL_MOUSE: { u8 *d = &device_data[0x90]; d[6] = 0; d[7] = 0; POKE2(d + 0x2, -10); POKE2(d + 0x4, -10); uxn_eval_asm(PEEK2(d)); } break; case CONTROL_KEYBOARD: { toggle_keyboard(); } break; } // Update ctrl_idx. ctrl_idx = (ctrl_idx + 1 > (int)LEN(ctrl_methods) - 1) ? 0 : ctrl_idx + 1; // Initialize controller variables here. if (ctrl_methods[ctrl_idx] == CONTROL_KEYBOARD) { toggle_keyboard(); } } if (ctrl_methods[ctrl_idx] == CONTROL_CONTROLLER) { u8 *d = &device_data[0x80]; // TODO: We don't need ifs if we use KEY_INPUTS directly and maybe just // swap some things if needed. u8 *flag = &d[2]; if (key_tap(KEY_A)) { *flag |= 0x01; } else { *flag &= ~0x01; } if (key_tap(KEY_B)) { *flag |= 0x02; } else { *flag &= ~0x02; } if (key_tap(KEY_SELECT)) { *flag |= 0x04; } else { *flag &= ~0x04; } if (key_tap(KEY_START)) { *flag |= 0x08; } else { *flag &= ~0x08; } if (key_tap(KEY_UP)) { *flag |= 0x10; } else { *flag &= ~0x10; } if (key_tap(KEY_DOWN)) { *flag |= 0x20; } else { *flag &= ~0x20; } if (key_tap(KEY_LEFT)) { *flag |= 0x40; } else { *flag &= ~0x40; } if (key_tap(KEY_RIGHT)) { *flag |= 0x80; } else { *flag &= ~0x80; } if (key_prev != key_curr) { uxn_eval_asm(PEEK2(d)); } d[3] = 0; } else if (ctrl_methods[ctrl_idx] == CONTROL_MOUSE) { u8 *d = &device_data[0x90]; // Detect "mouse key press". u8 flag = d[6]; bool event = false; if (key_tap(KEY_B)) { event = true; flag |= 0x01; } else if (key_released(KEY_B)) { event = true; flag &= ~0x01; } if (key_tap(KEY_A)) { event = true; flag |= 0x10; } else if (key_released(KEY_A)) { event = true; flag &= ~0x10; } // Handle chording. d[6] = flag; if(flag == 0x10 && (d[6] & 0x01)) { d[7] = 0x01; } if(flag == 0x01 && (d[6] & 0x10)) { d[7] = 0x10; } // Detect mouse movement. if (key_pressed(KEY_UP)) { event = true; mouse.y = CLAMP(mouse.y - MOUSE_DELTA, 0, SCREEN_HEIGHT - 8); } else if (key_pressed(KEY_DOWN)) { event = true; mouse.y = CLAMP(mouse.y + MOUSE_DELTA, 0, SCREEN_HEIGHT - 8); } if (key_pressed(KEY_LEFT)) { event = true; mouse.x = CLAMP(mouse.x - MOUSE_DELTA, 0, SCREEN_WIDTH - 8); } else if (key_pressed(KEY_RIGHT)) { event = true; mouse.x = CLAMP(mouse.x + MOUSE_DELTA, 0, SCREEN_WIDTH - 8); } // Eval mouse. POKE2(d + 0x2, mouse.x); POKE2(d + 0x4, mouse.y); if (event) { uxn_eval_asm(PEEK2(d)); } } else if (ctrl_methods[ctrl_idx] == CONTROL_KEYBOARD) { u8 *d = &device_data[0x80]; if (key_tap(KEY_LEFT)) { update_cursor(cursor_position - 1); } else if (key_tap(KEY_RIGHT)) { update_cursor(cursor_position + 1); } if (key_tap(KEY_UP) && cursor_position >= KEYBOARD_ROW_SIZE) { update_cursor(cursor_position - KEYBOARD_ROW_SIZE); } else if (key_tap(KEY_DOWN) && cursor_position < LEN(keyboard) - KEYBOARD_ROW_SIZE) { update_cursor(cursor_position + KEYBOARD_ROW_SIZE); } if (key_tap(KEY_B)) { u8 symbol = keyboard[cursor_position].symbol; switch (symbol) { case 0x7f: { // Backspace. d[3] = 0x08; } break; case 0x14: { // New line. d[3] = 0x0d; } break; case 0x18: { // Arrow up. d[2] = 0x10; } break; case 0x19: { // Arrow down. d[2] = 0x20; } break; case 0x1b: { // Arrow left. d[2] = 0x40; } break; case 0x1a: { // Arrow right. d[2] = 0x80; } break; default: { d[3] = symbol; } break; } uxn_eval_asm(PEEK2(d)); d[3] = 0; } } }