├── AUTHORS ├── README ├── .gitignore ├── scripts ├── CMakeLists.txt └── fcitx-fbterm-helper ├── src ├── keymap.h ├── CMakeLists.txt ├── keycode.h ├── input_key.h ├── imapi.h ├── imapi.c ├── keycode.c ├── immessage.h ├── keymap.c └── fcitx-fbterm.c ├── INSTALL ├── cmake └── cmake_uninstall.cmake.in ├── CMakeLists.txt └── COPYING /AUTHORS: -------------------------------------------------------------------------------- 1 | Weng Xuetian -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | fcitx-fbterm, add fbterm support to fcitx -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/* 2 | *.kdev4 3 | .kdev_include_paths 4 | .directory 5 | *.kate-swp 6 | *.orig 7 | *~ 8 | -------------------------------------------------------------------------------- /scripts/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | install(FILES fcitx-fbterm-helper DESTINATION ${bindir} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) 2 | -------------------------------------------------------------------------------- /src/keymap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * original from ibus-fbterm 3 | */ 4 | 5 | #include 6 | 7 | FcitxKeySym linux_keysym_to_fcitx_keysym(unsigned short keysym, unsigned short keycode); 8 | 9 | FcitxKeyState calculate_modifiers(FcitxKeyState state, FcitxKeySym keyval, char down); -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | fcitx-fbterm install instructions 2 | ================================================= 3 | 4 | To compile and install, go in the source directory and type: 5 | mkdir build; cd build 6 | cmake .. 7 | (If you want to install in a different path, use instead: 8 | cmake .. -DCMAKE_INSTALL_PREFIX=/install/path) 9 | make 10 | 11 | To install, become root if required: 12 | 13 | make install -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories( 2 | ${CMAKE_CURRENT_SOURCE_DIR} 3 | ${CMAKE_CURRENT_BINARY_DIR} 4 | ${FCITX4_FCITX_INCLUDE_DIRS} 5 | ${FCITX4_FCITX_UTILS_INCLUDE_DIRS} 6 | ${FCITX4_FCITX_CONFIG_INCLUDE_DIRS} 7 | ${FCITX_GCLIENT_INCLUDE_DIRS} 8 | ) 9 | 10 | link_directories( 11 | ${FCITX4_FCITX_LIBRARY_DIRS} 12 | ${FCITX4_FCITX_UTILS_LIBRARY_DIRS} 13 | ${FCITX4_FCITX_CONFIG_LIBRARY_DIRS} 14 | ${FCITX_GCLIENT_LIBRARY_DIRS} 15 | ) 16 | 17 | set(fcitx_fbterm_SOURCES 18 | imapi.c 19 | fcitx-fbterm.c 20 | keycode.c 21 | keymap.c 22 | ) 23 | 24 | add_executable(fcitx-fbterm ${fcitx_fbterm_SOURCES}) 25 | target_link_libraries(fcitx-fbterm 26 | ${FCITX_GCLIENT_LIBRARIES} 27 | ${FCITX4_FCITX_LIBRARIES} 28 | ${FCITX4_FCITX_CONFIG_LIBRARIES} 29 | ${FCITX4_FCITX_UTILS_LIBRARIES} 30 | ) 31 | 32 | install(TARGETS fcitx-fbterm DESTINATION ${bindir}) 33 | -------------------------------------------------------------------------------- /cmake/cmake_uninstall.cmake.in: -------------------------------------------------------------------------------- 1 | if (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 2 | message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") 3 | endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 4 | 5 | file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) 6 | string(REGEX REPLACE "\n" ";" files "${files}") 7 | foreach (file ${files}) 8 | message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") 9 | if (EXISTS "$ENV{DESTDIR}${file}" OR IS_SYMLINK "$ENV{DESTDIR}${file}") 10 | execute_process( 11 | COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}" 12 | OUTPUT_VARIABLE rm_out 13 | RESULT_VARIABLE rm_retval 14 | ) 15 | if(NOT ${rm_retval} EQUAL 0) 16 | message(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") 17 | endif (NOT ${rm_retval} EQUAL 0) 18 | else (EXISTS "$ENV{DESTDIR}${file}" OR IS_SYMLINK "$ENV{DESTDIR}${file}") 19 | message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") 20 | endif (EXISTS "$ENV{DESTDIR}${file}" OR IS_SYMLINK "$ENV{DESTDIR}${file}") 21 | endforeach(file) -------------------------------------------------------------------------------- /src/keycode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2008-2010 dragchan 3 | * This file is part of FbTerm. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 | * 19 | */ 20 | 21 | #ifndef KEYCODE_H 22 | #define KEYCODE_H 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | void init_keycode_state(); 29 | 30 | void update_term_mode(char crlf, char appkey, char curo); 31 | 32 | unsigned short keycode_to_keysym(unsigned short keycode, char down, int fallback); 33 | 34 | unsigned short keypad_keysym_redirect(unsigned short keysym); 35 | 36 | char *keysym_to_term_string(unsigned short keysym, char down); 37 | 38 | #ifdef __cplusplus 39 | } 40 | #endif 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | 3 | project(fcitx-fbterm) 4 | 5 | find_package(PkgConfig REQUIRED) 6 | find_package(Gettext REQUIRED) 7 | find_package(Fcitx 4.2.6 REQUIRED) 8 | 9 | pkg_check_modules(FCITX_GCLIENT "fcitx-gclient>=4.2.6" REQUIRED) 10 | 11 | # uninstall target 12 | configure_file( 13 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in" 14 | "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" 15 | IMMEDIATE @ONLY) 16 | 17 | add_custom_target(uninstall 18 | COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) 19 | 20 | if(NOT DEFINED LIB_INSTALL_DIR) 21 | set(LIB_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/lib) 22 | endif() 23 | 24 | include(FindPkgConfig) 25 | 26 | set(prefix ${CMAKE_INSTALL_PREFIX}) 27 | set(exec_prefix ${CMAKE_INSTALL_PREFIX}) 28 | set(bindir ${prefix}/bin) 29 | set(libdir ${LIB_INSTALL_DIR}) 30 | set(localedir ${CMAKE_INSTALL_PREFIX}/share/locale) 31 | set(includedir ${CMAKE_INSTALL_PREFIX}/include) 32 | set(CMAKE_C_FLAGS "-Wall -Wextra -Wno-sign-compare -Wno-unused-parameter -fvisibility=hidden ${CMAKE_C_FLAGS}") 33 | set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-sign-compare -Wno-unused-parameter -fvisibility=hidden ${CMAKE_CXX_FLAGS}") 34 | set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined,--as-needed ${CMAKE_SHARED_LINKER_FLAGS}") 35 | set(CMAKE_MODULE_LINKER_FLAGS "-Wl,--no-undefined,--as-needed ${CMAKE_MODULE_LINKER_FLAGS}") 36 | 37 | set(libdir ${LIB_INSTALL_DIR}) 38 | 39 | add_subdirectory(src) 40 | add_subdirectory(scripts) 41 | -------------------------------------------------------------------------------- /src/input_key.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2008-2010 dragchan 3 | * This file is part of FbTerm. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 | * 19 | */ 20 | 21 | #ifndef INPUT_KEY_H 22 | #define INPUT_KEY_H 23 | 24 | #include 25 | 26 | enum Keys { 27 | AC_START = K(KT_LATIN, 0x80), 28 | SHIFT_PAGEUP = AC_START, 29 | SHIFT_PAGEDOWN, 30 | SHIFT_LEFT, 31 | SHIFT_RIGHT, 32 | CTRL_SPACE, 33 | CTRL_ALT_1, 34 | CTRL_ALT_2, 35 | CTRL_ALT_3, 36 | CTRL_ALT_4, 37 | CTRL_ALT_5, 38 | CTRL_ALT_6, 39 | CTRL_ALT_7, 40 | CTRL_ALT_8, 41 | CTRL_ALT_9, 42 | CTRL_ALT_0, 43 | CTRL_ALT_C, 44 | CTRL_ALT_D, 45 | CTRL_ALT_E, 46 | CTRL_ALT_F1, 47 | CTRL_ALT_F2, 48 | CTRL_ALT_F3, 49 | CTRL_ALT_F4, 50 | CTRL_ALT_F5, 51 | CTRL_ALT_F6, 52 | CTRL_ALT_K, 53 | AC_END = CTRL_ALT_K 54 | }; 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /scripts/fcitx-fbterm-helper: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function Usage() 4 | { 5 | echo -e "$0 - Fcitx Fbterm launch helper" 6 | echo -e "\t-d [display number]\t\tspecify display number (For example 0)" 7 | echo -e "\t-l\t\t\t\tLaunch Fcitx automatically" 8 | echo -e "\t-h\t\t\t\tPrint this help" 9 | } 10 | 11 | LAUNCH=0 12 | FCITX_RUN=0 13 | 14 | if [ "x$SHELL" = "x" ]; then 15 | echo "\$SHELL is not set" 16 | fi 17 | 18 | while getopts "d:lh" opt; do 19 | case $opt in 20 | d) 21 | DISPLAY_NUM=$OPTARG 22 | ;; 23 | l) 24 | LAUNCH=1 25 | ;; 26 | *) 27 | Usage 28 | exit 0 29 | ;; 30 | esac 31 | done 32 | 33 | if [ "x$DISPLAY_NUM" != "x" ]; then 34 | export DISPLAY=":$DISPLAY_NUM" 35 | fi 36 | 37 | if [ "x$DISPLAY" != "x" ]; then 38 | number=`echo $DISPLAY | sed 's|\:\([0-9]\+\)\(\..*\)\?|\1|g'` 39 | if [ "x$number" == "x" ]; then 40 | echo '$DISPLAY parse error' 41 | exit 1 42 | fi 43 | echo "Your display number is $number" 44 | else 45 | number=0 46 | fi 47 | 48 | echo "Test whether fcitx is running correctly with dbus..." 49 | fcitx-remote > /dev/null 2>&1 50 | 51 | if [ $? == "1" ]; then 52 | echo "Cannot communicate fcitx with DBus." 53 | FCITX_RUN=0 54 | else 55 | echo "Fcitx is running correctly." 56 | FCITX_RUN=1 57 | fi 58 | 59 | echo '' 60 | echo '=========================================================' 61 | 62 | if [ "$FCITX_RUN" == "0" -a "$LAUNCH" == "1" ]; then 63 | echo "Try launch fcitx..." 64 | pgrep -u `whoami` '^fcitx$' > /dev/null 2>&1 65 | if [ $? == "0" ]; then 66 | echo "There is already a fcitx running, Fcitx cannot support multi instance currently" 67 | exit 1 68 | fi 69 | echo "Launch Fcitx..." 70 | fcitx -D > /dev/null 2>&1 & 71 | fcitxpid=$! 72 | FCITX_RUN=1 73 | fi 74 | 75 | if [ $FCITX_RUN == "1" ]; then 76 | echo "Launch fbterm..." 77 | fbterm -i fcitx-fbterm 78 | if [ "$LAUNCH" == "1" ] ; then 79 | if ! test -z "$fcitxpid" ; then 80 | kill $fcitxpid 81 | fi 82 | fi 83 | else 84 | echo '=========================================================' 85 | echo 'Fcitx is not running, you may setup it mannually' 86 | echo 'The easiest way is set $DISPLAY, start fcitx from X' 87 | echo 'Then try this helper' 88 | echo '=========================================================' 89 | fi 90 | -------------------------------------------------------------------------------- /src/imapi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2008-2010 dragchan 3 | * This file is part of FbTerm. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 | * 19 | */ 20 | 21 | /** 22 | * FbTerm provides a set of wrapped API to simply the IM server development. The API encapsulates input method message sending, 23 | * receiving and processing. 24 | */ 25 | 26 | #ifndef IM_API_H 27 | #define IM_API_H 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | #include "immessage.h" 34 | 35 | typedef void (*ActiveFun)(); 36 | typedef void (*DeactiveFun)(); 37 | 38 | /// @param winid indicates which window should be redrawn, -1 means redraw all UI window. @see set_im_window() 39 | typedef void (*ShowUIFun)(unsigned winid); 40 | typedef void (*HideUIFun)(); 41 | typedef void (*SendKeyFun)(char *keys, unsigned len); 42 | typedef void (*CursorPositionFun)(unsigned x, unsigned y); 43 | typedef void (*FbTermInfoFun)(Info *info); 44 | typedef void (*TermModeFun)(char crlf, char appkey, char curo); 45 | 46 | typedef struct { 47 | ActiveFun active; ///< called when receiving a Active message 48 | DeactiveFun deactive; ///< called when receiving a Deactive message 49 | ShowUIFun show_ui; ///< called when receiving a ShowUI message 50 | HideUIFun hide_ui; ///< called when receiving a HideUI message 51 | SendKeyFun send_key; ///< called when receiving a SendKey message 52 | CursorPositionFun cursor_position; ///< called when receiving a CursorPosition message 53 | FbTermInfoFun fbterm_info; ///< called when receiving a FbTermInfo message 54 | TermModeFun term_mode; ///< called when receiving a TermMode message 55 | } ImCallbacks; 56 | 57 | /** 58 | * @brief register message call-back functions: 59 | * @param callbacks 60 | */ 61 | extern void register_im_callbacks(ImCallbacks callbacks); 62 | 63 | /** 64 | * @brief send message Connect to FbTerm 65 | * @param mode keyboard input mode 66 | * 67 | * FbTerm provides two kinds of keyboard input modes, IM server can choose a favorite one with parameter mode of 68 | * connect_fbterm(). 69 | * 70 | * If mode equals zero, IM server will receive characters translated by kernel with current keymap in SendKey messages. 71 | * There are some disadvantages in this mode, for example, shortcuts composed with only modifiers are impossible. 72 | * ( shortcuts composed with modifiers and normal keys can create a map if they are not mapped in current kernel keymap, 73 | * maybe we need add new messages like RequestKeyMap and AckKeyMap used by IM server to ask FbTerm to do this work. ) 74 | 75 | * If mode is non-zero, FbTerm sets keyboard mode to K_MEDIUMRAW after Active Message, IM server will receive raw keycode 76 | * from kernel and have full control for keyboard, except FbTerm's shortcuts, e.g. Ctrl + Space. 77 | * Under this mode, IM server should translate keycodes to keysyms according current kernel keymap, change keyboard led 78 | * state and translate keysyms to characters if it want to send user input back to FbTerm. Because some translation of 79 | * keysyms to characters are not fixed (e.g. cursor movement keysym K_LEFT can be 'ESC [ D' or 'ESC O D'), message TermMode 80 | * sent by FbTerm is used to help IM server do this translation. 81 | * 82 | * keycode.c/keycode.h provides some functions to translate keycode to keysym and keysym to characters. 83 | */ 84 | extern void connect_fbterm(char mode); 85 | 86 | /** 87 | * @brief get the file descriptor of the unix socket used to transfer IM messages. 88 | * @return file id of the socket connected to FbTerm 89 | * 90 | * Because check_im_message() blocks until a message arrives, IM server can use select/poll to monitor other file 91 | * descriptors among with the one from get_im_socket(). 92 | */ 93 | extern int get_im_socket(); 94 | 95 | /** 96 | * @brief receive IM messages from FbTerm and dispatch them to functions registered with register_im_callbacks() 97 | * @return zero if DisconnectIM messages has been received, otherwise non-zero 98 | */ 99 | extern int check_im_message(); 100 | 101 | /** 102 | * @brief send message PutText to FbTerm 103 | * @param text translated text from user keyboard input, must be encoded with utf8 104 | * @param len text's length 105 | */ 106 | extern void put_im_text(const char *text, unsigned len); 107 | 108 | /** 109 | * @brief send message SetWin to FbTerm and wait until AckWin has arrived 110 | * @param winid the window id, must less than NR_IM_WINS 111 | * @param rect the rectangle of this window area 112 | * 113 | * every UI window (e.g. status bar, candidate table, etc) should have a unique win id. 114 | */ 115 | extern void set_im_window(unsigned winid, Rectangle rect); 116 | 117 | /** 118 | * The colors of xterm's 256 color mode supported by FbTerm can be used in fill_rect() and draw_text(). 119 | * ColorType defines the first 16 colors with standard linux console. 120 | * view 256colors.png for all colors. 121 | */ 122 | typedef enum { Black = 0, DarkRed, DarkGreen, DarkYellow, DarkBlue, DarkMagenta, DarkCyan, Gray, 123 | DarkGray, Red, Green, Yellow, Blue, Magenta, Cyan, White } ColorType; 124 | 125 | /** 126 | * @brief send message FillRect to FbTerm 127 | * @param rect the rectangle to be filled 128 | * @param color 129 | */ 130 | extern void fill_rect(Rectangle rect, unsigned char color); 131 | 132 | /** 133 | * @breif send message DrawText to FbTerm 134 | * @param x x axes of top left point 135 | * @param y y axes of top left point 136 | * @param fc foreground color 137 | * @param bc background color 138 | * @param text text to be drawn, must be encoding with utf8 139 | * @param len text's length 140 | */ 141 | extern void draw_text(unsigned x, unsigned y, unsigned char fc, unsigned char bc, const char *text, unsigned len); 142 | 143 | #ifdef __cplusplus 144 | } 145 | #endif 146 | 147 | #endif 148 | -------------------------------------------------------------------------------- /src/imapi.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2008-2010 dragchan 3 | * This file is part of FbTerm. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 | * 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "imapi.h" 27 | 28 | #define OFFSET(TYPE, MEMBER) ((size_t)(&(((TYPE *)0)->MEMBER))) 29 | #define MSG(a) ((Message *)(a)) 30 | 31 | static int imfd = -1; 32 | static ImCallbacks cbs; 33 | static char pending_msg_buf[10240]; 34 | static unsigned pending_msg_buf_len = 0; 35 | static int im_active = 0; 36 | 37 | static void wait_message(MessageType type); 38 | 39 | void register_im_callbacks(ImCallbacks callbacks) 40 | { 41 | cbs = callbacks; 42 | } 43 | 44 | int get_im_socket() 45 | { 46 | static char init = 0; 47 | if (!init) { 48 | init = 1; 49 | 50 | char *val = getenv("FBTERM_IM_SOCKET"); 51 | if (val) { 52 | char *tail; 53 | int fd = strtol(val, &tail, 0); 54 | if (!*tail) imfd = fd; 55 | } 56 | } 57 | 58 | return imfd; 59 | } 60 | 61 | void connect_fbterm(char raw) 62 | { 63 | get_im_socket(); 64 | if (imfd == -1) return; 65 | 66 | Message msg; 67 | msg.type = Connect; 68 | msg.len = sizeof(msg); 69 | msg.raw = (raw ? 1 : 0); 70 | int ret = write(imfd, (char *)&msg, sizeof(msg)); 71 | (void) ret; 72 | } 73 | 74 | void put_im_text(const char *text, unsigned len) 75 | { 76 | if (imfd == -1 || !im_active || !text || !len || (OFFSET(Message, texts) + len > UINT16_MAX)) return; 77 | 78 | char buf[OFFSET(Message, texts) + len]; 79 | 80 | MSG(buf)->type = PutText; 81 | MSG(buf)->len = sizeof(buf); 82 | memcpy(MSG(buf)->texts, text, len); 83 | 84 | int ret = write(imfd, buf, MSG(buf)->len); 85 | (void) ret; 86 | } 87 | 88 | void set_im_window(unsigned id, Rectangle rect) 89 | { 90 | if (imfd == -1 || !im_active || id >= NR_IM_WINS) return; 91 | 92 | Message msg; 93 | msg.type = SetWin; 94 | msg.len = sizeof(msg); 95 | msg.win.winid = id; 96 | msg.win.rect = rect; 97 | 98 | int ret = write(imfd, (char *)&msg, sizeof(msg)); 99 | (void) ret; 100 | wait_message(AckWin); 101 | } 102 | 103 | void fill_rect(Rectangle rect, unsigned char color) 104 | { 105 | Message msg; 106 | msg.type = FillRect; 107 | msg.len = sizeof(msg); 108 | 109 | msg.fillRect.rect = rect; 110 | msg.fillRect.color = color; 111 | 112 | int ret = write(imfd, (char *)&msg, sizeof(msg)); 113 | (void) ret; 114 | } 115 | 116 | void draw_text(unsigned x, unsigned y, unsigned char fc, unsigned char bc, const char *text, unsigned len) 117 | { 118 | if (!text || !len) return; 119 | 120 | char buf[OFFSET(Message, drawText.texts) + len]; 121 | 122 | MSG(buf)->type = DrawText; 123 | MSG(buf)->len = sizeof(buf); 124 | 125 | MSG(buf)->drawText.x = x; 126 | MSG(buf)->drawText.y = y; 127 | MSG(buf)->drawText.fc = fc; 128 | MSG(buf)->drawText.bc = bc; 129 | memcpy(MSG(buf)->drawText.texts, text, len); 130 | 131 | int ret = write(imfd, buf, MSG(buf)->len); 132 | (void) ret; 133 | } 134 | 135 | static int process_message(Message *msg) 136 | { 137 | int exit = 0; 138 | 139 | switch (msg->type) { 140 | case Disconnect: 141 | close(imfd); 142 | imfd = -1; 143 | exit = 1; 144 | break; 145 | 146 | case FbTermInfo: 147 | if (cbs.fbterm_info) { 148 | cbs.fbterm_info(&msg->info); 149 | } 150 | break; 151 | 152 | case Active: 153 | im_active = 1; 154 | if (cbs.active) { 155 | cbs.active(); 156 | } 157 | break; 158 | 159 | case Deactive: 160 | if (cbs.deactive) { 161 | cbs.deactive(); 162 | } 163 | im_active = 0; 164 | break; 165 | 166 | case ShowUI: 167 | if (im_active && cbs.show_ui) { 168 | cbs.show_ui(msg->winid); 169 | } 170 | break; 171 | 172 | case HideUI: { 173 | if (im_active && cbs.hide_ui) { 174 | cbs.hide_ui(); 175 | } 176 | 177 | Message msg; 178 | msg.type = AckHideUI; 179 | msg.len = sizeof(msg); 180 | int ret = write(imfd, (char *)&msg, sizeof(msg)); 181 | (void) ret; 182 | break; 183 | } 184 | 185 | case SendKey: 186 | if (im_active && cbs.send_key) { 187 | cbs.send_key(msg->keys, msg->len - OFFSET(Message, keys)); 188 | } 189 | break; 190 | 191 | case CursorPosition: 192 | if (im_active && cbs.cursor_position) { 193 | cbs.cursor_position(msg->cursor.x, msg->cursor.y); 194 | } 195 | break; 196 | 197 | case TermMode: 198 | if (im_active && cbs.term_mode) { 199 | cbs.term_mode(msg->term.crWithLf, msg->term.applicKeypad, msg->term.cursorEscO); 200 | } 201 | break; 202 | 203 | default: 204 | break; 205 | } 206 | 207 | return exit; 208 | } 209 | 210 | static int process_messages(char *buf, int len) 211 | { 212 | char *cur = buf, *end = cur + len; 213 | int exit = 0; 214 | 215 | for (; cur < end && MSG(cur)->len <= (end - cur); cur += MSG(cur)->len) { 216 | exit |= process_message(MSG(cur)); 217 | } 218 | 219 | return exit; 220 | } 221 | 222 | static void wait_message(MessageType type) 223 | { 224 | int ack = 0; 225 | while (!ack) { 226 | char *cur = pending_msg_buf + pending_msg_buf_len; 227 | int len = read(imfd, cur, sizeof(pending_msg_buf) - pending_msg_buf_len); 228 | 229 | if (len == -1 && (errno == EAGAIN || errno == EINTR)) continue; 230 | else if (len <= 0) { 231 | close(imfd); 232 | imfd = -1; 233 | return; 234 | } 235 | 236 | pending_msg_buf_len += len; 237 | 238 | char *end = cur + len; 239 | for (; cur < end && MSG(cur)->len <= (end - cur); cur += MSG(cur)->len) { 240 | if (MSG(cur)->type == type) { 241 | memcpy(cur, cur + MSG(cur)->len, end - cur - MSG(cur)->len); 242 | pending_msg_buf_len -= MSG(cur)->len; 243 | 244 | ack = 1; 245 | break; 246 | } 247 | } 248 | } 249 | 250 | if (pending_msg_buf_len) { 251 | Message msg; 252 | msg.type = Ping; 253 | msg.len = sizeof(msg); 254 | int ret = write(imfd, (char *)&msg, sizeof(msg)); 255 | (void) ret; 256 | } 257 | } 258 | 259 | int check_im_message() 260 | { 261 | if (imfd == -1) return 0; 262 | 263 | char buf[sizeof(pending_msg_buf)]; 264 | int len, exit = 0; 265 | 266 | if (pending_msg_buf_len) { 267 | len = pending_msg_buf_len; 268 | pending_msg_buf_len = 0; 269 | 270 | memcpy(buf, pending_msg_buf, len); 271 | exit |= process_messages(buf, len); 272 | } 273 | 274 | len = read(imfd, buf, sizeof(buf)); 275 | 276 | if (len == -1 && (errno == EAGAIN || errno == EINTR)) return 1; 277 | else if (len <= 0) { 278 | close(imfd); 279 | imfd = -1; 280 | return 0; 281 | } 282 | 283 | exit |= process_messages(buf, len); 284 | 285 | return !exit; 286 | } 287 | 288 | -------------------------------------------------------------------------------- /src/keycode.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2008-2010 dragchan 3 | * This file is part of FbTerm. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 | * 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "input_key.h" 29 | #include "keycode.h" 30 | 31 | static char key_down[NR_KEYS]; 32 | static unsigned char shift_down[NR_SHIFT]; 33 | static short shift_state; 34 | static char lock_state; 35 | static char cr_with_lf, applic_keypad, cursor_esco; 36 | static int npadch; 37 | 38 | void init_keycode_state() 39 | { 40 | npadch = -1; 41 | shift_state = 0; 42 | memset(key_down, 0, sizeof(char) * NR_KEYS); 43 | memset(shift_down, 0, sizeof(char) * NR_SHIFT); 44 | ioctl(STDIN_FILENO, KDGKBLED, &lock_state); 45 | } 46 | 47 | void update_term_mode(char crlf, char appkey, char curo) 48 | { 49 | cr_with_lf = crlf; 50 | applic_keypad = appkey; 51 | cursor_esco = curo; 52 | } 53 | 54 | unsigned short keycode_to_keysym(unsigned short keycode, char down, int fallback) 55 | { 56 | if (keycode >= NR_KEYS) return K_HOLE; 57 | 58 | char rep = (down && key_down[keycode]); 59 | key_down[keycode] = down; 60 | 61 | struct kbentry ke; 62 | if (!fallback) 63 | ke.kb_table = shift_state; 64 | else 65 | ke.kb_table = 0; 66 | ke.kb_index = keycode; 67 | 68 | if (ioctl(STDIN_FILENO, KDGKBENT, &ke) == -1) return K_HOLE; 69 | 70 | if (KTYP(ke.kb_value) == KT_LETTER && (lock_state & K_CAPSLOCK)) { 71 | ke.kb_table = shift_state ^ (1 << KG_SHIFT); 72 | if (ioctl(STDIN_FILENO, KDGKBENT, &ke) == -1) return K_HOLE; 73 | } 74 | 75 | if (ke.kb_value == K_HOLE || ke.kb_value == K_NOSUCHMAP) return K_HOLE; 76 | 77 | unsigned value = KVAL(ke.kb_value); 78 | 79 | switch (KTYP(ke.kb_value)) { 80 | case KT_SPEC: 81 | switch (ke.kb_value) { 82 | case K_NUM: 83 | if (applic_keypad) break; 84 | case K_BARENUMLOCK: 85 | case K_CAPS: 86 | case K_CAPSON: 87 | if (down && !rep) { 88 | if (value == KVAL(K_NUM) || value == KVAL(K_BARENUMLOCK)) lock_state ^= K_NUMLOCK; 89 | else if (value == KVAL(K_CAPS)) lock_state ^= K_CAPSLOCK; 90 | else if (value == KVAL(K_CAPSON)) lock_state |= K_CAPSLOCK; 91 | 92 | ioctl(STDIN_FILENO, KDSKBLED, lock_state); 93 | } 94 | break; 95 | 96 | default: 97 | break; 98 | } 99 | break; 100 | 101 | case KT_SHIFT: 102 | if (value >= NR_SHIFT || rep) break; 103 | 104 | if (value == KVAL(K_CAPSSHIFT)) { 105 | value = KVAL(K_SHIFT); 106 | 107 | if (down && (lock_state & K_CAPSLOCK)) { 108 | lock_state &= ~K_CAPSLOCK; 109 | ioctl(STDIN_FILENO, KDSKBLED, lock_state); 110 | } 111 | } 112 | 113 | if (down) shift_down[value]++; 114 | else if (shift_down[value]) shift_down[value]--; 115 | 116 | if (shift_down[value]) shift_state |= (1 << value); 117 | else shift_state &= ~(1 << value); 118 | 119 | break; 120 | 121 | case KT_LATIN: 122 | case KT_LETTER: 123 | case KT_FN: 124 | case KT_PAD: 125 | case KT_CONS: 126 | case KT_CUR: 127 | case KT_META: 128 | case KT_ASCII: 129 | break; 130 | 131 | default: 132 | printf("not support!\n"); 133 | break; 134 | } 135 | 136 | return ke.kb_value; 137 | } 138 | 139 | unsigned short keypad_keysym_redirect(unsigned short keysym) 140 | { 141 | if (applic_keypad || KTYP(keysym) != KT_PAD || KVAL(keysym) >= NR_PAD) return keysym; 142 | 143 | #define KL(val) K(KT_LATIN, val) 144 | static const unsigned short num_map[] = { 145 | KL('0'), KL('1'), KL('2'), KL('3'), KL('4'), 146 | KL('5'), KL('6'), KL('7'), KL('8'), KL('9'), 147 | KL('+'), KL('-'), KL('*'), KL('/'), K_ENTER, 148 | KL(','), KL('.'), KL('?'), KL('('), KL(')'), 149 | KL('#') 150 | }; 151 | 152 | static const unsigned short fn_map[] = { 153 | K_INSERT, K_SELECT, K_DOWN, K_PGDN, K_LEFT, 154 | K_P5, K_RIGHT, K_FIND, K_UP, K_PGUP, 155 | KL('+'), KL('-'), KL('*'), KL('/'), K_ENTER, 156 | K_REMOVE, K_REMOVE, KL('?'), KL('('), KL(')'), 157 | KL('#') 158 | }; 159 | 160 | if (lock_state & K_NUMLOCK) return num_map[keysym - K_P0]; 161 | return fn_map[keysym - K_P0]; 162 | } 163 | 164 | 165 | static unsigned to_utf8(unsigned c, char *buf) 166 | { 167 | unsigned index = 0; 168 | 169 | if (c < 0x80) 170 | buf[index++] = c; 171 | else if (c < 0x800) { 172 | // 110***** 10****** 173 | buf[index++] = 0xc0 | (c >> 6); 174 | buf[index++] = 0x80 | (c & 0x3f); 175 | } else if (c < 0x10000) { 176 | if (c >= 0xD800 && c < 0xE000) 177 | return index; 178 | if (c == 0xFFFF) 179 | return index; 180 | // 1110**** 10****** 10****** 181 | buf[index++] = 0xe0 | (c >> 12); 182 | buf[index++] = 0x80 | ((c >> 6) & 0x3f); 183 | buf[index++] = 0x80 | (c & 0x3f); 184 | } else if (c < 0x200000) { 185 | // 11110*** 10****** 10****** 10****** 186 | buf[index++] = 0xf0 | (c >> 18); 187 | buf[index++] = 0x80 | ((c >> 12) & 0x3f); 188 | buf[index++] = 0x80 | ((c >> 6) & 0x3f); 189 | buf[index++] = 0x80 | (c & 0x3f); 190 | } 191 | 192 | return index; 193 | } 194 | 195 | 196 | char *keysym_to_term_string(unsigned short keysym, char down) 197 | { 198 | static struct kbsentry kse; 199 | char *buf = (char *)kse.kb_string; 200 | *buf = 0; 201 | 202 | if (KTYP(keysym) != KT_SHIFT && !down) return buf; 203 | 204 | keysym = keypad_keysym_redirect(keysym); 205 | unsigned index = 0, value = KVAL(keysym); 206 | 207 | 208 | switch (KTYP(keysym)) { 209 | case KT_LATIN: 210 | case KT_LETTER: 211 | if (value < KVAL(AC_START) || value > KVAL(AC_END)) index = to_utf8(value, buf); 212 | break; 213 | 214 | case KT_FN: 215 | kse.kb_func = value; 216 | ioctl(STDIN_FILENO, KDGKBSENT, &kse); 217 | index = strlen(buf); 218 | break; 219 | 220 | case KT_SPEC: 221 | if (keysym == K_ENTER) { 222 | buf[index++] = '\r'; 223 | if (cr_with_lf) buf[index++] = '\n'; 224 | } else if (keysym == K_NUM && applic_keypad) { 225 | buf[index++] = '\e'; 226 | buf[index++] = 'O'; 227 | buf[index++] = 'P'; 228 | } 229 | break; 230 | 231 | case KT_PAD: 232 | if (applic_keypad && !shift_down[KG_SHIFT]) { 233 | if (value < NR_PAD) { 234 | static const char app_map[] = "pqrstuvwxylSRQMnnmPQS"; 235 | 236 | buf[index++] = '\e'; 237 | buf[index++] = 'O'; 238 | buf[index++] = app_map[value]; 239 | } 240 | } else if (keysym == K_P5 && !(lock_state & K_NUMLOCK)) { 241 | buf[index++] = '\e'; 242 | buf[index++] = (applic_keypad ? 'O' : '['); 243 | buf[index++] = 'G'; 244 | } 245 | break; 246 | 247 | case KT_CUR: 248 | if (value < 4) { 249 | static const char cur_chars[] = "BDCA"; 250 | 251 | buf[index++] = '\e'; 252 | buf[index++] = (cursor_esco ? 'O' : '['); 253 | buf[index++] = cur_chars[value]; 254 | } 255 | break; 256 | 257 | case KT_META: { 258 | long flag; 259 | ioctl(STDIN_FILENO, KDGKBMETA, &flag); 260 | 261 | if (flag == K_METABIT) { 262 | buf[index++] = 0x80 | value; 263 | } else { 264 | buf[index++] = '\e'; 265 | buf[index++] = value; 266 | } 267 | break; 268 | } 269 | 270 | case KT_SHIFT: 271 | if (!down && npadch != -1) { 272 | index = to_utf8(npadch, buf); 273 | npadch = -1; 274 | } 275 | break; 276 | 277 | case KT_ASCII: 278 | if (value < NR_ASCII) { 279 | int base = 10; 280 | 281 | if (value >= KVAL(K_HEX0)) { 282 | base = 16; 283 | value -= KVAL(K_HEX0); 284 | } 285 | 286 | if (npadch == -1) npadch = value; 287 | else npadch = npadch * base + value; 288 | } 289 | break; 290 | 291 | default: 292 | break; 293 | } 294 | 295 | buf[index] = 0; 296 | return buf; 297 | } 298 | 299 | -------------------------------------------------------------------------------- /src/immessage.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ? 2008-2009 dragchan 3 | * This file is part of FbTerm. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 | * 19 | */ 20 | 21 | /** 22 | * 23 | FbTerm implements a lightweight client-server input method architecture. Instead of processing user input and 24 | drawing input method UI itself, FbTerm acts as a client and requests the input method server to do all these works. 25 | 26 | 27 | Input Method Messages 28 | 29 | On startup, FbTerm forks a child process and executes the input method server program in it. FbTerm and the input 30 | method server will communicate each other with a unix socket pair created by FbTerm. When IM server startup, it sends 31 | a Connect message to FbTerm, indicates that the server has got ready. FbTerm response a FbTermInfo message, tell 32 | IM server things like current screen size, font size, rotation etc, help IM server draw it's UI. Of course, 33 | IM server may ignore these hints. 34 | 35 | When FbTerm exit, it sends a Disconnect to IM server, indicates it to exit. 36 | 37 | +------+ +------+ +------+ +------+ 38 | |FbTerm| | IM | |FbTerm| | IM | 39 | +--.---+ +---.--+ +--.---+ +---.--+ 40 | | | | | 41 | | | | | 42 | | Connect | | Disconnect | 43 | |<------------------| |------------------>| 44 | | | | | 45 | | FbTermInfo | | | 46 | |------------------>| | | 47 | | | | | 48 | | | | | 49 | 50 | 51 | If user presses the input method state switch shortcut (e.g. Ctrl + Space), FbTerm sends a Active message to 52 | IM server, and a CursorPosition message with current cursor position. After receiving the Active message, 53 | IM server may want to draw it's UI, e.g. a IM status bar, on frame buffer screen. In order to avoid FbTerm corrupting 54 | it's UI, IM server first sends a SetWin message, tell FbTerm the screen areas occupied by its status bar, and waits FbTerm 55 | to response a AckWin message. Now IM server can begin to draw the status bar. 56 | 57 | While user pressing Ctrl + Space again, FbTerm sends a Deactive message to IM server. IM server should response a 58 | SetWin message with a empty screen area to hide its status bar and ask FbTerm to redraw screen. 59 | 60 | +------+ +------+ +------+ +------+ 61 | |FbTerm| | IM | |FbTerm| | IM | 62 | +--.---+ +---.--+ +--.---+ +---.--+ 63 | | | | | 64 | | | | | 65 | | Active | | Deactive | 66 | |------------------>| |------------------>| 67 | | | | | 68 | | CursorPosition | | SetWin | 69 | |------------------>| |<------------------| 70 | | | | | 71 | | SetWin | | AckWin | 72 | |<------------------| |------------------>| 73 | | | | | 74 | | AckWin | | | 75 | |------------------>| | | 76 | | | | | 77 | | | | | 78 | 79 | 80 | When IM state is on, FbTerm doesn't process any keyboard input except its shortcuts and Alt-Fn, it redirects them 81 | to IM server with SendKey messages. After receiving SendKey message, IM server may draw it's preedit and candidate UI. 82 | As described above, it should first send SetWin messages to tell FbTerm the areas occupied by preedit and candidate UI 83 | and wait for responsed AckWin messages before drawing UI. 84 | 85 | IM server sends the converted texts in a PutText message back to FbTerm, and FbTerm will write them to the running 86 | program. In the common case, the running program will change cursor position, FbTerm notifies it to IM server with a 87 | CursorPosition message. If IM server provides a XIM "over the spot" style UI, it may response SetWin messages to move 88 | and redraw it's UI. 89 | 90 | +------+ +------+ +------+ +------+ 91 | |FbTerm| | IM | |FbTerm| | IM | 92 | +--.---+ +---.--+ +--.---+ +---.--+ 93 | | | | | 94 | | | | | 95 | | SendKey | | PutText | 96 | |------------------>| |<------------------| 97 | | | | | 98 | | SetWin | | CursorPosition | 99 | |<------------------| |------------------>| 100 | | | | | 101 | | AckWin | | SetWin | 102 | |------------------>| |<------------------| 103 | | | | | 104 | | | | AckWin | 105 | | | |------------------>| 106 | | | | | 107 | | | | | 108 | 109 | 110 | When IM state is on, user presses shortcuts for switching to other sub-window or Alt-Fn for other virtual console, FbTerm 111 | sends a HideUI message to IM server, then waits for a AckHideUI message responsed from IM server before switching. Maybe 112 | IM server is busy with the previous SendKey message when HideUI message is arrived, it continues it's work, then processes 113 | this HideUI message, sends back a AckHideUI message to FbTerm. 114 | 115 | When switching back, FbTerm sends a ShowUI message to IM server, indicates IM server to redraw it's UI. 116 | 117 | +------+ +------+ +------+ +------+ 118 | |FbTerm| | IM | |FbTerm| | IM | 119 | +--.---+ +---.--+ +--.---+ +---.--+ 120 | | | | | 121 | | | | | 122 | | HideUI | | ShowUI | 123 | |------------------>| |------------------>| 124 | | | | | 125 | | AckHideUI | | SetWin | 126 | |<------------------| |<------------------| 127 | | | | | 128 | | | | AckWin | 129 | | | |------------------>| 130 | | | | | 131 | | | | | 132 | | | | | 133 | | | | | 134 | | | | | 135 | */ 136 | 137 | #ifndef IM_MESSAGE_H 138 | #define IM_MESSAGE_H 139 | 140 | typedef enum { 141 | Connect = 0, Disconnect, 142 | Active, Deactive, 143 | SendKey, PutText, 144 | SetWin, AckWin, 145 | CursorPosition, FbTermInfo, TermMode, 146 | ShowUI, HideUI, AckHideUI, 147 | FillRect, DrawText, 148 | Ping, AckPing 149 | } MessageType; 150 | 151 | typedef struct { 152 | unsigned fontHeight, fontWidth; 153 | unsigned screenHeight, screenWidth; 154 | } Info; 155 | 156 | #define NR_IM_WINS 10 157 | 158 | typedef struct { 159 | unsigned x, y; 160 | unsigned w, h; 161 | } Rectangle; 162 | 163 | typedef struct { 164 | unsigned short type; ///< message's type, @see MessageType 165 | unsigned short len; ///< message's length, including head and body 166 | 167 | union { 168 | char keys[0]; ///< included in message SendKey 169 | char texts[0]; ///< included in message PutText 170 | char raw; ///< included in message Connect 171 | unsigned winid; ///< included in message ShowUI 172 | Info info; ///< included in message FbTermInfo 173 | 174 | struct { 175 | Rectangle rect; 176 | unsigned winid; 177 | } win; ///< included in message SetWin 178 | 179 | struct { 180 | char crWithLf; 181 | char applicKeypad; 182 | char cursorEscO; 183 | } term; ///< included in message TermMode; 184 | 185 | struct { 186 | unsigned x, y; 187 | } cursor; ///< included in message CursorPosition 188 | 189 | struct { 190 | Rectangle rect; 191 | unsigned char color; 192 | } fillRect; ///< included in message FillRect 193 | 194 | struct { 195 | unsigned x, y; 196 | unsigned char fc, bc; 197 | char texts[0]; 198 | } drawText; ///< included in message DrawText 199 | }; 200 | } Message; 201 | 202 | #endif 203 | 204 | // kate: indent-mode cstyle; space-indent on; indent-width 0; 205 | -------------------------------------------------------------------------------- /src/keymap.c: -------------------------------------------------------------------------------- 1 | /* 2 | * original from ibus-fbterm 3 | */ 4 | 5 | #include 6 | #include 7 | #include "keymap.h" 8 | 9 | static FcitxKeySym linux_to_x[256] = { 10 | FcitxKey_None, FcitxKey_None, FcitxKey_None, FcitxKey_None, 11 | FcitxKey_None, FcitxKey_None, FcitxKey_None, FcitxKey_None, 12 | FcitxKey_BackSpace, FcitxKey_Tab, FcitxKey_Linefeed, FcitxKey_None, 13 | FcitxKey_None, FcitxKey_None, FcitxKey_None, FcitxKey_None, 14 | FcitxKey_None, FcitxKey_None, FcitxKey_None, FcitxKey_None, 15 | FcitxKey_None, FcitxKey_None, FcitxKey_None, FcitxKey_None, 16 | FcitxKey_None, FcitxKey_None, FcitxKey_None, FcitxKey_Escape, 17 | FcitxKey_None, FcitxKey_None, FcitxKey_None, FcitxKey_None, 18 | FcitxKey_space, FcitxKey_exclam, FcitxKey_quotedbl, FcitxKey_numbersign, 19 | FcitxKey_dollar, FcitxKey_percent, FcitxKey_ampersand, FcitxKey_apostrophe, 20 | FcitxKey_parenleft, FcitxKey_parenright, FcitxKey_asterisk, FcitxKey_plus, 21 | FcitxKey_comma, FcitxKey_minus, FcitxKey_period, FcitxKey_slash, 22 | FcitxKey_0, FcitxKey_1, FcitxKey_2, FcitxKey_3, 23 | FcitxKey_4, FcitxKey_5, FcitxKey_6, FcitxKey_7, 24 | FcitxKey_8, FcitxKey_9, FcitxKey_colon, FcitxKey_semicolon, 25 | FcitxKey_less, FcitxKey_equal, FcitxKey_greater, FcitxKey_question, 26 | FcitxKey_at, FcitxKey_A, FcitxKey_B, FcitxKey_C, 27 | FcitxKey_D, FcitxKey_E, FcitxKey_F, FcitxKey_G, 28 | FcitxKey_H, FcitxKey_I, FcitxKey_J, FcitxKey_K, 29 | FcitxKey_L, FcitxKey_M, FcitxKey_N, FcitxKey_O, 30 | FcitxKey_P, FcitxKey_Q, FcitxKey_R, FcitxKey_S, 31 | FcitxKey_T, FcitxKey_U, FcitxKey_V, FcitxKey_W, 32 | FcitxKey_X, FcitxKey_Y, FcitxKey_Z, FcitxKey_bracketleft, 33 | FcitxKey_backslash, FcitxKey_bracketright,FcitxKey_asciicircum, FcitxKey_underscore, 34 | FcitxKey_grave, FcitxKey_a, FcitxKey_b, FcitxKey_c, 35 | FcitxKey_d, FcitxKey_e, FcitxKey_f, FcitxKey_g, 36 | FcitxKey_h, FcitxKey_i, FcitxKey_j, FcitxKey_k, 37 | FcitxKey_l, FcitxKey_m, FcitxKey_n, FcitxKey_o, 38 | FcitxKey_p, FcitxKey_q, FcitxKey_r, FcitxKey_s, 39 | FcitxKey_t, FcitxKey_u, FcitxKey_v, FcitxKey_w, 40 | FcitxKey_x, FcitxKey_y, FcitxKey_z, FcitxKey_braceleft, 41 | FcitxKey_bar, FcitxKey_braceright, FcitxKey_asciitilde, FcitxKey_BackSpace, 42 | FcitxKey_None, FcitxKey_None, FcitxKey_None, FcitxKey_None, 43 | FcitxKey_None, FcitxKey_None, FcitxKey_None, FcitxKey_None, 44 | FcitxKey_None, FcitxKey_None, FcitxKey_None, FcitxKey_None, 45 | FcitxKey_None, FcitxKey_None, FcitxKey_None, FcitxKey_None, 46 | FcitxKey_None, FcitxKey_None, FcitxKey_None, FcitxKey_None, 47 | FcitxKey_None, FcitxKey_None, FcitxKey_None, FcitxKey_None, 48 | FcitxKey_None, FcitxKey_None, FcitxKey_None, FcitxKey_None, 49 | FcitxKey_None, FcitxKey_None, FcitxKey_None, FcitxKey_None, 50 | FcitxKey_nobreakspace,FcitxKey_exclamdown, FcitxKey_cent, FcitxKey_sterling, 51 | FcitxKey_currency, FcitxKey_yen, FcitxKey_brokenbar, FcitxKey_section, 52 | FcitxKey_diaeresis, FcitxKey_copyright, FcitxKey_ordfeminine, FcitxKey_guillemotleft, 53 | FcitxKey_notsign, FcitxKey_hyphen, FcitxKey_registered, FcitxKey_macron, 54 | FcitxKey_degree, FcitxKey_plusminus, FcitxKey_twosuperior, FcitxKey_threesuperior, 55 | FcitxKey_acute, FcitxKey_mu, FcitxKey_paragraph, FcitxKey_periodcentered, 56 | FcitxKey_cedilla, FcitxKey_onesuperior, FcitxKey_masculine, FcitxKey_guillemotright, 57 | FcitxKey_onequarter, FcitxKey_onehalf, FcitxKey_threequarters,FcitxKey_questiondown, 58 | FcitxKey_Agrave, FcitxKey_Aacute, FcitxKey_Acircumflex, FcitxKey_Atilde, 59 | FcitxKey_Adiaeresis, FcitxKey_Aring, FcitxKey_AE, FcitxKey_Ccedilla, 60 | FcitxKey_Egrave, FcitxKey_Eacute, FcitxKey_Ecircumflex, FcitxKey_Ediaeresis, 61 | FcitxKey_Igrave, FcitxKey_Iacute, FcitxKey_Icircumflex, FcitxKey_Idiaeresis, 62 | FcitxKey_ETH, FcitxKey_Ntilde, FcitxKey_Ograve, FcitxKey_Oacute, 63 | FcitxKey_Ocircumflex, FcitxKey_Otilde, FcitxKey_Odiaeresis, FcitxKey_multiply, 64 | FcitxKey_Ooblique, FcitxKey_Ugrave, FcitxKey_Uacute, FcitxKey_Ucircumflex, 65 | FcitxKey_Udiaeresis, FcitxKey_Yacute, FcitxKey_THORN, FcitxKey_ssharp, 66 | FcitxKey_agrave, FcitxKey_aacute, FcitxKey_acircumflex, FcitxKey_atilde, 67 | FcitxKey_adiaeresis, FcitxKey_aring, FcitxKey_ae, FcitxKey_ccedilla, 68 | FcitxKey_egrave, FcitxKey_eacute, FcitxKey_ecircumflex, FcitxKey_ediaeresis, 69 | FcitxKey_igrave, FcitxKey_iacute, FcitxKey_icircumflex, FcitxKey_idiaeresis, 70 | FcitxKey_eth, FcitxKey_ntilde, FcitxKey_ograve, FcitxKey_oacute, 71 | FcitxKey_ocircumflex, FcitxKey_otilde, FcitxKey_odiaeresis, FcitxKey_division, 72 | FcitxKey_oslash, FcitxKey_ugrave, FcitxKey_uacute, FcitxKey_ucircumflex, 73 | FcitxKey_udiaeresis, FcitxKey_yacute, FcitxKey_thorn, FcitxKey_ydiaeresis 74 | }; 75 | 76 | FcitxKeySym linux_keysym_to_fcitx_keysym(unsigned short keysym, unsigned short keycode) 77 | { 78 | unsigned kval = KVAL(keysym), keyval = 0; 79 | 80 | switch (KTYP(keysym)) { 81 | case KT_LATIN: 82 | case KT_LETTER: 83 | keyval = linux_to_x[kval]; 84 | break; 85 | 86 | case KT_FN: 87 | if (kval <= 19) 88 | keyval = FcitxKey_F1 + kval; 89 | else switch (keysym) { 90 | case K_FIND: 91 | keyval = FcitxKey_Home; /* or FcitxKey_Find */ 92 | break; 93 | case K_INSERT: 94 | keyval = FcitxKey_Insert; 95 | break; 96 | case K_REMOVE: 97 | keyval = FcitxKey_Delete; 98 | break; 99 | case K_SELECT: 100 | keyval = FcitxKey_End; /* or FcitxKey_Select */ 101 | break; 102 | case K_PGUP: 103 | keyval = FcitxKey_Prior; 104 | break; 105 | case K_PGDN: 106 | keyval = FcitxKey_Next; 107 | break; 108 | case K_HELP: 109 | keyval = FcitxKey_Help; 110 | break; 111 | case K_DO: 112 | keyval = FcitxKey_Execute; 113 | break; 114 | case K_PAUSE: 115 | keyval = FcitxKey_Pause; 116 | break; 117 | case K_MACRO: 118 | keyval = FcitxKey_Menu; 119 | break; 120 | default: 121 | break; 122 | } 123 | break; 124 | 125 | case KT_SPEC: 126 | switch (keysym) { 127 | case K_ENTER: 128 | keyval = FcitxKey_Return; 129 | break; 130 | case K_BREAK: 131 | keyval = FcitxKey_Break; 132 | break; 133 | case K_CAPS: 134 | keyval = FcitxKey_Caps_Lock; 135 | break; 136 | case K_NUM: 137 | keyval = FcitxKey_Num_Lock; 138 | break; 139 | case K_HOLD: 140 | keyval = FcitxKey_Scroll_Lock; 141 | break; 142 | case K_COMPOSE: 143 | keyval = FcitxKey_Multi_key; 144 | break; 145 | default: 146 | break; 147 | } 148 | break; 149 | 150 | case KT_PAD: 151 | switch (keysym) { 152 | case K_PPLUS: 153 | keyval = FcitxKey_KP_Add; 154 | break; 155 | case K_PMINUS: 156 | keyval = FcitxKey_KP_Subtract; 157 | break; 158 | case K_PSTAR: 159 | keyval = FcitxKey_KP_Multiply; 160 | break; 161 | case K_PSLASH: 162 | keyval = FcitxKey_KP_Divide; 163 | break; 164 | case K_PENTER: 165 | keyval = FcitxKey_KP_Enter; 166 | break; 167 | case K_PCOMMA: 168 | keyval = FcitxKey_KP_Separator; 169 | break; 170 | case K_PDOT: 171 | keyval = FcitxKey_KP_Decimal; 172 | break; 173 | case K_PPLUSMINUS: 174 | keyval = FcitxKey_KP_Subtract; 175 | break; 176 | default: 177 | if (kval <= 9) 178 | keyval = FcitxKey_KP_0 + kval; 179 | break; 180 | } 181 | break; 182 | 183 | /* 184 | * KT_DEAD keys are for accelerated diacritical creation. 185 | */ 186 | case KT_DEAD: 187 | switch (keysym) { 188 | case K_DGRAVE: 189 | keyval = FcitxKey_dead_grave; 190 | break; 191 | case K_DACUTE: 192 | keyval = FcitxKey_dead_acute; 193 | break; 194 | case K_DCIRCM: 195 | keyval = FcitxKey_dead_circumflex; 196 | break; 197 | case K_DTILDE: 198 | keyval = FcitxKey_dead_tilde; 199 | break; 200 | case K_DDIERE: 201 | keyval = FcitxKey_dead_diaeresis; 202 | break; 203 | } 204 | break; 205 | 206 | case KT_CUR: 207 | switch (keysym) { 208 | case K_DOWN: 209 | keyval = FcitxKey_Down; 210 | break; 211 | case K_LEFT: 212 | keyval = FcitxKey_Left; 213 | break; 214 | case K_RIGHT: 215 | keyval = FcitxKey_Right; 216 | break; 217 | case K_UP: 218 | keyval = FcitxKey_Up; 219 | break; 220 | } 221 | break; 222 | 223 | case KT_SHIFT: 224 | switch (keysym) { 225 | case K_ALTGR: 226 | keyval = FcitxKey_Alt_R; 227 | break; 228 | case K_ALT: 229 | keyval = (keycode == 0x64 ? 230 | FcitxKey_Alt_R : FcitxKey_Alt_L); 231 | break; 232 | case K_CTRL: 233 | keyval = (keycode == 0x61 ? 234 | FcitxKey_Control_R : FcitxKey_Control_L); 235 | break; 236 | case K_CTRLL: 237 | keyval = FcitxKey_Control_L; 238 | break; 239 | case K_CTRLR: 240 | keyval = FcitxKey_Control_R; 241 | break; 242 | case K_SHIFT: 243 | keyval = (keycode == 0x36 ? 244 | FcitxKey_Shift_R : FcitxKey_Shift_L); 245 | break; 246 | case K_SHIFTL: 247 | keyval = FcitxKey_Shift_L; 248 | break; 249 | case K_SHIFTR: 250 | keyval = FcitxKey_Shift_R; 251 | break; 252 | default: 253 | break; 254 | } 255 | break; 256 | 257 | /* 258 | * KT_ASCII keys accumulate a 3 digit decimal number that gets 259 | * emitted when the shift state changes. We can't emulate that. 260 | */ 261 | case KT_ASCII: 262 | break; 263 | 264 | case KT_LOCK: 265 | if (keysym == K_SHIFTLOCK) 266 | keyval = FcitxKey_Shift_Lock; 267 | break; 268 | 269 | default: 270 | break; 271 | } 272 | 273 | return keyval; 274 | } 275 | 276 | FcitxKeyState calculate_modifiers(FcitxKeyState state, FcitxKeySym keyval, char down) 277 | { 278 | FcitxKeyState mask = 0; 279 | switch (keyval) { 280 | case FcitxKey_Shift_L: 281 | case FcitxKey_Shift_R: 282 | mask = FcitxKeyState_Shift; 283 | break; 284 | 285 | case FcitxKey_Control_L: 286 | case FcitxKey_Control_R: 287 | mask = FcitxKeyState_Ctrl; 288 | break; 289 | 290 | case FcitxKey_Alt_L: 291 | case FcitxKey_Alt_R: 292 | case FcitxKey_Meta_L: 293 | mask = FcitxKeyState_Alt; 294 | break; 295 | 296 | default: 297 | break; 298 | } 299 | 300 | if (mask) { 301 | if (down) state |= mask; 302 | else state &= ~mask; 303 | } 304 | 305 | return state; 306 | } 307 | 308 | -------------------------------------------------------------------------------- /src/fcitx-fbterm.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2010~2011 by CSSlayer * 3 | * * 4 | * This program is free software; you can redistribute it and/or modify * 5 | * it under the terms of the GNU General Public License as published by * 6 | * the Free Software Foundation; either version 2 of the License, or * 7 | * (at your option) any later version. * 8 | * * 9 | * This program is distributed in the hope that it will be useful, * 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 12 | * GNU General Public License for more details. * 13 | * * 14 | * You should have received a copy of the GNU General Public License * 15 | * along with this program; if not, write to the * 16 | * Free Software Foundation, Inc., * 17 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * 18 | ***************************************************************************/ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include "imapi.h" 31 | #include "keycode.h" 32 | #include "keymap.h" 33 | 34 | struct interval { 35 | unsigned first; 36 | unsigned last; 37 | }; 38 | 39 | #define DRAW_NEXT_STRING(STRING, INDEX, VISIBLE_CONDITION) \ 40 | do { \ 41 | rect.w = width; \ 42 | rect.h = MARGIN * 2 + currentInfo.fontHeight; \ 43 | \ 44 | if ((VISIBLE_CONDITION)) \ 45 | { \ 46 | set_im_window((INDEX), rect); \ 47 | fill_rect(rect, Gray); \ 48 | draw_text(rect.x + MARGIN, rect.y + MARGIN, Black, Gray, (STRING), strlen(STRING)); \ 49 | rect.y += rect.h; \ 50 | } \ 51 | else \ 52 | { \ 53 | rect.w = 0; \ 54 | set_im_window((INDEX), rect); \ 55 | } \ 56 | } while(0) 57 | 58 | static void im_active(void); 59 | static void im_deactive(void); 60 | static void im_show(unsigned winid); 61 | static void im_hide(void); 62 | static void process_raw_key(char *buf, unsigned int len); 63 | static void cursor_pos_changed(unsigned x, unsigned y); 64 | static void update_fbterm_info(Info *info); 65 | static gboolean iochannel_fbterm_callback(GIOChannel *source, GIOCondition condition, gpointer data); 66 | 67 | static void _fcitx_fbterm_connect_cb(FcitxClient* client, void* user_data); 68 | static void _fcitx_fbterm_destroy_cb(FcitxClient* client, void* user_data); 69 | static void 70 | _fcitx_fbterm_enable_im_cb(FcitxClient* client, void* user_data); 71 | static void 72 | _fcitx_fbterm_close_im_cb(FcitxClient* client, void* user_data); 73 | static void 74 | _fcitx_fbterm_commit_string_cb(FcitxClient* client, char* str, void* user_data); 75 | static void 76 | _fcitx_fbterm_forward_key_cb(FcitxClient* client, guint keyval, guint state, gint type, void* user_data); 77 | static void 78 | _fcitx_fbterm_update_client_side_ui_cb(FcitxClient* client, char* auxup, char* auxdown, char* preedit, char* candidateword, char* _imname, int cursor_pos, void* user_data); 79 | static unsigned text_width(char* str); 80 | static int bisearch(unsigned ucs, const struct interval *table, unsigned max); 81 | static int is_double_width(unsigned ucs); 82 | 83 | static ImCallbacks cbs = { 84 | im_active, // .active 85 | im_deactive, // .deactive 86 | im_show, 87 | im_hide, 88 | process_raw_key, // .send_key 89 | cursor_pos_changed, // .cursor_position 90 | update_fbterm_info, // .fbterm_info 91 | update_term_mode // .term_mode 92 | }; 93 | 94 | #define BUFSIZE 8192 95 | #define MARGIN 3 96 | 97 | static char raw_mode = 1; 98 | static int cursor_x; 99 | static int cursor_y; 100 | static GMainLoop *main_loop; 101 | static FcitxClient* client; 102 | static FcitxKeyState state; 103 | static int active = 0; 104 | static Info currentInfo; 105 | static char textup[BUFSIZE]; 106 | static char textdown[BUFSIZE]; 107 | static char imname[BUFSIZE]; 108 | static iconv_t iconvW; 109 | 110 | static void im_active(void) 111 | { 112 | if (raw_mode) { 113 | init_keycode_state(); 114 | } 115 | fcitx_client_focus_in(client); 116 | fcitx_client_enable_ic(client); 117 | active = 1; 118 | } 119 | 120 | static void im_deactive(void) 121 | { 122 | Rectangle rect = { 0, 0, 0, 0 }; 123 | set_im_window(0, rect); 124 | set_im_window(1, rect); 125 | set_im_window(2, rect); 126 | fcitx_client_close_ic(client); 127 | state = 0; 128 | active = 0; 129 | } 130 | 131 | static int bisearch(unsigned ucs, const struct interval *table, unsigned max) 132 | { 133 | unsigned min = 0; 134 | unsigned mid; 135 | 136 | if (ucs < table[0].first || ucs > table[max].last) 137 | return 0; 138 | while (max >= min) { 139 | mid = (min + max) / 2; 140 | if (ucs > table[mid].last) 141 | min = mid + 1; 142 | else if (ucs < table[mid].first) 143 | max = mid - 1; 144 | else 145 | return 1; 146 | } 147 | return 0; 148 | } 149 | 150 | static int is_double_width(unsigned ucs) 151 | { 152 | ucs = be32toh(ucs); 153 | static const struct interval double_width[] = { 154 | { 0x1100, 0x115F}, { 0x2329, 0x232A}, { 0x2E80, 0x303E}, 155 | { 0x3040, 0xA4CF}, { 0xAC00, 0xD7A3}, { 0xF900, 0xFAFF}, 156 | { 0xFE10, 0xFE19}, { 0xFE30, 0xFE6F}, { 0xFF00, 0xFF60}, 157 | { 0xFFE0, 0xFFE6}, { 0x20000, 0x2FFFD}, { 0x30000, 0x3FFFD} 158 | }; 159 | return bisearch(ucs, double_width, sizeof(double_width) / sizeof(struct interval) - 1); 160 | } 161 | 162 | static unsigned int text_width(char* str) 163 | { 164 | if (iconvW == NULL) 165 | iconvW = iconv_open("ucs-4be", "utf-8"); 166 | if (iconvW == (iconv_t) -1) 167 | { 168 | return fcitx_utf8_strlen(str); 169 | } 170 | else 171 | { 172 | size_t len = strlen(str); 173 | size_t charlen = fcitx_utf8_strlen(str); 174 | unsigned *wmessage; 175 | size_t wlen = (len + 1) * sizeof (unsigned); 176 | wmessage = (unsigned *) fcitx_utils_malloc0 ((len + 1) * sizeof (unsigned)); 177 | 178 | char *inp = str; 179 | char *outp = (char*) wmessage; 180 | 181 | iconv(iconvW, &inp, &len, &outp, &wlen); 182 | 183 | int i = 0; 184 | int width = 0; 185 | for (i = 0; i < charlen; i ++) 186 | { 187 | if (is_double_width(wmessage[i])) 188 | width += 2; 189 | else 190 | width += 1; 191 | } 192 | 193 | 194 | free(wmessage); 195 | return width; 196 | } 197 | } 198 | 199 | static void im_show(unsigned winid) 200 | { 201 | int sizeup = text_width(textup); 202 | int sizedown = text_width(textdown); 203 | int width = (sizeup > sizedown ? sizeup : sizedown) * currentInfo.fontWidth + MARGIN * 2; 204 | int totalheight = 3 * (MARGIN * 2 + currentInfo.fontHeight); 205 | 206 | Rectangle rect; 207 | int x, y; 208 | x = cursor_x + currentInfo.fontWidth; 209 | y = cursor_y + currentInfo.fontHeight; 210 | if (y + totalheight > currentInfo.screenHeight) 211 | y = cursor_y - totalheight - currentInfo.fontHeight * 2; 212 | if (y < 0) 213 | y = 0; 214 | if (x + width > currentInfo.screenWidth) 215 | x = currentInfo.screenWidth - width; 216 | if (x < 0) 217 | x = 0; 218 | rect.x = x; rect.y = y; 219 | 220 | DRAW_NEXT_STRING(textup, 0, textup[0]); 221 | DRAW_NEXT_STRING(textdown, 1, textdown[0]); 222 | DRAW_NEXT_STRING(imname, 2, textup[0] || textdown[0]); 223 | } 224 | 225 | static void im_hide() 226 | { 227 | } 228 | 229 | static void process_raw_key(char *buf, unsigned int len) 230 | { 231 | if ( len <= 0 ) { 232 | return; 233 | } 234 | else 235 | { 236 | unsigned int i; 237 | for (i = 0; i < len; i++) { 238 | char down = !(buf[i] & 0x80); 239 | short code = buf[i] & 0x7f; 240 | if (!code) { 241 | if (i + 2 >= len) break; 242 | 243 | code = (buf[++i] & 0x7f) << 7; 244 | code |= buf[++i] & 0x7f; 245 | if (!(buf[i] & 0x80) || !(buf[i - 1] & 0x80)) continue; 246 | } 247 | 248 | unsigned short linux_keysym = keycode_to_keysym(code, down, 0); 249 | FcitxKeySym keysym = linux_keysym_to_fcitx_keysym(linux_keysym, code); 250 | if (keysym == FcitxKey_None) { 251 | unsigned short fallback_keysym = keycode_to_keysym(code, down, 1); 252 | keysym = linux_keysym_to_fcitx_keysym(fallback_keysym, code); 253 | } 254 | 255 | fcitx_client_focus_in(client); 256 | 257 | if (keysym == FcitxKey_None || fcitx_client_process_key_sync(client, keysym, code, state, (down ? FCITX_PRESS_KEY : FCITX_RELEASE_KEY), 0) <= 0) { 258 | char *str = keysym_to_term_string(linux_keysym, down); 259 | if (str) 260 | put_im_text(str, strlen(str)); 261 | } 262 | 263 | state = calculate_modifiers(state, keysym, down); 264 | } 265 | } 266 | 267 | } 268 | 269 | static void cursor_pos_changed(unsigned x, unsigned y) 270 | { 271 | cursor_x = x; 272 | cursor_y = y; 273 | im_show(-1); 274 | } 275 | 276 | static void update_fbterm_info(Info *info) 277 | { 278 | currentInfo = *info; 279 | } 280 | 281 | static gboolean iochannel_fbterm_callback(GIOChannel *source, GIOCondition condition, gpointer data) 282 | { 283 | if (!check_im_message()) { 284 | g_main_loop_quit(main_loop); 285 | return FALSE; 286 | } 287 | 288 | return TRUE; 289 | } 290 | 291 | void _fcitx_fbterm_connect_cb(FcitxClient* client, void* user_data) 292 | { 293 | if (fcitx_client_is_valid(client)) 294 | { 295 | 296 | FcitxCapacityFlags flags = CAPACITY_CLIENT_SIDE_UI | CAPACITY_CLIENT_SIDE_CONTROL_STATE; 297 | fcitx_client_set_capacity(client, flags); 298 | 299 | if (active) 300 | { 301 | fcitx_client_focus_in(client); 302 | fcitx_client_enable_ic(client); 303 | } 304 | } 305 | } 306 | 307 | void _fcitx_fbterm_destroy_cb(FcitxClient* client, void* user_data) 308 | { 309 | state = 0; 310 | } 311 | 312 | void _fcitx_fbterm_close_im_cb(FcitxClient* client, void* user_data) 313 | { 314 | state = 0; 315 | } 316 | 317 | void _fcitx_fbterm_commit_string_cb(FcitxClient* client, char* str, void* user_data) 318 | { 319 | unsigned short result_len = strlen(str); 320 | put_im_text( str, result_len ); 321 | } 322 | 323 | void _fcitx_fbterm_enable_im_cb(FcitxClient* client, void* user_data) 324 | { 325 | state = 0; 326 | } 327 | 328 | void _fcitx_fbterm_forward_key_cb(FcitxClient* client, guint keyval, guint state, gint type, void* user_data) 329 | { 330 | 331 | } 332 | 333 | void _fcitx_fbterm_update_client_side_ui_cb(FcitxClient* client, char* auxup, char* auxdown, char* preedit, char* candidateword, char* _imname, int cursor_pos, void* user_data) 334 | { 335 | snprintf(textup, BUFSIZE, "%s%s", auxup, preedit); 336 | snprintf(textdown, BUFSIZE, "%s%s", auxdown, candidateword); 337 | snprintf(imname, BUFSIZE, "%s", _imname); 338 | textup[BUFSIZE - 1] = textdown[BUFSIZE - 1] = '\0'; 339 | im_show(-1); 340 | } 341 | 342 | int main() 343 | { 344 | if (get_im_socket() == -1) 345 | return 1; 346 | 347 | GIOChannel *iochannel_fbterm = g_io_channel_unix_new(get_im_socket()); 348 | g_io_add_watch(iochannel_fbterm, (GIOCondition)(G_IO_IN | G_IO_HUP | G_IO_ERR), (GIOFunc)iochannel_fbterm_callback, NULL); 349 | 350 | g_type_init(); 351 | 352 | client = fcitx_client_new(); 353 | g_signal_connect(client, "connected", G_CALLBACK(_fcitx_fbterm_connect_cb), NULL); 354 | g_signal_connect(client, "disconnected", G_CALLBACK(_fcitx_fbterm_destroy_cb), NULL); 355 | g_signal_connect(client, "enable-im", G_CALLBACK(_fcitx_fbterm_enable_im_cb), NULL); 356 | g_signal_connect(client, "close-im", G_CALLBACK(_fcitx_fbterm_close_im_cb), NULL); 357 | g_signal_connect(client, "forward-key", G_CALLBACK(_fcitx_fbterm_forward_key_cb), NULL); 358 | g_signal_connect(client, "commit-string", G_CALLBACK(_fcitx_fbterm_commit_string_cb), NULL); 359 | g_signal_connect(client, "update-client-side-ui", G_CALLBACK(_fcitx_fbterm_update_client_side_ui_cb), NULL); 360 | 361 | register_im_callbacks(cbs); 362 | connect_fbterm(1); 363 | 364 | main_loop = g_main_loop_new(NULL, FALSE); 365 | g_main_loop_run(main_loop); 366 | 367 | g_object_unref(client); 368 | g_io_channel_unref(iochannel_fbterm); 369 | g_main_loop_unref(main_loop); 370 | 371 | return 0; 372 | } 373 | 374 | // kate: indent-mode cstyle; space-indent on; indent-width 0; 375 | 376 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | --------------------------------------------------------------------------------