Fixed bug 2824 - Add Fcitx Input Method Support

Weitian Leung

Just moved ibus direct call to SDL_IME_* related functions, and adds fcitx IME support (uses DBus, too),
enable with env: SDL_IM_MODULE=fcitx (ibus still the default one)
This commit is contained in:
Sam Lantinga 2016-10-07 18:57:40 -07:00
parent 89abbbfe9e
commit 808c75d1cf
10 changed files with 967 additions and 22 deletions

123
configure vendored
View File

@ -849,7 +849,9 @@ enable_video_opengles1
enable_video_opengles2 enable_video_opengles2
enable_libudev enable_libudev
enable_dbus enable_dbus
enable_ime
enable_ibus enable_ibus
enable_fcitx
enable_input_tslib enable_input_tslib
enable_pthreads enable_pthreads
enable_pthread_sem enable_pthread_sem
@ -1587,7 +1589,9 @@ Optional Features:
include OpenGL ES 2.0 support [[default=yes]] include OpenGL ES 2.0 support [[default=yes]]
--enable-libudev enable libudev support [[default=yes]] --enable-libudev enable libudev support [[default=yes]]
--enable-dbus enable D-Bus support [[default=yes]] --enable-dbus enable D-Bus support [[default=yes]]
--enable-ime enable IME support [[default=yes]]
--enable-ibus enable IBus support [[default=yes]] --enable-ibus enable IBus support [[default=yes]]
--enable-fcitx enable fcitx support [[default=yes]]
--enable-input-tslib use the Touchscreen library for input --enable-input-tslib use the Touchscreen library for input
[[default=yes]] [[default=yes]]
--enable-pthreads use POSIX threads for multi-threading --enable-pthreads use POSIX threads for multi-threading
@ -21650,6 +21654,23 @@ $as_echo "#define HAVE_DBUS_DBUS_H 1" >>confdefs.h
fi fi
} }
CheckIME()
{
# Check whether --enable-ime was given.
if test "${enable_ime+set}" = set; then :
enableval=$enable_ime;
else
enable_ime=yes
fi
if test x$enable_ime = xyes; then
$as_echo "#define SDL_USE_IME 1" >>confdefs.h
SOURCES="$SOURCES $srcdir/src/core/linux/SDL_ime.c"
fi
}
CheckIBus() CheckIBus()
{ {
# Check whether --enable-ibus was given. # Check whether --enable-ibus was given.
@ -21723,7 +21744,11 @@ fi
CFLAGS="$save_CFLAGS" CFLAGS="$save_CFLAGS"
if test x$have_ibus_ibus_h_hdr = xyes; then if test x$have_ibus_ibus_h_hdr = xyes; then
if test x$enable_dbus != xyes; then if test x$enable_ime != xyes; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: IME support is required for IBus." >&5
$as_echo "$as_me: WARNING: IME support is required for IBus." >&2;}
have_ibus_ibus_h_hdr=no
elif test x$enable_dbus != xyes; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: DBus support is required for IBus." >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: DBus support is required for IBus." >&5
$as_echo "$as_me: WARNING: DBus support is required for IBus." >&2;} $as_echo "$as_me: WARNING: DBus support is required for IBus." >&2;}
have_ibus_ibus_h_hdr=no have_ibus_ibus_h_hdr=no
@ -21743,6 +21768,90 @@ $as_echo "#define HAVE_IBUS_IBUS_H 1" >>confdefs.h
fi fi
} }
CheckFcitx()
{
# Check whether --enable-fcitx was given.
if test "${enable_fcitx+set}" = set; then :
enableval=$enable_fcitx;
else
enable_fcitx=yes
fi
if test x$enable_fcitx = xyes; then
# Extract the first word of "pkg-config", so it can be a program name with args.
set dummy pkg-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_path_PKG_CONFIG+:} false; then :
$as_echo_n "(cached) " >&6
else
case $PKG_CONFIG in
[\\/]* | ?:[\\/]*)
ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
test -z "$ac_cv_path_PKG_CONFIG" && ac_cv_path_PKG_CONFIG="no"
;;
esac
fi
PKG_CONFIG=$ac_cv_path_PKG_CONFIG
if test -n "$PKG_CONFIG"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
$as_echo "$PKG_CONFIG" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
if test x$PKG_CONFIG != xno; then
FCITX_CFLAGS=`$PKG_CONFIG --cflags fcitx`
CFLAGS="$CFLAGS $FCITX_CFLAGS"
ac_fn_c_check_header_mongrel "$LINENO" "fcitx/frontend.h" "ac_cv_header_fcitx_frontend_h" "$ac_includes_default"
if test "x$ac_cv_header_fcitx_frontend_h" = xyes; then :
have_fcitx_frontend_h_hdr=yes
else
have_fcitx_frontend_h_hdr=no
fi
CFLAGS="$save_CFLAGS"
if test x$have_fcitx_frontend_h_hdr = xyes; then
if test x$enable_ime != xyes; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: IME support is required for fcitx." >&5
$as_echo "$as_me: WARNING: IME support is required for fcitx." >&2;}
have_fcitx_frontend_h_hdr=no
elif test x$enable_dbus != xyes; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: DBus support is required for fcitx." >&5
$as_echo "$as_me: WARNING: DBus support is required for fcitx." >&2;}
have_fcitx_frontend_h_hdr=no
else
$as_echo "#define HAVE_FCITX_FRONTEND_H 1" >>confdefs.h
EXTRA_CFLAGS="$EXTRA_CFLAGS $FCITX_CFLAGS"
SOURCES="$SOURCES $srcdir/src/core/linux/SDL_fcitx.c"
fi
fi
fi
fi
}
CheckTslib() CheckTslib()
{ {
# Check whether --enable-input-tslib was given. # Check whether --enable-input-tslib was given.
@ -23031,7 +23140,9 @@ case "$host" in
CheckWayland CheckWayland
CheckLibUDev CheckLibUDev
CheckDBus CheckDBus
CheckIME
CheckIBus CheckIBus
CheckFcitx
case $ARCH in case $ARCH in
linux) linux)
CheckInputEvents CheckInputEvents
@ -23944,11 +24055,21 @@ if test x$have_dbus_dbus_h_hdr = xyes; then
else else
SUMMARY="${SUMMARY}Using dbus : NO\n" SUMMARY="${SUMMARY}Using dbus : NO\n"
fi fi
if test x$enable_ime = xyes; then
SUMMARY="${SUMMARY}Using ime : YES\n"
else
SUMMARY="${SUMMARY}Using ime : NO\n"
fi
if test x$have_ibus_ibus_h_hdr = xyes; then if test x$have_ibus_ibus_h_hdr = xyes; then
SUMMARY="${SUMMARY}Using ibus : YES\n" SUMMARY="${SUMMARY}Using ibus : YES\n"
else else
SUMMARY="${SUMMARY}Using ibus : NO\n" SUMMARY="${SUMMARY}Using ibus : NO\n"
fi fi
if test x$have_fcitx_frontend_h_hdr = xyes; then
SUMMARY="${SUMMARY}Using fcitx : YES\n"
else
SUMMARY="${SUMMARY}Using fcitx : NO\n"
fi
ac_config_commands="$ac_config_commands summary" ac_config_commands="$ac_config_commands summary"

