mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-10-02 07:58:30 +00:00
wayland: Add support for text-input-unstable-v3
This commit is contained in:
@@ -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);
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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: */
|
||||
|
@@ -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_ */
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user