Skip to content

Commit

Permalink
wayland: Add support for text-input-unstable-v3
Browse files Browse the repository at this point in the history
  • Loading branch information
flibitijibibo committed Jun 3, 2021
1 parent 2af3f64 commit 41b9ca9
Show file tree
Hide file tree
Showing 7 changed files with 696 additions and 11 deletions.
154 changes: 151 additions & 3 deletions src/video/wayland/SDL_waylandevents.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include "xdg-shell-client-protocol.h"
#include "xdg-shell-unstable-v6-client-protocol.h"
#include "keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h"
#include "text-input-unstable-v3-client-protocol.h"

#ifdef SDL_INPUT_LINUXEV
#include <linux/input.h>
Expand Down Expand Up @@ -218,14 +219,17 @@ Wayland_PumpEvents(_THIS)
WAYLAND_wl_display_flush(d->display);

#ifdef SDL_USE_IME
if (SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE) {
if (!d->text_input_manager && SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE) {
SDL_IME_PumpEvents();
}
#endif

if (input) {
uint32_t now = SDL_GetTicks();
keyboard_repeat_handle(&input->keyboard_repeat, now);
if (input->text_input != NULL) {
input->text_input->got_text = SDL_FALSE;
}
}

if (SDL_IOReady(WAYLAND_wl_display_get_fd(d->display), SDL_FALSE, 0)) {
Expand Down Expand Up @@ -730,8 +734,11 @@ keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
window->keyboard_device = input;
SDL_SetKeyboardFocus(window->sdlwindow);
}

#ifdef SDL_USE_IME
SDL_IME_SetFocus(SDL_TRUE);
if (!input->display->text_input_manager) {
SDL_IME_SetFocus(SDL_TRUE);
}
#endif
}

Expand All @@ -746,8 +753,11 @@ keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,

/* This will release any keys still pressed */
SDL_SetKeyboardFocus(NULL);

#ifdef SDL_USE_IME
SDL_IME_SetFocus(SDL_FALSE);
if (!input->display->text_input_manager) {
SDL_IME_SetFocus(SDL_FALSE);
}
#endif
}

Expand All @@ -762,6 +772,10 @@ keyboard_input_get_text(char text[8], const struct SDL_WaylandInput *input, uint
return SDL_FALSE;
}

if (input->text_input) {
return input->text_input->got_text;
}

// TODO can this happen?
if (WAYLAND_xkb_state_key_get_syms(input->xkb.state, key + 8, &syms) != 1) {
return SDL_FALSE;
Expand Down Expand Up @@ -1210,6 +1224,97 @@ static const struct wl_data_device_listener data_device_listener = {
data_device_handle_selection
};

static void
text_input_enter(void *data,
struct zwp_text_input_v3 *zwp_text_input_v3,
struct wl_surface *surface)
{
/* No-op */
}

static void
text_input_leave(void *data,
struct zwp_text_input_v3 *zwp_text_input_v3,
struct wl_surface *surface)
{
/* No-op */
}

static void
text_input_preedit_string(void *data,
struct zwp_text_input_v3 *zwp_text_input_v3,
const char *text,
int32_t cursor_begin,
int32_t cursor_end)
{
struct SDL_WaylandTextInput *text_input = data;
char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
if (text) {
size_t text_bytes = SDL_strlen(text), i = 0;
size_t cursor = 0;

do {
const size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
const size_t chars = SDL_utf8strlen(buf);

SDL_SendEditingText(buf, cursor, chars);

i += sz;
cursor += chars;
} while (i < text_bytes);
} else {
buf[0] = '\0';
SDL_SendEditingText(buf, 0, 0);
}
text_input->got_text = SDL_TRUE;
}

static void
text_input_commit_string(void *data,
struct zwp_text_input_v3 *zwp_text_input_v3,
const char *text)
{
struct SDL_WaylandTextInput *text_input = data;
if (text && *text) {
char buf[SDL_TEXTINPUTEVENT_TEXT_SIZE];
size_t text_bytes = SDL_strlen(text), i = 0;

while (i < text_bytes) {
size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
SDL_SendKeyboardText(buf);

i += sz;
}
text_input->got_text = SDL_TRUE;
}
}

static void
text_input_delete_surrounding_text(void *data,
struct zwp_text_input_v3 *zwp_text_input_v3,
uint32_t before_length,
uint32_t after_length)
{
printf("Text input delete: %d %d\n", before_length, after_length);
}

static void
text_input_done(void *data,
struct zwp_text_input_v3 *zwp_text_input_v3,
uint32_t serial)
{
printf("Text input done! Serial: %d\n", serial);
}

static const struct zwp_text_input_v3_listener text_input_listener = {
text_input_enter,
text_input_leave,
text_input_preedit_string,
text_input_commit_string,
text_input_delete_surrounding_text,
text_input_done
};

static void
Wayland_create_data_device(SDL_VideoData *d)
{
Expand All @@ -1235,6 +1340,31 @@ Wayland_create_data_device(SDL_VideoData *d)
}
}

