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_assert.h"
|
||||
#include "SDL_timer.h"
|
||||
|
||||
#include "../../core/unix/SDL_poll.h"
|
||||
#include "../../events/SDL_sysevents.h"
|
||||
@ -57,6 +58,18 @@
|
||||
#include <unistd.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 {
|
||||
SDL_VideoData *display;
|
||||
struct wl_seat *seat;
|
||||
@ -90,6 +103,8 @@ struct SDL_WaylandInput {
|
||||
SDL_bool is_y_discrete;
|
||||
float y;
|
||||
} pointer_curr_axis_info;
|
||||
|
||||
SDL_WaylandKeyboardRepeat keyboard_repeat;
|
||||
};
|
||||
|
||||
struct SDL_WaylandTouchPoint {
|
||||
@ -196,14 +211,62 @@ touch_surface(SDL_TouchID id)
|
||||
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
|
||||
Wayland_PumpEvents(_THIS)
|
||||
{
|
||||
SDL_VideoData *d = _this->driverdata;
|
||||
struct SDL_WaylandInput *input = d->input;
|
||||
int err;
|
||||
|
||||
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)) {
|
||||
err = WAYLAND_wl_display_dispatch(d->display);
|
||||
} else {
|
||||
@ -365,8 +428,8 @@ pointer_handle_button_common(struct SDL_WaylandInput *input, uint32_t serial,
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
Wayland_data_device_set_serial(input->data_device, serial);
|
||||
|
||||
Wayland_data_device_set_serial(input->data_device, serial);
|
||||
|
||||
SDL_SendMouseButton(window->sdlwindow, 0,
|
||||
state ? SDL_PRESSED : SDL_RELEASED, sdl_button);
|
||||
@ -651,45 +714,53 @@ keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
|
||||
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
|
||||
keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
|
||||
uint32_t serial, uint32_t time, uint32_t key,
|
||||
uint32_t state_w)
|
||||
{
|
||||
struct SDL_WaylandInput *input = data;
|
||||
SDL_WindowData *window = input->keyboard_focus;
|
||||
enum wl_keyboard_key_state state = state_w;
|
||||
const xkb_keysym_t *syms;
|
||||
uint32_t scancode;
|
||||
uint32_t scancode = SDL_SCANCODE_UNKNOWN;
|
||||
char text[8];
|
||||
int size;
|
||||
|
||||
if (key < SDL_arraysize(xfree86_scancode_table2)) {
|
||||
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_PRESSED : SDL_RELEASED, scancode);
|
||||
}
|
||||
}
|
||||
|
||||
if (!window || window->keyboard_device != input || !input->xkb.state)
|
||||
return;
|
||||
|
||||
// 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;
|
||||
|
||||
if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||
SDL_bool has_text = keyboard_input_get_text(text, input, key);
|
||||
if (has_text) {
|
||||
Wayland_data_device_set_serial(input->data_device, serial);
|
||||
|
||||
SDL_Log("handle_key: posting: %s", 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,
|
||||
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 = {
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
data_source_handle_cancelled(void *data, struct wl_data_source *wl_data_source)
|
||||
{
|
||||
Wayland_data_source_destroy(data);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
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);
|
||||
}
|
||||
|
||||
if (id == NULL) {
|
||||
if (id == NULL) {
|
||||
SDL_SetError("Wayland unable to create data source");
|
||||
} else {
|
||||
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_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;
|
||||
|
||||
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 *last_char = NULL;
|
||||
char *current_char = NULL;
|
||||
|
||||
|
||||
if (data_device->drag_offer != NULL) {
|
||||
/* TODO: SDL Support more mime types */
|
||||
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
|
||||
data_device_handle_selection(void *data, struct wl_data_device *wl_data_device,
|
||||
struct wl_data_offer *id)
|
||||
{
|
||||
{
|
||||
SDL_WaylandDataDevice *data_device = data;
|
||||
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->sy_w = wl_fixed_from_int(0);
|
||||
d->input = input;
|
||||
|
||||
|
||||
if (d->data_device_manager != NULL) {
|
||||
data_device = SDL_calloc(1, sizeof *data_device);
|
||||
if (data_device == NULL) {
|
||||
|
Loading…
Reference in New Issue
Block a user