diff --git a/docs/Chinese-input-method.me b/docs/Chinese-input-method.me new file mode 100644 index 0000000000000000000000000000000000000000..8358958f761411f26675a964e23bb59ec6c6ad44 --- /dev/null +++ b/docs/Chinese-input-method.me @@ -0,0 +1,49 @@ +# Chinese input Method # + +This module is used to release Chinese input in anbox. +It is part of the Anbox Android delivery for Android. + +## Description ## + +This is the first version of the module for android. +the graphics that explains the working principle of this module is as follows: + ______________ ______________ ______________ + | | SDL_TEXTINPUT | | ime_socket | | + | SDL |-----------------> Anbox |-----------------------> Android | + |______________| |______________| |______________| + +Chinese input method module is Separated as follows: +``` +Create socket "ime_socket" to connect android-framework +get SDL_EVENT to collect Chinese input Characters +send Chinese input Characters to android-framework module +``` + +## Dependencies ## + +This module can not be used alone. It is part of the Anbox android delivery for Android. +It need to connect with local socket server which is start with anbox session-manager. + +## Code Detials ## + +The most of the code change is in ./src/anbox/platform/sdl/platform.cpp +And the key code is as follows: +``` +void Platform::process_events() { + ... + case SDL_FINGERMOTION: + process_input_event(event); + break; ++ case SDL_TEXTINPUT: ++ WARNING("Input Event TEXT=%s TYPE=%d WINDOWID=%d", event.text.text, event.type, event.text.windowID); ++ if (flag == 0 && ime_fd_) { ++ send(ime_fd_, event.text.text, strlen(event.text.text), 0); ++ } ++ break; + ... +} +``` + +## License ## + +This module is distributed under the Apache License, Version 2.0 found in the [LICENSE](./LICENSE)file. \ No newline at end of file diff --git a/src/anbox/cmds/session_manager.cpp b/src/anbox/cmds/session_manager.cpp index df19c3df1b418d5ec0b7f4070ef48c54d4e50605..683d378a83091f2f1c40726c4bae4604fe73c632 100644 --- a/src/anbox/cmds/session_manager.cpp +++ b/src/anbox/cmds/session_manager.cpp @@ -265,7 +265,7 @@ anbox::cmds::SessionManager::SessionManager() {bridge_connector->socket_file(), "/dev/anbox_bridge"}, {audio_server->socket_file(), "/dev/anbox_audio"}, {SystemConfiguration::instance().input_device_dir(), "/dev/input"}, - + {"/tmp/ime_socket","/dev/ime"}, }; container_configuration.devices = { diff --git a/src/anbox/platform/sdl/platform.cpp b/src/anbox/platform/sdl/platform.cpp index b1e728ef7bf365354bec0d21480c5e0eeced32bf..c2dc4d39438addd985463d71cd4b6f1afb24ae0f 100644 --- a/src/anbox/platform/sdl/platform.cpp +++ b/src/anbox/platform/sdl/platform.cpp @@ -42,8 +42,8 @@ Platform::Platform( const Configuration &config) : input_manager_(input_manager), event_thread_running_(false), + ime_thread_running_(false), config_(config) { - // Don't block the screensaver from kicking in. It will be blocked // by the desktop shell already and we don't have to do this again. // If we would leave this enabled it will prevent systems from @@ -131,6 +131,7 @@ Platform::Platform( touch_slots[i] = -1; event_thread_ = std::thread(&Platform::process_events, this); + ime_thread_ = std::thread(&Platform::create_ime_socket, this); } Platform::~Platform() { @@ -138,6 +139,13 @@ Platform::~Platform() { event_thread_running_ = false; event_thread_.join(); } + if (ime_thread_running_) { + ime_thread_running_ = false; + ime_thread_.join(); + } + if (ime_socket_ != -1) { + close(ime_socket_); + } } void Platform::set_renderer(const std::shared_ptr &renderer) { @@ -148,8 +156,52 @@ void Platform::set_window_manager(const std::shared_ptr &window_man window_manager_ = window_manager; } +// Added for Chinese input anbox begin +void Platform::create_ime_socket() { + int ime_socket = -1; + int client_socket = -1; + int rc = -1; + int len = 0; + struct sockaddr_un socket_addr, client_addr; + memset(&socket_addr, 0, sizeof(socket_addr)); + DEBUG("Starting create_ime_socket thread"); + ime_socket = socket(AF_UNIX, SOCK_STREAM, 0); + if (ime_socket == -1) { + ERROR("Create ime socket failed"); + return; + } + socket_addr.sun_family = AF_UNIX; + strcpy(socket_addr.sun_path, IME_SOCKET_PATH); + unlink(IME_SOCKET_PATH); + rc = bind(ime_socket, reinterpret_cast(&socket_addr), sizeof(socket_addr)); + if (rc == -1) { + ERROR("bind ime socket failed"); + close(ime_socket); + return; + } + rc = listen(ime_socket, 1); + if (rc == -1) { + ERROR("Listen ime socket failed"); + close(ime_socket); + return; + } + DEBUG("Before ime socket accept"); + client_socket = accept(ime_socket, reinterpret_cast(&client_addr), + reinterpret_cast(&len)); + if (client_socket == -1) { + ERROR("Accept ime socket failed"); + close(ime_socket); + return; + } + ime_fd_ = client_socket; + ime_socket_ = ime_socket; + DEBUG("accept ime socket successful"); +} +// Added for Chinese input anbox end + void Platform::process_events() { event_thread_running_ = true; + int flag = 0; while (event_thread_running_) { SDL_Event event; @@ -168,7 +220,12 @@ void Platform::process_events() { } break; case SDL_KEYDOWN: + flag = 1; + if (keyboard_) + process_input_event(event); + break; case SDL_KEYUP: + flag = 0; if (keyboard_) process_input_event(event); break; @@ -181,6 +238,12 @@ void Platform::process_events() { case SDL_FINGERMOTION: process_input_event(event); break; + case SDL_TEXTINPUT: + WARNING("Input Event TEXT=%s TYPE=%d WINDOWID=%d", event.text.text, event.type, event.text.windowID); + if (flag == 0 && ime_fd_) { + send(ime_fd_, event.text.text, strlen(event.text.text), 0); + } + break; default: break; } @@ -274,8 +337,7 @@ void Platform::process_input_event(const SDL_Event &event) { push_finger_up(event.tfinger.fingerId, touch_events); break; } - case SDL_FINGERMOTION: { - + case SDL_FINGERMOTION: { if (!calculate_touch_coordinates(event, x, y)) break; push_finger_motion(x, y, event.tfinger.fingerId, touch_events); @@ -286,7 +348,7 @@ void Platform::process_input_event(const SDL_Event &event) { } if (mouse_events.size() > 0) { - mouse_events.push_back({EV_SYN, SYN_REPORT, 0}); + mouse_events.push_back({EV_SYN, SYN_REPORT, 0}); pointer_->send_events(mouse_events); } @@ -298,52 +360,52 @@ void Platform::process_input_event(const SDL_Event &event) { } int Platform::find_touch_slot(int id){ - for (int i = 0; i < MAX_FINGERS; i++) { - if (touch_slots[i] == id) - return i; - } - return -1; + for (int i = 0; i < MAX_FINGERS; i++) { + if (touch_slots[i] == id) + return i; + } + return -1; } void Platform::push_slot(std::vector &touch_events, int slot){ - if (last_slot != slot) { - touch_events.push_back({EV_ABS, ABS_MT_SLOT, slot}); - last_slot = slot; - } + if (last_slot != slot) { + touch_events.push_back({EV_ABS, ABS_MT_SLOT, slot}); + last_slot = slot; + } } void Platform::push_finger_down(int x, int y, int finger_id, std::vector &touch_events){ - int slot = find_touch_slot(-1); - if (slot == -1) { - DEBUG("no free slot!"); - return; - } - touch_slots[slot] = finger_id; - push_slot(touch_events, slot); - touch_events.push_back({EV_ABS, ABS_MT_TRACKING_ID, static_cast(finger_id % MAX_TRACKING_ID + 1)}); - touch_events.push_back({EV_ABS, ABS_MT_POSITION_X, x}); - touch_events.push_back({EV_ABS, ABS_MT_POSITION_Y, y}); - touch_events.push_back({EV_SYN, SYN_REPORT, 0}); + int slot = find_touch_slot(-1); + if (slot == -1) { + DEBUG("no free slot!"); + return; + } + touch_slots[slot] = finger_id; + push_slot(touch_events, slot); + touch_events.push_back({EV_ABS, ABS_MT_TRACKING_ID, static_cast(finger_id % MAX_TRACKING_ID + 1)}); + touch_events.push_back({EV_ABS, ABS_MT_POSITION_X, x}); + touch_events.push_back({EV_ABS, ABS_MT_POSITION_Y, y}); + touch_events.push_back({EV_SYN, SYN_REPORT, 0}); } void Platform::push_finger_up(int finger_id, std::vector &touch_events){ - int slot = find_touch_slot(finger_id); - if (slot == -1) - return; - push_slot(touch_events, slot); - touch_events.push_back({EV_ABS, ABS_MT_TRACKING_ID, -1}); - touch_events.push_back({EV_SYN, SYN_REPORT, 0}); - touch_slots[slot] = -1; + int slot = find_touch_slot(finger_id); + if (slot == -1) + return; + push_slot(touch_events, slot); + touch_events.push_back({EV_ABS, ABS_MT_TRACKING_ID, -1}); + touch_events.push_back({EV_SYN, SYN_REPORT, 0}); + touch_slots[slot] = -1; } void Platform::push_finger_motion(int x, int y, int finger_id, std::vector &touch_events){ - int slot = find_touch_slot(finger_id); - if (slot == -1) - return; - push_slot(touch_events, slot); - touch_events.push_back({EV_ABS, ABS_MT_POSITION_X, x}); - touch_events.push_back({EV_ABS, ABS_MT_POSITION_Y, y}); - touch_events.push_back({EV_SYN, SYN_REPORT, 0}); + int slot = find_touch_slot(finger_id); + if (slot == -1) + return; + push_slot(touch_events, slot); + touch_events.push_back({EV_ABS, ABS_MT_POSITION_X, x}); + touch_events.push_back({EV_ABS, ABS_MT_POSITION_Y, y}); + touch_events.push_back({EV_SYN, SYN_REPORT, 0}); } diff --git a/src/anbox/platform/sdl/platform.h b/src/anbox/platform/sdl/platform.h index 898c5459dbf063034d4f772c6bdf901a392a882a..35df574dd8c7da1aac4d9ad9c494504149468969 100644 --- a/src/anbox/platform/sdl/platform.h +++ b/src/anbox/platform/sdl/platform.h @@ -39,6 +39,9 @@ class Manager; } // namespace wm namespace platform { namespace sdl { + +static const char IME_SOCKET_PATH[] = "/tmp/ime_socket"; + class Platform : public std::enable_shared_from_this, public platform::BasePlatform, public Window::Observer { @@ -90,7 +93,9 @@ class Platform : public std::enable_shared_from_this, std::map> windows_; std::shared_ptr current_window_; std::thread event_thread_; + std::thread ime_thread_; bool event_thread_running_; + bool ime_thread_running_; std::shared_ptr pointer_; std::shared_ptr keyboard_; std::shared_ptr touch_; @@ -101,8 +106,12 @@ class Platform : public std::enable_shared_from_this, static const int MAX_FINGERS = 10; static const int MAX_TRACKING_ID = 10; + int touch_slots[MAX_FINGERS]; int last_slot = -1; + int ime_fd_ = -1; + int ime_socket_ = -1; + void create_ime_socket(); int find_touch_slot(int id); void push_slot(std::vector &touch_events, int slot);