summaryrefslogtreecommitdiffstats
path: root/platform/linuxbsd/x11/display_server_x11.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'platform/linuxbsd/x11/display_server_x11.cpp')
-rw-r--r--platform/linuxbsd/x11/display_server_x11.cpp115
1 files changed, 108 insertions, 7 deletions
diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp
index e4553905cd..c09da2f7b3 100644
--- a/platform/linuxbsd/x11/display_server_x11.cpp
+++ b/platform/linuxbsd/x11/display_server_x11.cpp
@@ -1324,14 +1324,20 @@ void DisplayServerX11::delete_sub_window(WindowID p_id) {
}
#endif
- XDestroyWindow(x11_display, wd.x11_xim_window);
-
- XUnmapWindow(x11_display, wd.x11_window);
- XDestroyWindow(x11_display, wd.x11_window);
if (wd.xic) {
XDestroyIC(wd.xic);
wd.xic = nullptr;
}
+ XDestroyWindow(x11_display, wd.x11_xim_window);
+ if (xkb_loaded) {
+ if (wd.xkb_state) {
+ xkb_compose_state_unref(wd.xkb_state);
+ wd.xkb_state = nullptr;
+ }
+ }
+
+ XUnmapWindow(x11_display, wd.x11_window);
+ XDestroyWindow(x11_display, wd.x11_window);
windows.erase(p_id);
}
@@ -2515,7 +2521,7 @@ void DisplayServerX11::window_set_ime_active(const bool p_active, WindowID p_win
XSync(x11_display, False);
XGetWindowAttributes(x11_display, wd.x11_xim_window, &xwa);
if (xwa.map_state == IsViewable) {
- XSetInputFocus(x11_display, wd.x11_xim_window, RevertToPointerRoot, CurrentTime);
+ XSetInputFocus(x11_display, wd.x11_xim_window, RevertToParent, CurrentTime);
}
XSetICFocus(wd.xic);
} else {
@@ -2936,7 +2942,7 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
XLookupString(&xkeyevent_no_mod, nullptr, 0, &keysym_keycode, nullptr);
String keysym;
- if (xkb_keysym_to_utf32 && xkb_keysym_to_upper) {
+ if (xkb_loaded) {
KeySym keysym_unicode_nm = 0; // keysym used to find unicode
XLookupString(&xkeyevent_no_mod, nullptr, 0, &keysym_unicode_nm, nullptr);
keysym = String::chr(xkb_keysym_to_utf32(xkb_keysym_to_upper(keysym_unicode_nm)));
@@ -3029,6 +3035,64 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
}
} while (status == XBufferOverflow);
#endif
+ } else if (xkeyevent->type == KeyPress && wd.xkb_state && xkb_loaded) {
+ xkb_compose_feed_result res = xkb_compose_state_feed(wd.xkb_state, keysym_unicode);
+ if (res == XKB_COMPOSE_FEED_ACCEPTED) {
+ if (xkb_compose_state_get_status(wd.xkb_state) == XKB_COMPOSE_COMPOSED) {
+ bool keypress = xkeyevent->type == KeyPress;
+ Key keycode = KeyMappingX11::get_keycode(keysym_keycode);
+ Key physical_keycode = KeyMappingX11::get_scancode(xkeyevent->keycode);
+
+ if (keycode >= Key::A + 32 && keycode <= Key::Z + 32) {
+ keycode -= 'a' - 'A';
+ }
+
+ char str_xkb[256] = {};
+ int str_xkb_size = xkb_compose_state_get_utf8(wd.xkb_state, str_xkb, 255);
+
+ String tmp;
+ tmp.parse_utf8(str_xkb, str_xkb_size);
+ for (int i = 0; i < tmp.length(); i++) {
+ Ref<InputEventKey> k;
+ k.instantiate();
+ if (physical_keycode == Key::NONE && keycode == Key::NONE && tmp[i] == 0) {
+ continue;
+ }
+
+ if (keycode == Key::NONE) {
+ keycode = (Key)physical_keycode;
+ }
+
+ _get_key_modifier_state(xkeyevent->state, k);
+
+ k->set_window_id(p_window);
+ k->set_pressed(keypress);
+
+ k->set_keycode(keycode);
+ k->set_physical_keycode(physical_keycode);
+ if (!keysym.is_empty()) {
+ k->set_key_label(fix_key_label(keysym[0], keycode));
+ } else {
+ k->set_key_label(keycode);
+ }
+ if (keypress) {
+ k->set_unicode(fix_unicode(tmp[i]));
+ }
+
+ k->set_echo(false);
+
+ if (k->get_keycode() == Key::BACKTAB) {
+ //make it consistent across platforms.
+ k->set_keycode(Key::TAB);
+ k->set_physical_keycode(Key::TAB);
+ k->set_shift_pressed(true);
+ }
+
+ Input::get_singleton()->parse_input_event(k);
+ }
+ return;
+ }
+ }
}
/* Phase 2, obtain a Godot keycode from the keysym */
@@ -4866,6 +4930,10 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
wd.x11_xim_window = XCreateWindow(x11_display, wd.x11_window, 0, 0, 1, 1, 0, CopyFromParent, InputOnly, CopyFromParent, CWEventMask, &window_attributes_ime);
+ if (dead_tbl && xkb_loaded) {
+ wd.xkb_state = xkb_compose_state_new(dead_tbl, XKB_COMPOSE_STATE_NO_FLAGS);
+ }
+
// Enable receiving notification when the window is initialized (MapNotify)
// so the focus can be set at the right time.
if (!wd.no_focus && !wd.is_popup) {
@@ -5145,7 +5213,7 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
ERR_FAIL_MSG("Can't load XCursor dynamically.");
}
- initialize_xkbcommon(dylibloader_verbose); // Optional, used for key_label.
+ xkb_loaded = (initialize_xkbcommon(dylibloader_verbose) == 0);
if (initialize_xext(dylibloader_verbose) != 0) {
r_error = ERR_UNAVAILABLE;
@@ -5172,6 +5240,23 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
ERR_FAIL_MSG("Can't load Xinput2 dynamically.");
}
+ if (xkb_loaded) {
+ xkb_ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
+ if (xkb_ctx) {
+ const char *locale = getenv("LC_ALL");
+ if (!locale || !*locale) {
+ locale = getenv("LC_CTYPE");
+ }
+ if (!locale || !*locale) {
+ locale = getenv("LANG");
+ }
+ if (!locale || !*locale) {
+ locale = "C";
+ }
+ dead_tbl = xkb_compose_table_new_from_locale(xkb_ctx, locale, XKB_COMPOSE_COMPILE_NO_FLAGS);
+ }
+ }
+
Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events);
r_error = OK;
@@ -5612,10 +5697,26 @@ DisplayServerX11::~DisplayServerX11() {
XDestroyIC(wd.xic);
wd.xic = nullptr;
}
+ XDestroyWindow(x11_display, wd.x11_xim_window);
+ if (xkb_loaded) {
+ if (wd.xkb_state) {
+ xkb_compose_state_unref(wd.xkb_state);
+ wd.xkb_state = nullptr;
+ }
+ }
XUnmapWindow(x11_display, wd.x11_window);
XDestroyWindow(x11_display, wd.x11_window);
}
+ if (xkb_loaded) {
+ if (dead_tbl) {
+ xkb_compose_table_unref(dead_tbl);
+ }
+ if (xkb_ctx) {
+ xkb_context_unref(xkb_ctx);
+ }
+ }
+
//destroy drivers
#if defined(VULKAN_ENABLED)
if (rendering_device_vulkan) {