View File

@ -2260,6 +2260,18 @@ AC_HELP_STRING([--enable-dbus], [enable D-Bus support [[default=yes]]]),
fi fi
} }
dnl See if the platform wanna IME support.
CheckIME()
{
AC_ARG_ENABLE(ime,
AC_HELP_STRING([--enable-ime], [enable IME support [[default=yes]]]),
, enable_ime=yes)
if test x$enable_ime = xyes; then
AC_DEFINE(SDL_USE_IME, 1, [ ])
SOURCES="$SOURCES $srcdir/src/core/linux/SDL_ime.c"
fi
}
dnl See if the platform has libibus IME support. dnl See if the platform has libibus IME support.
CheckIBus() CheckIBus()
{ {
@ -2280,7 +2292,10 @@ AC_HELP_STRING([--enable-ibus], [enable IBus support [[default=yes]]]),
have_inotify_inotify_h_hdr=no) have_inotify_inotify_h_hdr=no)
CFLAGS="$save_CFLAGS" CFLAGS="$save_CFLAGS"
if test x$have_ibus_ibus_h_hdr = xyes; then if test x$have_ibus_ibus_h_hdr = xyes; then
if test x$enable_dbus != xyes; then if test x$enable_ime != xyes; then
AC_MSG_WARN([IME support is required for IBus.])
have_ibus_ibus_h_hdr=no
elif test x$enable_dbus != xyes; then
AC_MSG_WARN([DBus support is required for IBus.]) AC_MSG_WARN([DBus support is required for IBus.])
have_ibus_ibus_h_hdr=no have_ibus_ibus_h_hdr=no
elif test x$have_inotify_inotify_h_hdr != xyes; then elif test x$have_inotify_inotify_h_hdr != xyes; then
@ -2296,6 +2311,38 @@ AC_HELP_STRING([--enable-ibus], [enable IBus support [[default=yes]]]),
fi fi
} }
dnl See if the platform has fcitx IME support.
CheckFcitx()
{
AC_ARG_ENABLE(fcitx,
AC_HELP_STRING([--enable-fcitx], [enable fcitx support [[default=yes]]]),
, enable_fcitx=yes)
if test x$enable_fcitx = xyes; then
AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
if test x$PKG_CONFIG != xno; then
FCITX_CFLAGS=`$PKG_CONFIG --cflags fcitx`
CFLAGS="$CFLAGS $FCITX_CFLAGS"
AC_CHECK_HEADER(fcitx/frontend.h,
have_fcitx_frontend_h_hdr=yes,
have_fcitx_frontend_h_hdr=no)
CFLAGS="$save_CFLAGS"
if test x$have_fcitx_frontend_h_hdr = xyes; then
if test x$enable_ime != xyes; then
AC_MSG_WARN([IME support is required for fcitx.])
have_fcitx_frontend_h_hdr=no
elif test x$enable_dbus != xyes; then
AC_MSG_WARN([DBus support is required for fcitx.])
have_fcitx_frontend_h_hdr=no
else
AC_DEFINE(HAVE_FCITX_FRONTEND_H, 1, [ ])
EXTRA_CFLAGS="$EXTRA_CFLAGS $FCITX_CFLAGS"
SOURCES="$SOURCES $srcdir/src/core/linux/SDL_fcitx.c"
fi
fi
fi
fi
}
dnl See if we can use the Touchscreen input library dnl See if we can use the Touchscreen input library
CheckTslib() CheckTslib()
{ {
@ -2924,7 +2971,9 @@ case "$host" in
CheckWayland CheckWayland
CheckLibUDev CheckLibUDev
CheckDBus CheckDBus
CheckIME
CheckIBus CheckIBus
CheckFcitx
case $ARCH in case $ARCH in
linux) linux)
CheckInputEvents CheckInputEvents
@ -3679,11 +3728,21 @@ if test x$have_dbus_dbus_h_hdr = xyes; then
else else
SUMMARY="${SUMMARY}Using dbus : NO\n" SUMMARY="${SUMMARY}Using dbus : NO\n"
fi fi
if test x$enable_ime = xyes; then
SUMMARY="${SUMMARY}Using ime : YES\n"
else
SUMMARY="${SUMMARY}Using ime : NO\n"
fi
if test x$have_ibus_ibus_h_hdr = xyes; then if test x$have_ibus_ibus_h_hdr = xyes; then
SUMMARY="${SUMMARY}Using ibus : YES\n" SUMMARY="${SUMMARY}Using ibus : YES\n"
else else
SUMMARY="${SUMMARY}Using ibus : NO\n" SUMMARY="${SUMMARY}Using ibus : NO\n"
fi fi
if test x$have_fcitx_frontend_h_hdr = xyes; then
SUMMARY="${SUMMARY}Using fcitx : YES\n"
else
SUMMARY="${SUMMARY}Using fcitx : NO\n"
fi
AC_CONFIG_COMMANDS([summary], [echo -en "$SUMMARY"], [SUMMARY="$SUMMARY"]) AC_CONFIG_COMMANDS([summary], [echo -en "$SUMMARY"], [SUMMARY="$SUMMARY"])
AC_OUTPUT AC_OUTPUT

