mirror of
https://github.com/libretro/RetroArch
synced 2025-01-31 15:32:59 +00:00
454 lines
12 KiB
C
454 lines
12 KiB
C
/* RetroArch - A frontend for libretro.
|
|
* Copyright (C) 2011-2020 - Daniel De Matteis
|
|
*
|
|
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
|
* of the GNU General Public License as published by the Free Software Found-
|
|
* ation, either version 3 of the License, or (at your option) any later version.
|
|
*
|
|
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with RetroArch.
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include "wayland_common.h"
|
|
|
|
#include "../input_keymaps.h"
|
|
|
|
/* Generated from xdg-shell-unstable-v6.xml */
|
|
#include "../../gfx/common/wayland/xdg-shell-unstable-v6.h"
|
|
|
|
/* Generated from xdg-shell.xml */
|
|
#include "../../gfx/common/wayland/xdg-shell.h"
|
|
|
|
static void keyboard_handle_keymap(void* data,
|
|
struct wl_keyboard* keyboard,
|
|
uint32_t format,
|
|
int fd,
|
|
uint32_t size)
|
|
{
|
|
(void)data;
|
|
if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)
|
|
{
|
|
close(fd);
|
|
return;
|
|
}
|
|
|
|
#ifdef HAVE_XKBCOMMON
|
|
if (init_xkb(fd, size) < 0)
|
|
RARCH_ERR("[Wayland]: Failed to init keymap.\n");
|
|
#endif
|
|
close(fd);
|
|
|
|
RARCH_LOG("[Wayland]: Loaded keymap.\n");
|
|
}
|
|
|
|
static void keyboard_handle_enter(void* data,
|
|
struct wl_keyboard* keyboard,
|
|
uint32_t serial,
|
|
struct wl_surface* surface,
|
|
struct wl_array* keys)
|
|
{
|
|
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
|
|
wl->input.keyboard_focus = true;
|
|
}
|
|
|
|
static void keyboard_handle_leave(void *data,
|
|
struct wl_keyboard *keyboard,
|
|
uint32_t serial,
|
|
struct wl_surface *surface)
|
|
{
|
|
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
|
|
wl->input.keyboard_focus = false;
|
|
}
|
|
|
|
static void keyboard_handle_key(void *data,
|
|
struct wl_keyboard *keyboard,
|
|
uint32_t serial,
|
|
uint32_t time,
|
|
uint32_t key,
|
|
uint32_t state)
|
|
{
|
|
(void)serial;
|
|
(void)time;
|
|
(void)keyboard;
|
|
|
|
int value = 1;
|
|
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
|
|
|
|
if (state == WL_KEYBOARD_KEY_STATE_PRESSED)
|
|
{
|
|
BIT_SET(wl->input.key_state, key);
|
|
value = 1;
|
|
}
|
|
else if (state == WL_KEYBOARD_KEY_STATE_RELEASED)
|
|
{
|
|
BIT_CLEAR(wl->input.key_state, key);
|
|
value = 0;
|
|
}
|
|
|
|
#ifdef HAVE_XKBCOMMON
|
|
if (handle_xkb(key, value) == 0)
|
|
return;
|
|
#endif
|
|
input_keyboard_event(value,
|
|
input_keymaps_translate_keysym_to_rk(key),
|
|
0, 0, RETRO_DEVICE_KEYBOARD);
|
|
}
|
|
|
|
static void keyboard_handle_modifiers(void *data,
|
|
struct wl_keyboard *keyboard,
|
|
uint32_t serial,
|
|
uint32_t modsDepressed,
|
|
uint32_t modsLatched,
|
|
uint32_t modsLocked,
|
|
uint32_t group)
|
|
{
|
|
(void)data;
|
|
(void)keyboard;
|
|
(void)serial;
|
|
#ifdef HAVE_XKBCOMMON
|
|
handle_xkb_state_mask(modsDepressed, modsLatched, modsLocked, group);
|
|
#else
|
|
(void)modsDepressed;
|
|
(void)modsLatched;
|
|
(void)modsLocked;
|
|
(void)group;
|
|
#endif
|
|
}
|
|
|
|
void keyboard_handle_repeat_info(void *data,
|
|
struct wl_keyboard *wl_keyboard,
|
|
int32_t rate,
|
|
int32_t delay)
|
|
{
|
|
(void)data;
|
|
(void)wl_keyboard;
|
|
(void)rate;
|
|
(void)delay;
|
|
/* TODO: Seems like we'll need this to get
|
|
* repeat working. We'll have to do it on our own. */
|
|
}
|
|
|
|
void gfx_ctx_wl_show_mouse(void *data, bool state);
|
|
|
|
static void pointer_handle_enter(void *data,
|
|
struct wl_pointer *pointer,
|
|
uint32_t serial,
|
|
struct wl_surface *surface,
|
|
wl_fixed_t sx,
|
|
wl_fixed_t sy)
|
|
{
|
|
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
|
|
(void)pointer;
|
|
(void)serial;
|
|
(void)surface;
|
|
|
|
wl->input.mouse.last_x = wl_fixed_to_int(sx * (wl_fixed_t)wl->buffer_scale);
|
|
wl->input.mouse.last_y = wl_fixed_to_int(sy * (wl_fixed_t)wl->buffer_scale);
|
|
wl->input.mouse.x = wl->input.mouse.last_x;
|
|
wl->input.mouse.y = wl->input.mouse.last_y;
|
|
wl->input.mouse.focus = true;
|
|
wl->cursor.serial = serial;
|
|
|
|
gfx_ctx_wl_show_mouse(data, wl->cursor.visible);
|
|
}
|
|
|
|
static void pointer_handle_leave(void *data,
|
|
struct wl_pointer *pointer,
|
|
uint32_t serial,
|
|
struct wl_surface *surface)
|
|
{
|
|
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
|
|
wl->input.mouse.focus = false;
|
|
(void)pointer;
|
|
(void)serial;
|
|
(void)surface;
|
|
}
|
|
|
|
static void pointer_handle_motion(void *data,
|
|
struct wl_pointer *pointer,
|
|
uint32_t time,
|
|
wl_fixed_t sx,
|
|
wl_fixed_t sy)
|
|
{
|
|
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
|
|
wl->input.mouse.x = wl_fixed_to_int(
|
|
(wl_fixed_t)wl->buffer_scale * sx);
|
|
wl->input.mouse.y = wl_fixed_to_int(
|
|
(wl_fixed_t)wl->buffer_scale * sy);
|
|
}
|
|
|
|
static void pointer_handle_button(void *data,
|
|
struct wl_pointer *wl_pointer,
|
|
uint32_t serial,
|
|
uint32_t time,
|
|
uint32_t button,
|
|
uint32_t state)
|
|
{
|
|
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
|
|
|
|
if (state == WL_POINTER_BUTTON_STATE_PRESSED)
|
|
{
|
|
if (button == BTN_LEFT)
|
|
{
|
|
wl->input.mouse.left = true;
|
|
|
|
if (BIT_GET(wl->input.key_state, KEY_LEFTALT))
|
|
{
|
|
if (wl->xdg_toplevel)
|
|
xdg_toplevel_move(wl->xdg_toplevel, wl->seat, serial);
|
|
else if (wl->zxdg_toplevel)
|
|
zxdg_toplevel_v6_move(wl->zxdg_toplevel, wl->seat, serial);
|
|
}
|
|
}
|
|
else if (button == BTN_RIGHT)
|
|
wl->input.mouse.right = true;
|
|
else if (button == BTN_MIDDLE)
|
|
wl->input.mouse.middle = true;
|
|
}
|
|
else
|
|
{
|
|
if (button == BTN_LEFT)
|
|
wl->input.mouse.left = false;
|
|
else if (button == BTN_RIGHT)
|
|
wl->input.mouse.right = false;
|
|
else if (button == BTN_MIDDLE)
|
|
wl->input.mouse.middle = false;
|
|
}
|
|
}
|
|
|
|
static void pointer_handle_axis(void *data,
|
|
struct wl_pointer *wl_pointer,
|
|
uint32_t time,
|
|
uint32_t axis,
|
|
wl_fixed_t value)
|
|
{
|
|
(void)data;
|
|
(void)wl_pointer;
|
|
(void)time;
|
|
(void)axis;
|
|
(void)value;
|
|
}
|
|
|
|
/* TODO: implement check for resize */
|
|
|
|
static void touch_handle_down(void *data,
|
|
struct wl_touch *wl_touch,
|
|
uint32_t serial,
|
|
uint32_t time,
|
|
struct wl_surface *surface,
|
|
int32_t id,
|
|
wl_fixed_t x,
|
|
wl_fixed_t y)
|
|
{
|
|
int i;
|
|
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
|
|
|
|
if (wl->num_active_touches < MAX_TOUCHES)
|
|
{
|
|
for (i = 0; i < MAX_TOUCHES; i++)
|
|
{
|
|
/* Use next empty slot */
|
|
if (!wl->active_touch_positions[i].active)
|
|
{
|
|
wl->active_touch_positions[wl->num_active_touches].active = true;
|
|
wl->active_touch_positions[wl->num_active_touches].id = id;
|
|
wl->active_touch_positions[wl->num_active_touches].x = (unsigned)
|
|
wl_fixed_to_int(x);
|
|
wl->active_touch_positions[wl->num_active_touches].y = (unsigned)
|
|
wl_fixed_to_int(y);
|
|
wl->num_active_touches++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void reorder_touches(gfx_ctx_wayland_data_t *wl)
|
|
{
|
|
int i, j;
|
|
if (wl->num_active_touches == 0)
|
|
return;
|
|
|
|
for (i = 0; i < MAX_TOUCHES; i++)
|
|
{
|
|
if (!wl->active_touch_positions[i].active)
|
|
{
|
|
for (j=i+1; j<MAX_TOUCHES; j++)
|
|
{
|
|
if (wl->active_touch_positions[j].active)
|
|
{
|
|
wl->active_touch_positions[i].active =
|
|
wl->active_touch_positions[j].active;
|
|
wl->active_touch_positions[i].id =
|
|
wl->active_touch_positions[j].id;
|
|
wl->active_touch_positions[i].x = wl->active_touch_positions[j].x;
|
|
wl->active_touch_positions[i].y = wl->active_touch_positions[j].y;
|
|
wl->active_touch_positions[j].active = false;
|
|
wl->active_touch_positions[j].id = -1;
|
|
wl->active_touch_positions[j].x = (unsigned) 0;
|
|
wl->active_touch_positions[j].y = (unsigned) 0;
|
|
break;
|
|
}
|
|
|
|
if (j == MAX_TOUCHES)
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void touch_handle_up(void *data,
|
|
struct wl_touch *wl_touch,
|
|
uint32_t serial,
|
|
uint32_t time,
|
|
int32_t id)
|
|
{
|
|
int i;
|
|
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
|
|
|
|
for (i = 0; i < MAX_TOUCHES; i++)
|
|
{
|
|
if ( wl->active_touch_positions[i].active &&
|
|
wl->active_touch_positions[i].id == id)
|
|
{
|
|
wl->active_touch_positions[i].active = false;
|
|
wl->active_touch_positions[i].id = -1;
|
|
wl->active_touch_positions[i].x = (unsigned)0;
|
|
wl->active_touch_positions[i].y = (unsigned)0;
|
|
wl->num_active_touches--;
|
|
}
|
|
}
|
|
reorder_touches(wl);
|
|
}
|
|
|
|
static void touch_handle_motion(void *data,
|
|
struct wl_touch *wl_touch,
|
|
uint32_t time,
|
|
int32_t id,
|
|
wl_fixed_t x,
|
|
wl_fixed_t y)
|
|
{
|
|
int i;
|
|
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
|
|
|
|
for (i = 0; i < MAX_TOUCHES; i++)
|
|
{
|
|
if ( wl->active_touch_positions[i].active &&
|
|
wl->active_touch_positions[i].id == id)
|
|
{
|
|
wl->active_touch_positions[i].x = (unsigned) wl_fixed_to_int(x);
|
|
wl->active_touch_positions[i].y = (unsigned) wl_fixed_to_int(y);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void touch_handle_frame(void *data,
|
|
struct wl_touch *wl_touch)
|
|
{
|
|
/* TODO */
|
|
}
|
|
|
|
static void touch_handle_cancel(void *data,
|
|
struct wl_touch *wl_touch)
|
|
{
|
|
/* If i understand the spec correctly we have to reset all touches here
|
|
* since they were not ment for us anyway */
|
|
int i;
|
|
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
|
|
|
|
for (i = 0; i < MAX_TOUCHES; i++)
|
|
{
|
|
wl->active_touch_positions[i].active = false;
|
|
wl->active_touch_positions[i].id = -1;
|
|
wl->active_touch_positions[i].x = (unsigned) 0;
|
|
wl->active_touch_positions[i].y = (unsigned) 0;
|
|
}
|
|
|
|
wl->num_active_touches = 0;
|
|
}
|
|
|
|
static void seat_handle_capabilities(void *data,
|
|
struct wl_seat *seat, unsigned caps)
|
|
{
|
|
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
|
|
|
|
if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !wl->wl_keyboard)
|
|
{
|
|
wl->wl_keyboard = wl_seat_get_keyboard(seat);
|
|
wl_keyboard_add_listener(wl->wl_keyboard, &keyboard_listener, wl);
|
|
}
|
|
else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && wl->wl_keyboard)
|
|
{
|
|
wl_keyboard_destroy(wl->wl_keyboard);
|
|
wl->wl_keyboard = NULL;
|
|
}
|
|
if ((caps & WL_SEAT_CAPABILITY_POINTER) && !wl->wl_pointer)
|
|
{
|
|
wl->wl_pointer = wl_seat_get_pointer(seat);
|
|
wl_pointer_add_listener(wl->wl_pointer, &pointer_listener, wl);
|
|
}
|
|
else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && wl->wl_pointer)
|
|
{
|
|
wl_pointer_destroy(wl->wl_pointer);
|
|
wl->wl_pointer = NULL;
|
|
}
|
|
if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !wl->wl_touch)
|
|
{
|
|
wl->wl_touch = wl_seat_get_touch(seat);
|
|
wl_touch_add_listener(wl->wl_touch, &touch_listener, wl);
|
|
}
|
|
else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && wl->wl_touch)
|
|
{
|
|
wl_touch_destroy(wl->wl_touch);
|
|
wl->wl_touch = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
static void seat_handle_name(void *data,
|
|
struct wl_seat *seat, const char *name)
|
|
{
|
|
(void)data;
|
|
(void)seat;
|
|
RARCH_LOG("[Wayland]: Seat name: %s.\n", name);
|
|
}
|
|
|
|
const struct wl_seat_listener seat_listener = {
|
|
seat_handle_capabilities,
|
|
seat_handle_name,
|
|
};
|
|
|
|
const struct wl_touch_listener touch_listener = {
|
|
touch_handle_down,
|
|
touch_handle_up,
|
|
touch_handle_motion,
|
|
touch_handle_frame,
|
|
touch_handle_cancel,
|
|
};
|
|
|
|
const struct wl_keyboard_listener keyboard_listener = {
|
|
keyboard_handle_keymap,
|
|
keyboard_handle_enter,
|
|
keyboard_handle_leave,
|
|
keyboard_handle_key,
|
|
keyboard_handle_modifiers,
|
|
keyboard_handle_repeat_info
|
|
};
|
|
|
|
const struct wl_pointer_listener pointer_listener = {
|
|
pointer_handle_enter,
|
|
pointer_handle_leave,
|
|
pointer_handle_motion,
|
|
pointer_handle_button,
|
|
pointer_handle_axis,
|
|
};
|