static void
Wayland_create_text_input(SDL_VideoData *d)
{
SDL_WaylandTextInput *text_input = NULL;

text_input = SDL_calloc(1, sizeof *text_input);
if (text_input == NULL) {
return;
}

text_input->text_input = zwp_text_input_manager_v3_get_text_input(
d->text_input_manager, d->input->seat
);
text_input->video_data = d;

if (text_input->text_input == NULL) {
SDL_free(text_input);
} else {
zwp_text_input_v3_set_user_data(text_input->text_input, text_input);
zwp_text_input_v3_add_listener(text_input->text_input,
&text_input_listener, text_input);
d->input->text_input = text_input;
}
}

void
Wayland_add_data_device_manager(SDL_VideoData *d, uint32_t id, uint32_t version)
{
Expand All @@ -1245,6 +1375,16 @@ Wayland_add_data_device_manager(SDL_VideoData *d, uint32_t id, uint32_t version)
}
}

void
Wayland_add_text_input_manager(SDL_VideoData *d, uint32_t id, uint32_t version)
{
d->text_input_manager = wl_registry_bind(d->registry, id, &zwp_text_input_manager_v3_interface, 1);

if (d->input != NULL) {
Wayland_create_text_input(d);
}
}

void
Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version)
{
Expand All @@ -1263,6 +1403,9 @@ Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version)
if (d->data_device_manager != NULL) {
Wayland_create_data_device(d);
}
if (d->text_input_manager != NULL) {
Wayland_create_text_input(d);
}

wl_seat_add_listener(input->seat, &seat_listener, input);
wl_seat_set_user_data(input->seat, input);
Expand Down Expand Up @@ -1291,6 +1434,11 @@ void Wayland_display_destroy_input(SDL_VideoData *d)
SDL_free(input->data_device);
}

if (input->text_input != NULL) {
zwp_text_input_v3_destroy(input->text_input->text_input);
SDL_free(input->text_input);
}

if (input->keyboard)
wl_keyboard_destroy(input->keyboard);

Expand Down
3 changes: 3 additions & 0 deletions src/video/wayland/SDL_waylandevents_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "SDL_waylandvideo.h"
#include "SDL_waylandwindow.h"
#include "SDL_waylanddatamanager.h"
#include "SDL_waylandkeyboard.h"

