mirror of
https://github.com/libretro/RetroArch
synced 2025-02-22 12:40:09 +00:00
(Menu Input) Add mouse/touchscreen gesture support + full gesture support for XMB
This commit is contained in:
parent
0a123e8215
commit
3057c31798
@ -554,6 +554,8 @@ bool x11_alive(void *data)
|
||||
case 4: /* Grabbed */
|
||||
/* Scroll up */
|
||||
case 5: /* Scroll down */
|
||||
case 6: /* Scroll wheel left */
|
||||
case 7: /* Scroll wheel right */
|
||||
x_input_poll_wheel(&event.xbutton, true);
|
||||
break;
|
||||
}
|
||||
|
@ -20,6 +20,8 @@
|
||||
|
||||
static bool x11_mouse_wu;
|
||||
static bool x11_mouse_wd;
|
||||
static bool x11_mouse_hwu;
|
||||
static bool x11_mouse_hwd;
|
||||
|
||||
int16_t x_mouse_state_wheel(unsigned id)
|
||||
{
|
||||
@ -35,6 +37,14 @@ int16_t x_mouse_state_wheel(unsigned id)
|
||||
ret = x11_mouse_wd;
|
||||
x11_mouse_wd = 0;
|
||||
return ret;
|
||||
case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP:
|
||||
ret = x11_mouse_hwu;
|
||||
x11_mouse_hwu = 0;
|
||||
return ret;
|
||||
case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN:
|
||||
ret = x11_mouse_hwd;
|
||||
x11_mouse_hwd = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -50,5 +60,13 @@ void x_input_poll_wheel(XButtonEvent *event, bool latch)
|
||||
case 5:
|
||||
x11_mouse_wd = 1;
|
||||
break;
|
||||
case 6:
|
||||
/* Scroll wheel left == HORIZ_WHEELDOWN */
|
||||
x11_mouse_hwd = 1;
|
||||
break;
|
||||
case 7:
|
||||
/* Scroll wheel right == HORIZ_WHEELUP */
|
||||
x11_mouse_hwu = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -106,18 +106,9 @@ static bool x_mouse_button_pressed(
|
||||
|
||||
case RETRO_DEVICE_ID_MOUSE_WHEELUP:
|
||||
case RETRO_DEVICE_ID_MOUSE_WHEELDOWN:
|
||||
return x_mouse_state_wheel( key );
|
||||
|
||||
/* case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP:
|
||||
result = x11->mouse_hwu;
|
||||
x11->mouse_hwu = false;
|
||||
return result;
|
||||
|
||||
case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP:
|
||||
case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN:
|
||||
result = x11->mouse_hwd;
|
||||
x11->mouse_hwd = false;
|
||||
return result;
|
||||
*/
|
||||
return x_mouse_state_wheel( key );
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -237,6 +228,8 @@ static int16_t x_mouse_state(x11_input_t *x11, unsigned id)
|
||||
return x11->mouse_r;
|
||||
case RETRO_DEVICE_ID_MOUSE_WHEELUP:
|
||||
case RETRO_DEVICE_ID_MOUSE_WHEELDOWN:
|
||||
case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP:
|
||||
case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN:
|
||||
return x_mouse_state_wheel(id);
|
||||
case RETRO_DEVICE_ID_MOUSE_MIDDLE:
|
||||
return x11->mouse_m;
|
||||
|
@ -2348,14 +2348,16 @@ static int materialui_pointer_down(void *userdata,
|
||||
If we clicked on the tabs, we switch to a new list.
|
||||
If we clicked on a menu entry, we call the entry action callback. */
|
||||
static int materialui_pointer_up(void *userdata,
|
||||
unsigned x, unsigned y,
|
||||
unsigned ptr, menu_file_list_cbs_t *cbs,
|
||||
unsigned x, unsigned y, unsigned ptr,
|
||||
enum menu_input_pointer_gesture gesture,
|
||||
menu_file_list_cbs_t *cbs,
|
||||
menu_entry_t *entry, unsigned action)
|
||||
{
|
||||
unsigned width, height;
|
||||
unsigned header_height, i;
|
||||
size_t entries_end = menu_entries_get_size();
|
||||
materialui_handle_t *mui = (materialui_handle_t*)userdata;
|
||||
size_t selection = menu_navigation_get_selection();
|
||||
size_t entries_end = menu_entries_get_size();
|
||||
materialui_handle_t *mui = (materialui_handle_t*)userdata;
|
||||
|
||||
if (!mui)
|
||||
return 0;
|
||||
@ -2363,51 +2365,69 @@ static int materialui_pointer_up(void *userdata,
|
||||
header_height = menu_display_get_header_height();
|
||||
video_driver_get_size(&width, &height);
|
||||
|
||||
if (y < header_height)
|
||||
switch (gesture)
|
||||
{
|
||||
size_t selection = menu_navigation_get_selection();
|
||||
return menu_entry_action(entry, (unsigned)selection, MENU_ACTION_CANCEL);
|
||||
}
|
||||
else if (y > height - mui->tabs_height)
|
||||
{
|
||||
file_list_t *menu_stack = menu_entries_get_menu_stack_ptr(0);
|
||||
file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0);
|
||||
|
||||
for (i = 0; i <= MUI_SYSTEM_TAB_END; i++)
|
||||
{
|
||||
unsigned tab_width = width / (MUI_SYSTEM_TAB_END + 1);
|
||||
unsigned start = tab_width * i;
|
||||
|
||||
if ((x >= start) && (x < (start + tab_width)))
|
||||
case MENU_INPUT_GESTURE_TAP:
|
||||
case MENU_INPUT_GESTURE_SHORT_PRESS:
|
||||
{
|
||||
mui->categories_selection_ptr = i;
|
||||
/* Normal pointer input */
|
||||
if (y < header_height)
|
||||
{
|
||||
size_t selection = menu_navigation_get_selection();
|
||||
return menu_entry_action(entry, (unsigned)selection, MENU_ACTION_CANCEL);
|
||||
}
|
||||
else if (y > height - mui->tabs_height)
|
||||
{
|
||||
file_list_t *menu_stack = menu_entries_get_menu_stack_ptr(0);
|
||||
file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0);
|
||||
|
||||
materialui_preswitch_tabs(mui, action);
|
||||
for (i = 0; i <= MUI_SYSTEM_TAB_END; i++)
|
||||
{
|
||||
unsigned tab_width = width / (MUI_SYSTEM_TAB_END + 1);
|
||||
unsigned start = tab_width * i;
|
||||
|
||||
if (cbs && cbs->action_content_list_switch)
|
||||
return cbs->action_content_list_switch(selection_buf, menu_stack,
|
||||
"", "", 0);
|
||||
if ((x >= start) && (x < (start + tab_width)))
|
||||
{
|
||||
mui->categories_selection_ptr = i;
|
||||
|
||||
materialui_preswitch_tabs(mui, action);
|
||||
|
||||
if (cbs && cbs->action_content_list_switch)
|
||||
return cbs->action_content_list_switch(selection_buf, menu_stack,
|
||||
"", "", 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ptr <= (entries_end - 1))
|
||||
{
|
||||
size_t ii;
|
||||
file_list_t *list = menu_entries_get_selection_buf_ptr(0);
|
||||
|
||||
for (ii = 0; ii < entries_end; ii++)
|
||||
{
|
||||
materialui_node_t *node = (materialui_node_t*)
|
||||
file_list_get_userdata_at_offset(list, ii);
|
||||
|
||||
if (y > (-mui->scroll_y + header_height + node->y)
|
||||
&& y < (-mui->scroll_y + header_height + node->y + node->line_height)
|
||||
)
|
||||
{
|
||||
if (ptr == ii && cbs && cbs->action_select)
|
||||
return menu_entry_action(entry, (unsigned)ii, MENU_ACTION_SELECT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ptr <= (entries_end - 1))
|
||||
{
|
||||
size_t ii;
|
||||
file_list_t *list = menu_entries_get_selection_buf_ptr(0);
|
||||
|
||||
for (ii = 0; ii < entries_end; ii++)
|
||||
{
|
||||
materialui_node_t *node = (materialui_node_t*)
|
||||
file_list_get_userdata_at_offset(list, ii);
|
||||
|
||||
if (y > (-mui->scroll_y + header_height + node->y)
|
||||
&& y < (-mui->scroll_y + header_height + node->y + node->line_height)
|
||||
)
|
||||
{
|
||||
if (ptr == ii && cbs && cbs->action_select)
|
||||
return menu_entry_action(entry, (unsigned)ii, MENU_ACTION_SELECT);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MENU_INPUT_GESTURE_LONG_PRESS:
|
||||
/* 'Reset to default' action */
|
||||
if ((ptr <= (menu_entries_get_size() - 1)) &&
|
||||
(ptr == selection))
|
||||
return menu_entry_action(entry, (unsigned)selection, MENU_ACTION_START);
|
||||
break;
|
||||
default:
|
||||
/* Ignore input */
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -2294,15 +2294,33 @@ static bool ozone_get_load_content_animation_data(void *userdata, menu_texture_i
|
||||
|
||||
static int ozone_pointer_up(void *userdata,
|
||||
unsigned x, unsigned y, unsigned ptr,
|
||||
enum menu_input_pointer_gesture gesture,
|
||||
menu_file_list_cbs_t *cbs,
|
||||
menu_entry_t *entry, unsigned action)
|
||||
{
|
||||
size_t selection = menu_navigation_get_selection();
|
||||
if (ptr == selection)
|
||||
return (unsigned)menu_entry_action(entry, (unsigned)selection, MENU_ACTION_SELECT);
|
||||
|
||||
menu_navigation_set_selection(ptr);
|
||||
menu_driver_navigation_set(false);
|
||||
switch (gesture)
|
||||
{
|
||||
case MENU_INPUT_GESTURE_TAP:
|
||||
case MENU_INPUT_GESTURE_SHORT_PRESS:
|
||||
/* Normal pointer input */
|
||||
if (ptr == selection)
|
||||
return (unsigned)menu_entry_action(entry, (unsigned)selection, MENU_ACTION_SELECT);
|
||||
|
||||
menu_navigation_set_selection(ptr);
|
||||
menu_driver_navigation_set(false);
|
||||
break;
|
||||
case MENU_INPUT_GESTURE_LONG_PRESS:
|
||||
/* 'Reset to default' action */
|
||||
if ((ptr <= (menu_entries_get_size() - 1)) &&
|
||||
(ptr == selection))
|
||||
return menu_entry_action(entry, (unsigned)selection, MENU_ACTION_START);
|
||||
break;
|
||||
default:
|
||||
/* Ignore input */
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -4852,8 +4852,9 @@ static int rgui_environ(enum menu_environ_cb type,
|
||||
}
|
||||
|
||||
static int rgui_pointer_up(void *data,
|
||||
unsigned x, unsigned y,
|
||||
unsigned ptr, menu_file_list_cbs_t *cbs,
|
||||
unsigned x, unsigned y, unsigned ptr,
|
||||
enum menu_input_pointer_gesture gesture,
|
||||
menu_file_list_cbs_t *cbs,
|
||||
menu_entry_t *entry, unsigned action)
|
||||
{
|
||||
rgui_t *rgui = (rgui_t*)data;
|
||||
@ -4869,33 +4870,51 @@ static int rgui_pointer_up(void *data,
|
||||
rgui->entry_has_thumbnail &&
|
||||
(fs_thumbnail.is_valid || (rgui->thumbnail_queue_size > 0));
|
||||
|
||||
if (show_fs_thumbnail)
|
||||
switch (gesture)
|
||||
{
|
||||
/* If we are currently showing a fullscreen thumbnail:
|
||||
* - Must provide a mechanism for toggling it off
|
||||
* - A normal mouse press should just select the current
|
||||
* entry (for which the thumbnail is being shown) */
|
||||
if (y < header_height)
|
||||
rgui_update_thumbnail_image(rgui);
|
||||
else
|
||||
return menu_entry_action(entry, (unsigned)selection, MENU_ACTION_SELECT);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (y < header_height)
|
||||
return menu_entry_action(entry, (unsigned)selection, MENU_ACTION_CANCEL);
|
||||
else if (ptr <= (menu_entries_get_size() - 1))
|
||||
{
|
||||
/* If currently selected item matches 'pointer' value,
|
||||
* perform a MENU_ACTION_SELECT on it */
|
||||
if (ptr == selection)
|
||||
return menu_entry_action(entry, (unsigned)selection, MENU_ACTION_SELECT);
|
||||
case MENU_INPUT_GESTURE_TAP:
|
||||
case MENU_INPUT_GESTURE_SHORT_PRESS:
|
||||
{
|
||||
/* Normal pointer input */
|
||||
if (show_fs_thumbnail)
|
||||
{
|
||||
/* If we are currently showing a fullscreen thumbnail:
|
||||
* - Must provide a mechanism for toggling it off
|
||||
* - A normal mouse press should just select the current
|
||||
* entry (for which the thumbnail is being shown) */
|
||||
if (y < header_height)
|
||||
rgui_update_thumbnail_image(rgui);
|
||||
else
|
||||
return menu_entry_action(entry, (unsigned)selection, MENU_ACTION_SELECT);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (y < header_height)
|
||||
return menu_entry_action(entry, (unsigned)selection, MENU_ACTION_CANCEL);
|
||||
else if (ptr <= (menu_entries_get_size() - 1))
|
||||
{
|
||||
/* If currently selected item matches 'pointer' value,
|
||||
* perform a MENU_ACTION_SELECT on it */
|
||||
if (ptr == selection)
|
||||
return menu_entry_action(entry, (unsigned)selection, MENU_ACTION_SELECT);
|
||||
|
||||
/* Otherwise, just move the current selection to the
|
||||
* 'pointer' value */
|
||||
menu_navigation_set_selection(ptr);
|
||||
menu_driver_navigation_set(false);
|
||||
}
|
||||
/* Otherwise, just move the current selection to the
|
||||
* 'pointer' value */
|
||||
menu_navigation_set_selection(ptr);
|
||||
menu_driver_navigation_set(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MENU_INPUT_GESTURE_LONG_PRESS:
|
||||
/* 'Reset to default' action */
|
||||
if ((ptr <= (menu_entries_get_size() - 1)) &&
|
||||
(ptr == selection))
|
||||
return menu_entry_action(entry, (unsigned)selection, MENU_ACTION_START);
|
||||
break;
|
||||
default:
|
||||
/* Ignore input */
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -4388,24 +4388,41 @@ error:
|
||||
|
||||
static int stripes_pointer_up(void *userdata,
|
||||
unsigned x, unsigned y, unsigned ptr,
|
||||
enum menu_input_pointer_gesture gesture,
|
||||
menu_file_list_cbs_t *cbs,
|
||||
menu_entry_t *entry, unsigned action)
|
||||
{
|
||||
unsigned header_height = menu_display_get_header_height();
|
||||
size_t selection = menu_navigation_get_selection();
|
||||
|
||||
if (y < header_height)
|
||||
switch (gesture)
|
||||
{
|
||||
size_t selection = menu_navigation_get_selection();
|
||||
return (unsigned)menu_entry_action(entry, (unsigned)selection, MENU_ACTION_CANCEL);
|
||||
}
|
||||
else if (ptr <= (menu_entries_get_size() - 1))
|
||||
{
|
||||
size_t selection = menu_navigation_get_selection();
|
||||
if (ptr == selection && cbs && cbs->action_select)
|
||||
return (unsigned)menu_entry_action(entry, (unsigned)selection, MENU_ACTION_SELECT);
|
||||
case MENU_INPUT_GESTURE_TAP:
|
||||
case MENU_INPUT_GESTURE_SHORT_PRESS:
|
||||
{
|
||||
/* Normal pointer input */
|
||||
unsigned header_height = menu_display_get_header_height();
|
||||
|
||||
menu_navigation_set_selection(ptr);
|
||||
menu_driver_navigation_set(false);
|
||||
if (y < header_height)
|
||||
return (unsigned)menu_entry_action(entry, (unsigned)selection, MENU_ACTION_CANCEL);
|
||||
else if (ptr <= (menu_entries_get_size() - 1))
|
||||
{
|
||||
if (ptr == selection && cbs && cbs->action_select)
|
||||
return (unsigned)menu_entry_action(entry, (unsigned)selection, MENU_ACTION_SELECT);
|
||||
|
||||
menu_navigation_set_selection(ptr);
|
||||
menu_driver_navigation_set(false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MENU_INPUT_GESTURE_LONG_PRESS:
|
||||
/* 'Reset to default' action */
|
||||
if ((ptr <= (menu_entries_get_size() - 1)) &&
|
||||
(ptr == selection))
|
||||
return menu_entry_action(entry, (unsigned)selection, MENU_ACTION_START);
|
||||
break;
|
||||
default:
|
||||
/* Ignore input */
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -3345,25 +3345,108 @@ static void xmb_render(void *data,
|
||||
|
||||
if (pointer.type != MENU_POINTER_DISABLED)
|
||||
{
|
||||
size_t selection = menu_navigation_get_selection();
|
||||
int16_t pointer_y = pointer.y;
|
||||
unsigned first = 0, last = end;
|
||||
size_t selection = menu_navigation_get_selection();
|
||||
int16_t margin_top = (int16_t)xmb->margins_screen_top;
|
||||
int16_t margin_left = (int16_t)xmb->margins_screen_left;
|
||||
int16_t margin_right = (int16_t)((float)width - xmb->margins_screen_left);
|
||||
int16_t pointer_x = pointer.x;
|
||||
int16_t pointer_y = pointer.y;
|
||||
|
||||
pointer_y = (pointer.type == MENU_POINTER_MOUSE) ?
|
||||
pointer_y + (xmb->cursor_size/2) : pointer_y;
|
||||
/* This must be set every frame when using a pointer,
|
||||
* otherwise touchscreen input breaks when changing
|
||||
* orientation */
|
||||
menu_display_set_width(width);
|
||||
menu_display_set_height(height);
|
||||
|
||||
if (height)
|
||||
xmb_calculate_visible_range(xmb, height,
|
||||
end, (unsigned)selection, &first, &last);
|
||||
|
||||
for (i = first; i <= last; i++)
|
||||
/* When determining current pointer selection, we
|
||||
* only track pointer movements between the left
|
||||
* and right screen margins */
|
||||
if ((pointer_x > margin_left) && (pointer_x < margin_right))
|
||||
{
|
||||
float item_y1 = xmb->margins_screen_top
|
||||
+ xmb_item_y(xmb, (int)i, selection);
|
||||
float item_y2 = item_y1 + xmb->icon_size;
|
||||
unsigned first = 0;
|
||||
unsigned last = end;
|
||||
|
||||
if (pointer_y > item_y1 && pointer_y < item_y2)
|
||||
menu_input_set_pointer_selection(i);
|
||||
if (height)
|
||||
xmb_calculate_visible_range(xmb, height,
|
||||
end, (unsigned)selection, &first, &last);
|
||||
|
||||
for (i = first; i <= last; i++)
|
||||
{
|
||||
float entry_size = (i == selection) ?
|
||||
xmb->icon_spacing_vertical * xmb->active_item_factor : xmb->icon_spacing_vertical;
|
||||
float half_entry_size = entry_size * 0.5f;
|
||||
float y_curr;
|
||||
int y1;
|
||||
int y2;
|
||||
|
||||
y_curr = xmb_item_y(xmb, (int)i, selection) + xmb->margins_screen_top;
|
||||
|
||||
y1 = (int)((y_curr - half_entry_size) + 0.5f);
|
||||
y2 = (int)((y_curr + half_entry_size) + 0.5f);
|
||||
|
||||
if ((pointer_y > y1) && (pointer_y < y2))
|
||||
{
|
||||
menu_input_set_pointer_selection(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Areas beyond the top/right margins are used
|
||||
* as a sort of virtual dpad:
|
||||
* - Above top margin: navigate left/right
|
||||
* - Beyond right margin: navigate up/down */
|
||||
if ((pointer_y < margin_top) || (pointer_x > margin_right))
|
||||
{
|
||||
menu_entry_t entry;
|
||||
|
||||
if (pointer.press_direction != MENU_INPUT_PRESS_DIRECTION_NONE)
|
||||
{
|
||||
menu_entry_init(&entry);
|
||||
entry.path_enabled = false;
|
||||
entry.label_enabled = false;
|
||||
entry.rich_label_enabled = false;
|
||||
entry.value_enabled = false;
|
||||
entry.sublabel_enabled = false;
|
||||
menu_entry_get(&entry, 0, selection, NULL, true);
|
||||
}
|
||||
|
||||
switch (pointer.press_direction)
|
||||
{
|
||||
case MENU_INPUT_PRESS_DIRECTION_UP:
|
||||
/* Note: Direction is inverted, since 'up' should
|
||||
* move list upwards */
|
||||
if (pointer_x > margin_right)
|
||||
menu_entry_action(&entry, (unsigned)selection, MENU_ACTION_DOWN);
|
||||
break;
|
||||
case MENU_INPUT_PRESS_DIRECTION_DOWN:
|
||||
/* Note: Direction is inverted, since 'down' should
|
||||
* move list downwards */
|
||||
if (pointer_x > margin_right)
|
||||
menu_entry_action(&entry, (unsigned)selection, MENU_ACTION_UP);
|
||||
break;
|
||||
case MENU_INPUT_PRESS_DIRECTION_LEFT:
|
||||
/* Navigate left
|
||||
* Note: At the top level, navigating left
|
||||
* means switching to the 'next' horizontal list,
|
||||
* which is actually a movement to the *right* */
|
||||
if (pointer_y < margin_top)
|
||||
menu_entry_action(
|
||||
&entry, (unsigned)selection, (xmb->depth == 1) ? MENU_ACTION_RIGHT : MENU_ACTION_LEFT);
|
||||
break;
|
||||
case MENU_INPUT_PRESS_DIRECTION_RIGHT:
|
||||
/* Navigate right
|
||||
* Note: At the top level, navigating right
|
||||
* means switching to the 'previous' horizontal list,
|
||||
* which is actually a movement to the *left* */
|
||||
if (pointer_y < margin_top)
|
||||
menu_entry_action(
|
||||
&entry, (unsigned)selection, (xmb->depth == 1) ? MENU_ACTION_LEFT : MENU_ACTION_RIGHT);
|
||||
break;
|
||||
default:
|
||||
/* Do nothing */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5977,24 +6060,157 @@ error:
|
||||
|
||||
static int xmb_pointer_up(void *userdata,
|
||||
unsigned x, unsigned y, unsigned ptr,
|
||||
enum menu_input_pointer_gesture gesture,
|
||||
menu_file_list_cbs_t *cbs,
|
||||
menu_entry_t *entry, unsigned action)
|
||||
{
|
||||
xmb_handle_t *xmb = (xmb_handle_t*)userdata;
|
||||
unsigned header_height = menu_display_get_header_height();
|
||||
size_t selection = menu_navigation_get_selection();
|
||||
unsigned end = (unsigned)menu_entries_get_size();
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
int16_t margin_top;
|
||||
int16_t margin_left;
|
||||
int16_t margin_right;
|
||||
|
||||
if (y < header_height)
|
||||
{
|
||||
size_t selection = menu_navigation_get_selection();
|
||||
return (unsigned)menu_entry_action(entry, (unsigned)selection, MENU_ACTION_CANCEL);
|
||||
}
|
||||
else if (ptr <= (menu_entries_get_size() - 1))
|
||||
{
|
||||
size_t selection = menu_navigation_get_selection();
|
||||
if (ptr == selection)
|
||||
return (unsigned)menu_entry_action(entry, (unsigned)selection, MENU_ACTION_SELECT);
|
||||
if (!xmb)
|
||||
return -1;
|
||||
|
||||
menu_navigation_set_selection(ptr);
|
||||
menu_driver_navigation_set(false);
|
||||
video_driver_get_size(&width, &height);
|
||||
margin_top = (int16_t)xmb->margins_screen_top;
|
||||
margin_left = (int16_t)xmb->margins_screen_left;
|
||||
margin_right = (int16_t)((float)width - xmb->margins_screen_left);
|
||||
|
||||
switch (gesture)
|
||||
{
|
||||
case MENU_INPUT_GESTURE_TAP:
|
||||
case MENU_INPUT_GESTURE_SHORT_PRESS:
|
||||
/* - A touch in the left margin:
|
||||
* > ...triggers a 'cancel' action beneath the top margin
|
||||
* > ...triggers a 'search' action above the top margin
|
||||
* - A touch in the right margin triggers a 'select' action
|
||||
* for the current item
|
||||
* - Between the left/right margins input is handled normally */
|
||||
if (x < margin_left)
|
||||
{
|
||||
if (y >= margin_top)
|
||||
return menu_entry_action(entry, (unsigned)selection, MENU_ACTION_CANCEL);
|
||||
else
|
||||
return menu_input_dialog_start_search() ? 0 : -1;
|
||||
}
|
||||
else if (x > margin_right)
|
||||
return menu_entry_action(entry, (unsigned)selection, MENU_ACTION_SELECT);
|
||||
else if (ptr <= (end - 1))
|
||||
{
|
||||
/* If pointer item is already 'active', perform 'select' action */
|
||||
if (ptr == selection)
|
||||
return menu_entry_action(entry, (unsigned)selection, MENU_ACTION_SELECT);
|
||||
|
||||
/* ...otherwise navigate to the current pointer item */
|
||||
menu_navigation_set_selection(ptr);
|
||||
menu_driver_navigation_set(false);
|
||||
}
|
||||
break;
|
||||
case MENU_INPUT_GESTURE_LONG_PRESS:
|
||||
/* 'Reset to default' action */
|
||||
if ((ptr <= end - 1) && (ptr == selection))
|
||||
return menu_entry_action(entry, (unsigned)selection, MENU_ACTION_START);
|
||||
break;
|
||||
case MENU_INPUT_GESTURE_SWIPE_LEFT:
|
||||
/* Navigate left
|
||||
* Note: At the top level, navigating left
|
||||
* means switching to the 'next' horizontal list,
|
||||
* which is actually a movement to the *right* */
|
||||
if (y > margin_top)
|
||||
menu_entry_action(
|
||||
entry, (unsigned)selection, (xmb->depth == 1) ? MENU_ACTION_RIGHT : MENU_ACTION_LEFT);
|
||||
break;
|
||||
case MENU_INPUT_GESTURE_SWIPE_RIGHT:
|
||||
/* Navigate right
|
||||
* Note: At the top level, navigating right
|
||||
* means switching to the 'previous' horizontal list,
|
||||
* which is actually a movement to the *left* */
|
||||
if (y > margin_top)
|
||||
menu_entry_action(
|
||||
entry, (unsigned)selection, (xmb->depth == 1) ? MENU_ACTION_LEFT : MENU_ACTION_RIGHT);
|
||||
break;
|
||||
case MENU_INPUT_GESTURE_SWIPE_UP:
|
||||
/* Swipe up in left margin: ascend alphabet */
|
||||
if (x < margin_left)
|
||||
menu_entry_action(entry, (unsigned)selection, MENU_ACTION_SCROLL_DOWN);
|
||||
else if (x < margin_right)
|
||||
{
|
||||
/* Swipe up between left and right margins:
|
||||
* move selection pointer down by 1 'page' */
|
||||
unsigned first = 0;
|
||||
unsigned last = end;
|
||||
|
||||
if (height)
|
||||
xmb_calculate_visible_range(xmb, height,
|
||||
end, (unsigned)selection, &first, &last);
|
||||
|
||||
if (last < end)
|
||||
{
|
||||
menu_navigation_set_selection((size_t)last);
|
||||
menu_driver_navigation_set(true);
|
||||
}
|
||||
else
|
||||
menu_driver_ctl(MENU_NAVIGATION_CTL_SET_LAST, NULL);
|
||||
}
|
||||
break;
|
||||
case MENU_INPUT_GESTURE_SWIPE_DOWN:
|
||||
/* Swipe down in left margin: descend alphabet */
|
||||
if (x < margin_left)
|
||||
menu_entry_action(entry, (unsigned)selection, MENU_ACTION_SCROLL_UP);
|
||||
else if (x < margin_right)
|
||||
{
|
||||
/* Swipe down between left and right margins:
|
||||
* move selection pointer up by 1 'page' */
|
||||
unsigned bottom_idx = (unsigned)selection + 1;
|
||||
size_t new_idx;
|
||||
unsigned step;
|
||||
|
||||
/* Determine index of entry at bottom of screen
|
||||
* Note: cannot use xmb_calculate_visible_range()
|
||||
* here because there may not be sufficient entries
|
||||
* to reach the bottom of the screen - i.e. we just
|
||||
* want an index offset to subtract from the current
|
||||
* selection... */
|
||||
while (true)
|
||||
{
|
||||
float top = xmb_item_y(xmb, bottom_idx, selection) + xmb->margins_screen_top;
|
||||
|
||||
if (top > height)
|
||||
{
|
||||
/* Since this checks the top position, the
|
||||
* final index is always 1 greater than it
|
||||
* should be... */
|
||||
bottom_idx--;
|
||||
break;
|
||||
}
|
||||
|
||||
bottom_idx++;
|
||||
}
|
||||
|
||||
step = (bottom_idx >= selection) ? bottom_idx - selection : 0;
|
||||
new_idx = (selection > step) ? selection - step : 0;
|
||||
|
||||
if (new_idx > 0)
|
||||
{
|
||||
menu_navigation_set_selection(new_idx);
|
||||
menu_driver_navigation_set(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool pending_push = false;
|
||||
menu_driver_ctl(MENU_NAVIGATION_CTL_CLEAR, &pending_push);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Ignore input */
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -2712,7 +2712,6 @@ void menu_display_draw_cursor(
|
||||
settings_t *settings = config_get_ptr();
|
||||
bool cursor_visible = settings->bools.video_fullscreen ||
|
||||
!menu_display_has_windowed;
|
||||
|
||||
if (!settings->bools.menu_mouse_enable || !cursor_visible)
|
||||
return;
|
||||
|
||||
@ -3568,6 +3567,7 @@ bool menu_driver_ctl(enum rarch_menu_ctl_state state, void *data)
|
||||
}
|
||||
point->retcode = menu_driver_ctx->pointer_up(menu_userdata,
|
||||
point->x, point->y, point->ptr,
|
||||
point->gesture,
|
||||
point->cbs, point->entry, point->action);
|
||||
}
|
||||
break;
|
||||
|
@ -319,6 +319,7 @@ typedef struct menu_ctx_driver
|
||||
menu_file_list_cbs_t *cbs,
|
||||
menu_entry_t *entry, unsigned action);
|
||||
int (*pointer_up)(void *data, unsigned x, unsigned y, unsigned ptr,
|
||||
enum menu_input_pointer_gesture gesture,
|
||||
menu_file_list_cbs_t *cbs,
|
||||
menu_entry_t *entry, unsigned action);
|
||||
bool (*get_load_content_animation_data)(void *userdata, menu_texture_item *icon, char **playlist_name);
|
||||
@ -458,6 +459,7 @@ typedef struct menu_ctx_pointer
|
||||
unsigned y;
|
||||
unsigned ptr;
|
||||
unsigned action;
|
||||
enum menu_input_pointer_gesture gesture;
|
||||
int retcode;
|
||||
menu_file_list_cbs_t *cbs;
|
||||
menu_entry_t *entry;
|
||||
|
@ -32,16 +32,59 @@ RETRO_BEGIN_DECLS
|
||||
/* Mouse wheel tilt actions repeat at a very high
|
||||
* frequency - we ignore any input that occurs
|
||||
* with a period less than MENU_INPUT_HORIZ_WHEEL_DELAY */
|
||||
#define MENU_INPUT_HORIZ_WHEEL_DELAY 250000 /* 250 ms */
|
||||
#define MENU_INPUT_HORIZ_WHEEL_DELAY 250000 /* 250 ms */
|
||||
|
||||
#define MENU_INPUT_HIDE_CURSOR_DELAY 4000000 /* 4 seconds */
|
||||
/* Press directions are triggered as a pulse train.
|
||||
* Pulse period starts at MENU_INPUT_PRESS_DIRECTION_DELAY_MAX,
|
||||
* and decreases to MENU_INPUT_PRESS_DIRECTION_DELAY_MIN as
|
||||
* the start/current delta offset increases from
|
||||
* MENU_INPUT_DPI_THRESHOLD_PRESS_DIRECTION_MIN to
|
||||
* MENU_INPUT_DPI_THRESHOLD_PRESS_DIRECTION_MAX */
|
||||
#define MENU_INPUT_PRESS_DIRECTION_DELAY_MIN 100000 /* 100 ms */
|
||||
#define MENU_INPUT_PRESS_DIRECTION_DELAY_MAX 500000 /* 500 ms */
|
||||
|
||||
#define MENU_INPUT_PRESS_TIME_SHORT 250000 /* 250 ms */
|
||||
#define MENU_INPUT_PRESS_TIME_LONG 1500000 /* 1.5 second */
|
||||
/* (Anthing less than 'short' is considered a tap) */
|
||||
#define MENU_INPUT_HIDE_CURSOR_DELAY 4000000 /* 4 seconds */
|
||||
|
||||
#define MENU_INPUT_PRESS_TIME_SHORT 200000 /* 200 ms */
|
||||
#define MENU_INPUT_PRESS_TIME_LONG 1500000 /* 1.5 second */
|
||||
/* (Anything less than 'short' is considered a tap) */
|
||||
|
||||
#define MENU_INPUT_Y_ACCEL_DECAY_FACTOR 0.96f
|
||||
|
||||
/* Pointer is considered stationary if dx/dy remain
|
||||
* below (display DPI) * MENU_INPUT_DPI_THRESHOLD_DRAG */
|
||||
#define MENU_INPUT_DPI_THRESHOLD_DRAG 0.1f
|
||||
|
||||
/* Press direction detection:
|
||||
* While holding the pointer down, a press in a
|
||||
* specific direction (up, down, left, right) will
|
||||
* be detected if:
|
||||
* - Current delta (i.e. from start to current) in
|
||||
* press direction is greater than
|
||||
* (display DPI) * MENU_INPUT_DPI_THRESHOLD_PRESS_DIRECTION_MIN
|
||||
* - Current delta in perpendicular axis is less than
|
||||
* (display DPI) * MENU_INPUT_DPI_THRESHOLD_PRESS_DIRECTION_TANGENT
|
||||
* Press direction repeat rate is proportional to the current
|
||||
* delta in press direction.
|
||||
* Note: 'Tangent' is technically not the correct word here,
|
||||
* but the alternatives look silly, and the actual meaning
|
||||
* is transparent... */
|
||||
#define MENU_INPUT_DPI_THRESHOLD_PRESS_DIRECTION_MIN 0.55f
|
||||
#define MENU_INPUT_DPI_THRESHOLD_PRESS_DIRECTION_MAX 1.5f
|
||||
#define MENU_INPUT_DPI_THRESHOLD_PRESS_DIRECTION_TANGENT 0.35f
|
||||
|
||||
/* Swipe detection:
|
||||
* A gesture will register as a swipe if:
|
||||
* - Total delta in swipe direction is greater than
|
||||
* (display DPI) * MENU_INPUT_DPI_THRESHOLD_SWIPE
|
||||
* - Maximum frame delta in swipe direction is greater than
|
||||
* (display DPI) * MENU_INPUT_DPI_THRESHOLD_SWIPE_DELTA
|
||||
* - Maximum frame delta in all other directions is less than
|
||||
* (display DPI) * MENU_INPUT_DPI_THRESHOLD_SWIPE_DELTA_TANGENT */
|
||||
#define MENU_INPUT_DPI_THRESHOLD_SWIPE 0.7f
|
||||
#define MENU_INPUT_DPI_THRESHOLD_SWIPE_DELTA 0.4f
|
||||
#define MENU_INPUT_DPI_THRESHOLD_SWIPE_DELTA_TANGENT 0.3f
|
||||
|
||||
enum menu_pointer_type
|
||||
{
|
||||
MENU_POINTER_DISABLED = 0,
|
||||
@ -61,6 +104,27 @@ enum menu_input_mouse_hw_id
|
||||
MENU_MOUSE_HORIZ_WHEEL_DOWN
|
||||
};
|
||||
|
||||
enum menu_input_pointer_press_direction
|
||||
{
|
||||
MENU_INPUT_PRESS_DIRECTION_NONE = 0,
|
||||
MENU_INPUT_PRESS_DIRECTION_UP,
|
||||
MENU_INPUT_PRESS_DIRECTION_DOWN,
|
||||
MENU_INPUT_PRESS_DIRECTION_LEFT,
|
||||
MENU_INPUT_PRESS_DIRECTION_RIGHT
|
||||
};
|
||||
|
||||
enum menu_input_pointer_gesture
|
||||
{
|
||||
MENU_INPUT_GESTURE_NONE = 0,
|
||||
MENU_INPUT_GESTURE_TAP,
|
||||
MENU_INPUT_GESTURE_SHORT_PRESS,
|
||||
MENU_INPUT_GESTURE_LONG_PRESS,
|
||||
MENU_INPUT_GESTURE_SWIPE_UP,
|
||||
MENU_INPUT_GESTURE_SWIPE_DOWN,
|
||||
MENU_INPUT_GESTURE_SWIPE_LEFT,
|
||||
MENU_INPUT_GESTURE_SWIPE_RIGHT
|
||||
};
|
||||
|
||||
/* Defines set of (abstracted) inputs/states
|
||||
* common to mouse + touchscreen hardware */
|
||||
typedef struct menu_input_pointer_hw_state
|
||||
@ -83,6 +147,7 @@ typedef struct menu_input_pointer
|
||||
bool pressed;
|
||||
bool dragged;
|
||||
retro_time_t press_duration;
|
||||
enum menu_input_pointer_press_direction press_direction;
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
int16_t dx;
|
||||
|
384
retroarch.c
384
retroarch.c
@ -12393,7 +12393,15 @@ static void menu_input_get_mouse_hw_state(menu_input_pointer_hw_state_t *hw_stat
|
||||
static bool last_cancel_pressed = false;
|
||||
bool overlay_active = false;
|
||||
bool mouse_enabled = settings->bools.menu_mouse_enable;
|
||||
bool is_rgui = string_is_equal(settings->arrays.menu_driver, "rgui");
|
||||
/* Note: RGUI requires special treatment, but we can't just
|
||||
* check settings->arrays.menu_driver because this may change
|
||||
* while another menu driver is active (and applying RGUI corrections
|
||||
* while another menu driver is active will render the mouse unusable).
|
||||
* We therefore have to check for the existence of a framebuffer
|
||||
* texture instead (which is only ever set by RGUI) */
|
||||
menu_handle_t *menu_data = menu_driver_get_ptr();
|
||||
bool is_rgui =
|
||||
(menu_data && menu_data->driver_ctx && menu_data->driver_ctx->set_texture);
|
||||
|
||||
/* Easiest to set inactive by default, and toggle
|
||||
* when input is detected */
|
||||
@ -12843,7 +12851,7 @@ static unsigned menu_event(
|
||||
}
|
||||
|
||||
/* Populate menu_input_state
|
||||
* Note: dx, dy, ptr, accel entries are set elsewhere */
|
||||
* Note: dx, dy, ptr, y_accel, etc. entries are set elsewhere */
|
||||
if (menu_input->select_inhibit)
|
||||
{
|
||||
menu_input->pointer.active = false;
|
||||
@ -12963,6 +12971,50 @@ static void menu_input_set_pointer_visibility(retro_time_t current_time)
|
||||
}
|
||||
}
|
||||
|
||||
static float menu_input_get_dpi(void)
|
||||
{
|
||||
gfx_ctx_metrics_t metrics;
|
||||
float dpi = 0.0f;
|
||||
menu_handle_t *menu_data = menu_driver_get_ptr();
|
||||
bool is_rgui =
|
||||
(menu_data && menu_data->driver_ctx && menu_data->driver_ctx->set_texture);
|
||||
|
||||
/* Regardless of menu driver, need 'actual'
|
||||
* screen DPI */
|
||||
metrics.type = DISPLAY_METRIC_DPI;
|
||||
metrics.value = &dpi;
|
||||
|
||||
if (!video_context_driver_get_metrics(&metrics))
|
||||
dpi = 0.0f; /* Ensure a sane value (unnecessary check, but no harm being safe) */
|
||||
|
||||
/* RGUI uses a framebuffer texture, which means we
|
||||
* operate in menu space, not screen space.
|
||||
* DPI in a traditional sense is therefore meaningless,
|
||||
* so generate a substitute value based upon framebuffer
|
||||
* dimensions */
|
||||
if ((dpi > 0.0f) && is_rgui)
|
||||
{
|
||||
size_t fb_pitch;
|
||||
unsigned fb_width, fb_height;
|
||||
struct video_viewport vp;
|
||||
|
||||
/* Read display/framebuffer info */
|
||||
menu_display_get_fb_size(&fb_width, &fb_height, &fb_pitch);
|
||||
video_driver_get_viewport_info(&vp);
|
||||
|
||||
/* Rationale for current 'DPI' determination method:
|
||||
* - Divide screen height by DPI, to get number of vertical
|
||||
* '1 inch' squares
|
||||
* - Divide RGUI framebuffer height by number of vertical
|
||||
* '1 inch' squares to get number of menu space pixels
|
||||
* per inch
|
||||
* This is crude, but should be sufficient... */
|
||||
dpi = ((float)fb_height / (float)vp.full_height) * dpi;
|
||||
}
|
||||
|
||||
return dpi;
|
||||
}
|
||||
|
||||
static int menu_input_pointer_post_iterate(
|
||||
retro_time_t current_time,
|
||||
menu_file_list_cbs_t *cbs,
|
||||
@ -12973,12 +13025,17 @@ static int menu_input_pointer_post_iterate(
|
||||
static int16_t start_y = 0;
|
||||
static int16_t last_x = 0;
|
||||
static int16_t last_y = 0;
|
||||
static uint16_t dx_right_max = 0;
|
||||
static uint16_t dx_left_max = 0;
|
||||
static uint16_t dy_up_max = 0;
|
||||
static uint16_t dy_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_internal();
|
||||
int ret = 0;
|
||||
@ -12999,6 +13056,7 @@ static int menu_input_pointer_post_iterate(
|
||||
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);
|
||||
@ -13022,52 +13080,106 @@ static int menu_input_pointer_post_iterate(
|
||||
menu_ctx_pointer_t point;
|
||||
|
||||
/* Initialise variables */
|
||||
start_time = current_time;
|
||||
start_x = x;
|
||||
start_y = y;
|
||||
last_x = x;
|
||||
last_y = y;
|
||||
accel0 = 0.0f;
|
||||
accel1 = 0.0f;
|
||||
start_time = current_time;
|
||||
start_x = x;
|
||||
start_y = y;
|
||||
last_x = x;
|
||||
last_y = y;
|
||||
dx_right_max = 0;
|
||||
dx_left_max = 0;
|
||||
dy_up_max = 0;
|
||||
dy_down_max = 0;
|
||||
accel0 = 0.0f;
|
||||
accel1 = 0.0f;
|
||||
last_press_direction_time = 0;
|
||||
|
||||
/* If we are not currently showing the onscreen keyboard,
|
||||
* trigger a 'pointer down' event */
|
||||
if (!osk_active)
|
||||
{
|
||||
point.x = x;
|
||||
point.y = y;
|
||||
point.ptr = menu_input->ptr;
|
||||
point.cbs = cbs;
|
||||
point.entry = entry;
|
||||
point.action = action;
|
||||
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;
|
||||
|
||||
menu_driver_ctl(RARCH_MENU_CTL_POINTER_DOWN, &point);
|
||||
ret = point.retcode;
|
||||
}
|
||||
}
|
||||
else if (!osk_active)
|
||||
else
|
||||
{
|
||||
/* Pointer is being held down (i.e. for more than one frame)
|
||||
* Note: We do not track movement while the onscreen
|
||||
* keyboard is displayed */
|
||||
gfx_ctx_metrics_t metrics;
|
||||
float dpi;
|
||||
float dpi = menu_input_get_dpi();
|
||||
|
||||
metrics.type = DISPLAY_METRIC_DPI;
|
||||
metrics.value = &dpi;
|
||||
|
||||
/* > Update deltas + acceleration
|
||||
/* > 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 (video_context_driver_get_metrics(&metrics))
|
||||
if (dpi > 0.0f)
|
||||
{
|
||||
if ((abs(x - start_x) > (dpi / 10)) ||
|
||||
(abs(y - start_y) > (dpi / 10)))
|
||||
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;
|
||||
|
||||
int16_t dx = x - last_x;
|
||||
int16_t dy = y - last_y;
|
||||
|
||||
/* Pointer has moved a sufficient distance to
|
||||
* trigger a 'dragged' state */
|
||||
menu_input->pointer.dragged = true;
|
||||
|
||||
menu_input->pointer.dx = x - last_x;
|
||||
menu_input->pointer.dy = y - last_y;
|
||||
/* Assign current deltas */
|
||||
menu_input->pointer.dx = dx;
|
||||
menu_input->pointer.dy = dy;
|
||||
|
||||
/* Update maximum deltas */
|
||||
if (dx > 0)
|
||||
{
|
||||
if (dx > dx_right_max)
|
||||
dx_right_max = (uint16_t)dx;
|
||||
}
|
||||
else
|
||||
{
|
||||
dx *= -1;
|
||||
if (dx > dx_left_max)
|
||||
dx_left_max = (uint16_t)dx;
|
||||
}
|
||||
|
||||
if (dy > 0)
|
||||
{
|
||||
if (dy > dy_down_max)
|
||||
dy_down_max = (uint16_t)dy;
|
||||
}
|
||||
else
|
||||
{
|
||||
dy *= -1;
|
||||
if (dy > dy_up_max)
|
||||
dy_up_max = dy;
|
||||
}
|
||||
|
||||
/* Magic numbers... */
|
||||
menu_input->pointer.y_accel = (accel0 + accel1 + (float)menu_input->pointer.dy) / 3.0f;
|
||||
@ -13077,21 +13189,78 @@ static int menu_input_pointer_post_iterate(
|
||||
/* Acceleration decays over time - but if the value
|
||||
* has been set on this frame, attenuation should
|
||||
* be skipped */
|
||||
attenuate_y_accel = false;
|
||||
attenuate_y_accel = false;
|
||||
|
||||
/* Check if ponter 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.dx = 0;
|
||||
menu_input->pointer.dy = 0;
|
||||
menu_input->pointer.press_direction = MENU_INPUT_PRESS_DIRECTION_NONE;
|
||||
}
|
||||
}
|
||||
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.dx = 0;
|
||||
menu_input->pointer.dy = 0;
|
||||
menu_input->pointer.y_accel = 0.0f;
|
||||
menu_input->pointer.press_direction = MENU_INPUT_PRESS_DIRECTION_NONE;
|
||||
}
|
||||
|
||||
/* > Update remaining variables */
|
||||
@ -13103,28 +13272,44 @@ static int menu_input_pointer_post_iterate(
|
||||
else if (last_select_pressed)
|
||||
{
|
||||
/* Transition from select pressed to select unpressed */
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
menu_ctx_pointer_t point;
|
||||
|
||||
/* If pointer has been 'dragged', then it counts as
|
||||
* a miss. Only register 'release' event if pointer
|
||||
* has remained stationary
|
||||
* TODO/FIXME: Releasing select should *always* trigger a
|
||||
* pointer up event, but event type should be specified
|
||||
* - i.e. long press, short press, swipe left/right.
|
||||
* The menu driver can then choose how to interpret the
|
||||
* user action */
|
||||
if (!menu_input->pointer.dragged)
|
||||
if (menu_input->pointer.dragged)
|
||||
{
|
||||
menu_ctx_pointer_t point;
|
||||
/* Ponter has moved.
|
||||
* When using a touchscreen, relasing a press
|
||||
* resets the x/y postition - 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 = start_x;
|
||||
point.y = start_y;
|
||||
point.ptr = menu_input->ptr;
|
||||
point.cbs = cbs;
|
||||
point.entry = entry;
|
||||
point.action = action;
|
||||
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)
|
||||
/* 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)
|
||||
@ -13132,33 +13317,94 @@ static int menu_input_pointer_post_iterate(
|
||||
menu_event_set_osk_ptr(point.retcode);
|
||||
menu_event_osk_append(point.retcode);
|
||||
}
|
||||
ret = point.retcode;
|
||||
}
|
||||
}
|
||||
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
|
||||
{
|
||||
/* A 'long press' triggers a start (reset to default) action */
|
||||
if (menu_input->pointer.press_duration > MENU_INPUT_PRESS_TIME_LONG)
|
||||
/* Pointer has moved - check if this is a swipe */
|
||||
float dpi = menu_input_get_dpi();
|
||||
|
||||
if (dpi > 0.0f)
|
||||
{
|
||||
size_t selection = menu_navigation_get_selection();
|
||||
ret = menu_entry_action(entry, (unsigned)selection, MENU_ACTION_START);
|
||||
}
|
||||
else
|
||||
{
|
||||
menu_driver_ctl(RARCH_MENU_CTL_POINTER_UP, &point);
|
||||
ret = point.retcode;
|
||||
uint16_t dpi_threshold_swipe =
|
||||
(uint16_t)((dpi * MENU_INPUT_DPI_THRESHOLD_SWIPE) + 0.5f);
|
||||
uint16_t dpi_threshold_swipe_delta =
|
||||
(uint16_t)((dpi * MENU_INPUT_DPI_THRESHOLD_SWIPE_DELTA) + 0.5f);
|
||||
uint16_t dpi_threshold_swipe_delta_tangent =
|
||||
(uint16_t)((dpi * MENU_INPUT_DPI_THRESHOLD_SWIPE_DELTA_TANGENT) + 0.5f);
|
||||
|
||||
/* Swipe right */
|
||||
if (dx_right_max >= dpi_threshold_swipe_delta)
|
||||
{
|
||||
if ((dx_left_max < dpi_threshold_swipe_delta_tangent) &&
|
||||
(dy_up_max < dpi_threshold_swipe_delta_tangent) &&
|
||||
(dy_down_max < dpi_threshold_swipe_delta_tangent) &&
|
||||
(x - start_x > dpi_threshold_swipe))
|
||||
point.gesture = MENU_INPUT_GESTURE_SWIPE_RIGHT;
|
||||
}
|
||||
/* Swipe left */
|
||||
else if (dx_left_max >= dpi_threshold_swipe_delta)
|
||||
{
|
||||
if ((dx_right_max < dpi_threshold_swipe_delta_tangent) &&
|
||||
(dy_up_max < dpi_threshold_swipe_delta_tangent) &&
|
||||
(dy_down_max < dpi_threshold_swipe_delta_tangent) &&
|
||||
(start_x - x > dpi_threshold_swipe))
|
||||
point.gesture = MENU_INPUT_GESTURE_SWIPE_LEFT;
|
||||
}
|
||||
/* Swipe up */
|
||||
else if (dy_up_max >= dpi_threshold_swipe_delta)
|
||||
{
|
||||
if ((dx_right_max < dpi_threshold_swipe_delta_tangent) &&
|
||||
(dx_left_max < dpi_threshold_swipe_delta_tangent) &&
|
||||
(dy_down_max < dpi_threshold_swipe_delta_tangent) &&
|
||||
(start_y - y > dpi_threshold_swipe))
|
||||
point.gesture = MENU_INPUT_GESTURE_SWIPE_UP;
|
||||
}
|
||||
/* Swipe down */
|
||||
else if (dy_down_max >= dpi_threshold_swipe_delta)
|
||||
{
|
||||
if ((dx_right_max < dpi_threshold_swipe_delta_tangent) &&
|
||||
(dx_left_max < dpi_threshold_swipe_delta_tangent) &&
|
||||
(dy_up_max < dpi_threshold_swipe_delta_tangent) &&
|
||||
(y - start_y > 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;
|
||||
menu_input->pointer.press_duration = 0;
|
||||
menu_input->pointer.dx = 0;
|
||||
menu_input->pointer.dy = 0;
|
||||
menu_input->pointer.dragged = false;
|
||||
start_x = 0;
|
||||
start_y = 0;
|
||||
last_x = 0;
|
||||
last_y = 0;
|
||||
dx_right_max = 0;
|
||||
dx_left_max = 0;
|
||||
dy_up_max = 0;
|
||||
dy_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;
|
||||
}
|
||||
}
|
||||
last_select_pressed = pointer_hw_state->select_pressed;
|
||||
|
Loading…
x
Reference in New Issue
Block a user