diff --git a/input/input_driver.c b/input/input_driver.c index 565f763a9e..2aea7d7b7d 100644 --- a/input/input_driver.c +++ b/input/input_driver.c @@ -62,7 +62,31 @@ #define INPUT_REMOTE_KEY_PRESSED(input_st, key, port) (input_st->remote_st_ptr.buttons[(port)] & (UINT64_C(1) << (key))) +/** + * check_input_driver_block_hotkey: + * + * Checks if 'hotkey enable' key is pressed. + * + * If we haven't bound anything to this, + * always allow hotkeys. + + * If we hold ENABLE_HOTKEY button, block all libretro input to allow + * hotkeys to be bound to same keys as RetroPad. + **/ +#define CHECK_INPUT_DRIVER_BLOCK_HOTKEY(normal_bind, autoconf_bind) \ +( \ + (((normal_bind)->key != RETROK_UNKNOWN) \ + || ((normal_bind)->mbutton != NO_BTN) \ + || ((normal_bind)->joykey != NO_BTN) \ + || ((normal_bind)->joyaxis != AXIS_NONE) \ + || ((autoconf_bind)->key != RETROK_UNKNOWN) \ + || ((autoconf_bind)->joykey != NO_BTN) \ + || ((autoconf_bind)->joyaxis != AXIS_NONE)) \ +) + /**************************************/ +/* TODO/FIXME - turn these into static global variable */ +uint64_t lifecycle_state = 0; static void *input_null_init(const char *joypad_driver) { return (void*)-1; } static void input_null_poll(void *data) { } @@ -3244,7 +3268,7 @@ static void input_overlay_loaded(retro_task_t *task, bool inp_overlay_auto_rotate = settings->bools.input_overlay_auto_rotate; bool input_overlay_enable = settings->bools.input_overlay_enable; video_driver_state_t *video_st = video_state_get_ptr(); - input_driver_state_t *input_st = input_state_get_ptr(); + input_driver_state_t *input_st = &input_driver_st; if (err) return; @@ -3450,6 +3474,139 @@ bool input_keys_pressed_other_sources( return false; } +void input_keys_pressed( + unsigned port, + bool is_menu, + int input_hotkey_block_delay, + input_bits_t *p_new_state, + const struct retro_keybind **binds, + const struct retro_keybind *binds_norm, + const struct retro_keybind *binds_auto, + const input_device_driver_t *joypad, + const input_device_driver_t *sec_joypad, + rarch_joypad_info_t *joypad_info) +{ + unsigned i; + input_driver_state_t *input_st = &input_driver_st; + + if (CHECK_INPUT_DRIVER_BLOCK_HOTKEY(binds_norm, binds_auto)) + { + if ( input_state_wrap( + input_st->current_driver, + input_st->current_data, + input_st->primary_joypad, + sec_joypad, + joypad_info, + &binds[port], + input_st->keyboard_mapping_blocked, + port, RETRO_DEVICE_JOYPAD, 0, + RARCH_ENABLE_HOTKEY)) + { + if (input_st->input_hotkey_block_counter < input_hotkey_block_delay) + input_st->input_hotkey_block_counter++; + else + input_st->block_libretro_input = true; + } + else + { + input_st->input_hotkey_block_counter = 0; + input_st->block_hotkey = true; + } + } + + if ( !is_menu + && binds[port][RARCH_GAME_FOCUS_TOGGLE].valid) + { + const struct retro_keybind *focus_binds_auto = + &input_autoconf_binds[port][RARCH_GAME_FOCUS_TOGGLE]; + const struct retro_keybind *focus_normal = + &binds[port][RARCH_GAME_FOCUS_TOGGLE]; + + /* Allows rarch_focus_toggle hotkey to still work + * even though every hotkey is blocked */ + if (CHECK_INPUT_DRIVER_BLOCK_HOTKEY( + focus_normal, focus_binds_auto)) + { + if (input_state_wrap( + input_st->current_driver, + input_st->current_data, + input_st->primary_joypad, + sec_joypad, + joypad_info, + &binds[port], + input_st->keyboard_mapping_blocked, + port, + RETRO_DEVICE_JOYPAD, 0, RARCH_GAME_FOCUS_TOGGLE)) + input_st->block_hotkey = false; + } + } + + { + int16_t ret = 0; + + /* Check the libretro input first */ + if (!input_st->block_libretro_input) + ret = input_state_wrap( + input_st->current_driver, + input_st->current_data, + input_st->primary_joypad, + sec_joypad, + joypad_info, &binds[port], + input_st->keyboard_mapping_blocked, + port, RETRO_DEVICE_JOYPAD, 0, + RETRO_DEVICE_ID_JOYPAD_MASK); + + for (i = 0; i < RARCH_FIRST_META_KEY; i++) + { + if ( + (ret & (UINT64_C(1) << i)) || + input_keys_pressed_other_sources(input_st, + i, p_new_state)) + { + BIT256_SET_PTR(p_new_state, i); + } + } + } + + /* Check the hotkeys */ + if (input_st->block_hotkey) + { + for (i = RARCH_FIRST_META_KEY; i < RARCH_BIND_LIST_END; i++) + { + if ( + BIT64_GET(lifecycle_state, i) + || input_keys_pressed_other_sources(input_st, + i, p_new_state)) + { + BIT256_SET_PTR(p_new_state, i); + } + } + } + else + { + for (i = RARCH_FIRST_META_KEY; i < RARCH_BIND_LIST_END; i++) + { + bool bit_pressed = binds[port][i].valid + && input_state_wrap( + input_st->current_driver, + input_st->current_data, + input_st->primary_joypad, + sec_joypad, + joypad_info, + &binds[port], + input_st->keyboard_mapping_blocked, + port, RETRO_DEVICE_JOYPAD, 0, i); + if ( bit_pressed + || BIT64_GET(lifecycle_state, i) + || input_keys_pressed_other_sources(input_st, + i, p_new_state)) + { + BIT256_SET_PTR(p_new_state, i); + } + } + } +} + int16_t input_state_device( input_driver_state_t *input_st, settings_t *settings, @@ -4891,4 +5048,3 @@ int16_t input_driver_state_wrapper(unsigned port, unsigned device, return result; } - diff --git a/input/input_driver.h b/input/input_driver.h index 77737a2f81..4dc10798c0 100644 --- a/input/input_driver.h +++ b/input/input_driver.h @@ -1009,6 +1009,25 @@ void input_driver_poll(void); int16_t input_driver_state_wrapper(unsigned port, unsigned device, unsigned idx, unsigned id); +/** + * input_keys_pressed: + * + * Grab an input sample for this frame. + * + * Returns: Input sample containing a mask of all pressed keys. + */ +void input_keys_pressed( + unsigned port, + bool is_menu, + int input_hotkey_block_delay, + input_bits_t *p_new_state, + const struct retro_keybind **binds, + const struct retro_keybind *binds_norm, + const struct retro_keybind *binds_auto, + const input_device_driver_t *joypad, + const input_device_driver_t *sec_joypad, + rarch_joypad_info_t *joypad_info); + extern input_device_driver_t *joypad_drivers[]; extern input_driver_t *input_drivers[]; #ifdef HAVE_HID diff --git a/menu/menu_driver.c b/menu/menu_driver.c index 4d1aa3a889..fef6e175c5 100644 --- a/menu/menu_driver.c +++ b/menu/menu_driver.c @@ -5642,7 +5642,7 @@ current_time; bool menu_input_dialog_get_display_kb(void) { - struct menu_state *menu_st = menu_state_get_ptr(); + struct menu_state *menu_st = &menu_driver_state; #ifdef HAVE_LIBNX input_driver_state_t *input_st = input_state_get_ptr(); SwkbdConfig kbd; @@ -5738,7 +5738,7 @@ unsigned menu_event( unsigned ret = MENU_ACTION_NOOP; bool set_scroll = false; size_t new_scroll_accel = 0; - struct menu_state *menu_st = menu_state_get_ptr(); + struct menu_state *menu_st = &menu_driver_state; menu_input_t *menu_input = &menu_st->input_state; input_driver_state_t *input_st = input_state_get_ptr(); input_driver_t *current_input = input_st->current_driver; @@ -6094,3 +6094,619 @@ unsigned menu_event( return ret; } + +static int menu_input_pointer_post_iterate( + gfx_display_t *p_disp, + retro_time_t current_time, + menu_file_list_cbs_t *cbs, + menu_entry_t *entry, unsigned action) +{ + static retro_time_t start_time = 0; + static int16_t start_x = 0; + static int16_t start_y = 0; + static int16_t last_x = 0; + static int16_t last_y = 0; + static uint16_t dx_start_right_max = 0; + static uint16_t dx_start_left_max = 0; + static uint16_t dy_start_up_max = 0; + static uint16_t dy_start_down_max = 0; + static bool last_select_pressed = false; + static bool last_cancel_pressed = false; + static bool last_left_pressed = false; + static bool last_right_pressed = false; + static retro_time_t last_left_action_time = 0; + static retro_time_t last_right_action_time = 0; + static retro_time_t last_press_direction_time = 0; + bool attenuate_y_accel = true; + bool osk_active = menu_input_dialog_get_display_kb(); + bool messagebox_active = false; + int ret = 0; + struct menu_state *menu_st = &menu_driver_state; + menu_input_pointer_hw_state_t *pointer_hw_state = &menu_st->input_pointer_hw_state; + menu_input_t *menu_input = &menu_st->input_state; + menu_handle_t *menu = menu_st->driver_data; + video_driver_state_t *video_st = video_state_get_ptr(); + input_driver_state_t *input_st = input_state_get_ptr(); + + /* Check whether a message box is currently + * being shown + * > Note: This ignores input bind dialogs, + * since input binding overrides normal input + * and must be handled separately... */ + if (menu) + messagebox_active = BIT64_GET( + menu->state, MENU_STATE_RENDER_MESSAGEBOX) && + !string_is_empty(menu->menu_state_msg); + + /* If onscreen keyboard is shown and we currently have + * active mouse input, highlight key under mouse cursor */ + if (osk_active && + (menu_input->pointer.type == MENU_POINTER_MOUSE) && + pointer_hw_state->active) + { + menu_ctx_pointer_t point; + + point.x = pointer_hw_state->x; + point.y = pointer_hw_state->y; + point.ptr = 0; + point.cbs = NULL; + point.entry = NULL; + point.action = 0; + point.gesture = MENU_INPUT_GESTURE_NONE; + point.retcode = 0; + + menu_driver_ctl(RARCH_MENU_CTL_OSK_PTR_AT_POS, &point); + if (point.retcode > -1) + input_st->osk_ptr = point.retcode; + } + + /* Select + X/Y position */ + if (!menu_input->select_inhibit) + { + if (pointer_hw_state->select_pressed) + { + int16_t x = pointer_hw_state->x; + int16_t y = pointer_hw_state->y; + static float accel0 = 0.0f; + static float accel1 = 0.0f; + + /* Transition from select unpressed to select pressed */ + if (!last_select_pressed) + { + menu_ctx_pointer_t point; + + /* Initialise variables */ + start_time = current_time; + start_x = x; + start_y = y; + last_x = x; + last_y = y; + dx_start_right_max = 0; + dx_start_left_max = 0; + dy_start_up_max = 0; + dy_start_down_max = 0; + accel0 = 0.0f; + accel1 = 0.0f; + last_press_direction_time = 0; + + /* If we are not currently showing the onscreen + * keyboard or a message box, trigger a 'pointer + * down' event */ + if (!osk_active && !messagebox_active) + { + point.x = x; + point.y = y; + /* Note: menu_input->ptr is meaningless here when + * using a touchscreen... */ + point.ptr = menu_input->ptr; + point.cbs = cbs; + point.entry = entry; + point.action = action; + point.gesture = MENU_INPUT_GESTURE_NONE; + + menu_driver_ctl(RARCH_MENU_CTL_POINTER_DOWN, &point); + ret = point.retcode; + } + } + else + { + /* Pointer is being held down + * (i.e. for more than one frame) */ + float dpi = menu ? menu_input_get_dpi(menu, p_disp, + video_st->width, video_st->height) : 0.0f; + + /* > Update deltas + acceleration & detect press direction + * Note: We only do this if the pointer has moved above + * a certain threshold - this requires dpi info */ + if (dpi > 0.0f) + { + uint16_t dpi_threshold_drag = + (uint16_t)((dpi * MENU_INPUT_DPI_THRESHOLD_DRAG) + 0.5f); + + int16_t dx_start = x - start_x; + int16_t dy_start = y - start_y; + uint16_t dx_start_abs = dx_start < 0 ? dx_start * -1 : dx_start; + uint16_t dy_start_abs = dy_start < 0 ? dy_start * -1 : dy_start; + + if ((dx_start_abs > dpi_threshold_drag) || + (dy_start_abs > dpi_threshold_drag)) + { + uint16_t dpi_threshold_press_direction_min = + (uint16_t)((dpi * MENU_INPUT_DPI_THRESHOLD_PRESS_DIRECTION_MIN) + 0.5f); + uint16_t dpi_threshold_press_direction_max = + (uint16_t)((dpi * MENU_INPUT_DPI_THRESHOLD_PRESS_DIRECTION_MAX) + 0.5f); + uint16_t dpi_threshold_press_direction_tangent = + (uint16_t)((dpi * MENU_INPUT_DPI_THRESHOLD_PRESS_DIRECTION_TANGENT) + 0.5f); + + enum menu_input_pointer_press_direction + press_direction = MENU_INPUT_PRESS_DIRECTION_NONE; + float press_direction_amplitude = 0.0f; + retro_time_t press_direction_delay = MENU_INPUT_PRESS_DIRECTION_DELAY_MAX; + + /* Pointer has moved a sufficient distance to + * trigger a 'dragged' state */ + menu_input->pointer.dragged = true; + + /* Here we diverge: + * > If onscreen keyboard or a message box is + * active, pointer deltas, acceleration and + * press direction must be inhibited + * > If not, input is processed normally */ + if (osk_active || messagebox_active) + { + /* Inhibit normal pointer input */ + menu_input->pointer.dx = 0; + menu_input->pointer.dy = 0; + menu_input->pointer.y_accel = 0.0f; + menu_input->pointer.press_direction = MENU_INPUT_PRESS_DIRECTION_NONE; + accel0 = 0.0f; + accel1 = 0.0f; + attenuate_y_accel = false; + } + else + { + /* Assign current deltas */ + menu_input->pointer.dx = x - last_x; + menu_input->pointer.dy = y - last_y; + + /* Update maximum start->current deltas */ + if (dx_start > 0) + dx_start_right_max = (dx_start_abs > dx_start_right_max) ? + dx_start_abs : dx_start_right_max; + else + dx_start_left_max = (dx_start_abs > dx_start_left_max) ? + dx_start_abs : dx_start_left_max; + + if (dy_start > 0) + dy_start_down_max = (dy_start_abs > dy_start_down_max) ? + dy_start_abs : dy_start_down_max; + else + dy_start_up_max = (dy_start_abs > dy_start_up_max) ? + dy_start_abs : dy_start_up_max; + + /* Magic numbers... */ + menu_input->pointer.y_accel = (accel0 + accel1 + (float)menu_input->pointer.dy) / 3.0f; + accel0 = accel1; + accel1 = menu_input->pointer.y_accel; + + /* Acceleration decays over time - but if the value + * has been set on this frame, attenuation should + * be skipped */ + attenuate_y_accel = false; + + /* Check if pointer is being held in a particular + * direction */ + menu_input->pointer.press_direction = MENU_INPUT_PRESS_DIRECTION_NONE; + + /* > Press directions are actually triggered as a pulse train, + * since a continuous direction prevents fine control in the + * context of menu actions (i.e. it would be the same + * as always holding down a cursor key all the time - too fast + * to control). We therefore apply a low pass filter, with + * a variable frequency based upon the distance the user has + * dragged the pointer */ + + /* > Horizontal */ + if ((dx_start_abs >= dpi_threshold_press_direction_min) && + (dy_start_abs < dpi_threshold_press_direction_tangent)) + { + press_direction = (dx_start > 0) ? + MENU_INPUT_PRESS_DIRECTION_RIGHT : MENU_INPUT_PRESS_DIRECTION_LEFT; + + /* Get effective amplitude of press direction offset */ + press_direction_amplitude = + (float)(dx_start_abs - dpi_threshold_press_direction_min) / + (float)(dpi_threshold_press_direction_max - dpi_threshold_press_direction_min); + } + /* > Vertical */ + else if ((dy_start_abs >= dpi_threshold_press_direction_min) && + (dx_start_abs < dpi_threshold_press_direction_tangent)) + { + press_direction = (dy_start > 0) ? + MENU_INPUT_PRESS_DIRECTION_DOWN : MENU_INPUT_PRESS_DIRECTION_UP; + + /* Get effective amplitude of press direction offset */ + press_direction_amplitude = + (float)(dy_start_abs - dpi_threshold_press_direction_min) / + (float)(dpi_threshold_press_direction_max - dpi_threshold_press_direction_min); + } + + if (press_direction != MENU_INPUT_PRESS_DIRECTION_NONE) + { + /* > Update low pass filter frequency */ + if (press_direction_amplitude > 1.0f) + press_direction_delay = MENU_INPUT_PRESS_DIRECTION_DELAY_MIN; + else + press_direction_delay = MENU_INPUT_PRESS_DIRECTION_DELAY_MIN + + ((MENU_INPUT_PRESS_DIRECTION_DELAY_MAX - MENU_INPUT_PRESS_DIRECTION_DELAY_MIN)* + (1.0f - press_direction_amplitude)); + + /* > Apply low pass filter */ + if (current_time - last_press_direction_time > press_direction_delay) + { + menu_input->pointer.press_direction = press_direction; + last_press_direction_time = current_time; + } + } + } + } + else + { + /* Pointer is stationary */ + menu_input->pointer.dx = 0; + menu_input->pointer.dy = 0; + menu_input->pointer.press_direction = MENU_INPUT_PRESS_DIRECTION_NONE; + + /* Standard behaviour (on Android, at least) is to stop + * scrolling when the user touches the screen. We should + * therefore 'reset' y acceleration whenever the pointer + * is stationary - with two caveats: + * - We only disable scrolling if the pointer *remains* + * stationary. If the pointer is held down then + * subsequently moves, normal scrolling should resume + * - Halting the scroll immediately produces a very + * unpleasant 'jerky' user experience. To avoid this, + * we add a small delay between detecting a pointer + * down event and forcing y acceleration to zero + * NOTE: Of course, we must also 'reset' y acceleration + * whenever the onscreen keyboard or a message box is + * shown */ + if ((!menu_input->pointer.dragged && + (menu_input->pointer.press_duration > MENU_INPUT_Y_ACCEL_RESET_DELAY)) || + (osk_active || messagebox_active)) + { + menu_input->pointer.y_accel = 0.0f; + accel0 = 0.0f; + accel1 = 0.0f; + attenuate_y_accel = false; + } + } + } + else + { + /* No dpi info - just fallback to zero... */ + menu_input->pointer.dx = 0; + menu_input->pointer.dy = 0; + menu_input->pointer.y_accel = 0.0f; + menu_input->pointer.press_direction = MENU_INPUT_PRESS_DIRECTION_NONE; + accel0 = 0.0f; + accel1 = 0.0f; + attenuate_y_accel = false; + } + + /* > Update remaining variables */ + menu_input->pointer.press_duration = current_time - start_time; + last_x = x; + last_y = y; + } + } + else if (last_select_pressed) + { + /* Transition from select pressed to select unpressed */ + int16_t x; + int16_t y; + menu_ctx_pointer_t point; + + if (menu_input->pointer.dragged) + { + /* Pointer has moved. + * When using a touchscreen, releasing a press + * resets the x/y position - so cannot use + * current hardware x/y values. Instead, use + * previous position from last time that a + * press was active */ + x = last_x; + y = last_y; + } + else + { + /* Pointer is considered stationary, + * so use start position */ + x = start_x; + y = start_y; + } + + point.x = x; + point.y = y; + point.ptr = menu_input->ptr; + point.cbs = cbs; + point.entry = entry; + point.action = action; + point.gesture = MENU_INPUT_GESTURE_NONE; + + /* On screen keyboard overrides normal menu input... */ + if (osk_active) + { + /* If pointer has been 'dragged', then it counts as + * a miss. Only register 'release' event if pointer + * has remained stationary */ + if (!menu_input->pointer.dragged) + { + menu_driver_ctl(RARCH_MENU_CTL_OSK_PTR_AT_POS, &point); + if (point.retcode > -1) + { + bool show_osk_symbols = input_event_osk_show_symbol_pages(menu_st->driver_data); + + input_st->osk_ptr = point.retcode; + input_event_osk_append( + &input_st->keyboard_line, + &input_st->osk_idx, + &input_st->osk_last_codepoint, + &input_st->osk_last_codepoint_len, + point.retcode, + show_osk_symbols, + input_st->osk_grid[input_st->osk_ptr]); + } + } + } + /* Message boxes override normal menu input... + * > If a message box is shown, any kind of pointer + * gesture should close it */ + else if (messagebox_active) + menu_input_pointer_close_messagebox( + menu_st); + /* Normal menu input */ + else + { + /* Detect gesture type */ + if (!menu_input->pointer.dragged) + { + /* Pointer hasn't moved - check press duration */ + if (menu_input->pointer.press_duration + < MENU_INPUT_PRESS_TIME_SHORT) + point.gesture = MENU_INPUT_GESTURE_TAP; + else if (menu_input->pointer.press_duration + < MENU_INPUT_PRESS_TIME_LONG) + point.gesture = MENU_INPUT_GESTURE_SHORT_PRESS; + else + point.gesture = MENU_INPUT_GESTURE_LONG_PRESS; + } + else + { + /* Pointer has moved - check if this is a swipe */ + float dpi = menu ? menu_input_get_dpi(menu, p_disp, +video_st->width, video_st->height) : 0.0f; + + if ((dpi > 0.0f) + && + (menu_input->pointer.press_duration < + MENU_INPUT_SWIPE_TIMEOUT)) + { + uint16_t dpi_threshold_swipe = + (uint16_t)((dpi * MENU_INPUT_DPI_THRESHOLD_SWIPE) + 0.5f); + uint16_t dpi_threshold_swipe_tangent = + (uint16_t)((dpi * MENU_INPUT_DPI_THRESHOLD_SWIPE_TANGENT) + 0.5f); + + int16_t dx_start = x - start_x; + int16_t dy_start = y - start_y; + uint16_t dx_start_right_final = 0; + uint16_t dx_start_left_final = 0; + uint16_t dy_start_up_final = 0; + uint16_t dy_start_down_final = 0; + + /* Get final deltas */ + if (dx_start > 0) + dx_start_right_final = (uint16_t)dx_start; + else + dx_start_left_final = (uint16_t) + (dx_start * -1); + + if (dy_start > 0) + dy_start_down_final = (uint16_t)dy_start; + else + dy_start_up_final = (uint16_t) + (dy_start * -1); + + /* Swipe right */ + if ( (dx_start_right_final > dpi_threshold_swipe) + && (dx_start_left_max < dpi_threshold_swipe_tangent) + && (dy_start_up_max < dpi_threshold_swipe_tangent) + && (dy_start_down_max < dpi_threshold_swipe_tangent) + ) + point.gesture = MENU_INPUT_GESTURE_SWIPE_RIGHT; + /* Swipe left */ + else if ( + (dx_start_right_max < dpi_threshold_swipe_tangent) + && (dx_start_left_final > dpi_threshold_swipe) + && (dy_start_up_max < dpi_threshold_swipe_tangent) + && (dy_start_down_max < dpi_threshold_swipe_tangent) + ) + point.gesture = MENU_INPUT_GESTURE_SWIPE_LEFT; + /* Swipe up */ + else if ( + (dx_start_right_max < dpi_threshold_swipe_tangent) + && (dx_start_left_max < dpi_threshold_swipe_tangent) + && (dy_start_up_final > dpi_threshold_swipe) + && (dy_start_down_max < dpi_threshold_swipe_tangent) + ) + point.gesture = MENU_INPUT_GESTURE_SWIPE_UP; + /* Swipe down */ + else if ( + (dx_start_right_max < dpi_threshold_swipe_tangent) + && (dx_start_left_max < dpi_threshold_swipe_tangent) + && (dy_start_up_max < dpi_threshold_swipe_tangent) + && (dy_start_down_final > dpi_threshold_swipe) + ) + point.gesture = MENU_INPUT_GESTURE_SWIPE_DOWN; + } + } + + /* Trigger a 'pointer up' event */ + menu_driver_ctl(RARCH_MENU_CTL_POINTER_UP, &point); + ret = point.retcode; + } + + /* Reset variables */ + start_x = 0; + start_y = 0; + last_x = 0; + last_y = 0; + dx_start_right_max = 0; + dx_start_left_max = 0; + dy_start_up_max = 0; + dy_start_down_max = 0; + last_press_direction_time = 0; + menu_input->pointer.press_duration = 0; + menu_input->pointer.press_direction = MENU_INPUT_PRESS_DIRECTION_NONE; + menu_input->pointer.dx = 0; + menu_input->pointer.dy = 0; + menu_input->pointer.dragged = false; + } + } + + /* Adjust acceleration + * > If acceleration has not been set on this frame, + * apply normal attenuation */ + if (attenuate_y_accel) + menu_input->pointer.y_accel *= MENU_INPUT_Y_ACCEL_DECAY_FACTOR; + + /* If select has been released, disable any existing + * select inhibit */ + if (!pointer_hw_state->select_pressed) + menu_input->select_inhibit = false; + + /* Cancel */ + if ( !menu_input->cancel_inhibit + && pointer_hw_state->cancel_pressed + && !last_cancel_pressed) + { + /* If currently showing a message box, close it */ + if (messagebox_active) + menu_input_pointer_close_messagebox(menu_st); + /* If onscreen keyboard is shown, send a 'backspace' */ + else if (osk_active) + input_keyboard_event(true, '\x7f', '\x7f', + 0, RETRO_DEVICE_KEYBOARD); + /* ...otherwise, invoke standard MENU_ACTION_CANCEL + * action */ + else + { + size_t selection = menu_st->selection_ptr; + ret = menu_entry_action(entry, selection, MENU_ACTION_CANCEL); + } + } + + /* If cancel has been released, disable any existing + * cancel inhibit */ + if (!pointer_hw_state->cancel_pressed) + menu_input->cancel_inhibit = false; + + if (!messagebox_active) + { + /* Up/Down + * > Note 1: These always correspond to a mouse wheel, which + * handles differently from other inputs - i.e. we don't + * want a 'last pressed' check + * > Note 2: If a message box is currently shown, must + * inhibit input */ + + /* > Up */ + if (pointer_hw_state->up_pressed) + { + size_t selection = menu_st->selection_ptr; + ret = menu_entry_action( + entry, selection, MENU_ACTION_UP); + } + + /* > Down */ + if (pointer_hw_state->down_pressed) + { + size_t selection = menu_st->selection_ptr; + ret = menu_entry_action( + entry, selection, MENU_ACTION_DOWN); + } + + /* Left/Right + * > Note 1: These also always correspond to a mouse wheel... + * In this case, it's a mouse wheel *tilt* operation, which + * is incredibly annoying because holding a tilt direction + * rapidly toggles the input state. The repeat speed is so + * high that any sort of useable control is impossible - so + * we have to apply a 'low pass' filter by ignoring inputs + * that occur below a certain frequency... + * > Note 2: If a message box is currently shown, must + * inhibit input */ + + /* > Left */ + if ( pointer_hw_state->left_pressed + && !last_left_pressed) + { + if (current_time - last_left_action_time + > MENU_INPUT_HORIZ_WHEEL_DELAY) + { + size_t selection = menu_st->selection_ptr; + last_left_action_time = current_time; + ret = menu_entry_action( + entry, selection, MENU_ACTION_LEFT); + } + } + + /* > Right */ + if ( + pointer_hw_state->right_pressed + && !last_right_pressed) + { + if (current_time - last_right_action_time + > MENU_INPUT_HORIZ_WHEEL_DELAY) + { + size_t selection = menu_st->selection_ptr; + last_right_action_time = current_time; + ret = menu_entry_action( + entry, selection, MENU_ACTION_RIGHT); + } + } + } + + last_select_pressed = pointer_hw_state->select_pressed; + last_cancel_pressed = pointer_hw_state->cancel_pressed; + last_left_pressed = pointer_hw_state->left_pressed; + last_right_pressed = pointer_hw_state->right_pressed; + + return ret; +} + +int menu_input_post_iterate( + gfx_display_t *p_disp, + struct menu_state *menu_st, + unsigned action, + retro_time_t current_time) +{ + menu_entry_t entry; + menu_list_t *menu_list = menu_st->entries.list; + file_list_t *selection_buf = menu_list ? MENU_LIST_GET_SELECTION(menu_list, (unsigned)0) : NULL; + size_t selection = menu_st->selection_ptr; + menu_file_list_cbs_t *cbs = selection_buf ? + (menu_file_list_cbs_t*)selection_buf->list[selection].actiondata + : NULL; + + MENU_ENTRY_INIT(entry); + /* Note: If menu_input_pointer_post_iterate() is + * modified, will have to verify that these + * parameters remain unused... */ + entry.rich_label_enabled = false; + entry.value_enabled = false; + entry.sublabel_enabled = false; + menu_entry_get(&entry, 0, selection, NULL, false); + return menu_input_pointer_post_iterate(p_disp, + current_time, cbs, &entry, action); +} diff --git a/menu/menu_driver.h b/menu/menu_driver.h index 5713c21ae3..204a3f66f2 100644 --- a/menu/menu_driver.h +++ b/menu/menu_driver.h @@ -891,6 +891,13 @@ unsigned menu_event( input_bits_t *p_trigger_input, bool display_kb); +int menu_input_post_iterate( + gfx_display_t *p_disp, + struct menu_state *menu_st, + unsigned action, + retro_time_t current_time); + + extern const menu_ctx_driver_t *menu_ctx_drivers[]; RETRO_END_DECLS diff --git a/menu/menu_input.h b/menu/menu_input.h index 3e4caebaac..a40573ffc0 100644 --- a/menu/menu_input.h +++ b/menu/menu_input.h @@ -27,6 +27,7 @@ #include "menu_defines.h" #include "../input/input_types.h" #include "../input/input_driver.h" +#include "../gfx/gfx_display.h" #include "../performance_counters.h" RETRO_BEGIN_DECLS diff --git a/retroarch.c b/retroarch.c index 57ae4aaa45..25f1381160 100644 --- a/retroarch.c +++ b/retroarch.c @@ -304,7 +304,6 @@ struct aspect_ratio_elem aspectratio_lut[ASPECT_RATIO_END] = { #ifdef HAVE_DISCORD bool discord_is_inited = false; #endif -uint64_t lifecycle_state = 0; unsigned subsystem_current_count = 0; struct retro_keybind input_config_binds[MAX_USERS][RARCH_BIND_LIST_END]; struct retro_keybind input_autoconf_binds[MAX_USERS][RARCH_BIND_LIST_END]; @@ -837,7 +836,7 @@ static int generic_menu_iterate( if (menu_input->pointer.type == MENU_POINTER_DISABLED) ret = 0; else - ret = menu_input_post_iterate(p_rarch, p_disp, menu_st, action, + ret = menu_input_post_iterate(p_disp, menu_st, action, current_time); menu_input_set_pointer_visibility( &menu_st->input_pointer_hw_state, @@ -858,7 +857,7 @@ int generic_menu_entry_action( const menu_ctx_driver_t *menu_driver_ctx = menu_st->driver_ctx; menu_handle_t *menu = menu_st->driver_data; - settings_t *settings = p_rarch->configuration_settings; + settings_t *settings = config_get_ptr(); void *menu_userdata = menu_st->userdata; bool wraparound_enable = settings->bools.menu_navigation_wraparound_enable; size_t scroll_accel = menu_st->scroll.acceleration; @@ -13989,765 +13988,6 @@ const char* config_get_input_driver_options(void) } /* MENU INPUT */ -#ifdef HAVE_MENU -static int menu_input_pointer_post_iterate( - struct rarch_state *p_rarch, - gfx_display_t *p_disp, - retro_time_t current_time, - menu_file_list_cbs_t *cbs, - menu_entry_t *entry, unsigned action) -{ - static retro_time_t start_time = 0; - static int16_t start_x = 0; - static int16_t start_y = 0; - static int16_t last_x = 0; - static int16_t last_y = 0; - static uint16_t dx_start_right_max = 0; - static uint16_t dx_start_left_max = 0; - static uint16_t dy_start_up_max = 0; - static uint16_t dy_start_down_max = 0; - static bool last_select_pressed = false; - static bool last_cancel_pressed = false; - static bool last_left_pressed = false; - static bool last_right_pressed = false; - static retro_time_t last_left_action_time = 0; - static retro_time_t last_right_action_time = 0; - static retro_time_t last_press_direction_time = 0; - bool attenuate_y_accel = true; - bool osk_active = menu_input_dialog_get_display_kb(); - bool messagebox_active = false; - int ret = 0; - struct menu_state *menu_st = menu_state_get_ptr(); - menu_input_pointer_hw_state_t *pointer_hw_state = &menu_st->input_pointer_hw_state; - menu_input_t *menu_input = &menu_st->input_state; - menu_handle_t *menu = menu_st->driver_data; - video_driver_state_t *video_st = video_state_get_ptr(); - input_driver_state_t *input_st = input_state_get_ptr(); - - /* Check whether a message box is currently - * being shown - * > Note: This ignores input bind dialogs, - * since input binding overrides normal input - * and must be handled separately... */ - if (menu) - messagebox_active = BIT64_GET( - menu->state, MENU_STATE_RENDER_MESSAGEBOX) && - !string_is_empty(menu->menu_state_msg); - - /* If onscreen keyboard is shown and we currently have - * active mouse input, highlight key under mouse cursor */ - if (osk_active && - (menu_input->pointer.type == MENU_POINTER_MOUSE) && - pointer_hw_state->active) - { - menu_ctx_pointer_t point; - - point.x = pointer_hw_state->x; - point.y = pointer_hw_state->y; - point.ptr = 0; - point.cbs = NULL; - point.entry = NULL; - point.action = 0; - point.gesture = MENU_INPUT_GESTURE_NONE; - point.retcode = 0; - - menu_driver_ctl(RARCH_MENU_CTL_OSK_PTR_AT_POS, &point); - if (point.retcode > -1) - input_st->osk_ptr = point.retcode; - } - - /* Select + X/Y position */ - if (!menu_input->select_inhibit) - { - if (pointer_hw_state->select_pressed) - { - int16_t x = pointer_hw_state->x; - int16_t y = pointer_hw_state->y; - static float accel0 = 0.0f; - static float accel1 = 0.0f; - - /* Transition from select unpressed to select pressed */ - if (!last_select_pressed) - { - menu_ctx_pointer_t point; - - /* Initialise variables */ - start_time = current_time; - start_x = x; - start_y = y; - last_x = x; - last_y = y; - dx_start_right_max = 0; - dx_start_left_max = 0; - dy_start_up_max = 0; - dy_start_down_max = 0; - accel0 = 0.0f; - accel1 = 0.0f; - last_press_direction_time = 0; - - /* If we are not currently showing the onscreen - * keyboard or a message box, trigger a 'pointer - * down' event */ - if (!osk_active && !messagebox_active) - { - point.x = x; - point.y = y; - /* Note: menu_input->ptr is meaningless here when - * using a touchscreen... */ - point.ptr = menu_input->ptr; - point.cbs = cbs; - point.entry = entry; - point.action = action; - point.gesture = MENU_INPUT_GESTURE_NONE; - - menu_driver_ctl(RARCH_MENU_CTL_POINTER_DOWN, &point); - ret = point.retcode; - } - } - else - { - /* Pointer is being held down - * (i.e. for more than one frame) */ - float dpi = menu ? menu_input_get_dpi(menu, p_disp, - video_st->width, video_st->height) : 0.0f; - - /* > Update deltas + acceleration & detect press direction - * Note: We only do this if the pointer has moved above - * a certain threshold - this requires dpi info */ - if (dpi > 0.0f) - { - uint16_t dpi_threshold_drag = - (uint16_t)((dpi * MENU_INPUT_DPI_THRESHOLD_DRAG) + 0.5f); - - int16_t dx_start = x - start_x; - int16_t dy_start = y - start_y; - uint16_t dx_start_abs = dx_start < 0 ? dx_start * -1 : dx_start; - uint16_t dy_start_abs = dy_start < 0 ? dy_start * -1 : dy_start; - - if ((dx_start_abs > dpi_threshold_drag) || - (dy_start_abs > dpi_threshold_drag)) - { - uint16_t dpi_threshold_press_direction_min = - (uint16_t)((dpi * MENU_INPUT_DPI_THRESHOLD_PRESS_DIRECTION_MIN) + 0.5f); - uint16_t dpi_threshold_press_direction_max = - (uint16_t)((dpi * MENU_INPUT_DPI_THRESHOLD_PRESS_DIRECTION_MAX) + 0.5f); - uint16_t dpi_threshold_press_direction_tangent = - (uint16_t)((dpi * MENU_INPUT_DPI_THRESHOLD_PRESS_DIRECTION_TANGENT) + 0.5f); - - enum menu_input_pointer_press_direction - press_direction = MENU_INPUT_PRESS_DIRECTION_NONE; - float press_direction_amplitude = 0.0f; - retro_time_t press_direction_delay = MENU_INPUT_PRESS_DIRECTION_DELAY_MAX; - - /* Pointer has moved a sufficient distance to - * trigger a 'dragged' state */ - menu_input->pointer.dragged = true; - - /* Here we diverge: - * > If onscreen keyboard or a message box is - * active, pointer deltas, acceleration and - * press direction must be inhibited - * > If not, input is processed normally */ - if (osk_active || messagebox_active) - { - /* Inhibit normal pointer input */ - menu_input->pointer.dx = 0; - menu_input->pointer.dy = 0; - menu_input->pointer.y_accel = 0.0f; - menu_input->pointer.press_direction = MENU_INPUT_PRESS_DIRECTION_NONE; - accel0 = 0.0f; - accel1 = 0.0f; - attenuate_y_accel = false; - } - else - { - /* Assign current deltas */ - menu_input->pointer.dx = x - last_x; - menu_input->pointer.dy = y - last_y; - - /* Update maximum start->current deltas */ - if (dx_start > 0) - dx_start_right_max = (dx_start_abs > dx_start_right_max) ? - dx_start_abs : dx_start_right_max; - else - dx_start_left_max = (dx_start_abs > dx_start_left_max) ? - dx_start_abs : dx_start_left_max; - - if (dy_start > 0) - dy_start_down_max = (dy_start_abs > dy_start_down_max) ? - dy_start_abs : dy_start_down_max; - else - dy_start_up_max = (dy_start_abs > dy_start_up_max) ? - dy_start_abs : dy_start_up_max; - - /* Magic numbers... */ - menu_input->pointer.y_accel = (accel0 + accel1 + (float)menu_input->pointer.dy) / 3.0f; - accel0 = accel1; - accel1 = menu_input->pointer.y_accel; - - /* Acceleration decays over time - but if the value - * has been set on this frame, attenuation should - * be skipped */ - attenuate_y_accel = false; - - /* Check if pointer is being held in a particular - * direction */ - menu_input->pointer.press_direction = MENU_INPUT_PRESS_DIRECTION_NONE; - - /* > Press directions are actually triggered as a pulse train, - * since a continuous direction prevents fine control in the - * context of menu actions (i.e. it would be the same - * as always holding down a cursor key all the time - too fast - * to control). We therefore apply a low pass filter, with - * a variable frequency based upon the distance the user has - * dragged the pointer */ - - /* > Horizontal */ - if ((dx_start_abs >= dpi_threshold_press_direction_min) && - (dy_start_abs < dpi_threshold_press_direction_tangent)) - { - press_direction = (dx_start > 0) ? - MENU_INPUT_PRESS_DIRECTION_RIGHT : MENU_INPUT_PRESS_DIRECTION_LEFT; - - /* Get effective amplitude of press direction offset */ - press_direction_amplitude = - (float)(dx_start_abs - dpi_threshold_press_direction_min) / - (float)(dpi_threshold_press_direction_max - dpi_threshold_press_direction_min); - } - /* > Vertical */ - else if ((dy_start_abs >= dpi_threshold_press_direction_min) && - (dx_start_abs < dpi_threshold_press_direction_tangent)) - { - press_direction = (dy_start > 0) ? - MENU_INPUT_PRESS_DIRECTION_DOWN : MENU_INPUT_PRESS_DIRECTION_UP; - - /* Get effective amplitude of press direction offset */ - press_direction_amplitude = - (float)(dy_start_abs - dpi_threshold_press_direction_min) / - (float)(dpi_threshold_press_direction_max - dpi_threshold_press_direction_min); - } - - if (press_direction != MENU_INPUT_PRESS_DIRECTION_NONE) - { - /* > Update low pass filter frequency */ - if (press_direction_amplitude > 1.0f) - press_direction_delay = MENU_INPUT_PRESS_DIRECTION_DELAY_MIN; - else - press_direction_delay = MENU_INPUT_PRESS_DIRECTION_DELAY_MIN + - ((MENU_INPUT_PRESS_DIRECTION_DELAY_MAX - MENU_INPUT_PRESS_DIRECTION_DELAY_MIN)* - (1.0f - press_direction_amplitude)); - - /* > Apply low pass filter */ - if (current_time - last_press_direction_time > press_direction_delay) - { - menu_input->pointer.press_direction = press_direction; - last_press_direction_time = current_time; - } - } - } - } - else - { - /* Pointer is stationary */ - menu_input->pointer.dx = 0; - menu_input->pointer.dy = 0; - menu_input->pointer.press_direction = MENU_INPUT_PRESS_DIRECTION_NONE; - - /* Standard behaviour (on Android, at least) is to stop - * scrolling when the user touches the screen. We should - * therefore 'reset' y acceleration whenever the pointer - * is stationary - with two caveats: - * - We only disable scrolling if the pointer *remains* - * stationary. If the pointer is held down then - * subsequently moves, normal scrolling should resume - * - Halting the scroll immediately produces a very - * unpleasant 'jerky' user experience. To avoid this, - * we add a small delay between detecting a pointer - * down event and forcing y acceleration to zero - * NOTE: Of course, we must also 'reset' y acceleration - * whenever the onscreen keyboard or a message box is - * shown */ - if ((!menu_input->pointer.dragged && - (menu_input->pointer.press_duration > MENU_INPUT_Y_ACCEL_RESET_DELAY)) || - (osk_active || messagebox_active)) - { - menu_input->pointer.y_accel = 0.0f; - accel0 = 0.0f; - accel1 = 0.0f; - attenuate_y_accel = false; - } - } - } - else - { - /* No dpi info - just fallback to zero... */ - menu_input->pointer.dx = 0; - menu_input->pointer.dy = 0; - menu_input->pointer.y_accel = 0.0f; - menu_input->pointer.press_direction = MENU_INPUT_PRESS_DIRECTION_NONE; - accel0 = 0.0f; - accel1 = 0.0f; - attenuate_y_accel = false; - } - - /* > Update remaining variables */ - menu_input->pointer.press_duration = current_time - start_time; - last_x = x; - last_y = y; - } - } - else if (last_select_pressed) - { - /* Transition from select pressed to select unpressed */ - int16_t x; - int16_t y; - menu_ctx_pointer_t point; - - if (menu_input->pointer.dragged) - { - /* Pointer has moved. - * When using a touchscreen, releasing a press - * resets the x/y position - so cannot use - * current hardware x/y values. Instead, use - * previous position from last time that a - * press was active */ - x = last_x; - y = last_y; - } - else - { - /* Pointer is considered stationary, - * so use start position */ - x = start_x; - y = start_y; - } - - point.x = x; - point.y = y; - point.ptr = menu_input->ptr; - point.cbs = cbs; - point.entry = entry; - point.action = action; - point.gesture = MENU_INPUT_GESTURE_NONE; - - /* On screen keyboard overrides normal menu input... */ - if (osk_active) - { - /* If pointer has been 'dragged', then it counts as - * a miss. Only register 'release' event if pointer - * has remained stationary */ - if (!menu_input->pointer.dragged) - { - menu_driver_ctl(RARCH_MENU_CTL_OSK_PTR_AT_POS, &point); - if (point.retcode > -1) - { - bool show_osk_symbols = input_event_osk_show_symbol_pages(menu_st->driver_data); - - input_st->osk_ptr = point.retcode; - input_event_osk_append( - &input_st->keyboard_line, - &input_st->osk_idx, - &input_st->osk_last_codepoint, - &input_st->osk_last_codepoint_len, - point.retcode, - show_osk_symbols, - input_st->osk_grid[input_st->osk_ptr]); - } - } - } - /* Message boxes override normal menu input... - * > If a message box is shown, any kind of pointer - * gesture should close it */ - else if (messagebox_active) - menu_input_pointer_close_messagebox( - menu_st); - /* Normal menu input */ - else - { - /* Detect gesture type */ - if (!menu_input->pointer.dragged) - { - /* Pointer hasn't moved - check press duration */ - if (menu_input->pointer.press_duration - < MENU_INPUT_PRESS_TIME_SHORT) - point.gesture = MENU_INPUT_GESTURE_TAP; - else if (menu_input->pointer.press_duration - < MENU_INPUT_PRESS_TIME_LONG) - point.gesture = MENU_INPUT_GESTURE_SHORT_PRESS; - else - point.gesture = MENU_INPUT_GESTURE_LONG_PRESS; - } - else - { - /* Pointer has moved - check if this is a swipe */ - float dpi = menu ? menu_input_get_dpi(menu, p_disp, -video_st->width, video_st->height) : 0.0f; - - if ((dpi > 0.0f) - && - (menu_input->pointer.press_duration < - MENU_INPUT_SWIPE_TIMEOUT)) - { - uint16_t dpi_threshold_swipe = - (uint16_t)((dpi * MENU_INPUT_DPI_THRESHOLD_SWIPE) + 0.5f); - uint16_t dpi_threshold_swipe_tangent = - (uint16_t)((dpi * MENU_INPUT_DPI_THRESHOLD_SWIPE_TANGENT) + 0.5f); - - int16_t dx_start = x - start_x; - int16_t dy_start = y - start_y; - uint16_t dx_start_right_final = 0; - uint16_t dx_start_left_final = 0; - uint16_t dy_start_up_final = 0; - uint16_t dy_start_down_final = 0; - - /* Get final deltas */ - if (dx_start > 0) - dx_start_right_final = (uint16_t)dx_start; - else - dx_start_left_final = (uint16_t) - (dx_start * -1); - - if (dy_start > 0) - dy_start_down_final = (uint16_t)dy_start; - else - dy_start_up_final = (uint16_t) - (dy_start * -1); - - /* Swipe right */ - if ( (dx_start_right_final > dpi_threshold_swipe) - && (dx_start_left_max < dpi_threshold_swipe_tangent) - && (dy_start_up_max < dpi_threshold_swipe_tangent) - && (dy_start_down_max < dpi_threshold_swipe_tangent) - ) - point.gesture = MENU_INPUT_GESTURE_SWIPE_RIGHT; - /* Swipe left */ - else if ( - (dx_start_right_max < dpi_threshold_swipe_tangent) - && (dx_start_left_final > dpi_threshold_swipe) - && (dy_start_up_max < dpi_threshold_swipe_tangent) - && (dy_start_down_max < dpi_threshold_swipe_tangent) - ) - point.gesture = MENU_INPUT_GESTURE_SWIPE_LEFT; - /* Swipe up */ - else if ( - (dx_start_right_max < dpi_threshold_swipe_tangent) - && (dx_start_left_max < dpi_threshold_swipe_tangent) - && (dy_start_up_final > dpi_threshold_swipe) - && (dy_start_down_max < dpi_threshold_swipe_tangent) - ) - point.gesture = MENU_INPUT_GESTURE_SWIPE_UP; - /* Swipe down */ - else if ( - (dx_start_right_max < dpi_threshold_swipe_tangent) - && (dx_start_left_max < dpi_threshold_swipe_tangent) - && (dy_start_up_max < dpi_threshold_swipe_tangent) - && (dy_start_down_final > dpi_threshold_swipe) - ) - point.gesture = MENU_INPUT_GESTURE_SWIPE_DOWN; - } - } - - /* Trigger a 'pointer up' event */ - menu_driver_ctl(RARCH_MENU_CTL_POINTER_UP, &point); - ret = point.retcode; - } - - /* Reset variables */ - start_x = 0; - start_y = 0; - last_x = 0; - last_y = 0; - dx_start_right_max = 0; - dx_start_left_max = 0; - dy_start_up_max = 0; - dy_start_down_max = 0; - last_press_direction_time = 0; - menu_input->pointer.press_duration = 0; - menu_input->pointer.press_direction = MENU_INPUT_PRESS_DIRECTION_NONE; - menu_input->pointer.dx = 0; - menu_input->pointer.dy = 0; - menu_input->pointer.dragged = false; - } - } - - /* Adjust acceleration - * > If acceleration has not been set on this frame, - * apply normal attenuation */ - if (attenuate_y_accel) - menu_input->pointer.y_accel *= MENU_INPUT_Y_ACCEL_DECAY_FACTOR; - - /* If select has been released, disable any existing - * select inhibit */ - if (!pointer_hw_state->select_pressed) - menu_input->select_inhibit = false; - - /* Cancel */ - if ( !menu_input->cancel_inhibit - && pointer_hw_state->cancel_pressed - && !last_cancel_pressed) - { - /* If currently showing a message box, close it */ - if (messagebox_active) - menu_input_pointer_close_messagebox(menu_st); - /* If onscreen keyboard is shown, send a 'backspace' */ - else if (osk_active) - input_keyboard_event(true, '\x7f', '\x7f', - 0, RETRO_DEVICE_KEYBOARD); - /* ...otherwise, invoke standard MENU_ACTION_CANCEL - * action */ - else - { - size_t selection = menu_st->selection_ptr; - ret = menu_entry_action(entry, selection, MENU_ACTION_CANCEL); - } - } - - /* If cancel has been released, disable any existing - * cancel inhibit */ - if (!pointer_hw_state->cancel_pressed) - menu_input->cancel_inhibit = false; - - if (!messagebox_active) - { - /* Up/Down - * > Note 1: These always correspond to a mouse wheel, which - * handles differently from other inputs - i.e. we don't - * want a 'last pressed' check - * > Note 2: If a message box is currently shown, must - * inhibit input */ - - /* > Up */ - if (pointer_hw_state->up_pressed) - { - size_t selection = menu_st->selection_ptr; - ret = menu_entry_action( - entry, selection, MENU_ACTION_UP); - } - - /* > Down */ - if (pointer_hw_state->down_pressed) - { - size_t selection = menu_st->selection_ptr; - ret = menu_entry_action( - entry, selection, MENU_ACTION_DOWN); - } - - /* Left/Right - * > Note 1: These also always correspond to a mouse wheel... - * In this case, it's a mouse wheel *tilt* operation, which - * is incredibly annoying because holding a tilt direction - * rapidly toggles the input state. The repeat speed is so - * high that any sort of useable control is impossible - so - * we have to apply a 'low pass' filter by ignoring inputs - * that occur below a certain frequency... - * > Note 2: If a message box is currently shown, must - * inhibit input */ - - /* > Left */ - if ( pointer_hw_state->left_pressed - && !last_left_pressed) - { - if (current_time - last_left_action_time - > MENU_INPUT_HORIZ_WHEEL_DELAY) - { - size_t selection = menu_st->selection_ptr; - last_left_action_time = current_time; - ret = menu_entry_action( - entry, selection, MENU_ACTION_LEFT); - } - } - - /* > Right */ - if ( - pointer_hw_state->right_pressed - && !last_right_pressed) - { - if (current_time - last_right_action_time - > MENU_INPUT_HORIZ_WHEEL_DELAY) - { - size_t selection = menu_st->selection_ptr; - last_right_action_time = current_time; - ret = menu_entry_action( - entry, selection, MENU_ACTION_RIGHT); - } - } - } - - last_select_pressed = pointer_hw_state->select_pressed; - last_cancel_pressed = pointer_hw_state->cancel_pressed; - last_left_pressed = pointer_hw_state->left_pressed; - last_right_pressed = pointer_hw_state->right_pressed; - - return ret; -} - -static int menu_input_post_iterate( - struct rarch_state *p_rarch, - gfx_display_t *p_disp, - struct menu_state *menu_st, - unsigned action, - retro_time_t current_time) -{ - menu_entry_t entry; - menu_list_t *menu_list = menu_st->entries.list; - file_list_t *selection_buf = menu_list ? MENU_LIST_GET_SELECTION(menu_list, (unsigned)0) : NULL; - size_t selection = menu_st->selection_ptr; - menu_file_list_cbs_t *cbs = selection_buf ? - (menu_file_list_cbs_t*)selection_buf->list[selection].actiondata - : NULL; - - MENU_ENTRY_INIT(entry); - /* Note: If menu_input_pointer_post_iterate() is - * modified, will have to verify that these - * parameters remain unused... */ - entry.rich_label_enabled = false; - entry.value_enabled = false; - entry.sublabel_enabled = false; - menu_entry_get(&entry, 0, selection, NULL, false); - return menu_input_pointer_post_iterate(p_rarch, p_disp, - current_time, cbs, &entry, action); -} -#endif - -/** - * input_keys_pressed: - * - * Grab an input sample for this frame. - * - * Returns: Input sample containing a mask of all pressed keys. - */ -static void input_keys_pressed( - unsigned port, - bool is_menu, - int input_hotkey_block_delay, - input_bits_t *p_new_state, - const struct retro_keybind **binds, - const struct retro_keybind *binds_norm, - const struct retro_keybind *binds_auto, - const input_device_driver_t *joypad, - const input_device_driver_t *sec_joypad, - rarch_joypad_info_t *joypad_info) -{ - unsigned i; - input_driver_state_t *input_st = input_state_get_ptr(); - - if (CHECK_INPUT_DRIVER_BLOCK_HOTKEY(binds_norm, binds_auto)) - { - if ( input_state_wrap( - input_st->current_driver, - input_st->current_data, - input_st->primary_joypad, - sec_joypad, - joypad_info, - &binds[port], - input_st->keyboard_mapping_blocked, - port, RETRO_DEVICE_JOYPAD, 0, - RARCH_ENABLE_HOTKEY)) - { - if (input_st->input_hotkey_block_counter < input_hotkey_block_delay) - input_st->input_hotkey_block_counter++; - else - input_st->block_libretro_input = true; - } - else - { - input_st->input_hotkey_block_counter = 0; - input_st->block_hotkey = true; - } - } - - if ( !is_menu - && binds[port][RARCH_GAME_FOCUS_TOGGLE].valid) - { - const struct retro_keybind *focus_binds_auto = - &input_autoconf_binds[port][RARCH_GAME_FOCUS_TOGGLE]; - const struct retro_keybind *focus_normal = - &binds[port][RARCH_GAME_FOCUS_TOGGLE]; - - /* Allows rarch_focus_toggle hotkey to still work - * even though every hotkey is blocked */ - if (CHECK_INPUT_DRIVER_BLOCK_HOTKEY( - focus_normal, focus_binds_auto)) - { - if (input_state_wrap( - input_st->current_driver, - input_st->current_data, - input_st->primary_joypad, - sec_joypad, - joypad_info, - &binds[port], - input_st->keyboard_mapping_blocked, - port, - RETRO_DEVICE_JOYPAD, 0, RARCH_GAME_FOCUS_TOGGLE)) - input_st->block_hotkey = false; - } - } - - { - int16_t ret = 0; - - /* Check the libretro input first */ - if (!input_st->block_libretro_input) - ret = input_state_wrap( - input_st->current_driver, - input_st->current_data, - input_st->primary_joypad, - sec_joypad, - joypad_info, &binds[port], - input_st->keyboard_mapping_blocked, - port, RETRO_DEVICE_JOYPAD, 0, - RETRO_DEVICE_ID_JOYPAD_MASK); - - for (i = 0; i < RARCH_FIRST_META_KEY; i++) - { - if ( - (ret & (UINT64_C(1) << i)) || - input_keys_pressed_other_sources(input_st, - i, p_new_state)) - { - BIT256_SET_PTR(p_new_state, i); - } - } - } - - /* Check the hotkeys */ - if (input_st->block_hotkey) - { - for (i = RARCH_FIRST_META_KEY; i < RARCH_BIND_LIST_END; i++) - { - if ( - BIT64_GET(lifecycle_state, i) - || input_keys_pressed_other_sources(input_st, - i, p_new_state)) - { - BIT256_SET_PTR(p_new_state, i); - } - } - } - else - { - for (i = RARCH_FIRST_META_KEY; i < RARCH_BIND_LIST_END; i++) - { - bool bit_pressed = binds[port][i].valid - && input_state_wrap( - input_st->current_driver, - input_st->current_data, - input_st->primary_joypad, - sec_joypad, - joypad_info, - &binds[port], - input_st->keyboard_mapping_blocked, - port, RETRO_DEVICE_JOYPAD, 0, i); - if ( bit_pressed - || BIT64_GET(lifecycle_state, i) - || input_keys_pressed_other_sources(input_st, - i, p_new_state)) - { - BIT256_SET_PTR(p_new_state, i); - } - } - } -} /** * config_get_joypad_driver_options: diff --git a/retroarch_data.h b/retroarch_data.h index 78795fdea2..662ce47df5 100644 --- a/retroarch_data.h +++ b/retroarch_data.h @@ -122,28 +122,6 @@ input_st->bsv_movie_state.eof_exit) old_pressed3 = pressed3; \ } -/** - * check_input_driver_block_hotkey: - * - * Checks if 'hotkey enable' key is pressed. - * - * If we haven't bound anything to this, - * always allow hotkeys. - - * If we hold ENABLE_HOTKEY button, block all libretro input to allow - * hotkeys to be bound to same keys as RetroPad. - **/ -#define CHECK_INPUT_DRIVER_BLOCK_HOTKEY(normal_bind, autoconf_bind) \ -( \ - (((normal_bind)->key != RETROK_UNKNOWN) \ - || ((normal_bind)->mbutton != NO_BTN) \ - || ((normal_bind)->joykey != NO_BTN) \ - || ((normal_bind)->joyaxis != AXIS_NONE) \ - || ((autoconf_bind)->key != RETROK_UNKNOWN) \ - || ((autoconf_bind)->joykey != NO_BTN) \ - || ((autoconf_bind)->joyaxis != AXIS_NONE)) \ -) - #define INHERIT_JOYAXIS(binds) (((binds)[x_plus].joyaxis == (binds)[x_minus].joyaxis) || ( (binds)[y_plus].joyaxis == (binds)[y_minus].joyaxis)) #define CDN_URL "https://cdn.discordapp.com/avatars" diff --git a/retroarch_fwd_decls.h b/retroarch_fwd_decls.h index 2f8785bc73..dd14c99a95 100644 --- a/retroarch_fwd_decls.h +++ b/retroarch_fwd_decls.h @@ -99,15 +99,6 @@ static bool accessibility_speak_priority( const char* speak_text, int priority); #endif -#ifdef HAVE_MENU -static int menu_input_post_iterate( - struct rarch_state *p_rarch, - gfx_display_t *p_disp, - struct menu_state *menu_st, - unsigned action, - retro_time_t current_time); -#endif - static bool retroarch_apply_shader( struct rarch_state *p_rarch, settings_t *settings,