View File

@ -82,6 +82,7 @@
#undef HAVE_LIBUDEV_H #undef HAVE_LIBUDEV_H
#undef HAVE_DBUS_DBUS_H #undef HAVE_DBUS_DBUS_H
#undef HAVE_IBUS_IBUS_H #undef HAVE_IBUS_IBUS_H
#undef HAVE_FCITX_FRONTEND_H
/* C library functions */ /* C library functions */
#undef HAVE_MALLOC #undef HAVE_MALLOC
@ -356,4 +357,7 @@
#undef SDL_ASSEMBLY_ROUTINES #undef SDL_ASSEMBLY_ROUTINES
#undef SDL_ALTIVEC_BLITTERS #undef SDL_ALTIVEC_BLITTERS
/* Enable ime support */
#undef SDL_USE_IME
#endif /* _SDL_config_h */ #endif /* _SDL_config_h */

548
src/core/linux/SDL_fcitx.c Normal file
View File

@ -0,0 +1,548 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include <fcitx/frontend.h>
#include <unistd.h>
#include "SDL_fcitx.h"
#include "SDL_keycode.h"
#include "SDL_keyboard.h"
#include "../../events/SDL_keyboard_c.h"
#include "SDL_dbus.h"
#include "SDL_syswm.h"
#if SDL_VIDEO_DRIVER_X11
# include "../../video/x11/SDL_x11video.h"
#endif
#include "SDL_hints.h"
#define FCITX_DBUS_SERVICE "org.fcitx.Fcitx"
#define FCITX_IM_DBUS_PATH "/inputmethod"
#define FCITX_IC_DBUS_PATH "/inputcontext_%d"
#define FCITX_IM_DBUS_INTERFACE "org.fcitx.Fcitx.InputMethod"
#define FCITX_IC_DBUS_INTERFACE "org.fcitx.Fcitx.InputContext"
#define IC_NAME_MAX 64
#define DBUS_TIMEOUT 500
typedef struct _FcitxClient
{
SDL_DBusContext *dbus;
char servicename[IC_NAME_MAX];
char icname[IC_NAME_MAX];
int id;
SDL_Rect cursor_rect;
} FcitxClient;
static FcitxClient fcitx_client;
static int
GetDisplayNumber()
{
const char *display = SDL_getenv("DISPLAY");
const char *p = NULL;;
int number = 0;
if (display == NULL)
return 0;
display = SDL_strchr(display, ':');
if (display == NULL)
return 0;
display++;
p = SDL_strchr(display, '.');
if (p == NULL && display != NULL) {
number = SDL_strtod(display, NULL);
} else {
char *buffer = SDL_strdup(display);
buffer[p - display] = '\0';
number = SDL_strtod(buffer, NULL);
SDL_free(buffer);
}
return number;
}
static char*
GetAppName()
{
#if defined(__LINUX__) || defined(__FREEBSD__)
char *spot;
char procfile[1024];
char linkfile[1024];
int linksize;
#if defined(__LINUX__)
SDL_snprintf(procfile, sizeof(procfile), "/proc/%d/exe", getpid());
#elif defined(__FREEBSD__)
SDL_snprintf(procfile, sizeof(procfile), "/proc/%d/file", getpid());
#endif
linksize = readlink(procfile, linkfile, sizeof(linkfile) - 1);
if (linksize > 0) {
linkfile[linksize] = '\0';
spot = SDL_strrchr(linkfile, '/');
if (spot) {
return SDL_strdup(spot + 1);
} else {
return SDL_strdup(linkfile);
}
}
#endif /* __LINUX__ || __FREEBSD__ */
return SDL_strdup("SDL_App");
}
/*
* Copied from fcitx source
*/
#define CONT(i) ISUTF8_CB(in[i])
#define VAL(i, s) ((in[i]&0x3f) << s)
static char *
_fcitx_utf8_get_char(const char *i, uint32_t *chr)
{
const unsigned char* in = (const unsigned char *)i;
if (!(in[0] & 0x80)) {
*(chr) = *(in);
return (char *)in + 1;
}
/* 2-byte, 0x80-0x7ff */
if ((in[0] & 0xe0) == 0xc0 && CONT(1)) {
*chr = ((in[0] & 0x1f) << 6) | VAL(1, 0);
return (char *)in + 2;
}
/* 3-byte, 0x800-0xffff */
if ((in[0] & 0xf0) == 0xe0 && CONT(1) && CONT(2)) {
*chr = ((in[0] & 0xf) << 12) | VAL(1, 6) | VAL(2, 0);
return (char *)in + 3;
}
/* 4-byte, 0x10000-0x1FFFFF */
if ((in[0] & 0xf8) == 0xf0 && CONT(1) && CONT(2) && CONT(3)) {
*chr = ((in[0] & 0x7) << 18) | VAL(1, 12) | VAL(2, 6) | VAL(3, 0);
return (char *)in + 4;
}
/* 5-byte, 0x200000-0x3FFFFFF */
if ((in[0] & 0xfc) == 0xf8 && CONT(1) && CONT(2) && CONT(3) && CONT(4)) {
*chr = ((in[0] & 0x3) << 24) | VAL(1, 18) | VAL(2, 12) | VAL(3, 6) | VAL(4, 0);
return (char *)in + 5;
}
/* 6-byte, 0x400000-0x7FFFFFF */
if ((in[0] & 0xfe) == 0xfc && CONT(1) && CONT(2) && CONT(3) && CONT(4) && CONT(5)) {
*chr = ((in[0] & 0x1) << 30) | VAL(1, 24) | VAL(2, 18) | VAL(3, 12) | VAL(4, 6) | VAL(5, 0);
return (char *)in + 6;
}
*chr = *in;
return (char *)in + 1;
}
static size_t
_fcitx_utf8_strlen(const char *s)
{
unsigned int l = 0;
while (*s) {
uint32_t chr;
s = _fcitx_utf8_get_char(s, &chr);
l++;
}
return l;
}
static DBusHandlerResult
DBus_MessageFilter(DBusConnection *conn, DBusMessage *msg, void *data)
{
SDL_DBusContext *dbus = (SDL_DBusContext *)data;
if (dbus->message_is_signal(msg, FCITX_IC_DBUS_INTERFACE, "CommitString")) {
DBusMessageIter iter;
const char *text = NULL;
dbus->message_iter_init(msg, &iter);
dbus->message_iter_get_basic(&iter, &text);
if (text)
SDL_SendKeyboardText(text);
return DBUS_HANDLER_RESULT_HANDLED;
}
if (dbus->message_is_signal(msg, FCITX_IC_DBUS_INTERFACE, "UpdatePreedit")) {
DBusMessageIter iter;
const char *text;
dbus->message_iter_init(msg, &iter);
dbus->message_iter_get_basic(&iter, &text);
if (text && *text) {
char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
size_t text_bytes = SDL_strlen(text), i = 0;
size_t cursor = 0;
while (i < text_bytes) {
size_t sz = SDL_utf8strlcpy(buf, text + i, sizeof(buf));
size_t chars = _fcitx_utf8_strlen(buf);
SDL_SendEditingText(buf, cursor, chars);
i += sz;
cursor += chars;
}
}
SDL_Fcitx_UpdateTextRect(NULL);
return DBUS_HANDLER_RESULT_HANDLED;
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static DBusMessage*
FcitxClientICNewMethod(FcitxClient *client,
const char *method)
{
SDL_DBusContext *dbus = client->dbus;
return dbus->message_new_method_call(
client->servicename,
client->icname,
FCITX_IC_DBUS_INTERFACE,
method);
}
static void
FcitxClientICCallMethod(FcitxClient *client,
const char *method)
{
SDL_DBusContext *dbus = client->dbus;
DBusMessage *msg = FcitxClientICNewMethod(client, method);
if (msg == NULL)
return ;
if (dbus->connection_send(dbus->session_conn, msg, NULL)) {
dbus->connection_flush(dbus->session_conn);
}
dbus->message_unref(msg);
}
static void
Fcitx_SetCapabilities(void *data,
const char *name,
const char *old_val,
const char *internal_editing)
{
FcitxClient *client = (FcitxClient *)data;
SDL_DBusContext *dbus = client->dbus;
Uint32 caps = CAPACITY_NONE;
DBusMessage *msg = FcitxClientICNewMethod(client, "SetCapacity");
if (msg == NULL)
return ;
if (!(internal_editing && *internal_editing == '1')) {
caps |= CAPACITY_PREEDIT;
}
dbus->message_append_args(msg,
DBUS_TYPE_UINT32, &caps,
DBUS_TYPE_INVALID);
if (dbus->connection_send(dbus->session_conn, msg, NULL)) {
dbus->connection_flush(dbus->session_conn);
}
dbus->message_unref(msg);
}
static void
FcitxClientCreateIC(FcitxClient *client)
{
char *appname = NULL;
pid_t pid = 0;
int id = 0;
SDL_bool enable;
Uint32 arg1, arg2, arg3, arg4;
SDL_DBusContext *dbus = client->dbus;
DBusMessage *reply = NULL;
DBusMessage *msg = dbus->message_new_method_call(
client->servicename,
FCITX_IM_DBUS_PATH,
FCITX_IM_DBUS_INTERFACE,
"CreateICv3"
);
if (msg == NULL)
return ;
appname = GetAppName();
pid = getpid();
dbus->message_append_args(msg,
DBUS_TYPE_STRING, &appname,
DBUS_TYPE_INT32, &pid,
DBUS_TYPE_INVALID);
do {
reply = dbus->connection_send_with_reply_and_block(
dbus->session_conn,
msg,
DBUS_TIMEOUT,
NULL);
if (!reply)
break;
if (!dbus->message_get_args(reply, NULL,
DBUS_TYPE_INT32, &id,
DBUS_TYPE_BOOLEAN, &enable,
DBUS_TYPE_UINT32, &arg1,
DBUS_TYPE_UINT32, &arg2,
DBUS_TYPE_UINT32, &arg3,
DBUS_TYPE_UINT32, &arg4,
DBUS_TYPE_INVALID))
break;
if (id < 0)
break;
client->id = id;
SDL_snprintf(client->icname, IC_NAME_MAX,
FCITX_IC_DBUS_PATH, client->id);
dbus->bus_add_match(dbus->session_conn,
"type='signal', interface='org.fcitx.Fcitx.InputContext'",
NULL);
dbus->connection_add_filter(dbus->session_conn,
&DBus_MessageFilter, dbus,
NULL);
dbus->connection_flush(dbus->session_conn);
SDL_AddHintCallback(SDL_HINT_IME_INTERNAL_EDITING, &Fcitx_SetCapabilities, client);
}
while (0);
if (reply)
dbus->message_unref(reply);
dbus->message_unref(msg);
SDL_free(appname);
}
static Uint32
Fcitx_ModState(void)
{
Uint32 fcitx_mods = 0;
SDL_Keymod sdl_mods = SDL_GetModState();
if (sdl_mods & KMOD_SHIFT) fcitx_mods |= FcitxKeyState_Shift;
if (sdl_mods & KMOD_CAPS) fcitx_mods |= FcitxKeyState_CapsLock;
if (sdl_mods & KMOD_CTRL) fcitx_mods |= FcitxKeyState_Ctrl;
if (sdl_mods & KMOD_ALT) fcitx_mods |= FcitxKeyState_Alt;
if (sdl_mods & KMOD_NUM) fcitx_mods |= FcitxKeyState_NumLock;
if (sdl_mods & KMOD_LGUI) fcitx_mods |= FcitxKeyState_Super;
if (sdl_mods & KMOD_RGUI) fcitx_mods |= FcitxKeyState_Meta;
return fcitx_mods;
}
SDL_bool
SDL_Fcitx_Init()
{
fcitx_client.dbus = SDL_DBus_GetContext();
fcitx_client.cursor_rect.x = -1;
fcitx_client.cursor_rect.y = -1;
fcitx_client.cursor_rect.w = 0;
fcitx_client.cursor_rect.h = 0;
SDL_snprintf(fcitx_client.servicename, IC_NAME_MAX,
"%s-%d",
FCITX_DBUS_SERVICE, GetDisplayNumber());
FcitxClientCreateIC(&fcitx_client);
return SDL_TRUE;
}
void
SDL_Fcitx_Quit()
{
FcitxClientICCallMethod(&fcitx_client, "DestroyIC");
}
void
SDL_Fcitx_SetFocus(SDL_bool focused)
{
if (focused) {
FcitxClientICCallMethod(&fcitx_client, "FocusIn");
} else {
FcitxClientICCallMethod(&fcitx_client, "FocusOut");
}
}
void
SDL_Fcitx_Reset(void)
{
FcitxClientICCallMethod(&fcitx_client, "Reset");
FcitxClientICCallMethod(&fcitx_client, "CloseIC");
}
SDL_bool
SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode)
{
DBusMessage *msg = NULL;
DBusMessage *reply = NULL;
SDL_DBusContext *dbus = fcitx_client.dbus;
Uint32 state = 0;
SDL_bool handled = SDL_FALSE;
int type = FCITX_PRESS_KEY;
Uint32 event_time = 0;
msg = FcitxClientICNewMethod(&fcitx_client, "ProcessKeyEvent");
if (msg == NULL)
return SDL_FALSE;
state = Fcitx_ModState();
dbus->message_append_args(msg,
DBUS_TYPE_UINT32, &keysym,
DBUS_TYPE_UINT32, &keycode,
DBUS_TYPE_UINT32, &state,
DBUS_TYPE_INT32, &type,
DBUS_TYPE_UINT32, &event_time,
DBUS_TYPE_INVALID);
reply = dbus->connection_send_with_reply_and_block(dbus->session_conn,
msg,
-1,
NULL);
if (reply) {
dbus->message_get_args(reply,
NULL,
DBUS_TYPE_INT32, &handled,
DBUS_TYPE_INVALID);
dbus->message_unref(reply);
}
if (handled) {
SDL_Fcitx_UpdateTextRect(NULL);
}
return handled;
}
void
SDL_Fcitx_UpdateTextRect(SDL_Rect *rect)
{
SDL_Window *focused_win = NULL;
SDL_SysWMinfo info;
int x = 0, y = 0;
SDL_Rect *cursor = &fcitx_client.cursor_rect;
SDL_DBusContext *dbus = fcitx_client.dbus;
DBusMessage *msg = NULL;
DBusConnection *conn;
if (rect) {
SDL_memcpy(cursor, rect, sizeof(SDL_Rect));
}
focused_win = SDL_GetKeyboardFocus();
if (!focused_win) {
return ;
}
SDL_VERSION(&info.version);
if (!SDL_GetWindowWMInfo(focused_win, &info)) {
return;
}
SDL_GetWindowPosition(focused_win, &x, &y);
#if SDL_VIDEO_DRIVER_X11
if (info.subsystem == SDL_SYSWM_X11) {
SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayForWindow(focused_win)->driverdata;
Display *x_disp = info.info.x11.display;
Window x_win = info.info.x11.window;
int x_screen = displaydata->screen;
Window unused;
X11_XTranslateCoordinates(x_disp, x_win, RootWindow(x_disp, x_screen), 0, 0, &x, &y, &unused);
}
#endif
if (cursor->x == -1 && cursor->y == -1 && cursor->w == 0 && cursor->h == 0) {
// move to bottom left
int w = 0, h = 0;
SDL_GetWindowSize(focused_win, &w, &h);
cursor->x = 0;
cursor->y = h;
}
x += cursor->x;
y += cursor->y;
msg = FcitxClientICNewMethod(&fcitx_client, "SetCursorRect");
if (msg == NULL)
return ;
dbus->message_append_args(msg,
DBUS_TYPE_INT32, &x,
DBUS_TYPE_INT32, &y,
DBUS_TYPE_INT32, &cursor->w,
DBUS_TYPE_INT32, &cursor->h,
DBUS_TYPE_INVALID);
conn = dbus->session_conn;
if (dbus->connection_send(conn, msg, NULL))
dbus->connection_flush(conn);
dbus->message_unref(msg);
}
void
SDL_Fcitx_PumpEvents()
{
SDL_DBusContext *dbus = fcitx_client.dbus;
DBusConnection *conn = dbus->session_conn;
dbus->connection_read_write(conn, 0);
while (dbus->connection_dispatch(conn) == DBUS_DISPATCH_DATA_REMAINS) {
/* Do nothing, actual work happens in DBus_MessageFilter */
usleep(10);
}
}
/* vi: set ts=4 sw=4 expandtab: */

View File

@ -0,0 +1,40 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef _SDL_fcitx_h
#define _SDL_fcitx_h
#include "../../SDL_internal.h"
#include "SDL_stdinc.h"
#include "SDL_rect.h"
extern SDL_bool SDL_Fcitx_Init(void);
extern void SDL_Fcitx_Quit(void);
extern void SDL_Fcitx_SetFocus(SDL_bool focused);
extern void SDL_Fcitx_Reset(void);
extern SDL_bool SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode);
extern void SDL_Fcitx_UpdateTextRect(SDL_Rect *rect);
extern void SDL_Fcitx_PumpEvents();
#endif /* _SDL_fcitx_h */
/* vi: set ts=4 sw=4 expandtab: */