typedef struct {
// repeat_rate in range of [1, 1000]
Expand All @@ -47,6 +48,7 @@ struct SDL_WaylandInput {
struct wl_touch *touch;
struct wl_keyboard *keyboard;
SDL_WaylandDataDevice *data_device;
SDL_WaylandTextInput *text_input;
struct zwp_relative_pointer_v1 *relative_pointer;
struct zwp_confined_pointer_v1 *confined_pointer;
SDL_Window *confined_pointer_window;
Expand Down Expand Up @@ -83,6 +85,7 @@ struct SDL_WaylandInput {
extern void Wayland_PumpEvents(_THIS);

extern void Wayland_add_data_device_manager(SDL_VideoData *d, uint32_t id, uint32_t version);
extern void Wayland_add_text_input_manager(SDL_VideoData *d, uint32_t id, uint32_t version);

extern void Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version);
extern void Wayland_display_destroy_input(SDL_VideoData *d);
Expand Down
79 changes: 73 additions & 6 deletions src/video/wayland/SDL_waylandkeyboard.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,18 @@

#include "../SDL_sysvideo.h"
#include "SDL_waylandvideo.h"
#include "SDL_waylandevents_c.h"
#include "text-input-unstable-v3-client-protocol.h"

int
Wayland_InitKeyboard(_THIS)
{
SDL_VideoData *driverdata = _this->driverdata;

#ifdef SDL_USE_IME
SDL_IME_Init();
if (!driverdata->text_input_manager) {
SDL_IME_Init();
}
#endif

return 0;
Expand All @@ -38,35 +44,96 @@ Wayland_InitKeyboard(_THIS)
void
Wayland_QuitKeyboard(_THIS)
{
SDL_VideoData *driverdata = _this->driverdata;

#ifdef SDL_USE_IME
SDL_IME_Quit();
if (!driverdata->text_input_manager) {
SDL_IME_Quit();
}
#endif
}

void
Wayland_StartTextInput(_THIS)
{
/* No-op */
SDL_VideoData *driverdata = _this->driverdata;

if (driverdata->text_input_manager) {
struct SDL_WaylandInput *input = driverdata->input;
if (input != NULL && input->text_input) {
const SDL_Rect *rect = &input->text_input->cursor_rect;

/* For some reason this has to be done twice, it appears to be a
* bug in mutter? Maybe?
* -flibit
*/
zwp_text_input_v3_enable(input->text_input->text_input);
zwp_text_input_v3_commit(input->text_input->text_input);
zwp_text_input_v3_enable(input->text_input->text_input);
zwp_text_input_v3_commit(input->text_input->text_input);

/* Now that it's enabled, set the input properties */
zwp_text_input_v3_set_content_type(input->text_input->text_input,
ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE,
ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NORMAL);
if (!SDL_RectEmpty(rect)) {
/* This gets reset on enable so we have to cache it */
zwp_text_input_v3_set_cursor_rectangle(input->text_input->text_input,
rect->x,
rect->y,
rect->w,
rect->h);
}
zwp_text_input_v3_commit(input->text_input->text_input);
}
}
}

void
Wayland_StopTextInput(_THIS)
{
SDL_VideoData *driverdata = _this->driverdata;

if (driverdata->text_input_manager) {
struct SDL_WaylandInput *input = driverdata->input;
if (input != NULL && input->text_input) {
zwp_text_input_v3_disable(input->text_input->text_input);
zwp_text_input_v3_commit(input->text_input->text_input);
}
}
#ifdef SDL_USE_IME
SDL_IME_Reset();
else {
SDL_IME_Reset();
}
#endif
}

void
Wayland_SetTextInputRect(_THIS, SDL_Rect *rect)
{
SDL_VideoData *driverdata = _this->driverdata;

if (!rect) {
SDL_InvalidParamError("rect");
return;
}


if (driverdata->text_input_manager) {
struct SDL_WaylandInput *input = driverdata->input;
if (input != NULL && input->text_input) {
SDL_memcpy(&input->text_input->cursor_rect, rect, sizeof(SDL_Rect));
zwp_text_input_v3_set_cursor_rectangle(input->text_input->text_input,
rect->x,
rect->y,
rect->w,
rect->h);
zwp_text_input_v3_commit(input->text_input->text_input);
}
}
#ifdef SDL_USE_IME
SDL_IME_UpdateTextRect(rect);
else {
SDL_IME_UpdateTextRect(rect);
}
#endif
}

Expand Down
8 changes: 8 additions & 0 deletions src/video/wayland/SDL_waylandkeyboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@
#ifndef SDL_waylandkeyboard_h_
#define SDL_waylandkeyboard_h_

typedef struct SDL_WaylandTextInput
{
struct zwp_text_input_v3 *text_input;
SDL_bool got_text;
SDL_Rect cursor_rect;
SDL_VideoData *video_data;
} SDL_WaylandTextInput;

extern int Wayland_InitKeyboard(_THIS);
extern void Wayland_QuitKeyboard(_THIS);
extern void Wayland_StartTextInput(_THIS);
Expand Down
Loading

0 comments on commit 41b9ca9

Please sign in to comment.