wayland: Add support for text-input-unstable-v3

This commit is contained in:
Ethan Lee
2021-07-29 13:27:31 -04:00
committed by Sam Lantinga
parent e4411505ab
commit 74162b7401
7 changed files with 690 additions and 11 deletions

View File

@@ -41,6 +41,7 @@
#include "relative-pointer-unstable-v1-client-protocol.h"
#include "xdg-shell-client-protocol.h"
#include "keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h"
#include "text-input-unstable-v3-client-protocol.h"
#ifdef HAVE_LIBDECOR_H
#include <libdecor.h>
@@ -221,7 +222,7 @@ 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 == NULL && SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE) {
SDL_IME_PumpEvents();
}
#endif
@@ -741,7 +742,9 @@ keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
SDL_SetKeyboardFocus(window->sdlwindow);
}
#ifdef SDL_USE_IME
SDL_IME_SetFocus(SDL_TRUE);
if (!input->text_input) {
SDL_IME_SetFocus(SDL_TRUE);
}
#endif
}
@@ -760,8 +763,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->text_input) {
SDL_IME_SetFocus(SDL_FALSE);
}
#endif
}
@@ -1224,6 +1230,93 @@ 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)
{
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);
}
}
static void
text_input_commit_string(void *data,
struct zwp_text_input_v3 *zwp_text_input_v3,
const char *text)
{
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;
}
}
}
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)
{
/* FIXME: Do we care about this event? */
}
static void
text_input_done(void *data,
struct zwp_text_input_v3 *zwp_text_input_v3,
uint32_t serial)
{
/* No-op */
}
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)
{
@@ -1249,6 +1342,30 @@ 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
);
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)
{
@@ -1259,6 +1376,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)
{
@@ -1277,6 +1404,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);
@@ -1305,6 +1435,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);

View File

@@ -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]
@@ -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;
@@ -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);

View File

@@ -24,12 +24,17 @@
#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)
{
#ifdef SDL_USE_IME
SDL_IME_Init();
SDL_VideoData *driverdata = _this->driverdata;
if (driverdata->text_input_manager == NULL) {
SDL_IME_Init();
}
#endif
return 0;
@@ -39,37 +44,106 @@ void
Wayland_QuitKeyboard(_THIS)
{
#ifdef SDL_USE_IME
SDL_IME_Quit();
SDL_VideoData *driverdata = _this->driverdata;
if (driverdata->text_input_manager == NULL) {
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
}
SDL_bool
Wayland_HasScreenKeyboardSupport(_THIS)
{
SDL_VideoData *driverdata = _this->driverdata;
return (driverdata->text_input_manager != NULL);
}
#endif /* SDL_VIDEO_DRIVER_WAYLAND */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -23,11 +23,18 @@
#ifndef SDL_waylandkeyboard_h_
#define SDL_waylandkeyboard_h_
typedef struct SDL_WaylandTextInput
{
struct zwp_text_input_v3 *text_input;
SDL_Rect cursor_rect;
} SDL_WaylandTextInput;
extern int Wayland_InitKeyboard(_THIS);
extern void Wayland_QuitKeyboard(_THIS);
extern void Wayland_StartTextInput(_THIS);
extern void Wayland_StopTextInput(_THIS);
extern void Wayland_SetTextInputRect(_THIS, SDL_Rect *rect);
extern SDL_bool Wayland_HasScreenKeyboardSupport(_THIS);
#endif /* SDL_waylandkeyboard_h_ */

View File

@@ -51,6 +51,7 @@
#include "keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h"
#include "idle-inhibit-unstable-v1-client-protocol.h"
#include "xdg-activation-v1-client-protocol.h"
#include "text-input-unstable-v3-client-protocol.h"
#ifdef HAVE_LIBDECOR_H
#include <libdecor.h>
@@ -253,6 +254,7 @@ Wayland_CreateDevice(int devindex)
device->DestroyWindow = Wayland_DestroyWindow;
device->SetWindowHitTest = Wayland_SetWindowHitTest;
device->FlashWindow = Wayland_FlashWindow;
device->HasScreenKeyboardSupport = Wayland_HasScreenKeyboardSupport;
device->SetClipboardText = Wayland_SetClipboardText;
device->GetClipboardText = Wayland_GetClipboardText;
@@ -507,6 +509,8 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
d->idle_inhibit_manager = wl_registry_bind(d->registry, id, &zwp_idle_inhibit_manager_v1_interface, 1);
} else if (SDL_strcmp(interface, "xdg_activation_v1") == 0) {
d->activation_manager = wl_registry_bind(d->registry, id, &xdg_activation_v1_interface, 1);
} else if (strcmp(interface, "zwp_text_input_manager_v3") == 0) {
Wayland_add_text_input_manager(d, id, version);
} else if (SDL_strcmp(interface, "wl_data_device_manager") == 0) {
Wayland_add_data_device_manager(d, id, version);
} else if (SDL_strcmp(interface, "zxdg_decoration_manager_v1") == 0) {
@@ -642,6 +646,11 @@ Wayland_VideoQuit(_THIS)
if (data->key_inhibitor_manager)
zwp_keyboard_shortcuts_inhibit_manager_v1_destroy(data->key_inhibitor_manager);
Wayland_QuitKeyboard(_this);
if (data->text_input_manager)
zwp_text_input_manager_v3_destroy(data->text_input_manager);
if (data->xkb_context) {
WAYLAND_xkb_context_unref(data->xkb_context);
data->xkb_context = NULL;
@@ -684,8 +693,6 @@ Wayland_VideoQuit(_THIS)
if (data->registry)
wl_registry_destroy(data->registry);
Wayland_QuitKeyboard(_this);
SDL_free(data->classname);
}

View File

@@ -62,6 +62,7 @@ typedef struct {
struct zwp_keyboard_shortcuts_inhibit_manager_v1 *key_inhibitor_manager;
struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager;
struct xdg_activation_v1 *activation_manager;
struct zwp_text_input_manager_v3 *text_input_manager;
EGLDisplay edpy;
EGLContext context;