135
src/core/linux/SDL_ime.c Normal file
View File

@ -0,0 +1,135 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_ime.h"
#include "SDL_ibus.h"
#include "SDL_fcitx.h"
typedef SDL_bool (*_SDL_IME_Init)();
typedef void (*_SDL_IME_Quit)();
typedef void (*_SDL_IME_SetFocus)(SDL_bool);
typedef void (*_SDL_IME_Reset)();
typedef SDL_bool (*_SDL_IME_ProcessKeyEvent)(Uint32, Uint32);
typedef void (*_SDL_IME_UpdateTextRect)(SDL_Rect *);
typedef void (*_SDL_IME_PumpEvents)();
static _SDL_IME_Init SDL_IME_Init_Real = NULL;
static _SDL_IME_Quit SDL_IME_Quit_Real = NULL;
static _SDL_IME_SetFocus SDL_IME_SetFocus_Real = NULL;
static _SDL_IME_Reset SDL_IME_Reset_Real = NULL;
static _SDL_IME_ProcessKeyEvent SDL_IME_ProcessKeyEvent_Real = NULL;
static _SDL_IME_UpdateTextRect SDL_IME_UpdateTextRect_Real = NULL;
static _SDL_IME_PumpEvents SDL_IME_PumpEvents_Real = NULL;
static void
InitIME()
{
static SDL_bool inited = SDL_FALSE;
const char *im_module = NULL;
if (inited == SDL_TRUE)
return ;
inited = SDL_TRUE;
// TODO:
// better move every ime implenment to a shared library
// default to IBus
#ifdef HAVE_IBUS_IBUS_H
SDL_IME_Init_Real = SDL_IBus_Init;
SDL_IME_Quit_Real = SDL_IBus_Quit;
SDL_IME_SetFocus_Real = SDL_IBus_SetFocus;
SDL_IME_Reset_Real = SDL_IBus_Reset;
SDL_IME_ProcessKeyEvent_Real = SDL_IBus_ProcessKeyEvent;
SDL_IME_UpdateTextRect_Real = SDL_IBus_UpdateTextRect;
SDL_IME_PumpEvents_Real = SDL_IBus_PumpEvents;
#endif
im_module = SDL_getenv("SDL_IM_MODULE");
if (im_module) {
if (SDL_strcmp(im_module, "fcitx") == 0) {
#ifdef HAVE_FCITX_FRONTEND_H
SDL_IME_Init_Real = SDL_Fcitx_Init;
SDL_IME_Quit_Real = SDL_Fcitx_Quit;
SDL_IME_SetFocus_Real = SDL_Fcitx_SetFocus;
SDL_IME_Reset_Real = SDL_Fcitx_Reset;
SDL_IME_ProcessKeyEvent_Real = SDL_Fcitx_ProcessKeyEvent;
SDL_IME_UpdateTextRect_Real = SDL_Fcitx_UpdateTextRect;
SDL_IME_PumpEvents_Real = SDL_Fcitx_PumpEvents;
#endif
}
}
}
SDL_bool
SDL_IME_Init(void)
{
InitIME();
if (SDL_IME_Init_Real)
return SDL_IME_Init_Real();
return SDL_FALSE;
}
void
SDL_IME_Quit(void)
{
if (SDL_IME_Quit_Real)
SDL_IME_Quit_Real();
}
void
SDL_IME_SetFocus(SDL_bool focused)
{
if (SDL_IME_SetFocus_Real)
SDL_IME_SetFocus_Real(focused);
}
void
SDL_IME_Reset(void)
{
if (SDL_IME_Reset_Real)
SDL_IME_Reset_Real();
}
SDL_bool
SDL_IME_ProcessKeyEvent(Uint32 keysym, Uint32 keycode)
{
if (SDL_IME_ProcessKeyEvent_Real)
return SDL_IME_ProcessKeyEvent_Real(keysym, keycode);
return SDL_FALSE;
}
void
SDL_IME_UpdateTextRect(SDL_Rect *rect)
{
if (SDL_IME_UpdateTextRect_Real)
SDL_IME_UpdateTextRect_Real(rect);
}
void
SDL_IME_PumpEvents()
{
if (SDL_IME_PumpEvents_Real)
SDL_IME_PumpEvents_Real();
}

