IME: Add direct support for Fcitx IME input, with SDL2 on *nix/X11.
This commit is contained in:
61
config.lib
61
config.lib
@@ -72,6 +72,7 @@ set_default() {
|
|||||||
with_lzma="1"
|
with_lzma="1"
|
||||||
with_lzo2="1"
|
with_lzo2="1"
|
||||||
with_xdg_basedir="1"
|
with_xdg_basedir="1"
|
||||||
|
with_fcitx="1"
|
||||||
with_png="1"
|
with_png="1"
|
||||||
enable_builtin_depend="1"
|
enable_builtin_depend="1"
|
||||||
with_makedepend="0"
|
with_makedepend="0"
|
||||||
@@ -152,6 +153,7 @@ set_default() {
|
|||||||
with_lzma
|
with_lzma
|
||||||
with_lzo2
|
with_lzo2
|
||||||
with_xdg_basedir
|
with_xdg_basedir
|
||||||
|
with_fcitx
|
||||||
with_png
|
with_png
|
||||||
enable_builtin_depend
|
enable_builtin_depend
|
||||||
with_makedepend
|
with_makedepend
|
||||||
@@ -364,6 +366,10 @@ detect_params() {
|
|||||||
--without-libxdg-basedir) with_xdg_basedir="0";;
|
--without-libxdg-basedir) with_xdg_basedir="0";;
|
||||||
--with-libxdg-basedir=*) with_xdg_basedir="$optarg";;
|
--with-libxdg-basedir=*) with_xdg_basedir="$optarg";;
|
||||||
|
|
||||||
|
--with-fcitx) with_fcitx="2";;
|
||||||
|
--without-fcitx) with_fcitx="0";;
|
||||||
|
--with-fcitx=*) with_fcitx="$optarg";;
|
||||||
|
|
||||||
--with-png) with_png="2";;
|
--with-png) with_png="2";;
|
||||||
--without-png) with_png="0";;
|
--without-png) with_png="0";;
|
||||||
--with-png=*) with_png="$optarg";;
|
--with-png=*) with_png="$optarg";;
|
||||||
@@ -895,6 +901,7 @@ check_params() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
detect_xdg_basedir
|
detect_xdg_basedir
|
||||||
|
detect_fcitx
|
||||||
detect_png
|
detect_png
|
||||||
detect_freetype
|
detect_freetype
|
||||||
detect_fontconfig
|
detect_fontconfig
|
||||||
@@ -2107,6 +2114,39 @@ EOL
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -n "$dbus_config" ]; then
|
||||||
|
CFLAGS="$CFLAGS -DWITH_DBUS"
|
||||||
|
CFLAGS="$CFLAGS `$dbus_config --cflags | tr '\n\r' ' '`"
|
||||||
|
|
||||||
|
if [ "$enable_static" != "0" ]; then
|
||||||
|
LIBS="$LIBS `$dbus_config --libs --static | tr '\n\r' ' '`"
|
||||||
|
else
|
||||||
|
LIBS="$LIBS `$dbus_config --libs | tr '\n\r' ' '`"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$x11_config" ]; then
|
||||||
|
CFLAGS="$CFLAGS -DWITH_X11"
|
||||||
|
CFLAGS="$CFLAGS `$x11_config --cflags | tr '\n\r' ' '`"
|
||||||
|
|
||||||
|
if [ "$enable_static" != "0" ]; then
|
||||||
|
LIBS="$LIBS `$x11_config --libs --static | tr '\n\r' ' '`"
|
||||||
|
else
|
||||||
|
LIBS="$LIBS `$x11_config --libs | tr '\n\r' ' '`"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$fcitx_config" ]; then
|
||||||
|
CFLAGS="$CFLAGS -DWITH_FCITX"
|
||||||
|
CFLAGS="$CFLAGS `$fcitx_config --cflags | tr '\n\r' ' '`"
|
||||||
|
|
||||||
|
if [ "$enable_static" != "0" ]; then
|
||||||
|
LIBS="$LIBS `$fcitx_config --libs --static | tr '\n\r' ' '`"
|
||||||
|
else
|
||||||
|
LIBS="$LIBS `$fcitx_config --libs | tr '\n\r' ' '`"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# 64bit machines need -D_SQ64
|
# 64bit machines need -D_SQ64
|
||||||
if [ "$cpu_type" = "64" ] && [ "$enable_universal" = "0" ]; then
|
if [ "$cpu_type" = "64" ] && [ "$enable_universal" = "0" ]; then
|
||||||
CFLAGS="$CFLAGS -D_SQ64"
|
CFLAGS="$CFLAGS -D_SQ64"
|
||||||
@@ -3207,6 +3247,27 @@ detect_xdg_basedir() {
|
|||||||
detect_pkg_config "$with_xdg_basedir" "libxdg-basedir" "xdg_basedir_config" "1.2"
|
detect_pkg_config "$with_xdg_basedir" "libxdg-basedir" "xdg_basedir_config" "1.2"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
detect_fcitx() {
|
||||||
|
if ([ "$with_fcitx" = "1" ] && [ "$enable_dedicated" = "0" ]) || [ "$with_fcitx" = "2" ]; then
|
||||||
|
detect_pkg_config "$with_fcitx" "dbus-1" "dbus_config" "1.0" "1"
|
||||||
|
detect_pkg_config "$with_fcitx" "x11" "x11_config" "1.0" "1"
|
||||||
|
if [ -z "$dbus_config" ]; then
|
||||||
|
log 1 "checking fcitx... no dbus, skipping"
|
||||||
|
fcitx_config=""
|
||||||
|
dbus_config=""
|
||||||
|
x11_config=""
|
||||||
|
return 0
|
||||||
|
elif [ -z "$x11_config" ]; then
|
||||||
|
log 1 "checking fcitx... no x11, skipping"
|
||||||
|
fcitx_config=""
|
||||||
|
dbus_config=""
|
||||||
|
x11_config=""
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
detect_pkg_config "$with_fcitx" "fcitx" "fcitx_config" "4.0" "1"
|
||||||
|
}
|
||||||
|
|
||||||
detect_png() {
|
detect_png() {
|
||||||
detect_pkg_config "$with_png" "libpng" "png_config" "1.2"
|
detect_pkg_config "$with_png" "libpng" "png_config" "1.2"
|
||||||
}
|
}
|
||||||
|
@@ -23,8 +23,7 @@
|
|||||||
#include "../core/math_func.hpp"
|
#include "../core/math_func.hpp"
|
||||||
#include "../fileio_func.h"
|
#include "../fileio_func.h"
|
||||||
#include "../framerate_type.h"
|
#include "../framerate_type.h"
|
||||||
#include "../window_func.h"
|
#include "../scope.h"
|
||||||
#include "../window_gui.h"
|
|
||||||
#include "sdl2_v.h"
|
#include "sdl2_v.h"
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
@@ -35,6 +34,15 @@
|
|||||||
#include "../3rdparty/mingw-std-threads/mingw.condition_variable.h"
|
#include "../3rdparty/mingw-std-threads/mingw.condition_variable.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(WITH_FCITX)
|
||||||
|
#include <fcitx/frontend.h>
|
||||||
|
#include <dbus/dbus.h>
|
||||||
|
#include <SDL_syswm.h>
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/keysym.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "../safeguards.h"
|
#include "../safeguards.h"
|
||||||
|
|
||||||
static FVideoDriver_SDL iFVideoDriver_SDL;
|
static FVideoDriver_SDL iFVideoDriver_SDL;
|
||||||
@@ -64,6 +72,191 @@ static int _window_size_h;
|
|||||||
|
|
||||||
static std::string _editing_text;
|
static std::string _editing_text;
|
||||||
|
|
||||||
|
static void SetTextInputRect();
|
||||||
|
|
||||||
|
Point GetFocusedWindowCaret();
|
||||||
|
Point GetFocusedWindowTopLeft();
|
||||||
|
bool FocusedWindowIsConsole();
|
||||||
|
bool EditBoxInGlobalFocus();
|
||||||
|
|
||||||
|
#if defined(WITH_FCITX)
|
||||||
|
static bool _fcitx_mode = false;
|
||||||
|
static char _fcitx_service_name[64];
|
||||||
|
static char _fcitx_ic_name[64];
|
||||||
|
static DBusConnection *_fcitx_dbus_session_conn = nullptr;
|
||||||
|
|
||||||
|
static void FcitxICMethod(const char *method)
|
||||||
|
{
|
||||||
|
DBusMessage *msg = dbus_message_new_method_call(_fcitx_service_name, _fcitx_ic_name, "org.fcitx.Fcitx.InputContext", method);
|
||||||
|
if (!msg) return;
|
||||||
|
dbus_connection_send(_fcitx_dbus_session_conn, msg, NULL);
|
||||||
|
dbus_connection_flush(_fcitx_dbus_session_conn);
|
||||||
|
dbus_message_unref(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int GetXDisplayNum()
|
||||||
|
{
|
||||||
|
const char *display = getenv("DISPLAY");
|
||||||
|
if (!display) return 0;
|
||||||
|
const char *colon = strchr(display, ':');
|
||||||
|
if (!colon) return 0;
|
||||||
|
return atoi(colon + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FcitxDeinit() {
|
||||||
|
if (_fcitx_mode) {
|
||||||
|
FcitxICMethod("DestroyIC");
|
||||||
|
_fcitx_mode = false;
|
||||||
|
}
|
||||||
|
if (_fcitx_dbus_session_conn) {
|
||||||
|
dbus_connection_close(_fcitx_dbus_session_conn);
|
||||||
|
_fcitx_dbus_session_conn = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static DBusHandlerResult FcitxDBusMessageFilter(DBusConnection *connection, DBusMessage *message, void *user_data)
|
||||||
|
{
|
||||||
|
if (dbus_message_is_signal(message, "org.fcitx.Fcitx.InputContext", "CommitString")) {
|
||||||
|
DBusMessageIter iter;
|
||||||
|
const char *text = nullptr;
|
||||||
|
dbus_message_iter_init(message, &iter);
|
||||||
|
dbus_message_iter_get_basic(&iter, &text);
|
||||||
|
|
||||||
|
if (text != nullptr && EditBoxInGlobalFocus()) {
|
||||||
|
HandleTextInput(nullptr, true);
|
||||||
|
HandleTextInput(text);
|
||||||
|
SetTextInputRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
return DBUS_HANDLER_RESULT_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dbus_message_is_signal(message, "org.fcitx.Fcitx.InputContext", "UpdatePreedit")) {
|
||||||
|
const char *text = nullptr;
|
||||||
|
int32 cursor;
|
||||||
|
if (!dbus_message_get_args(message, nullptr, DBUS_TYPE_STRING, &text, DBUS_TYPE_INT32, &cursor, DBUS_TYPE_INVALID)) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||||
|
|
||||||
|
if (text != nullptr && EditBoxInGlobalFocus()) {
|
||||||
|
HandleTextInput(text, true, text + min<uint>(cursor, strlen(text)));
|
||||||
|
}
|
||||||
|
return DBUS_HANDLER_RESULT_HANDLED;
|
||||||
|
}
|
||||||
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FcitxInit()
|
||||||
|
{
|
||||||
|
DBusError err;
|
||||||
|
dbus_error_init(&err);
|
||||||
|
_fcitx_dbus_session_conn = dbus_bus_get_private(DBUS_BUS_SESSION, &err);
|
||||||
|
if (dbus_error_is_set(&err)) {
|
||||||
|
dbus_error_free(&err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dbus_connection_set_exit_on_disconnect(_fcitx_dbus_session_conn, false);
|
||||||
|
seprintf(_fcitx_service_name, lastof(_fcitx_service_name), "org.fcitx.Fcitx-%d", GetXDisplayNum());
|
||||||
|
|
||||||
|
auto guard = scope_guard([]() {
|
||||||
|
if (!_fcitx_mode) FcitxDeinit();
|
||||||
|
});
|
||||||
|
|
||||||
|
int pid = getpid();
|
||||||
|
int id = -1;
|
||||||
|
uint32 enable, hk1sym, hk1state, hk2sym, hk2state;
|
||||||
|
DBusMessage *msg = dbus_message_new_method_call(_fcitx_service_name, "/inputmethod", "org.fcitx.Fcitx.InputMethod", "CreateICv3");
|
||||||
|
if (!msg) return;
|
||||||
|
auto guard1 = scope_guard([&]() {
|
||||||
|
dbus_message_unref(msg);
|
||||||
|
});
|
||||||
|
const char *name = "OpenTTD";
|
||||||
|
if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INT32, &pid, DBUS_TYPE_INVALID)) return;
|
||||||
|
DBusMessage *reply = dbus_connection_send_with_reply_and_block(_fcitx_dbus_session_conn, msg, 100, nullptr);
|
||||||
|
if (!reply) return;
|
||||||
|
auto guard2 = scope_guard([&]() {
|
||||||
|
dbus_message_unref(reply);
|
||||||
|
});
|
||||||
|
if (!dbus_message_get_args(reply, nullptr, DBUS_TYPE_INT32, &id, DBUS_TYPE_BOOLEAN, &enable, DBUS_TYPE_UINT32, &hk1sym, DBUS_TYPE_UINT32, &hk1state, DBUS_TYPE_UINT32, &hk2sym, DBUS_TYPE_UINT32, &hk2state, DBUS_TYPE_INVALID)) return;
|
||||||
|
|
||||||
|
if (id < 0) return;
|
||||||
|
|
||||||
|
seprintf(_fcitx_ic_name, lastof(_fcitx_ic_name), "/inputcontext_%d", id);
|
||||||
|
dbus_bus_add_match(_fcitx_dbus_session_conn, "type='signal', interface='org.fcitx.Fcitx.InputContext'", nullptr);
|
||||||
|
dbus_connection_add_filter(_fcitx_dbus_session_conn, &FcitxDBusMessageFilter, nullptr, nullptr);
|
||||||
|
dbus_connection_flush(_fcitx_dbus_session_conn);
|
||||||
|
|
||||||
|
uint32 caps = CAPACITY_PREEDIT;
|
||||||
|
DBusMessage *msg2 = dbus_message_new_method_call(_fcitx_service_name, _fcitx_ic_name, "org.fcitx.Fcitx.InputContext", "SetCapacity");
|
||||||
|
if (!msg2) return;
|
||||||
|
auto guard3 = scope_guard([&]() {
|
||||||
|
dbus_message_unref(msg2);
|
||||||
|
});
|
||||||
|
if (!dbus_message_append_args(msg2, DBUS_TYPE_UINT32, &caps, DBUS_TYPE_INVALID)) return;
|
||||||
|
dbus_connection_send(_fcitx_dbus_session_conn, msg2, NULL);
|
||||||
|
dbus_connection_flush(_fcitx_dbus_session_conn);
|
||||||
|
|
||||||
|
SDL_EventState(SDL_SYSWMEVENT, 1);
|
||||||
|
|
||||||
|
_fcitx_mode = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32 _fcitx_last_keycode;
|
||||||
|
static uint32 _fcitx_last_keysym;
|
||||||
|
static bool FcitxProcessKey(const SDL_Keysym &key)
|
||||||
|
{
|
||||||
|
uint32 fcitx_mods = 0;
|
||||||
|
if (key.mod & KMOD_SHIFT) fcitx_mods |= FcitxKeyState_Shift;
|
||||||
|
if (key.mod & KMOD_CAPS) fcitx_mods |= FcitxKeyState_CapsLock;
|
||||||
|
if (key.mod & KMOD_CTRL) fcitx_mods |= FcitxKeyState_Ctrl;
|
||||||
|
if (key.mod & KMOD_ALT) fcitx_mods |= FcitxKeyState_Alt;
|
||||||
|
if (key.mod & KMOD_NUM) fcitx_mods |= FcitxKeyState_NumLock;
|
||||||
|
if (key.mod & KMOD_LGUI) fcitx_mods |= FcitxKeyState_Super;
|
||||||
|
if (key.mod & KMOD_RGUI) fcitx_mods |= FcitxKeyState_Meta;
|
||||||
|
|
||||||
|
int type = FCITX_PRESS_KEY;
|
||||||
|
uint32 event_time = 0;
|
||||||
|
|
||||||
|
DBusMessage *msg = dbus_message_new_method_call(_fcitx_service_name, _fcitx_ic_name, "org.fcitx.Fcitx.InputContext", "ProcessKeyEvent");
|
||||||
|
if (!msg) return false;
|
||||||
|
auto guard1 = scope_guard([&]() {
|
||||||
|
dbus_message_unref(msg);
|
||||||
|
});
|
||||||
|
if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &_fcitx_last_keysym, DBUS_TYPE_UINT32, &_fcitx_last_keycode, DBUS_TYPE_UINT32, &fcitx_mods,
|
||||||
|
DBUS_TYPE_INT32, &type, DBUS_TYPE_UINT32, &event_time, DBUS_TYPE_INVALID)) return false;
|
||||||
|
DBusMessage *reply = dbus_connection_send_with_reply_and_block(_fcitx_dbus_session_conn, msg, 300, nullptr);
|
||||||
|
if (!reply) return false;
|
||||||
|
auto guard2 = scope_guard([&]() {
|
||||||
|
dbus_message_unref(reply);
|
||||||
|
});
|
||||||
|
uint32 handled = 0;
|
||||||
|
if (!dbus_message_get_args(reply, nullptr, DBUS_TYPE_INT32, &handled, DBUS_TYPE_INVALID)) return false;
|
||||||
|
return handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FcitxPoll()
|
||||||
|
{
|
||||||
|
dbus_connection_read_write(_fcitx_dbus_session_conn, 0);
|
||||||
|
while (dbus_connection_dispatch(_fcitx_dbus_session_conn) == DBUS_DISPATCH_DATA_REMAINS) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FcitxFocusChange(bool focused)
|
||||||
|
{
|
||||||
|
FcitxICMethod(focused ? "FocusIn" : "FocusOut");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FcitxSYSWMEVENT(const SDL_SysWMEvent &event)
|
||||||
|
{
|
||||||
|
if (event.msg->subsystem != SDL_SYSWM_X11) return;
|
||||||
|
XEvent &xevent = event.msg->msg.x11.event;
|
||||||
|
if (xevent.type == KeyPress) {
|
||||||
|
KeySym keysym = XLookupKeysym(&xevent.xkey, 0);
|
||||||
|
_fcitx_last_keycode = xevent.xkey.keycode;
|
||||||
|
_fcitx_last_keysym = keysym;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
const static bool _fcitx_mode = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
void VideoDriver_SDL::MakeDirty(int left, int top, int width, int height)
|
void VideoDriver_SDL::MakeDirty(int left, int top, int width, int height)
|
||||||
{
|
{
|
||||||
if (_num_dirty_rects < MAX_DIRTY_RECTS) {
|
if (_num_dirty_rects < MAX_DIRTY_RECTS) {
|
||||||
@@ -362,21 +555,79 @@ bool VideoDriver_SDL::ClaimMousePointer()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void StartTextInput()
|
||||||
|
{
|
||||||
|
#if defined(WITH_FCITX)
|
||||||
|
if (_fcitx_mode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
SDL_StartTextInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void StopTextInput()
|
||||||
|
{
|
||||||
|
#if defined(WITH_FCITX)
|
||||||
|
if (_fcitx_mode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
SDL_StopTextInput();
|
||||||
|
}
|
||||||
|
|
||||||
static void SetTextInputRect()
|
static void SetTextInputRect()
|
||||||
{
|
{
|
||||||
SDL_Rect winrect;
|
SDL_Rect winrect;
|
||||||
Point pt = _focused_window->GetCaretPosition();
|
Point caret = GetFocusedWindowCaret();
|
||||||
winrect.x = _focused_window->left + pt.x;
|
Point win = GetFocusedWindowTopLeft();
|
||||||
winrect.y = _focused_window->top + pt.y;
|
winrect.x = win.x + caret.x;
|
||||||
|
winrect.y = win.y + caret.y;
|
||||||
winrect.w = 1;
|
winrect.w = 1;
|
||||||
winrect.h = FONT_HEIGHT_NORMAL;
|
winrect.h = FONT_HEIGHT_NORMAL;
|
||||||
|
|
||||||
|
#if defined(WITH_FCITX)
|
||||||
|
if (_fcitx_mode) {
|
||||||
|
SDL_SysWMinfo info;
|
||||||
|
SDL_VERSION(&info.version);
|
||||||
|
if (!SDL_GetWindowWMInfo(_sdl_window, &info)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int x = 0;
|
||||||
|
int y = 0;
|
||||||
|
if (info.subsystem == SDL_SYSWM_X11) {
|
||||||
|
Display *x_disp = info.info.x11.display;
|
||||||
|
Window x_win = info.info.x11.window;
|
||||||
|
XWindowAttributes attrib;
|
||||||
|
XGetWindowAttributes(x_disp, x_win, &attrib);
|
||||||
|
Window unused;
|
||||||
|
XTranslateCoordinates(x_disp, x_win, attrib.root, 0, 0, &x, &y, &unused);
|
||||||
|
} else {
|
||||||
|
SDL_GetWindowPosition(_sdl_window, &x, &y);
|
||||||
|
}
|
||||||
|
x += winrect.x;
|
||||||
|
y += winrect.y;
|
||||||
|
DBusMessage *msg = dbus_message_new_method_call(_fcitx_service_name, _fcitx_ic_name, "org.fcitx.Fcitx.InputContext", "SetCursorRect");
|
||||||
|
if (!msg) return;
|
||||||
|
auto guard = scope_guard([&]() {
|
||||||
|
dbus_message_unref(msg);
|
||||||
|
});
|
||||||
|
if (!dbus_message_append_args(msg, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y, DBUS_TYPE_INT32, &winrect.w,
|
||||||
|
DBUS_TYPE_INT32, &winrect.h, DBUS_TYPE_INVALID)) return;
|
||||||
|
dbus_connection_send(_fcitx_dbus_session_conn, msg, NULL);
|
||||||
|
dbus_connection_flush(_fcitx_dbus_session_conn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
SDL_SetTextInputRect(&winrect);
|
SDL_SetTextInputRect(&winrect);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoDriver_SDL::EditBoxGainedFocus()
|
void VideoDriver_SDL::EditBoxGainedFocus()
|
||||||
{
|
{
|
||||||
if (!this->edit_box_focused) {
|
if (!this->edit_box_focused) {
|
||||||
SDL_StartTextInput();
|
if (!_fcitx_mode) {
|
||||||
|
StartTextInput();
|
||||||
|
}
|
||||||
this->edit_box_focused = true;
|
this->edit_box_focused = true;
|
||||||
}
|
}
|
||||||
SetTextInputRect();
|
SetTextInputRect();
|
||||||
@@ -385,7 +636,14 @@ void VideoDriver_SDL::EditBoxGainedFocus()
|
|||||||
void VideoDriver_SDL::EditBoxLostFocus()
|
void VideoDriver_SDL::EditBoxLostFocus()
|
||||||
{
|
{
|
||||||
if (this->edit_box_focused) {
|
if (this->edit_box_focused) {
|
||||||
SDL_StopTextInput();
|
if (_fcitx_mode) {
|
||||||
|
#if defined(WITH_FCITX)
|
||||||
|
FcitxICMethod("Reset");
|
||||||
|
FcitxICMethod("CloseIC");
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
StopTextInput();
|
||||||
|
}
|
||||||
this->edit_box_focused = false;
|
this->edit_box_focused = false;
|
||||||
}
|
}
|
||||||
/* Clear any marked string from the current edit box. */
|
/* Clear any marked string from the current edit box. */
|
||||||
@@ -525,8 +783,11 @@ static uint ConvertSdlKeycodeIntoMy(SDL_Keycode kc)
|
|||||||
|
|
||||||
int VideoDriver_SDL::PollEvent()
|
int VideoDriver_SDL::PollEvent()
|
||||||
{
|
{
|
||||||
SDL_Event ev;
|
#if defined(WITH_FCITX)
|
||||||
|
if (_fcitx_mode) FcitxPoll();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SDL_Event ev;
|
||||||
if (!SDL_PollEvent(&ev)) return -2;
|
if (!SDL_PollEvent(&ev)) return -2;
|
||||||
|
|
||||||
switch (ev.type) {
|
switch (ev.type) {
|
||||||
@@ -584,6 +845,15 @@ int VideoDriver_SDL::PollEvent()
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_KEYDOWN: // Toggle full-screen on ALT + ENTER/F
|
case SDL_KEYDOWN: // Toggle full-screen on ALT + ENTER/F
|
||||||
|
#if defined(WITH_FCITX)
|
||||||
|
if (_fcitx_mode && EditBoxInGlobalFocus() && !(FocusedWindowIsConsole() &&
|
||||||
|
ConvertSdlKeycodeIntoMy(SDL_GetKeyFromName(ev.text.text)) == WKC_BACKQUOTE)) {
|
||||||
|
if (FcitxProcessKey(ev.key.keysym)) {
|
||||||
|
/* key press handled by Fcitx */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if ((ev.key.keysym.mod & (KMOD_ALT | KMOD_GUI)) &&
|
if ((ev.key.keysym.mod & (KMOD_ALT | KMOD_GUI)) &&
|
||||||
(ev.key.keysym.sym == SDLK_RETURN || ev.key.keysym.sym == SDLK_f)) {
|
(ev.key.keysym.sym == SDLK_RETURN || ev.key.keysym.sym == SDLK_f)) {
|
||||||
if (ev.key.repeat == 0) ToggleFullScreen(!_fullscreen);
|
if (ev.key.repeat == 0) ToggleFullScreen(!_fullscreen);
|
||||||
@@ -603,14 +873,15 @@ int VideoDriver_SDL::PollEvent()
|
|||||||
keycode & WKC_ALT ||
|
keycode & WKC_ALT ||
|
||||||
(keycode >= WKC_F1 && keycode <= WKC_F12) ||
|
(keycode >= WKC_F1 && keycode <= WKC_F12) ||
|
||||||
!IsValidChar(character, CS_ALPHANUMERAL) ||
|
!IsValidChar(character, CS_ALPHANUMERAL) ||
|
||||||
!this->edit_box_focused) {
|
!this->edit_box_focused ||
|
||||||
|
_fcitx_mode) {
|
||||||
HandleKeypress(keycode, character);
|
HandleKeypress(keycode, character);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_TEXTINPUT: {
|
case SDL_TEXTINPUT: {
|
||||||
if (EditBoxInGlobalFocus() && !(_focused_window->window_class == WC_CONSOLE &&
|
if (EditBoxInGlobalFocus() && !(FocusedWindowIsConsole() &&
|
||||||
ConvertSdlKeycodeIntoMy(SDL_GetKeyFromName(ev.text.text)) == WKC_BACKQUOTE)) {
|
ConvertSdlKeycodeIntoMy(SDL_GetKeyFromName(ev.text.text)) == WKC_BACKQUOTE)) {
|
||||||
HandleTextInput(nullptr, true);
|
HandleTextInput(nullptr, true);
|
||||||
HandleTextInput(ev.text.text);
|
HandleTextInput(ev.text.text);
|
||||||
@@ -652,9 +923,25 @@ int VideoDriver_SDL::PollEvent()
|
|||||||
// mouse left the window, undraw cursor
|
// mouse left the window, undraw cursor
|
||||||
UndrawMouseCursor();
|
UndrawMouseCursor();
|
||||||
_cursor.in_window = false;
|
_cursor.in_window = false;
|
||||||
|
} else if (ev.window.event == SDL_WINDOWEVENT_MOVED) {
|
||||||
|
if (_fcitx_mode) SetTextInputRect();
|
||||||
|
} else if (ev.window.event == SDL_WINDOWEVENT_FOCUS_GAINED) {
|
||||||
|
#if defined(WITH_FCITX)
|
||||||
|
if (_fcitx_mode) FcitxFocusChange(true);
|
||||||
|
#endif
|
||||||
|
} else if (ev.window.event == SDL_WINDOWEVENT_FOCUS_LOST) {
|
||||||
|
#if defined(WITH_FCITX)
|
||||||
|
if (_fcitx_mode) FcitxFocusChange(false);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case SDL_SYSWMEVENT: {
|
||||||
|
#if defined(WITH_FCITX)
|
||||||
|
if (_fcitx_mode) FcitxSYSWMEVENT(ev.syswm);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -690,11 +977,18 @@ const char *VideoDriver_SDL::Start(const char * const *parm)
|
|||||||
SDL_StopTextInput();
|
SDL_StopTextInput();
|
||||||
this->edit_box_focused = false;
|
this->edit_box_focused = false;
|
||||||
|
|
||||||
|
#if defined(WITH_FCITX)
|
||||||
|
FcitxInit();
|
||||||
|
#endif
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoDriver_SDL::Stop()
|
void VideoDriver_SDL::Stop()
|
||||||
{
|
{
|
||||||
|
#if defined(WITH_FCITX)
|
||||||
|
FcitxDeinit();
|
||||||
|
#endif
|
||||||
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||||
if (SDL_WasInit(SDL_INIT_EVERYTHING) == 0) {
|
if (SDL_WasInit(SDL_INIT_EVERYTHING) == 0) {
|
||||||
SDL_Quit(); // If there's nothing left, quit SDL
|
SDL_Quit(); // If there's nothing left, quit SDL
|
||||||
|
@@ -454,6 +454,21 @@ void SetFocusedWindow(Window *w)
|
|||||||
if (_focused_window != nullptr) _focused_window->OnFocus(old_focused);
|
if (_focused_window != nullptr) _focused_window->OnFocus(old_focused);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Point GetFocusedWindowCaret()
|
||||||
|
{
|
||||||
|
return _focused_window->GetCaretPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
Point GetFocusedWindowTopLeft()
|
||||||
|
{
|
||||||
|
return { _focused_window->left, _focused_window->top };
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FocusedWindowIsConsole()
|
||||||
|
{
|
||||||
|
return _focused_window && _focused_window->window_class == WC_CONSOLE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if an edit box is in global focus. That is if focused window
|
* Check if an edit box is in global focus. That is if focused window
|
||||||
* has a edit box as focused widget, or if a console is focused.
|
* has a edit box as focused widget, or if a console is focused.
|
||||||
|
Reference in New Issue
Block a user