-
-
Notifications
You must be signed in to change notification settings - Fork 294
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement keyboard rebinding support #1301
Changes from all commits
b2e81c9
c8a8c5d
154bf73
e345c02
0880d67
d81bc5e
13490b0
5051911
eb04bf5
323f995
eb3df6b
a95cdb0
b828dfd
1d3bb78
4a0c89f
0bea80b
b18a1a5
241aea6
de95d9c
46a0015
2668daf
ab396c7
159e571
a5be7a3
d4199b3
6883c4e
c54a930
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -298,6 +298,10 @@ void xemu_input_process_sdl_events(const SDL_Event *event) | |
} | ||
} else if (event->type == SDL_CONTROLLERDEVICEREMAPPED) { | ||
DPRINTF("Controller Remapped: %d\n", event->cdevice.which); | ||
} else if (is_remapping_active) { | ||
xemu_input_keyboard_rebind(event); | ||
} else if (restore_controls) { | ||
xemu_input_restore_defaults(); | ||
} | ||
} | ||
|
||
|
@@ -353,6 +357,138 @@ void xemu_input_update_sdl_kbd_controller_state(ControllerState *state) | |
if (kbd[sdl_kbd_scancode_map[24]]) state->axis[CONTROLLER_AXIS_RTRIG] = 32767; | ||
} | ||
|
||
void xemu_input_restore_defaults(void) | ||
{ | ||
sdl_kbd_scancode_map[0] = SDL_SCANCODE_A; | ||
sdl_kbd_scancode_map[1] = SDL_SCANCODE_B; | ||
sdl_kbd_scancode_map[2] = SDL_SCANCODE_X; | ||
sdl_kbd_scancode_map[3] = SDL_SCANCODE_Y; | ||
sdl_kbd_scancode_map[4] = SDL_SCANCODE_LEFT; | ||
sdl_kbd_scancode_map[5] = SDL_SCANCODE_UP; | ||
sdl_kbd_scancode_map[6] = SDL_SCANCODE_RIGHT; | ||
sdl_kbd_scancode_map[7] = SDL_SCANCODE_DOWN; | ||
sdl_kbd_scancode_map[8] = SDL_SCANCODE_BACKSPACE; | ||
sdl_kbd_scancode_map[9] = SDL_SCANCODE_RETURN; | ||
sdl_kbd_scancode_map[10] = SDL_SCANCODE_1; | ||
sdl_kbd_scancode_map[11] = SDL_SCANCODE_2; | ||
sdl_kbd_scancode_map[12] = SDL_SCANCODE_3; | ||
sdl_kbd_scancode_map[13] = SDL_SCANCODE_4; | ||
sdl_kbd_scancode_map[14] = SDL_SCANCODE_5; | ||
sdl_kbd_scancode_map[15] = SDL_SCANCODE_E; | ||
sdl_kbd_scancode_map[16] = SDL_SCANCODE_S; | ||
sdl_kbd_scancode_map[17] = SDL_SCANCODE_F; | ||
sdl_kbd_scancode_map[18] = SDL_SCANCODE_D; | ||
sdl_kbd_scancode_map[19] = SDL_SCANCODE_W; | ||
sdl_kbd_scancode_map[20] = SDL_SCANCODE_I; | ||
sdl_kbd_scancode_map[21] = SDL_SCANCODE_J; | ||
sdl_kbd_scancode_map[22] = SDL_SCANCODE_L; | ||
sdl_kbd_scancode_map[23] = SDL_SCANCODE_K; | ||
sdl_kbd_scancode_map[24] = SDL_SCANCODE_O; | ||
|
||
g_config.input.keyboard_controller_scancode_map.a = SDL_SCANCODE_A; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Create a function that takes |
||
g_config.input.keyboard_controller_scancode_map.b = SDL_SCANCODE_B; | ||
g_config.input.keyboard_controller_scancode_map.x = SDL_SCANCODE_X; | ||
g_config.input.keyboard_controller_scancode_map.y = SDL_SCANCODE_Y; | ||
g_config.input.keyboard_controller_scancode_map.dpad_left = SDL_SCANCODE_LEFT; | ||
g_config.input.keyboard_controller_scancode_map.dpad_up = SDL_SCANCODE_UP; | ||
g_config.input.keyboard_controller_scancode_map.dpad_right = SDL_SCANCODE_RIGHT; | ||
g_config.input.keyboard_controller_scancode_map.dpad_down = SDL_SCANCODE_DOWN; | ||
g_config.input.keyboard_controller_scancode_map.back = SDL_SCANCODE_BACKSPACE; | ||
g_config.input.keyboard_controller_scancode_map.start = SDL_SCANCODE_RETURN; | ||
g_config.input.keyboard_controller_scancode_map.white = SDL_SCANCODE_1; | ||
g_config.input.keyboard_controller_scancode_map.black = SDL_SCANCODE_2; | ||
g_config.input.keyboard_controller_scancode_map.lstick_btn = SDL_SCANCODE_3; | ||
g_config.input.keyboard_controller_scancode_map.rstick_btn = SDL_SCANCODE_4; | ||
g_config.input.keyboard_controller_scancode_map.guide = SDL_SCANCODE_5; | ||
g_config.input.keyboard_controller_scancode_map.lstick_up = SDL_SCANCODE_E; | ||
g_config.input.keyboard_controller_scancode_map.lstick_left = SDL_SCANCODE_S; | ||
g_config.input.keyboard_controller_scancode_map.lstick_right = SDL_SCANCODE_F; | ||
g_config.input.keyboard_controller_scancode_map.lstick_down = SDL_SCANCODE_D; | ||
g_config.input.keyboard_controller_scancode_map.ltrigger = SDL_SCANCODE_W; | ||
g_config.input.keyboard_controller_scancode_map.rstick_up = SDL_SCANCODE_I; | ||
g_config.input.keyboard_controller_scancode_map.rstick_left = SDL_SCANCODE_J; | ||
g_config.input.keyboard_controller_scancode_map.rstick_right = SDL_SCANCODE_L; | ||
g_config.input.keyboard_controller_scancode_map.rstick_down = SDL_SCANCODE_K; | ||
g_config.input.keyboard_controller_scancode_map.rtrigger = SDL_SCANCODE_O; | ||
|
||
char *buf = g_strdup_printf("INFO: Keys restored to default."); | ||
xemu_queue_notification(buf); | ||
free(buf); | ||
|
||
restore_controls = false; | ||
} | ||
|
||
void xemu_input_keyboard_rebind(const SDL_Event *ev) | ||
{ | ||
//Check if the user aborts the remapping process. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: This comment adds no value |
||
if (abort_rebinding) { | ||
char *buf = g_strdup_printf("INFO: Remapping process aborted"); | ||
xemu_queue_notification(buf); | ||
free(buf); | ||
is_remapping_active = false; | ||
abort_rebinding = false; | ||
} | ||
|
||
if (ev->type == SDL_KEYDOWN) { | ||
sdl_kbd_scancode_map[currently_remapping] = ev->key.keysym.scancode; | ||
//check for duplicated keybindings, if found, rebind that button. | ||
for (size_t i = 0; i < currently_remapping; i++) { | ||
if (sdl_kbd_scancode_map[currently_remapping] == sdl_kbd_scancode_map[i]) { | ||
already_mapped = i; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This variable isn't used anywhere else, seems like it can be removed. |
||
currently_remapping--; | ||
char *buf = g_strdup_printf("WARNING: Keybind already in use for: %s. Try another key.", bindings[already_mapped]); | ||
xemu_queue_notification(buf); | ||
free(buf); | ||
break; | ||
} | ||
} | ||
|
||
if ((sdl_kbd_scancode_map[currently_remapping] < SDL_SCANCODE_UNKNOWN) || | ||
(sdl_kbd_scancode_map[currently_remapping] >= SDL_NUM_SCANCODES)) { | ||
char *buf = g_strdup_printf("WARNING: Keyboard scancode out of range, try another key."); | ||
xemu_queue_notification(buf); | ||
free(buf); | ||
currently_remapping--; | ||
} | ||
|
||
currently_remapping++; | ||
|
||
//If the user has mapped all the buttons, store the new bindings. | ||
if (currently_remapping == 25) { | ||
g_config.input.keyboard_controller_scancode_map.a = sdl_kbd_scancode_map[0]; | ||
g_config.input.keyboard_controller_scancode_map.b = sdl_kbd_scancode_map[1]; | ||
g_config.input.keyboard_controller_scancode_map.x = sdl_kbd_scancode_map[2]; | ||
g_config.input.keyboard_controller_scancode_map.y = sdl_kbd_scancode_map[3]; | ||
g_config.input.keyboard_controller_scancode_map.dpad_left = sdl_kbd_scancode_map[4]; | ||
g_config.input.keyboard_controller_scancode_map.dpad_up = sdl_kbd_scancode_map[5]; | ||
g_config.input.keyboard_controller_scancode_map.dpad_right = sdl_kbd_scancode_map[6]; | ||
g_config.input.keyboard_controller_scancode_map.dpad_down = sdl_kbd_scancode_map[7]; | ||
g_config.input.keyboard_controller_scancode_map.back = sdl_kbd_scancode_map[8]; | ||
g_config.input.keyboard_controller_scancode_map.start = sdl_kbd_scancode_map[9]; | ||
g_config.input.keyboard_controller_scancode_map.white = sdl_kbd_scancode_map[10]; | ||
g_config.input.keyboard_controller_scancode_map.black = sdl_kbd_scancode_map[11]; | ||
g_config.input.keyboard_controller_scancode_map.lstick_btn = sdl_kbd_scancode_map[12]; | ||
g_config.input.keyboard_controller_scancode_map.rstick_btn = sdl_kbd_scancode_map[13]; | ||
g_config.input.keyboard_controller_scancode_map.guide = sdl_kbd_scancode_map[14]; | ||
g_config.input.keyboard_controller_scancode_map.lstick_up = sdl_kbd_scancode_map[15]; | ||
g_config.input.keyboard_controller_scancode_map.lstick_left = sdl_kbd_scancode_map[16]; | ||
g_config.input.keyboard_controller_scancode_map.lstick_right = sdl_kbd_scancode_map[17]; | ||
g_config.input.keyboard_controller_scancode_map.lstick_down = sdl_kbd_scancode_map[18]; | ||
g_config.input.keyboard_controller_scancode_map.ltrigger = sdl_kbd_scancode_map[19]; | ||
g_config.input.keyboard_controller_scancode_map.rstick_up = sdl_kbd_scancode_map[20]; | ||
g_config.input.keyboard_controller_scancode_map.rstick_left = sdl_kbd_scancode_map[21]; | ||
g_config.input.keyboard_controller_scancode_map.rstick_right = sdl_kbd_scancode_map[22]; | ||
g_config.input.keyboard_controller_scancode_map.rstick_down = sdl_kbd_scancode_map[23]; | ||
g_config.input.keyboard_controller_scancode_map.rtrigger = sdl_kbd_scancode_map[24]; | ||
|
||
char *buf = g_strdup_printf("INFO: Successfully remapped keyboard."); | ||
xemu_queue_notification(buf); | ||
free(buf); | ||
is_remapping_active = false; | ||
} | ||
} | ||
} | ||
|
||
void xemu_input_update_sdl_controller_state(ControllerState *state) | ||
{ | ||
state->buttons = 0; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -501,25 +501,28 @@ void RenderController(float frame_x, float frame_y, uint32_t primary_color, | |
|
||
uint32_t jewel_color = secondary_color; | ||
|
||
// Check to see if the guide button is pressed | ||
const uint32_t animate_guide_button_duration = 2000; | ||
if (state->buttons & CONTROLLER_BUTTON_GUIDE) { | ||
state->animate_guide_button_end = now + animate_guide_button_duration; | ||
} | ||
// Check to see if the guide button is pressed only when not remapping. | ||
if (!is_remapping_active) { | ||
const uint32_t animate_guide_button_duration = 2000; | ||
if (state->buttons & CONTROLLER_BUTTON_GUIDE) { | ||
state->animate_guide_button_end = now + animate_guide_button_duration; | ||
} | ||
|
||
if (now < state->animate_guide_button_end) { | ||
t = 1.0f - (float)(state->animate_guide_button_end-now)/(float)animate_guide_button_duration; | ||
float sin_wav = (1-sin(M_PI * t / 2.0f)); | ||
if (now < state->animate_guide_button_end) { | ||
t = 1.0f - (float)(state->animate_guide_button_end-now)/(float)animate_guide_button_duration; | ||
float sin_wav = (1-sin(M_PI * t / 2.0f)); | ||
|
||
// Animate guide button by highlighting logo jewel and fading out over time | ||
alpha = sin_wav * 255.0f; | ||
jewel_color = primary_color + alpha; | ||
// Animate guide button by highlighting logo jewel and fading out over time | ||
alpha = sin_wav * 255.0f; | ||
jewel_color = primary_color + alpha; | ||
|
||
// Add a little extra flare: wiggle the frame around while we rumble | ||
frame_x += ((float)(rand() % 5)-2.5) * (1-t); | ||
frame_y += ((float)(rand() % 5)-2.5) * (1-t); | ||
rumble_l = rumble_r = sin_wav; | ||
// Add a little extra flare: wiggle the frame around while we rumble | ||
frame_x += ((float)(rand() % 5)-2.5) * (1-t); | ||
frame_y += ((float)(rand() % 5)-2.5) * (1-t); | ||
rumble_l = rumble_r = sin_wav; | ||
} | ||
Fabxx marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: Extra newline |
||
|
||
// Render controller texture | ||
RenderDecal(g_decal_shader, frame_x + 0, frame_y + 0, | ||
|
@@ -534,51 +537,70 @@ void RenderController(float frame_x, float frame_y, uint32_t primary_color, | |
|
||
// The controller has alpha cutouts where the buttons are. Draw a surface | ||
// behind the buttons if they are activated | ||
for (int i = 0; i < 12; i++) { | ||
if (state->buttons & (1 << i)) { | ||
RenderDecal(g_decal_shader, frame_x + buttons[i].x, | ||
frame_y + buttons[i].y, buttons[i].w, buttons[i].h, 0, | ||
0, 1, 1, 0, 0, primary_color + 0xff); | ||
// Do not highlight the buttons while remapping. | ||
if (!is_remapping_active) { | ||
for (int i = 0; i < 12; i++) { | ||
if (state->buttons & (1 << i)) { | ||
RenderDecal(g_decal_shader, frame_x + buttons[i].x, | ||
frame_y + buttons[i].y, buttons[i].w, buttons[i].h, 0, | ||
0, 1, 1, 0, 0, primary_color + 0xff); | ||
} | ||
} | ||
} | ||
|
||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Blend with controller | ||
|
||
// Render left thumbstick | ||
// Render left thumbstick, do not make move/highlight while remapping. | ||
float w = tex_items[obj_lstick].w; | ||
float h = tex_items[obj_lstick].h; | ||
float c_x = frame_x+lstick_ctr.x; | ||
float c_y = frame_y+lstick_ctr.y; | ||
float lstick_x = (float)state->axis[CONTROLLER_AXIS_LSTICK_X]/32768.0; | ||
float lstick_y = (float)state->axis[CONTROLLER_AXIS_LSTICK_Y]/32768.0; | ||
int lstick_press_anim = CONTROLLER_BUTTON_LSTICK; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this take the remapping into account? |
||
|
||
if (is_remapping_active) { | ||
lstick_x = 0; | ||
lstick_y = 0; | ||
lstick_press_anim = SDL_SCANCODE_UNKNOWN; | ||
} | ||
|
||
RenderDecal(g_decal_shader, (int)(c_x - w / 2.0f + 10.0f * lstick_x), | ||
(int)(c_y - h / 2.0f + 10.0f * lstick_y), w, h, | ||
tex_items[obj_lstick].x, tex_items[obj_lstick].y, w, h, | ||
(state->buttons & CONTROLLER_BUTTON_LSTICK) ? secondary_color : | ||
(state->buttons & lstick_press_anim) ? secondary_color : | ||
primary_color, | ||
(state->buttons & CONTROLLER_BUTTON_LSTICK) ? primary_color : | ||
(state->buttons & lstick_press_anim) ? primary_color : | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of using |
||
secondary_color, | ||
0); | ||
|
||
// Render right thumbstick | ||
// Render right thumbstick, do not make move/highlight while remapping | ||
w = tex_items[obj_rstick].w; | ||
h = tex_items[obj_rstick].h; | ||
c_x = frame_x+rstick_ctr.x; | ||
c_y = frame_y+rstick_ctr.y; | ||
float rstick_x = (float)state->axis[CONTROLLER_AXIS_RSTICK_X]/32768.0; | ||
float rstick_y = (float)state->axis[CONTROLLER_AXIS_RSTICK_Y]/32768.0; | ||
int rstick_press_anim = CONTROLLER_BUTTON_RSTICK; | ||
|
||
if (is_remapping_active) { | ||
rstick_x = 0; | ||
rstick_y = 0; | ||
rstick_press_anim = SDL_SCANCODE_UNKNOWN; | ||
} | ||
|
||
RenderDecal(g_decal_shader, (int)(c_x - w / 2.0f + 10.0f * rstick_x), | ||
(int)(c_y - h / 2.0f + 10.0f * rstick_y), w, h, | ||
tex_items[obj_rstick].x, tex_items[obj_rstick].y, w, h, | ||
(state->buttons & CONTROLLER_BUTTON_RSTICK) ? secondary_color : | ||
(state->buttons & rstick_press_anim) ? secondary_color : | ||
primary_color, | ||
(state->buttons & CONTROLLER_BUTTON_RSTICK) ? primary_color : | ||
(state->buttons & rstick_press_anim) ? primary_color : | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above |
||
secondary_color, | ||
0); | ||
|
||
glBlendFunc(GL_ONE, GL_ZERO); // Don't blend, just overwrite values in buffer | ||
|
||
// Render trigger bars | ||
// Render trigger bars, do not highlight when remapping. | ||
float ltrig = state->axis[CONTROLLER_AXIS_LTRIG] / 32767.0; | ||
float rtrig = state->axis[CONTROLLER_AXIS_RTRIG] / 32767.0; | ||
const uint32_t animate_trigger_duration = 1000; | ||
|
@@ -596,6 +618,12 @@ void RenderController(float frame_x, float frame_y, uint32_t primary_color, | |
alpha += fmin(sin_wav * 0x40, 0x80); | ||
} | ||
|
||
if (is_remapping_active) { | ||
ltrig = 0; | ||
rtrig = 0; | ||
alpha = 0x80; | ||
} | ||
|
||
RenderMeter(g_decal_shader, original_frame_x + 10, | ||
original_frame_y + tex_items[obj_controller].h + 20, 150, 5, | ||
ltrig, primary_color + alpha, primary_color + 0xff); | ||
|
@@ -604,9 +632,12 @@ void RenderController(float frame_x, float frame_y, uint32_t primary_color, | |
original_frame_y + tex_items[obj_controller].h + 20, 150, 5, | ||
rtrig, primary_color + alpha, primary_color + 0xff); | ||
|
||
// Apply rumble updates | ||
state->rumble_l = (int)(rumble_l * (float)0xffff); | ||
state->rumble_r = (int)(rumble_r * (float)0xffff); | ||
|
||
// Apply rumble updates when not remapping | ||
if (!is_remapping_active) { | ||
state->rumble_l = (int)(rumble_l * (float)0xffff); | ||
state->rumble_r = (int)(rumble_r * (float)0xffff); | ||
} | ||
|
||
glBindVertexArray(0); | ||
glUseProgram(0); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this done here instead of being called directly when the restore button is pressed?