38
src/core/linux/SDL_ime.h Normal file
View File

@ -0,0 +1,38 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef _SDL_ime_h
#define _SDL_ime_h
#include "../../SDL_internal.h"
#include "SDL_stdinc.h"
#include "SDL_rect.h"
extern SDL_bool SDL_IME_Init();
extern void SDL_IME_Quit();
extern void SDL_IME_SetFocus(SDL_bool focused);
extern void SDL_IME_Reset();
extern SDL_bool SDL_IME_ProcessKeyEvent(Uint32 keysym, Uint32 keycode);
extern void SDL_IME_UpdateTextRect(SDL_Rect *rect);
extern void SDL_IME_PumpEvents();
#endif /* _SDL_ime_h */

View File

@ -380,8 +380,8 @@ X11_DispatchFocusIn(_THIS, SDL_WindowData *data)
X11_XSetICFocus(data->ic); X11_XSetICFocus(data->ic);
} }
#endif #endif
#ifdef SDL_USE_IBUS #ifdef SDL_USE_IME
SDL_IBus_SetFocus(SDL_TRUE); SDL_IME_SetFocus(SDL_TRUE);
#endif #endif
} }
@ -403,8 +403,8 @@ X11_DispatchFocusOut(_THIS, SDL_WindowData *data)
X11_XUnsetICFocus(data->ic); X11_XUnsetICFocus(data->ic);
} }
#endif #endif
#ifdef SDL_USE_IBUS #ifdef SDL_USE_IME
SDL_IBus_SetFocus(SDL_FALSE); SDL_IME_SetFocus(SDL_FALSE);
#endif #endif
} }
@ -786,9 +786,9 @@ X11_DispatchEvent(_THIS)
X11_XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL); X11_XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL);
#endif #endif
#ifdef SDL_USE_IBUS #ifdef SDL_USE_IME
if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){ if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){
handled_by_ime = SDL_IBus_ProcessKeyEvent(keysym, keycode); handled_by_ime = SDL_IME_ProcessKeyEvent(keysym, keycode);
} }
#endif #endif
if (!handled_by_ime) { if (!handled_by_ime) {
@ -860,10 +860,10 @@ X11_DispatchEvent(_THIS)
xevent.xconfigure.y != data->last_xconfigure.y) { xevent.xconfigure.y != data->last_xconfigure.y) {
SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED, SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED,
xevent.xconfigure.x, xevent.xconfigure.y); xevent.xconfigure.x, xevent.xconfigure.y);
#ifdef SDL_USE_IBUS #ifdef SDL_USE_IME
if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){ if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){
/* Update IBus candidate list position */ /* Update IME candidate list position */
SDL_IBus_UpdateTextRect(NULL); SDL_IME_UpdateTextRect(NULL);
} }
#endif #endif
} }
@ -1408,9 +1408,9 @@ X11_PumpEvents(_THIS)
X11_DispatchEvent(_this); X11_DispatchEvent(_this);
} }
#ifdef SDL_USE_IBUS #ifdef SDL_USE_IME
if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){ if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){
SDL_IBus_PumpEvents(); SDL_IME_PumpEvents();
} }
#endif #endif

