[Wayland] Implement IME support.
This commit is contained in:
@ -448,6 +448,12 @@ void WaylandThread::_wl_registry_on_global(void *data, struct wl_registry *wl_re
|
||||
zwp_tablet_seat_v2_add_listener(ss->wp_tablet_seat, &wp_tablet_seat_listener, ss);
|
||||
}
|
||||
|
||||
if (!ss->wp_text_input && registry->wp_text_input_manager) {
|
||||
// IME.
|
||||
ss->wp_text_input = zwp_text_input_manager_v3_get_text_input(registry->wp_text_input_manager, wl_seat);
|
||||
zwp_text_input_v3_add_listener(ss->wp_text_input, &wp_text_input_listener, ss);
|
||||
}
|
||||
|
||||
registry->wl_seats.push_back(wl_seat);
|
||||
|
||||
wl_seat_add_listener(wl_seat, &wl_seat_listener, ss);
|
||||
@ -547,6 +553,22 @@ void WaylandThread::_wl_registry_on_global(void *data, struct wl_registry *wl_re
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(interface, zwp_text_input_manager_v3_interface.name) == 0) {
|
||||
registry->wp_text_input_manager = (struct zwp_text_input_manager_v3 *)wl_registry_bind(wl_registry, name, &zwp_text_input_manager_v3_interface, 1);
|
||||
registry->wp_text_input_manager_name = name;
|
||||
|
||||
// This global creates some seat data. Let's do that for the ones already available.
|
||||
for (struct wl_seat *wl_seat : registry->wl_seats) {
|
||||
SeatState *ss = wl_seat_get_seat_state(wl_seat);
|
||||
ERR_FAIL_NULL(ss);
|
||||
|
||||
ss->wp_text_input = zwp_text_input_manager_v3_get_text_input(registry->wp_text_input_manager, wl_seat);
|
||||
zwp_text_input_v3_add_listener(ss->wp_text_input, &wp_text_input_listener, ss);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void WaylandThread::_wl_registry_on_global_remove(void *data, struct wl_registry *wl_registry, uint32_t name) {
|
||||
@ -825,6 +847,25 @@ void WaylandThread::_wl_registry_on_global_remove(void *data, struct wl_registry
|
||||
return;
|
||||
}
|
||||
|
||||
if (name == registry->wp_text_input_manager_name) {
|
||||
if (registry->wp_text_input_manager) {
|
||||
zwp_text_input_manager_v3_destroy(registry->wp_text_input_manager);
|
||||
registry->wp_text_input_manager = nullptr;
|
||||
}
|
||||
|
||||
registry->wp_text_input_manager_name = 0;
|
||||
|
||||
for (struct wl_seat *wl_seat : registry->wl_seats) {
|
||||
SeatState *ss = wl_seat_get_seat_state(wl_seat);
|
||||
ERR_FAIL_NULL(ss);
|
||||
|
||||
zwp_text_input_v3_destroy(ss->wp_text_input);
|
||||
ss->wp_text_input = nullptr;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
// Iterate through all of the seats to find if any got removed.
|
||||
List<struct wl_seat *>::Element *E = registry->wl_seats.front();
|
||||
@ -2535,6 +2576,118 @@ void WaylandThread::_wp_tablet_tool_on_frame(void *data, struct zwp_tablet_tool_
|
||||
old_td = td;
|
||||
}
|
||||
|
||||
void WaylandThread::_wp_text_input_on_enter(void *data, struct zwp_text_input_v3 *wp_text_input_v3, struct wl_surface *surface) {
|
||||
SeatState *ss = (SeatState *)data;
|
||||
if (!ss) {
|
||||
return;
|
||||
}
|
||||
|
||||
ss->ime_enabled = true;
|
||||
}
|
||||
|
||||
void WaylandThread::_wp_text_input_on_leave(void *data, struct zwp_text_input_v3 *wp_text_input_v3, struct wl_surface *surface) {
|
||||
SeatState *ss = (SeatState *)data;
|
||||
if (!ss) {
|
||||
return;
|
||||
}
|
||||
|
||||
ss->ime_enabled = false;
|
||||
ss->ime_active = false;
|
||||
ss->ime_text = String();
|
||||
ss->ime_text_commit = String();
|
||||
ss->ime_cursor = Vector2i();
|
||||
|
||||
Ref<IMEUpdateEventMessage> msg;
|
||||
msg.instantiate();
|
||||
msg->text = String();
|
||||
msg->selection = Vector2i();
|
||||
ss->wayland_thread->push_message(msg);
|
||||
}
|
||||
|
||||
void WaylandThread::_wp_text_input_on_preedit_string(void *data, struct zwp_text_input_v3 *wp_text_input_v3, const char *text, int32_t cursor_begin, int32_t cursor_end) {
|
||||
SeatState *ss = (SeatState *)data;
|
||||
if (!ss) {
|
||||
return;
|
||||
}
|
||||
|
||||
ss->ime_text = String::utf8(text);
|
||||
|
||||
// Convert cursor positions from UTF-8 to UTF-32 offset.
|
||||
int32_t cursor_begin_utf32 = 0;
|
||||
int32_t cursor_end_utf32 = 0;
|
||||
for (int i = 0; i < ss->ime_text.length(); i++) {
|
||||
uint32_t c = ss->ime_text[i];
|
||||
if (c <= 0x7f) { // 7 bits.
|
||||
cursor_begin -= 1;
|
||||
cursor_end -= 1;
|
||||
} else if (c <= 0x7ff) { // 11 bits
|
||||
cursor_begin -= 2;
|
||||
cursor_end -= 2;
|
||||
} else if (c <= 0xffff) { // 16 bits
|
||||
cursor_begin -= 3;
|
||||
cursor_end -= 3;
|
||||
} else if (c <= 0x001fffff) { // 21 bits
|
||||
cursor_begin -= 4;
|
||||
cursor_end -= 4;
|
||||
} else if (c <= 0x03ffffff) { // 26 bits
|
||||
cursor_begin -= 5;
|
||||
cursor_end -= 5;
|
||||
} else if (c <= 0x7fffffff) { // 31 bits
|
||||
cursor_begin -= 6;
|
||||
cursor_end -= 6;
|
||||
} else {
|
||||
cursor_begin -= 1;
|
||||
cursor_end -= 1;
|
||||
}
|
||||
if (cursor_begin == 0) {
|
||||
cursor_begin_utf32 = i + 1;
|
||||
}
|
||||
if (cursor_end == 0) {
|
||||
cursor_end_utf32 = i + 1;
|
||||
}
|
||||
if (cursor_begin <= 0 && cursor_end <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ss->ime_cursor = Vector2i(cursor_begin_utf32, cursor_end_utf32 - cursor_begin_utf32);
|
||||
}
|
||||
|
||||
void WaylandThread::_wp_text_input_on_commit_string(void *data, struct zwp_text_input_v3 *wp_text_input_v3, const char *text) {
|
||||
SeatState *ss = (SeatState *)data;
|
||||
if (!ss) {
|
||||
return;
|
||||
}
|
||||
|
||||
ss->ime_text_commit = String::utf8(text);
|
||||
}
|
||||
|
||||
void WaylandThread::_wp_text_input_on_delete_surrounding_text(void *data, struct zwp_text_input_v3 *wp_text_input_v3, uint32_t before_length, uint32_t after_length) {
|
||||
// Not implemented.
|
||||
}
|
||||
|
||||
void WaylandThread::_wp_text_input_on_done(void *data, struct zwp_text_input_v3 *wp_text_input_v3, uint32_t serial) {
|
||||
SeatState *ss = (SeatState *)data;
|
||||
if (!ss) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ss->ime_text_commit.is_empty()) {
|
||||
Ref<IMECommitEventMessage> msg;
|
||||
msg.instantiate();
|
||||
msg->text = ss->ime_text_commit;
|
||||
ss->wayland_thread->push_message(msg);
|
||||
} else if (!ss->ime_text.is_empty()) {
|
||||
Ref<IMEUpdateEventMessage> msg;
|
||||
msg.instantiate();
|
||||
msg->text = ss->ime_text;
|
||||
msg->selection = ss->ime_cursor;
|
||||
ss->wayland_thread->push_message(msg);
|
||||
}
|
||||
ss->ime_text = String();
|
||||
ss->ime_text_commit = String();
|
||||
ss->ime_cursor = Vector2i();
|
||||
}
|
||||
|
||||
void WaylandThread::_xdg_activation_token_on_done(void *data, struct xdg_activation_token_v1 *xdg_activation_token, const char *token) {
|
||||
WindowState *ws = (WindowState *)data;
|
||||
ERR_FAIL_NULL(ws);
|
||||
@ -3729,6 +3882,35 @@ void WaylandThread::cursor_shape_clear_custom_image(DisplayServer::CursorShape p
|
||||
}
|
||||
}
|
||||
|
||||
void WaylandThread::window_set_ime_active(const bool p_active, DisplayServer::WindowID p_window_id) {
|
||||
SeatState *ss = wl_seat_get_seat_state(wl_seat_current);
|
||||
|
||||
if (ss && ss->wp_text_input && ss->ime_enabled) {
|
||||
if (p_active) {
|
||||
ss->ime_active = true;
|
||||
zwp_text_input_v3_enable(ss->wp_text_input);
|
||||
zwp_text_input_v3_set_cursor_rectangle(ss->wp_text_input, ss->ime_rect.position.x, ss->ime_rect.position.y, ss->ime_rect.size.x, ss->ime_rect.size.y);
|
||||
} else {
|
||||
ss->ime_active = false;
|
||||
ss->ime_text = String();
|
||||
ss->ime_text_commit = String();
|
||||
ss->ime_cursor = Vector2i();
|
||||
zwp_text_input_v3_disable(ss->wp_text_input);
|
||||
}
|
||||
zwp_text_input_v3_commit(ss->wp_text_input);
|
||||
}
|
||||
}
|
||||
|
||||
void WaylandThread::window_set_ime_position(const Point2i &p_pos, DisplayServer::WindowID p_window_id) {
|
||||
SeatState *ss = wl_seat_get_seat_state(wl_seat_current);
|
||||
|
||||
if (ss && ss->wp_text_input && ss->ime_enabled) {
|
||||
ss->ime_rect = Rect2i(p_pos, Size2i(1, 10));
|
||||
zwp_text_input_v3_set_cursor_rectangle(ss->wp_text_input, ss->ime_rect.position.x, ss->ime_rect.position.y, ss->ime_rect.size.x, ss->ime_rect.size.y);
|
||||
zwp_text_input_v3_commit(ss->wp_text_input);
|
||||
}
|
||||
}
|
||||
|
||||
int WaylandThread::keyboard_get_layout_count() const {
|
||||
SeatState *ss = wl_seat_get_seat_state(wl_seat_current);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user