Atlas - SDL_fcitx.c

Home / ext / SDL2 / src / core / linux Lines: 1 | Size: 10504 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2018 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "../../SDL_internal.h" 22 23#ifdef HAVE_FCITX_FRONTEND_H 24 25#include <fcitx/frontend.h> 26#include <unistd.h> 27 28#include "SDL_fcitx.h" 29#include "SDL_keycode.h" 30#include "SDL_keyboard.h" 31#include "../../events/SDL_keyboard_c.h" 32#include "SDL_dbus.h" 33#include "SDL_syswm.h" 34#if SDL_VIDEO_DRIVER_X11 35# include "../../video/x11/SDL_x11video.h" 36#endif 37#include "SDL_hints.h" 38 39#define FCITX_DBUS_SERVICE "org.fcitx.Fcitx" 40 41#define FCITX_IM_DBUS_PATH "/inputmethod" 42#define FCITX_IC_DBUS_PATH "/inputcontext_%d" 43 44#define FCITX_IM_DBUS_INTERFACE "org.fcitx.Fcitx.InputMethod" 45#define FCITX_IC_DBUS_INTERFACE "org.fcitx.Fcitx.InputContext" 46 47#define IC_NAME_MAX 64 48#define DBUS_TIMEOUT 500 49 50typedef struct _FcitxClient 51{ 52 SDL_DBusContext *dbus; 53 54 char servicename[IC_NAME_MAX]; 55 char icname[IC_NAME_MAX]; 56 57 int id; 58 59 SDL_Rect cursor_rect; 60} FcitxClient; 61 62static FcitxClient fcitx_client; 63 64static int 65GetDisplayNumber() 66{ 67 const char *display = SDL_getenv("DISPLAY"); 68 const char *p = NULL; 69 int number = 0; 70 71 if (display == NULL) 72 return 0; 73 74 display = SDL_strchr(display, ':'); 75 if (display == NULL) 76 return 0; 77 78 display++; 79 p = SDL_strchr(display, '.'); 80 if (p == NULL && display != NULL) { 81 number = SDL_strtod(display, NULL); 82 } else { 83 char *buffer = SDL_strdup(display); 84 buffer[p - display] = '\0'; 85 number = SDL_strtod(buffer, NULL); 86 SDL_free(buffer); 87 } 88 89 return number; 90} 91 92static char* 93GetAppName() 94{ 95#if defined(__LINUX__) || defined(__FREEBSD__) 96 char *spot; 97 char procfile[1024]; 98 char linkfile[1024]; 99 int linksize; 100 101#if defined(__LINUX__) 102 SDL_snprintf(procfile, sizeof(procfile), "/proc/%d/exe", getpid()); 103#elif defined(__FREEBSD__) 104 SDL_snprintf(procfile, sizeof(procfile), "/proc/%d/file", getpid()); 105#endif 106 linksize = readlink(procfile, linkfile, sizeof(linkfile) - 1); 107 if (linksize > 0) { 108 linkfile[linksize] = '\0'; 109 spot = SDL_strrchr(linkfile, '/'); 110 if (spot) { 111 return SDL_strdup(spot + 1); 112 } else { 113 return SDL_strdup(linkfile); 114 } 115 } 116#endif /* __LINUX__ || __FREEBSD__ */ 117 118 return SDL_strdup("SDL_App"); 119} 120 121static DBusHandlerResult 122DBus_MessageFilter(DBusConnection *conn, DBusMessage *msg, void *data) 123{ 124 SDL_DBusContext *dbus = (SDL_DBusContext *)data; 125 126 if (dbus->message_is_signal(msg, FCITX_IC_DBUS_INTERFACE, "CommitString")) { 127 DBusMessageIter iter; 128 const char *text = NULL; 129 130 dbus->message_iter_init(msg, &iter); 131 dbus->message_iter_get_basic(&iter, &text); 132 133 if (text) 134 SDL_SendKeyboardText(text); 135 136 return DBUS_HANDLER_RESULT_HANDLED; 137 } 138 139 if (dbus->message_is_signal(msg, FCITX_IC_DBUS_INTERFACE, "UpdatePreedit")) { 140 DBusMessageIter iter; 141 const char *text; 142 143 dbus->message_iter_init(msg, &iter); 144 dbus->message_iter_get_basic(&iter, &text); 145 146 if (text && *text) { 147 char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE]; 148 size_t text_bytes = SDL_strlen(text), i = 0; 149 size_t cursor = 0; 150 151 while (i < text_bytes) { 152 const size_t sz = SDL_utf8strlcpy(buf, text + i, sizeof(buf)); 153 const size_t chars = SDL_utf8strlen(buf); 154 155 SDL_SendEditingText(buf, cursor, chars); 156 157 i += sz; 158 cursor += chars; 159 } 160 } 161 162 SDL_Fcitx_UpdateTextRect(NULL); 163 return DBUS_HANDLER_RESULT_HANDLED; 164 } 165 166 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 167} 168 169static void 170FcitxClientICCallMethod(FcitxClient *client, const char *method) 171{ 172 SDL_DBus_CallVoidMethod(client->servicename, client->icname, FCITX_IC_DBUS_INTERFACE, method, DBUS_TYPE_INVALID); 173} 174 175static void SDLCALL 176Fcitx_SetCapabilities(void *data, 177 const char *name, 178 const char *old_val, 179 const char *internal_editing) 180{ 181 FcitxClient *client = (FcitxClient *)data; 182 Uint32 caps = CAPACITY_NONE; 183 184 if (!(internal_editing && *internal_editing == '1')) { 185 caps |= CAPACITY_PREEDIT; 186 } 187 188 SDL_DBus_CallVoidMethod(client->servicename, client->icname, FCITX_IC_DBUS_INTERFACE, "SetCapacity", DBUS_TYPE_UINT32, &caps, DBUS_TYPE_INVALID); 189} 190 191static SDL_bool 192FcitxClientCreateIC(FcitxClient *client) 193{ 194 char *appname = GetAppName(); 195 pid_t pid = getpid(); 196 int id = -1; 197 Uint32 enable, arg1, arg2, arg3, arg4; 198 199 if (!SDL_DBus_CallMethod(client->servicename, FCITX_IM_DBUS_PATH, FCITX_IM_DBUS_INTERFACE, "CreateICv3", 200 DBUS_TYPE_STRING, &appname, DBUS_TYPE_INT32, &pid, DBUS_TYPE_INVALID, 201 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)) { 202 id = -1; /* just in case. */ 203 } 204 205 SDL_free(appname); 206 207 if (id >= 0) { 208 SDL_DBusContext *dbus = client->dbus; 209 210 client->id = id; 211 212 SDL_snprintf(client->icname, IC_NAME_MAX, FCITX_IC_DBUS_PATH, client->id); 213 214 dbus->bus_add_match(dbus->session_conn, 215 "type='signal', interface='org.fcitx.Fcitx.InputContext'", 216 NULL); 217 dbus->connection_add_filter(dbus->session_conn, 218 &DBus_MessageFilter, dbus, 219 NULL); 220 dbus->connection_flush(dbus->session_conn); 221 222 SDL_AddHintCallback(SDL_HINT_IME_INTERNAL_EDITING, Fcitx_SetCapabilities, client); 223 return SDL_TRUE; 224 } 225 226 return SDL_FALSE; 227} 228 229static Uint32 230Fcitx_ModState(void) 231{ 232 Uint32 fcitx_mods = 0; 233 SDL_Keymod sdl_mods = SDL_GetModState(); 234 235 if (sdl_mods & KMOD_SHIFT) fcitx_mods |= FcitxKeyState_Shift; 236 if (sdl_mods & KMOD_CAPS) fcitx_mods |= FcitxKeyState_CapsLock; 237 if (sdl_mods & KMOD_CTRL) fcitx_mods |= FcitxKeyState_Ctrl; 238 if (sdl_mods & KMOD_ALT) fcitx_mods |= FcitxKeyState_Alt; 239 if (sdl_mods & KMOD_NUM) fcitx_mods |= FcitxKeyState_NumLock; 240 if (sdl_mods & KMOD_LGUI) fcitx_mods |= FcitxKeyState_Super; 241 if (sdl_mods & KMOD_RGUI) fcitx_mods |= FcitxKeyState_Meta; 242 243 return fcitx_mods; 244} 245 246SDL_bool 247SDL_Fcitx_Init() 248{ 249 fcitx_client.dbus = SDL_DBus_GetContext(); 250 251 fcitx_client.cursor_rect.x = -1; 252 fcitx_client.cursor_rect.y = -1; 253 fcitx_client.cursor_rect.w = 0; 254 fcitx_client.cursor_rect.h = 0; 255 256 SDL_snprintf(fcitx_client.servicename, IC_NAME_MAX, 257 "%s-%d", 258 FCITX_DBUS_SERVICE, GetDisplayNumber()); 259 260 return FcitxClientCreateIC(&fcitx_client); 261} 262 263void 264SDL_Fcitx_Quit() 265{ 266 FcitxClientICCallMethod(&fcitx_client, "DestroyIC"); 267} 268 269void 270SDL_Fcitx_SetFocus(SDL_bool focused) 271{ 272 if (focused) { 273 FcitxClientICCallMethod(&fcitx_client, "FocusIn"); 274 } else { 275 FcitxClientICCallMethod(&fcitx_client, "FocusOut"); 276 } 277} 278 279void 280SDL_Fcitx_Reset(void) 281{ 282 FcitxClientICCallMethod(&fcitx_client, "Reset"); 283 FcitxClientICCallMethod(&fcitx_client, "CloseIC"); 284} 285 286SDL_bool 287SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode) 288{ 289 Uint32 state = Fcitx_ModState(); 290 Uint32 handled = SDL_FALSE; 291 int type = FCITX_PRESS_KEY; 292 Uint32 event_time = 0; 293 294 if (SDL_DBus_CallMethod(fcitx_client.servicename, fcitx_client.icname, FCITX_IC_DBUS_INTERFACE, "ProcessKeyEvent", 295 DBUS_TYPE_UINT32, &keysym, DBUS_TYPE_UINT32, &keycode, DBUS_TYPE_UINT32, &state, DBUS_TYPE_INT32, &type, DBUS_TYPE_UINT32, &event_time, DBUS_TYPE_INVALID, 296 DBUS_TYPE_INT32, &handled, DBUS_TYPE_INVALID)) { 297 if (handled) { 298 SDL_Fcitx_UpdateTextRect(NULL); 299 return SDL_TRUE; 300 } 301 } 302 303 return SDL_FALSE; 304} 305 306void 307SDL_Fcitx_UpdateTextRect(SDL_Rect *rect) 308{ 309 SDL_Window *focused_win = NULL; 310 SDL_SysWMinfo info; 311 int x = 0, y = 0; 312 SDL_Rect *cursor = &fcitx_client.cursor_rect; 313 314 if (rect) { 315 SDL_memcpy(cursor, rect, sizeof(SDL_Rect)); 316 } 317 318 focused_win = SDL_GetKeyboardFocus(); 319 if (!focused_win) { 320 return ; 321 } 322 323 SDL_VERSION(&info.version); 324 if (!SDL_GetWindowWMInfo(focused_win, &info)) { 325 return; 326 } 327 328 SDL_GetWindowPosition(focused_win, &x, &y); 329 330#if SDL_VIDEO_DRIVER_X11 331 if (info.subsystem == SDL_SYSWM_X11) { 332 SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayForWindow(focused_win)->driverdata; 333 334 Display *x_disp = info.info.x11.display; 335 Window x_win = info.info.x11.window; 336 int x_screen = displaydata->screen; 337 Window unused; 338 X11_XTranslateCoordinates(x_disp, x_win, RootWindow(x_disp, x_screen), 0, 0, &x, &y, &unused); 339 } 340#endif 341 342 if (cursor->x == -1 && cursor->y == -1 && cursor->w == 0 && cursor->h == 0) { 343 /* move to bottom left */ 344 int w = 0, h = 0; 345 SDL_GetWindowSize(focused_win, &w, &h); 346 cursor->x = 0; 347 cursor->y = h; 348 } 349 350 x += cursor->x; 351 y += cursor->y; 352 353 SDL_DBus_CallVoidMethod(fcitx_client.servicename, fcitx_client.icname, FCITX_IC_DBUS_INTERFACE, "SetCursorRect", 354 DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y, DBUS_TYPE_INT32, &cursor->w, DBUS_TYPE_INT32, &cursor->h, DBUS_TYPE_INVALID); 355} 356 357void 358SDL_Fcitx_PumpEvents(void) 359{ 360 SDL_DBusContext *dbus = fcitx_client.dbus; 361 DBusConnection *conn = dbus->session_conn; 362 363 dbus->connection_read_write(conn, 0); 364 365 while (dbus->connection_dispatch(conn) == DBUS_DISPATCH_DATA_REMAINS) { 366 /* Do nothing, actual work happens in DBus_MessageFilter */ 367 usleep(10); 368 } 369} 370 371#endif /* HAVE_FCITX_FRONTEND_H */ 372 373/* vi: set ts=4 sw=4 expandtab: */ 374
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.