View File

@ -339,8 +339,8 @@ X11_InitKeyboard(_THIS)
SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu"); SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu");
#ifdef SDL_USE_IBUS #ifdef SDL_USE_IME
SDL_IBus_Init(); SDL_IME_Init();
#endif #endif
return 0; return 0;
@ -422,8 +422,8 @@ X11_QuitKeyboard(_THIS)
} }
#endif #endif
#ifdef SDL_USE_IBUS #ifdef SDL_USE_IME
SDL_IBus_Quit(); SDL_IME_Quit();
#endif #endif
} }
@ -436,8 +436,8 @@ X11_StartTextInput(_THIS)
void void
X11_StopTextInput(_THIS) X11_StopTextInput(_THIS)
{ {
#ifdef SDL_USE_IBUS #ifdef SDL_USE_IME
SDL_IBus_Reset(); SDL_IME_Reset();
#endif #endif
} }
@ -449,8 +449,8 @@ X11_SetTextInputRect(_THIS, SDL_Rect *rect)
return; return;
} }
#ifdef SDL_USE_IBUS #ifdef SDL_USE_IME
SDL_IBus_UpdateTextRect(rect); SDL_IME_UpdateTextRect(rect);
#endif #endif
} }

View File

@ -57,7 +57,7 @@
#endif #endif
#include "../../core/linux/SDL_dbus.h" #include "../../core/linux/SDL_dbus.h"
#include "../../core/linux/SDL_ibus.h" #include "../../core/linux/SDL_ime.h"
#include "SDL_x11dyn.h" #include "SDL_x11dyn.h"