mirror of
https://github.com/Relintai/sdl2_frt.git
synced 2024-12-16 11:06:49 +01:00
Implement keyboard repeat in wayland video driver
This commit is contained in:
parent
73010da4dc
commit
f31ad57fde
@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include "SDL_stdinc.h"
|
#include "SDL_stdinc.h"
|
||||||
#include "SDL_assert.h"
|
#include "SDL_assert.h"
|
||||||
|
#include "SDL_timer.h"
|
||||||
|
|
||||||
#include "../../core/unix/SDL_poll.h"
|
#include "../../core/unix/SDL_poll.h"
|
||||||
#include "../../events/SDL_sysevents.h"
|
#include "../../events/SDL_sysevents.h"
|
||||||
@ -57,6 +58,18 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <xkbcommon/xkbcommon.h>
|
#include <xkbcommon/xkbcommon.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
// repeat_rate in range of [1, 1000]
|
||||||
|
int32_t repeat_rate;
|
||||||
|
int32_t repeat_delay;
|
||||||
|
SDL_bool is_initialized;
|
||||||
|
|
||||||
|
SDL_bool is_key_down;
|
||||||
|
uint32_t next_repeat_ms;
|
||||||
|
uint32_t scancode;
|
||||||
|
char text[8];
|
||||||
|
} SDL_WaylandKeyboardRepeat;
|
||||||
|
|
||||||
struct SDL_WaylandInput {
|
struct SDL_WaylandInput {
|
||||||
SDL_VideoData *display;
|
SDL_VideoData *display;
|
||||||
struct wl_seat *seat;
|
struct wl_seat *seat;
|
||||||
@ -90,6 +103,8 @@ struct SDL_WaylandInput {
|
|||||||
SDL_bool is_y_discrete;
|
SDL_bool is_y_discrete;
|
||||||
float y;
|
float y;
|
||||||
} pointer_curr_axis_info;
|
} pointer_curr_axis_info;
|
||||||
|
|
||||||
|
SDL_WaylandKeyboardRepeat keyboard_repeat;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SDL_WaylandTouchPoint {
|
struct SDL_WaylandTouchPoint {
|
||||||
@ -196,14 +211,62 @@ touch_surface(SDL_TouchID id)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returns the time till next repeat, or 0 if no key is down. */
|
||||||
|
static void
|
||||||
|
keyboard_repeat_handle(SDL_WaylandKeyboardRepeat* repeat_info, uint32_t now)
|
||||||
|
{
|
||||||
|
if (!repeat_info->is_key_down || !repeat_info->is_initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (repeat_info->next_repeat_ms <= now) {
|
||||||
|
if (repeat_info->scancode != SDL_SCANCODE_UNKNOWN) {
|
||||||
|
SDL_SendKeyboardKey(SDL_PRESSED, repeat_info->scancode);
|
||||||
|
}
|
||||||
|
if (repeat_info->text[0]) {
|
||||||
|
SDL_SendKeyboardText(repeat_info->text);
|
||||||
|
}
|
||||||
|
repeat_info->next_repeat_ms += 1000 / repeat_info->repeat_rate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
keyboard_repeat_clear(SDL_WaylandKeyboardRepeat* repeat_info) {
|
||||||
|
if (!repeat_info->is_initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
repeat_info->is_key_down = SDL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
keyboard_repeat_set(SDL_WaylandKeyboardRepeat* repeat_info,
|
||||||
|
uint32_t scancode, SDL_bool has_text, char text[8]) {
|
||||||
|
if (!repeat_info->is_initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
repeat_info->is_key_down = SDL_TRUE;
|
||||||
|
repeat_info->next_repeat_ms = SDL_GetTicks() + repeat_info->repeat_delay;
|
||||||
|
repeat_info->scancode = scancode;
|
||||||
|
if (has_text) {
|
||||||
|
memcpy(repeat_info->text, text, 8);
|
||||||
|
} else {
|
||||||
|
repeat_info->text[0] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Wayland_PumpEvents(_THIS)
|
Wayland_PumpEvents(_THIS)
|
||||||
{
|
{
|
||||||
SDL_VideoData *d = _this->driverdata;
|
SDL_VideoData *d = _this->driverdata;
|
||||||
|
struct SDL_WaylandInput *input = d->input;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
WAYLAND_wl_display_flush(d->display);
|
WAYLAND_wl_display_flush(d->display);
|
||||||
|
|
||||||
|
if (input) {
|
||||||
|
uint32_t now = SDL_GetTicks();
|
||||||
|
keyboard_repeat_handle(&input->keyboard_repeat, now);
|
||||||
|
}
|
||||||
|
|
||||||
if (SDL_IOReady(WAYLAND_wl_display_get_fd(d->display), SDL_FALSE, 0)) {
|
if (SDL_IOReady(WAYLAND_wl_display_get_fd(d->display), SDL_FALSE, 0)) {
|
||||||
err = WAYLAND_wl_display_dispatch(d->display);
|
err = WAYLAND_wl_display_dispatch(d->display);
|
||||||
} else {
|
} else {
|
||||||
@ -365,8 +428,8 @@ pointer_handle_button_common(struct SDL_WaylandInput *input, uint32_t serial,
|
|||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Wayland_data_device_set_serial(input->data_device, serial);
|
Wayland_data_device_set_serial(input->data_device, serial);
|
||||||
|
|
||||||
SDL_SendMouseButton(window->sdlwindow, 0,
|
SDL_SendMouseButton(window->sdlwindow, 0,
|
||||||
state ? SDL_PRESSED : SDL_RELEASED, sdl_button);
|
state ? SDL_PRESSED : SDL_RELEASED, sdl_button);
|
||||||
@ -651,45 +714,53 @@ keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
|
|||||||
SDL_SetKeyboardFocus(NULL);
|
SDL_SetKeyboardFocus(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SDL_bool
|
||||||
|
keyboard_input_get_text(char text[8], const struct SDL_WaylandInput *input, uint32_t key)
|
||||||
|
{
|
||||||
|
SDL_WindowData *window = input->keyboard_focus;
|
||||||
|
const xkb_keysym_t *syms;
|
||||||
|
|
||||||
|
if (!window || window->keyboard_device != input || !input->xkb.state) {
|
||||||
|
return SDL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO can this happen?
|
||||||
|
if (WAYLAND_xkb_state_key_get_syms(input->xkb.state, key + 8, &syms) != 1) {
|
||||||
|
return SDL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return WAYLAND_xkb_keysym_to_utf8(syms[0], text, 8) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
|
keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
|
||||||
uint32_t serial, uint32_t time, uint32_t key,
|
uint32_t serial, uint32_t time, uint32_t key,
|
||||||
uint32_t state_w)
|
uint32_t state_w)
|
||||||
{
|
{
|
||||||
struct SDL_WaylandInput *input = data;
|
struct SDL_WaylandInput *input = data;
|
||||||
SDL_WindowData *window = input->keyboard_focus;
|
|
||||||
enum wl_keyboard_key_state state = state_w;
|
enum wl_keyboard_key_state state = state_w;
|
||||||
const xkb_keysym_t *syms;
|
uint32_t scancode = SDL_SCANCODE_UNKNOWN;
|
||||||
uint32_t scancode;
|
|
||||||
char text[8];
|
char text[8];
|
||||||
int size;
|
|
||||||
|
|
||||||
if (key < SDL_arraysize(xfree86_scancode_table2)) {
|
if (key < SDL_arraysize(xfree86_scancode_table2)) {
|
||||||
scancode = xfree86_scancode_table2[key];
|
scancode = xfree86_scancode_table2[key];
|
||||||
|
|
||||||
// TODO when do we get WL_KEYBOARD_KEY_STATE_REPEAT?
|
if (scancode != SDL_SCANCODE_UNKNOWN) {
|
||||||
if (scancode != SDL_SCANCODE_UNKNOWN)
|
|
||||||
SDL_SendKeyboardKey(state == WL_KEYBOARD_KEY_STATE_PRESSED ?
|
SDL_SendKeyboardKey(state == WL_KEYBOARD_KEY_STATE_PRESSED ?
|
||||||
SDL_PRESSED : SDL_RELEASED, scancode);
|
SDL_PRESSED : SDL_RELEASED, scancode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!window || window->keyboard_device != input || !input->xkb.state)
|
if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||||
return;
|
SDL_bool has_text = keyboard_input_get_text(text, input, key);
|
||||||
|
if (has_text) {
|
||||||
// TODO can this happen?
|
|
||||||
if (WAYLAND_xkb_state_key_get_syms(input->xkb.state, key + 8, &syms) != 1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (state) {
|
|
||||||
size = WAYLAND_xkb_keysym_to_utf8(syms[0], text, sizeof text);
|
|
||||||
|
|
||||||
if (size > 0) {
|
|
||||||
text[size] = 0;
|
|
||||||
|
|
||||||
Wayland_data_device_set_serial(input->data_device, serial);
|
Wayland_data_device_set_serial(input->data_device, serial);
|
||||||
|
SDL_Log("handle_key: posting: %s", text);
|
||||||
SDL_SendKeyboardText(text);
|
SDL_SendKeyboardText(text);
|
||||||
}
|
}
|
||||||
|
keyboard_repeat_set(&input->keyboard_repeat, scancode, has_text, text);
|
||||||
|
} else {
|
||||||
|
keyboard_repeat_clear(&input->keyboard_repeat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -709,7 +780,10 @@ static void
|
|||||||
keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keyboard,
|
keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keyboard,
|
||||||
int32_t rate, int32_t delay)
|
int32_t rate, int32_t delay)
|
||||||
{
|
{
|
||||||
/* unimplemented */
|
struct SDL_WaylandInput *input = data;
|
||||||
|
input->keyboard_repeat.repeat_rate = SDL_max(0, SDL_min(rate, 1000));
|
||||||
|
input->keyboard_repeat.repeat_delay = delay;
|
||||||
|
input->keyboard_repeat.is_initialized = SDL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct wl_keyboard_listener keyboard_listener = {
|
static const struct wl_keyboard_listener keyboard_listener = {
|
||||||
@ -786,13 +860,13 @@ data_source_handle_send(void *data, struct wl_data_source *wl_data_source,
|
|||||||
{
|
{
|
||||||
Wayland_data_source_send((SDL_WaylandDataSource *)data, mime_type, fd);
|
Wayland_data_source_send((SDL_WaylandDataSource *)data, mime_type, fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
data_source_handle_cancelled(void *data, struct wl_data_source *wl_data_source)
|
data_source_handle_cancelled(void *data, struct wl_data_source *wl_data_source)
|
||||||
{
|
{
|
||||||
Wayland_data_source_destroy(data);
|
Wayland_data_source_destroy(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
data_source_handle_dnd_drop_performed(void *data, struct wl_data_source *wl_data_source)
|
data_source_handle_dnd_drop_performed(void *data, struct wl_data_source *wl_data_source)
|
||||||
{
|
{
|
||||||
@ -835,7 +909,7 @@ Wayland_data_source_create(_THIS)
|
|||||||
driver_data->data_device_manager);
|
driver_data->data_device_manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (id == NULL) {
|
if (id == NULL) {
|
||||||
SDL_SetError("Wayland unable to create data source");
|
SDL_SetError("Wayland unable to create data source");
|
||||||
} else {
|
} else {
|
||||||
data_source = SDL_calloc(1, sizeof *data_source);
|
data_source = SDL_calloc(1, sizeof *data_source);
|
||||||
@ -905,8 +979,8 @@ data_device_handle_enter(void *data, struct wl_data_device *wl_data_device,
|
|||||||
{
|
{
|
||||||
SDL_WaylandDataDevice *data_device = data;
|
SDL_WaylandDataDevice *data_device = data;
|
||||||
SDL_bool has_mime = SDL_FALSE;
|
SDL_bool has_mime = SDL_FALSE;
|
||||||
uint32_t dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
|
uint32_t dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
|
||||||
|
|
||||||
data_device->drag_serial = serial;
|
data_device->drag_serial = serial;
|
||||||
|
|
||||||
if (id != NULL) {
|
if (id != NULL) {
|
||||||
@ -959,7 +1033,7 @@ data_device_handle_drop(void *data, struct wl_data_device *wl_data_device)
|
|||||||
const char *current_uri = NULL;
|
const char *current_uri = NULL;
|
||||||
const char *last_char = NULL;
|
const char *last_char = NULL;
|
||||||
char *current_char = NULL;
|
char *current_char = NULL;
|
||||||
|
|
||||||
if (data_device->drag_offer != NULL) {
|
if (data_device->drag_offer != NULL) {
|
||||||
/* TODO: SDL Support more mime types */
|
/* TODO: SDL Support more mime types */
|
||||||
buffer = Wayland_data_offer_receive(data_device->drag_offer,
|
buffer = Wayland_data_offer_receive(data_device->drag_offer,
|
||||||
@ -985,7 +1059,7 @@ data_device_handle_drop(void *data, struct wl_data_device *wl_data_device)
|
|||||||
static void
|
static void
|
||||||
data_device_handle_selection(void *data, struct wl_data_device *wl_data_device,
|
data_device_handle_selection(void *data, struct wl_data_device *wl_data_device,
|
||||||
struct wl_data_offer *id)
|
struct wl_data_offer *id)
|
||||||
{
|
{
|
||||||
SDL_WaylandDataDevice *data_device = data;
|
SDL_WaylandDataDevice *data_device = data;
|
||||||
SDL_WaylandDataOffer *offer = NULL;
|
SDL_WaylandDataOffer *offer = NULL;
|
||||||
|
|
||||||
@ -1025,7 +1099,7 @@ Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version)
|
|||||||
input->sx_w = wl_fixed_from_int(0);
|
input->sx_w = wl_fixed_from_int(0);
|
||||||
input->sy_w = wl_fixed_from_int(0);
|
input->sy_w = wl_fixed_from_int(0);
|
||||||
d->input = input;
|
d->input = input;
|
||||||
|
|
||||||
if (d->data_device_manager != NULL) {
|
if (d->data_device_manager != NULL) {
|
||||||
data_device = SDL_calloc(1, sizeof *data_device);
|
data_device = SDL_calloc(1, sizeof *data_device);
|
||||||
if (data_device == NULL) {
|
if (data_device == NULL) {
|
||||||
|
Loading…
Reference in New Issue
Block a user