From: Ji-hoon Lee Date: Mon, 23 Nov 2020 03:11:02 +0000 (+0900) Subject: Reorganize directory structure X-Git-Tag: submit/tizen/20201126.112926~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F36%2F248136%2F1;p=platform%2Fcore%2Fuifw%2Flibscl-core.git Reorganize directory structure Change-Id: Ide6e34f653e78ec0e5474015dca62e277fa81645 --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 2fe6e33..928a940 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,6 @@ MESSAGE(STATUS "Build type: ${CMAKE_BUILD_TYPE}") INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/src/include - ${CMAKE_SOURCE_DIR}/src/legacy_support ) INCLUDE(FindPkgConfig) @@ -47,8 +46,8 @@ ENDIF(with_wayland) IF (with_websocket) ADD_DEFINITIONS("-DWEBSOCKET") SET(SRCS ${SRCS} - src/legacy_support/websocket.cpp - src/legacy_support/web_helper_agent.cpp) + src/websocket.cpp + src/web_helper_agent.cpp) SET(PKGS_CHECK_MODULES ${PKGS_CHECK_MODULES} libwebsockets) ENDIF(with_websocket) diff --git a/src/legacy_support/web_helper_agent.cpp b/src/legacy_support/web_helper_agent.cpp deleted file mode 100644 index 1d3cfc5..0000000 --- a/src/legacy_support/web_helper_agent.cpp +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (c) 2012 - 2016 Samsung Electronics Co., Ltd All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the License); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include -#include - -#include "web_helper_agent.h" - -#include "websocket.h" -#include "sclcoreimpl.h" - -using namespace scl; - -typedef struct { - int major_version; - WEB_HELPER_AGENT_TYPE agent_type; -} WEB_HELPER_AGENT_TYPES_FOR_VERSIONS; - -static WEB_HELPER_AGENT_TYPES_FOR_VERSIONS web_helper_agent_types_for_versions[] = { - {1, WEB_HELPER_AGENT_WEBSOCKET}, /* Major version 1 indicates that it uses websocket for communication */ -}; - -static int WEB_HELPER_AGENT_TYPES_FOR_VERSIONS_NUM = \ - sizeof(web_helper_agent_types_for_versions) / sizeof(WEB_HELPER_AGENT_TYPES_FOR_VERSIONS); - -WEB_HELPER_AGENT_TYPE CWebHelperAgent::get_web_helper_agent_type_from_major_version(int version) -{ - for (int loop = 0;loop < WEB_HELPER_AGENT_TYPES_FOR_VERSIONS_NUM;loop++) { - if (web_helper_agent_types_for_versions[loop].major_version == version) { - return web_helper_agent_types_for_versions[loop].agent_type; - } - } - return WEB_HELPER_AGENT_UNKNOWN; -} - -CWebHelperAgent* CWebHelperAgent::create_web_helper_agent(WEB_HELPER_AGENT_TYPE type) -{ - CWebHelperAgent *ret = NULL; - if (type == WEB_HELPER_AGENT_WEBSOCKET) { - ret = new CWebHelperAgentWebSocket; - } - return ret; -} - -void CWebHelperAgent::destroy_web_helper_agent(CWebHelperAgent* agent) -{ - if (agent) delete agent; -} - -CWebHelperAgent::CWebHelperAgent() -{ -} - -CWebHelperAgent::~CWebHelperAgent() -{ -} - -bool CWebHelperAgent::init() -{ - return true; -} - -bool CWebHelperAgent::exit() -{ - return true; -} - -void CWebHelperAgent::signal(int sig) -{ -} - -void CWebHelperAgent::log(const char *str) -{ - CSCLCoreImpl *impl = CSCLCoreImpl::get_instance(); - if (impl) { - //impl->logise_log(str); - } -} - -void CWebHelperAgent::commit_string(const char *str) -{ - CSCLCoreImpl *impl = CSCLCoreImpl::get_instance(); - if (impl) { - impl->commit_string(-1, "", str); - } -} - -void CWebHelperAgent::update_preedit_string(const char *str) -{ - CSCLCoreImpl *impl = CSCLCoreImpl::get_instance(); - if (impl) { - impl->update_preedit_string(-1, "", str); - } -} - -void CWebHelperAgent::send_key_event(unsigned int key, unsigned int key_mask) -{ - CSCLCoreImpl *impl = CSCLCoreImpl::get_instance(); - if (impl) { - impl->send_key_event(-1, "", key, key_mask); - } -} - -void CWebHelperAgent::forward_key_event(unsigned int key) -{ - CSCLCoreImpl *impl = CSCLCoreImpl::get_instance(); - if (impl) { - impl->forward_key_event(-1, "", key, scim::SCIM_KEY_NullMask); - } -} - -void CWebHelperAgent::set_keyboard_sizes(int portrait_width, int portrait_height, int landscape_width, int landscape_height) -{ - CSCLCoreImpl *impl = CSCLCoreImpl::get_instance(); - if (impl) { - SclSize portrait, landscape; - portrait.width = portrait_width; - portrait.height = portrait_height; - landscape.width = landscape_width; - landscape.height = landscape_height; - impl->set_keyboard_size_hints(portrait, landscape); - } -} - -void CWebHelperAgent::set_selection(int start_index, int end_index) -{ - CSCLCoreImpl *impl = CSCLCoreImpl::get_instance(); - if (impl) { - impl->set_selection(start_index, end_index); - } -} - -void CWebHelperAgent::get_selection() -{ - CSCLCoreImpl *impl = CSCLCoreImpl::get_instance(); - if (impl) { - //impl->get_selection(-1, "", ); - } -} - -void CWebHelperAgent::get_surrounding_text(int maxlen_before, int maxlen_after) -{ - CSCLCoreImpl *impl = CSCLCoreImpl::get_instance(); - if (impl) { - impl->get_surrounding_text("", maxlen_before, maxlen_after); - } -} - -void CWebHelperAgent::delete_surrounding_text(int offset, int len) -{ - CSCLCoreImpl *impl = CSCLCoreImpl::get_instance(); - if (impl) { - impl->delete_surrounding_text(offset, len); - } -} - -std::string CMagicKeyManager::get_magic_key() -{ - static std::string current_magic_key; - - /* If we don't have magic key generated yet */ - if (current_magic_key.length() != MAGIC_KEY_LENGTH) { - char magic_key[MAGIC_KEY_LENGTH + 1]; - /* We are going to generate a magic key that contains ascii characters in the range of '0' to 'z' */ - const char magic_key_range_lower = '0'; - const char magic_key_range_upper = 'Z'; - - unsigned int seed = time(NULL); - for (int loop = 0;loop < MAGIC_KEY_LENGTH;loop++) { - magic_key[loop] = (rand_r(&seed) % (magic_key_range_upper - magic_key_range_lower)) + magic_key_range_lower; - } - magic_key[MAGIC_KEY_LENGTH] = '\0'; - - current_magic_key = magic_key; - } - - return current_magic_key; -} diff --git a/src/legacy_support/web_helper_agent.h b/src/legacy_support/web_helper_agent.h deleted file mode 100644 index c05c572..0000000 --- a/src/legacy_support/web_helper_agent.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2012 - 2016 Samsung Electronics Co., Ltd All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the License); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifndef _WEB_HELPER_AGENT_H_ -#define _WEB_HELPER_AGENT_H_ - -#define MAGIC_KEY_LENGTH 32 -#define VERSION_DELIMITER '.' -#define VERSION_TOKEN_NUM 2 // We are expecting 2 version tokens : MAJOR and MINOR - -#include -#include -#include - -class CStringTokenizer -{ -public: - static std::vector &split(const std::string &s, char delim, std::vector &elems) { - unsigned int loop = 0; - unsigned int start = 0; - for (loop = 0;loop < s.length();loop++) { - if (s.at(loop) == delim) { - std::string item = s.substr(start, loop - start); - elems.push_back(item); - start = loop + 1; - } - } - std::string item = s.substr(start, loop - start); - elems.push_back(item); - return elems; - } - - static std::vector split(const std::string &s, char delim) { - std::vector elems; - split(s, delim, elems); - return elems; - } -}; - -typedef enum { - WEB_HELPER_AGENT_UNKNOWN, - WEB_HELPER_AGENT_WEBSOCKET, - WEB_HELPER_AGENT_DIRECT, -} WEB_HELPER_AGENT_TYPE; - -class CMagicKeyManager -{ -public: - static std::string get_magic_key(); -}; - -class CWebHelperAgent -{ -public: - CWebHelperAgent(); - virtual ~CWebHelperAgent(); - - virtual bool init(); - virtual bool exit(); - - virtual bool run() { return false; } - virtual void signal(int sig); - - virtual void on_init() {} - virtual void on_exit() {} - - virtual void on_focus_in(int ic) {} - virtual void on_focus_out(int ic) {} - - virtual void on_show(int ic) {} - virtual void on_hide(int ic) {} - - virtual void on_set_rotation(int degree) {} - - virtual void on_update_cursor_position(int ic, int cursor_pos) {} - virtual void on_update_surrounding_text(int ic, const char *text, int cursor) {} - virtual void on_update_selection(int ic, const char *text) {} - - virtual void on_set_language(unsigned int language) {} - - virtual void on_set_imdata(char *buf, unsigned int len) {} - virtual void on_get_imdata(char **buf, unsigned int *len) {} - - virtual void on_set_return_key_type(unsigned int type) {} - virtual void on_get_return_key_type(unsigned int *type) {} - - virtual void on_set_return_key_disable(unsigned int disabled) {} - virtual void on_get_return_key_disable(unsigned int *disabled) {} - - virtual void on_set_layout(unsigned int layout) {} - virtual void on_get_layout(unsigned int *layout) {} - - virtual void on_reset_input_context(int ic) {} - - virtual void on_process_key_event(unsigned int code, unsigned int mask, unsigned int layout, unsigned int *ret) {} - - - virtual void log(const char *str); - virtual void commit_string(const char *str); - virtual void update_preedit_string(const char *str); - virtual void send_key_event(unsigned int key, unsigned int key_mask); - virtual void forward_key_event(unsigned int key); - virtual void set_keyboard_sizes(int portrait_width, int portrait_height, int landscape_width, int landscape_height); - virtual void set_selection(int start_index, int end_index); - virtual void get_selection(); - virtual void get_surrounding_text(int maxlen_before, int maxlen_after); - virtual void delete_surrounding_text(int offset, int len); - -public: - static WEB_HELPER_AGENT_TYPE get_web_helper_agent_type_from_major_version(int version); - static CWebHelperAgent* create_web_helper_agent(WEB_HELPER_AGENT_TYPE type); - static void destroy_web_helper_agent(CWebHelperAgent* agent); -}; - -#endif // _WEB_HELPER_AGENT_H_ diff --git a/src/legacy_support/websocket.cpp b/src/legacy_support/websocket.cpp deleted file mode 100644 index 2ae2565..0000000 --- a/src/legacy_support/websocket.cpp +++ /dev/null @@ -1,1252 +0,0 @@ -/* - * Copyright (c) 2012 - 2016 Samsung Electronics Co., Ltd All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the License); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "websocket.h" - -#include -#include - -#include - -#ifdef WAYLAND -#define EFL_BETA_API_SUPPORT -#include -#endif - -#define WEBSOCKET_PORT 7681 - -#define RECVED_MESSAGE "recved" -#define MESSAGE_LEFT "left" - -pthread_t g_ws_server_thread = (pthread_t)NULL; -pthread_mutex_t g_ws_server_mutex = PTHREAD_MUTEX_INITIALIZER; - -pthread_cond_t g_ws_query_condition = PTHREAD_COND_INITIALIZER; -pthread_mutex_t g_ws_query_mutex = PTHREAD_MUTEX_INITIALIZER; - -bool g_ws_server_exit = false; -struct lws_context *g_ws_server_context = NULL; - -CWebHelperAgentWebSocket* CWebHelperAgentWebSocket::m_current_instance = NULL; - -int force_exit = 0; - -enum protocols { - /* always first */ - PROTOCOL_HTTP = 0, - - PROTOCOL_KEYBOARD, - - /* always last */ - MAX_PROTOCOL_COUNT -}; - -struct per_session_data__http { - int fd; -}; - -static int callback_http(struct lws *wsi, - enum lws_callback_reasons reason, - void *user, void *in, size_t len) -{ - return 0; -} - -struct per_session_data__keyboard { - int session_id; - int valid; - int need_init; - int initialized; -}; - -static int callback_keyboard(struct lws *wsi, - enum lws_callback_reasons reason, - void *user, void *in, size_t len); - -static struct lws_protocols protocols[] = { - { - "http-only", - callback_http, - sizeof(struct per_session_data__http), - 0, - }, - { - "keyboard-protocol", - callback_keyboard, - sizeof(struct per_session_data__keyboard), - 32, - }, - { NULL, NULL, 0, 0 } -}; - - -static int callback_client(struct lws *wsi, - enum lws_callback_reasons reason, - void *user, void *in, size_t len) -{ - switch (reason) { - case LWS_CALLBACK_CLIENT_ESTABLISHED: - LOGD("[ClientTest] Connection established"); - break; - - case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: - LOGD("[ClientTest] Connection error"); - break; - - case LWS_CALLBACK_CLOSED: - LOGD("[ClientTest] Connection closed"); - break; - - default: - break; - } - - return 0; -} - -int test_client_connection(void) -{ - struct lws_context *context = NULL; - struct lws_context_creation_info context_info; - struct lws_client_connect_info connect_info; - struct lws *wsi = NULL; - - memset(&context_info, 0, sizeof context_info); - memset(&connect_info, 0, sizeof(connect_info)); - - const int protocols_num = sizeof(protocols) / sizeof(lws_protocols); - static struct lws_protocols client_protocols[protocols_num]; - - memcpy(&client_protocols, protocols, sizeof(protocols)); - for (int loop = 0; loop < protocols_num - 1; loop++) { - client_protocols[loop].callback = callback_client; - } - - context_info.port = CONTEXT_PORT_NO_LISTEN; - context_info.protocols = protocols; - context_info.gid = -1; - context_info.uid = -1; - - context = lws_create_context(&context_info); - LOGD("[ClientTest] create_context : %p", context); - if (context == NULL) { - return -1; - } - - connect_info.address = "localhost"; - connect_info.port = WEBSOCKET_PORT; - connect_info.path = "/"; - connect_info.context = context; - connect_info.ssl_connection = 0; - connect_info.host = connect_info.address; - connect_info.origin = connect_info.address; - connect_info.ietf_version_or_minus_one = -1; - connect_info.protocol = "keyboard-protocol"; - - wsi = lws_client_connect_via_info(&connect_info); - LOGD("[ClientTest] wsi created : %p", wsi); - - if (wsi) { - lws_service(context, 50); - } - - lws_context_destroy(context); - - return 0; -} - -static Ecore_Timer *g_flush_server_recv_buffer_timer = NULL; -static std::string server_recv_buffer; -static Eina_Bool flush_server_recv_buffer_func(void *user) -{ - LOGD("flushing recv buffer"); - CWebHelperAgentWebSocket *agent = CWebHelperAgentWebSocket::get_current_instance(); - struct per_session_data__keyboard *pss = (struct per_session_data__keyboard *)user; - - if (g_flush_server_recv_buffer_timer) - ecore_timer_del(g_flush_server_recv_buffer_timer); - g_flush_server_recv_buffer_timer = NULL; - - if (!agent || !pss) return ECORE_CALLBACK_CANCEL; - - pthread_mutex_lock(&g_ws_server_mutex); - ISE_MESSAGE message = CISEMessageSerializer::deserialize(server_recv_buffer); - server_recv_buffer.clear(); - pthread_mutex_unlock(&g_ws_server_mutex); - - if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_LOGIN]) == 0) { - /* - if (message.values.at(0).compare(CMagicKeyManager::get_magic_key()) == 0) { - LOGD("LOGIN successful, validating client"); - pss->valid = true; - } else { - LOGD("LOGIN failed, invalidating client"); - pss->valid = false; - } - */ - pss->valid = true; - - if (agent->initialized()) { - pss->need_init = true; - ecore_pipe_write(agent->get_message_pipe(), MESSAGE_LEFT, strlen(MESSAGE_LEFT)); - } - } - - /* Ignore valid check since the magic key is not used anymore */ - if (!pss->valid) pss->valid = true; - - if (pss->valid) { - pthread_mutex_lock(&g_ws_server_mutex); - std::queue& messages = agent->get_recv_message_queue(); - messages.push(message); - pthread_mutex_unlock(&g_ws_server_mutex); - - ecore_pipe_write(agent->get_message_pipe(), RECVED_MESSAGE, strlen(RECVED_MESSAGE)); - - /* If we received reply message, let's send signal to wake up our main thread */ - if (message.type.compare(ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY]) == 0) { - pthread_mutex_lock(&g_ws_query_mutex); - pthread_cond_signal(&g_ws_query_condition); - pthread_mutex_unlock(&g_ws_query_mutex); - } - } else { - LOGD("Ignoring data received since client is not valid %d", pss->session_id); - } - - return ECORE_CALLBACK_CANCEL; -} - -static int callback_keyboard(struct lws *wsi, - enum lws_callback_reasons reason, - void *user, void *in, size_t len) -{ - static int last_session_id = 0; - const int bufsize = 512; - int n = 0; - unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + bufsize + - LWS_SEND_BUFFER_POST_PADDING]; - unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING]; - struct per_session_data__keyboard *pss = (struct per_session_data__keyboard *)user; - CWebHelperAgentWebSocket *agent = CWebHelperAgentWebSocket::get_current_instance(); - - switch (reason) { - case LWS_CALLBACK_ESTABLISHED: - pss->session_id = ++last_session_id; - LOGD("LWS_CALLBACK_ESTABLISHED : %p %d", g_ws_server_context, pss->session_id); - pss->valid = false; - pss->need_init = false; - pss->initialized = false; - if (g_ws_server_context) { - ecore_pipe_write(agent->get_message_pipe(), MESSAGE_LEFT, strlen(MESSAGE_LEFT)); - } - break; - - case LWS_CALLBACK_CLOSED: - LOGD("LWS_CALLBACK_CLOSED : %d", pss->session_id); - break; - - case LWS_CALLBACK_SERVER_WRITEABLE: - if (agent) { - /* Ignore valid check since the magic key is not used anymore */ - if (!pss->valid) pss->valid = true; - - /* We allow data tranmission only if this client is guaranteed to be valid */ - if (pss->valid) { - pthread_mutex_lock(&g_ws_server_mutex); - std::queue& messages = agent->get_send_message_queue(); - - if (pss->need_init && !pss->initialized) { - ISE_MESSAGE message; - message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN]; - message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_INIT]; - std::string str = CISEMessageSerializer::serialize(message); - SECURE_LOGD("SEND_WEBSOCKET_MESSAGE : %d %s", pss->session_id, str.c_str()); - n = snprintf((char *)p, bufsize, "%s", str.c_str()); - /* too small for partial */ - n = lws_write(wsi, p, n, LWS_WRITE_TEXT); - pss->need_init = false; - pss->initialized = true; - } else { - /* One write allowed per one writable callback */ - if (messages.size() > 0) { - ISE_MESSAGE &message = messages.front(); - bool drop = false; - if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_INIT]) == 0) { - if (pss->initialized) { - drop = true; - } else { - pss->initialized = true; - } - } - if (!drop) { - std::string str = CISEMessageSerializer::serialize(message); - SECURE_LOGD("SEND_WEBSOCKET_MESSAGE : %d %s", pss->session_id, str.c_str()); - n = snprintf((char *)p, bufsize, "%s", str.c_str()); - /* too small for partial */ - n = lws_write(wsi, p, n, LWS_WRITE_TEXT); - } - messages.pop(); - } - } - if (messages.size() > 0) { - ecore_pipe_write(agent->get_message_pipe(), MESSAGE_LEFT, strlen(MESSAGE_LEFT)); - } - pthread_mutex_unlock(&g_ws_server_mutex); - - if (n < 0) { - LOGE("ERROR %d writing to di socket %d", n, pss->session_id); - } - - if (messages.size() > 0) { - lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); - } - } else { - LOGD("Rejecting data transmission since client is not valid : %d", pss->session_id); - } - } - break; - - case LWS_CALLBACK_RECEIVE: - if (in) { - if (g_flush_server_recv_buffer_timer) { - ecore_thread_main_loop_begin(); - ecore_timer_del(g_flush_server_recv_buffer_timer); - g_flush_server_recv_buffer_timer = NULL; - ecore_thread_main_loop_end(); - } - - std::string str = std::string((const char *)in, len); - if (CISEMessageSerializer::valid(str)) { - LOGD("A valid new message received, flush previous buffer"); - flush_server_recv_buffer_func((void*)pss); - } - - pthread_mutex_lock(&g_ws_server_mutex); - server_recv_buffer += str; - SECURE_LOGD("RECEIVE callback : [%zu] [%s], [%s]", len, str.c_str(), server_recv_buffer.c_str()); - pthread_mutex_unlock(&g_ws_server_mutex); - - ecore_thread_main_loop_begin(); - g_flush_server_recv_buffer_timer = ecore_timer_add(0.05, flush_server_recv_buffer_func, (void*)pss); - SECURE_LOGD("flush timer registered : %p", g_flush_server_recv_buffer_timer); - ecore_thread_main_loop_end(); - } - - break; - default: - break; - } - - return 0; -} - -void *process_ws_server(void *data) -{ - while (!force_exit && !g_ws_server_exit) { - struct timeval tv; - gettimeofday(&tv, NULL); - - if (g_ws_server_context) { - lws_service(g_ws_server_context, 50); - } else { - LOGD("WARNING : g_ws_server_context is NULL"); - } - } - LOGD("process_ws_server exits now"); - return NULL; -} - -void log_func(int level, const char *line) -{ - if (line) { - LOGD("LEVEL : %d , %s", level, line); - } -} - -CWebHelperAgentWebSocket::CWebHelperAgentWebSocket() -{ - if (m_current_instance != NULL) { - LOGD("WARNING : m_current_instance is NOT NULL"); - } - m_current_instance = this; - m_message_pipe = NULL; - m_initialized = false; -} - -CWebHelperAgentWebSocket::~CWebHelperAgentWebSocket() -{ - if (m_current_instance == this) { - m_current_instance = NULL; - } - - if (m_message_pipe) { - ecore_pipe_del(m_message_pipe); - m_message_pipe = NULL; - } -} - -static void message_pipe_handler(void *data, void *buffer, unsigned int nbyte) -{ - if (buffer) { - if (strncmp((const char*)buffer, RECVED_MESSAGE, strlen(RECVED_MESSAGE)) == 0) { - CWebHelperAgentWebSocket *agent = CWebHelperAgentWebSocket::get_current_instance(); - if (agent) { - agent->process_recved_messages(); - } - } else { - if (g_ws_server_context) { - lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); - } else { - LOGD("WARNING : g_ws_server_context is NULL"); - } - } - } -} - -bool CWebHelperAgentWebSocket::init() -{ - bool ret = true; - - struct lws_context_creation_info info; - - memset(&info, 0, sizeof info); - info.port = WEBSOCKET_PORT; - - int log_level = LLL_ERR | LLL_WARN | LLL_DEBUG; - lws_set_log_level(log_level, log_func); - - info.iface = NULL; - info.protocols = protocols; - info.extensions = NULL; - info.ssl_cert_filepath = NULL; - info.ssl_private_key_filepath = NULL; - info.gid = -1; - info.uid = -1; - info.options = 0; - - ecore_init(); - - /* The WebSocket server is running on a separate thread, and let the thread send a message - through this pipe to guarantee thread safety */ - m_message_pipe = ecore_pipe_add(message_pipe_handler, NULL); - - /* Let's retry creating server context for a certain number of times */ - const int max_retry_num = 30; - int retry_num = 0; - - do { - g_ws_server_context = lws_create_context(&info); - LOGD("libwebsocket context : %p", g_ws_server_context); - usleep(100 * 1000); - } while (g_ws_server_context == NULL && retry_num++ < max_retry_num); - - pthread_mutex_init(&g_ws_server_mutex, NULL); - - pthread_mutex_init(&g_ws_query_mutex, NULL); - pthread_cond_init(&g_ws_query_condition, NULL); - - m_initialized = true; - - return ret; -} - -bool CWebHelperAgentWebSocket::exit() -{ - if (g_flush_server_recv_buffer_timer) - ecore_timer_del(g_flush_server_recv_buffer_timer); - g_flush_server_recv_buffer_timer = NULL; - - on_exit(); - - g_ws_server_exit = true; - if (g_ws_server_context) { - lws_cancel_service(g_ws_server_context); - } - - if (m_message_pipe) { - ecore_pipe_del(m_message_pipe); - m_message_pipe = NULL; - } - - if (g_ws_server_thread) { - pthread_join(g_ws_server_thread, NULL); - } - - pthread_cond_destroy(&g_ws_query_condition); - pthread_mutex_destroy(&g_ws_query_mutex); - - pthread_mutex_destroy(&g_ws_server_mutex); - - if (g_ws_server_context) { - lws_context_destroy(g_ws_server_context); - g_ws_server_context = NULL; - } - - ecore_shutdown(); - - return true; -} - -bool CWebHelperAgentWebSocket::run() -{ - if (!m_initialized) { - LOGE("Not initialized"); - return false; - } - - bool ret = false; - if (g_ws_server_context) { - if (pthread_create(&g_ws_server_thread, NULL, &process_ws_server, NULL) != 0) { - g_ws_server_thread = (pthread_t)NULL; - ret = false; - - on_init(); - - test_client_connection(); - } - } else { - LOGE("Failed creating server context : %p", g_ws_server_context); - ret = false; - } - return ret; -} - -void CWebHelperAgentWebSocket::signal(int sig) -{ - force_exit = 1; -} - -template -std::string to_string(T i) -{ - std::stringstream ss; - std::string s; - ss << i; - s = ss.str(); - - return s; -} - -void CWebHelperAgentWebSocket::on_init() -{ - ISE_MESSAGE message; - message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN]; - message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_INIT]; - - pthread_mutex_lock(&g_ws_server_mutex); - m_send_message_queue.push(message); - pthread_mutex_unlock(&g_ws_server_mutex); - - if (g_ws_server_context) { - lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); - } else { - LOGD("WARNING : g_ws_server_context is NULL"); - } -} - -void CWebHelperAgentWebSocket::on_exit() -{ - ISE_MESSAGE message; - message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN]; - message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_EXIT]; - - pthread_mutex_lock(&g_ws_server_mutex); - m_send_message_queue.push(message); - pthread_mutex_unlock(&g_ws_server_mutex); - - if (g_ws_server_context) { - lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); - } else { - LOGD("WARNING : g_ws_server_context is NULL"); - } -} - -void CWebHelperAgentWebSocket::on_focus_in(int ic) -{ - ISE_MESSAGE message; - message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN]; - message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_FOCUS_IN]; - message.values.push_back(to_string(ic)); - - pthread_mutex_lock(&g_ws_server_mutex); - m_send_message_queue.push(message); - pthread_mutex_unlock(&g_ws_server_mutex); - - if (g_ws_server_context) { - lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); - } else { - LOGD("WARNING : g_ws_server_context is NULL"); - } -} - -void CWebHelperAgentWebSocket::on_focus_out(int ic) -{ - ISE_MESSAGE message; - message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN]; - message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_FOCUS_OUT]; - message.values.push_back(to_string(ic)); - - pthread_mutex_lock(&g_ws_server_mutex); - m_send_message_queue.push(message); - pthread_mutex_unlock(&g_ws_server_mutex); - - if (g_ws_server_context) { - lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); - } else { - LOGD("WARNING : g_ws_server_context is NULL"); - } -} - -void CWebHelperAgentWebSocket::on_show(int ic) -{ - ISE_MESSAGE message; - message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN]; - message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SHOW]; - message.values.push_back(to_string(ic)); - - pthread_mutex_lock(&g_ws_server_mutex); - m_send_message_queue.push(message); - pthread_mutex_unlock(&g_ws_server_mutex); - - if (g_ws_server_context) { - lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); - } else { - LOGD("WARNING : g_ws_server_context is NULL"); - } - - LOGD("put into send message buffer"); -} - -void CWebHelperAgentWebSocket::on_hide(int ic) -{ - ISE_MESSAGE message; - message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN]; - message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_HIDE]; - message.values.push_back(to_string(ic)); - - pthread_mutex_lock(&g_ws_server_mutex); - m_send_message_queue.push(message); - pthread_mutex_unlock(&g_ws_server_mutex); - - if (g_ws_server_context) { - lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); - } else { - LOGD("WARNING : g_ws_server_context is NULL"); - } -} - -void CWebHelperAgentWebSocket::on_set_rotation(int degree) -{ - ISE_MESSAGE message; - message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN]; - message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_ROTATION]; - message.values.push_back(to_string(degree)); - - pthread_mutex_lock(&g_ws_server_mutex); - m_send_message_queue.push(message); - pthread_mutex_unlock(&g_ws_server_mutex); - - if (g_ws_server_context) { - lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); - } else { - LOGD("WARNING : g_ws_server_context is NULL"); - } -} - -void CWebHelperAgentWebSocket::on_update_cursor_position(int ic, int cursor_pos) -{ - ISE_MESSAGE message; - message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN]; - message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_CURSOR_POSITION]; - message.values.push_back(to_string(ic)); - message.values.push_back(to_string(cursor_pos)); - - pthread_mutex_lock(&g_ws_server_mutex); - m_send_message_queue.push(message); - pthread_mutex_unlock(&g_ws_server_mutex); - - if (g_ws_server_context) { - lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); - } else { - LOGD("WARNING : g_ws_server_context is NULL"); - } -} - -void CWebHelperAgentWebSocket::on_update_surrounding_text(int ic, const char *text, int cursor) -{ - ISE_MESSAGE message; - message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY]; - message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_SURROUNDING_TEXT]; - message.values.push_back(to_string(cursor)); - message.values.push_back(text); - - pthread_mutex_lock(&g_ws_server_mutex); - m_send_message_queue.push(message); - pthread_mutex_unlock(&g_ws_server_mutex); - - if (g_ws_server_context) { - lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); - } else { - LOGD("WARNING : g_ws_server_context is NULL"); - } -} - -void CWebHelperAgentWebSocket::on_update_selection(int ic, const char *text) -{ - ISE_MESSAGE message; - message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY]; - message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_SELECTION]; - message.values.push_back(text); - - pthread_mutex_lock(&g_ws_server_mutex); - m_send_message_queue.push(message); - pthread_mutex_unlock(&g_ws_server_mutex); - - if (g_ws_server_context) { - lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); - } else { - LOGD("WARNING : g_ws_server_context is NULL"); - } -} - -void CWebHelperAgentWebSocket::on_set_language(unsigned int language) -{ - ISE_MESSAGE message; - message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN]; - message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_LANGUAGE]; - - bool found = false; - for (unsigned int loop = 0;loop < sizeof(ISE_LANGUAGE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) { - if (language == (unsigned int)ISE_LANGUAGE_TYPES[loop].type_value) { - message.values.push_back(ISE_LANGUAGE_TYPES[loop].type_string); - found = true; - } - } - - if (found) { - pthread_mutex_lock(&g_ws_server_mutex); - m_send_message_queue.push(message); - pthread_mutex_unlock(&g_ws_server_mutex); - - if (g_ws_server_context) { - lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); - } else { - LOGD("WARNING : g_ws_server_context is NULL"); - } - } -} - -void CWebHelperAgentWebSocket::on_set_imdata(char *buf, unsigned int len) -{ - ISE_MESSAGE message; - message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN]; - message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_IMDATA]; - message.values.push_back(buf); - - pthread_mutex_lock(&g_ws_server_mutex); - m_send_message_queue.push(message); - pthread_mutex_unlock(&g_ws_server_mutex); - - if (g_ws_server_context) { - lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); - } else { - LOGD("WARNING : g_ws_server_context is NULL"); - } -} - -void CWebHelperAgentWebSocket::on_get_imdata(char **buf, unsigned int *len) -{ - ISE_MESSAGE message; - message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY]; - message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_IMDATA]; - - pthread_mutex_lock(&g_ws_server_mutex); - m_send_message_queue.push(message); - pthread_mutex_unlock(&g_ws_server_mutex); - - if (g_ws_server_context) { - lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); - } else { - LOGD("WARNING : g_ws_server_context is NULL"); - } - - wait_for_reply_message(); - - std::vector values; - /* Check if we received reply for GET_IMDATA message */ - if (process_recved_messages_until_reply_found( - ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_IMDATA], values)) { - if (values.size() > 0 && buf && len) { - int string_length = values.at(0).length(); - (*buf) = new char[string_length + 1]; - if (*buf) { - strncpy(*buf, values.at(0).c_str(), string_length); - /* Make sure this is a null-terminated string */ - *(*buf + string_length) = '\0'; - *len = string_length; - } - } - } else { - LOGD("process_recved_messages_until_reply_found returned FALSE"); - } - /* Now process the rest in the recv buffer */ - process_recved_messages(); -} - -void CWebHelperAgentWebSocket::on_set_return_key_type(unsigned int type) -{ - ISE_MESSAGE message; - message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN]; - message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_RETURN_KEY_TYPE]; - - bool found = false; - for (unsigned int loop = 0;loop < sizeof(ISE_RETURN_KEY_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) { - if (type == (unsigned int)ISE_RETURN_KEY_TYPES[loop].type_value) { - message.values.push_back(ISE_RETURN_KEY_TYPES[loop].type_string); - found = true; - } - } - - if (found) { - pthread_mutex_lock(&g_ws_server_mutex); - m_send_message_queue.push(message); - pthread_mutex_unlock(&g_ws_server_mutex); - - if (g_ws_server_context) { - lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); - } else { - LOGD("WARNING : g_ws_server_context is NULL"); - } - } -} - -void CWebHelperAgentWebSocket::on_get_return_key_type(unsigned int *type) -{ - ISE_MESSAGE message; - message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY]; - message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_TYPE]; - - pthread_mutex_lock(&g_ws_server_mutex); - m_send_message_queue.push(message); - pthread_mutex_unlock(&g_ws_server_mutex); - - if (g_ws_server_context) { - lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); - } else { - LOGD("WARNING : g_ws_server_context is NULL"); - } - - wait_for_reply_message(); - - std::vector values; - /* Check if we received reply for GET_RETURN_KEY_TYPE message */ - if (process_recved_messages_until_reply_found( - ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_TYPE], values)) { - if (type) { - for (unsigned int loop = 0;loop < sizeof(ISE_RETURN_KEY_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) { - if (values.at(0).compare(ISE_RETURN_KEY_TYPES[loop].type_string) == 0) { - *type = ISE_RETURN_KEY_TYPES[loop].type_value; - } - } - } - } - /* Now process the rest in the recv buffer */ - process_recved_messages(); -} - -void CWebHelperAgentWebSocket::on_set_return_key_disable(unsigned int disabled) -{ - ISE_MESSAGE message; - message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN]; - message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_RETURN_KEY_DISABLE]; - - bool found = false; - for (unsigned int loop = 0;loop < sizeof(ISE_TRUEFALSE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) { - if (disabled == (unsigned int)ISE_TRUEFALSE_TYPES[loop].type_value) { - message.values.push_back(ISE_TRUEFALSE_TYPES[loop].type_string); - found = true; - } - } - - if (found) { - pthread_mutex_lock(&g_ws_server_mutex); - m_send_message_queue.push(message); - pthread_mutex_unlock(&g_ws_server_mutex); - - if (g_ws_server_context) { - lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); - } else { - LOGD("WARNING : g_ws_server_context is NULL"); - } - } -} - -void CWebHelperAgentWebSocket::on_get_return_key_disable(unsigned int *disabled) -{ - ISE_MESSAGE message; - message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY]; - message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_DISABLE]; - - pthread_mutex_lock(&g_ws_server_mutex); - m_send_message_queue.push(message); - pthread_mutex_unlock(&g_ws_server_mutex); - - if (g_ws_server_context) { - lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); - } else { - LOGD("WARNING : g_ws_server_context is NULL"); - } - - wait_for_reply_message(); - - std::vector values; - /* Check if we received reply for GET_RETURN_KEY_DISABLE message */ - if (process_recved_messages_until_reply_found( - ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_DISABLE], values)) { - if (disabled) { - for (unsigned int loop = 0;loop < sizeof(ISE_TRUEFALSE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) { - if (values.at(0).compare(ISE_TRUEFALSE_TYPES[loop].type_string) == 0) { - *disabled = ISE_TRUEFALSE_TYPES[loop].type_value; - } - } - } - } - /* Now process the rest in the recv buffer */ - process_recved_messages(); -} - -void CWebHelperAgentWebSocket::on_set_layout(unsigned int layout) -{ - ISE_MESSAGE message; - message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN]; - message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_LAYOUT]; - - bool found = false; - for (unsigned int loop = 0;loop < sizeof(ISE_LAYOUT_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) { - if (layout == (unsigned int)ISE_LAYOUT_TYPES[loop].type_value) { - message.values.push_back(ISE_LAYOUT_TYPES[loop].type_string); - found = true; - } - } - - if (found) { - pthread_mutex_lock(&g_ws_server_mutex); - m_send_message_queue.push(message); - pthread_mutex_unlock(&g_ws_server_mutex); - - if (g_ws_server_context) { - lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); - } else { - LOGD("WARNING : g_ws_server_context is NULL"); - } - } -} - -void CWebHelperAgentWebSocket::on_get_layout(unsigned int *layout) -{ - ISE_MESSAGE message; - message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY]; - message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_LAYOUT]; - - pthread_mutex_lock(&g_ws_server_mutex); - m_send_message_queue.push(message); - pthread_mutex_unlock(&g_ws_server_mutex); - - if (g_ws_server_context) { - lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); - } else { - LOGD("WARNING : g_ws_server_context is NULL"); - } - - wait_for_reply_message(); - - std::vector values; - /* Check if we received reply for GET_LAYOUT message */ - if (process_recved_messages_until_reply_found( - ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_LAYOUT], values)) { - if (layout) { - for (unsigned int loop = 0;loop < sizeof(ISE_LAYOUT_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) { - if (values.at(0).compare(ISE_LAYOUT_TYPES[loop].type_string) == 0) { - *layout = ISE_LAYOUT_TYPES[loop].type_value; - } - } - } - } - /* Now process the rest in the recv buffer */ - process_recved_messages(); -} - -void CWebHelperAgentWebSocket::on_reset_input_context(int ic) -{ - ISE_MESSAGE message; - message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN]; - message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_RESET_INPUT_CONTEXT]; - message.values.push_back(to_string(ic)); - - pthread_mutex_lock(&g_ws_server_mutex); - m_send_message_queue.push(message); - pthread_mutex_unlock(&g_ws_server_mutex); - - if (g_ws_server_context) { - lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); - } else { - LOGD("WARNING : g_ws_server_context is NULL"); - } -} - -void CWebHelperAgentWebSocket::on_process_key_event(unsigned int code, unsigned int mask, unsigned int layout, unsigned int *ret) -{ - ISE_MESSAGE message; - message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY]; - message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_PROCESS_KEY_EVENT]; - message.values.push_back(to_string(code)); - message.values.push_back(to_string(mask)); - message.values.push_back(to_string(layout)); - - pthread_mutex_lock(&g_ws_server_mutex); - m_send_message_queue.push(message); - pthread_mutex_unlock(&g_ws_server_mutex); - - if (g_ws_server_context) { - lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); - } else { - LOGD("WARNING : g_ws_server_context is NULL"); - } - - wait_for_reply_message(); - - std::vector values; - /* Check if we received reply for PROCESS_KEY_EVENT message */ - if (process_recved_messages_until_reply_found( - ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_PROCESS_KEY_EVENT], values)) { - if (ret) { - for (unsigned int loop = 0;loop < sizeof(ISE_TRUEFALSE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) { - if (values.at(0).compare(ISE_TRUEFALSE_TYPES[loop].type_string) == 0) { - *ret = ISE_TRUEFALSE_TYPES[loop].type_value; - } - } - } - } - /* Now process the rest in the recv buffer */ - process_recved_messages(); -} - -CWebHelperAgentWebSocket* CWebHelperAgentWebSocket::get_current_instance() -{ - return m_current_instance; -} - -std::queue& CWebHelperAgentWebSocket::get_send_message_queue() -{ - return m_send_message_queue; -} - -std::queue& CWebHelperAgentWebSocket::get_recv_message_queue() -{ - return m_recv_message_queue; -} - -Ecore_Pipe* CWebHelperAgentWebSocket::get_message_pipe() -{ - return m_message_pipe; -} - -void CWebHelperAgentWebSocket::wait_for_reply_message() -{ - /* Let's wait for at most REPLY_TIMEOUT */ - struct timeval now; - struct timespec timeout; - gettimeofday(&now, NULL); - timeout.tv_sec = now.tv_sec + REPLY_TIMEOUT.tv_sec; - timeout.tv_nsec = (now.tv_usec + REPLY_TIMEOUT.tv_usec) * 1000; - pthread_mutex_lock(&g_ws_query_mutex); - pthread_cond_timedwait(&g_ws_query_condition, &g_ws_query_mutex, &timeout); - pthread_mutex_unlock(&g_ws_query_mutex); -} - -void CWebHelperAgentWebSocket::process_recved_messages() -{ - pthread_mutex_lock(&g_ws_server_mutex); - - while (m_recv_message_queue.size() > 0) { - ISE_MESSAGE &message = m_recv_message_queue.front(); - - handle_recved_message(message); - - m_recv_message_queue.pop(); - } - - pthread_mutex_unlock(&g_ws_server_mutex); -} - -bool CWebHelperAgentWebSocket::process_recved_messages_until_reply_found(std::string command, std::vector &values) -{ - bool ret = false; - - pthread_mutex_lock(&g_ws_server_mutex); - - while (ret == false && m_recv_message_queue.size() > 0) { - ISE_MESSAGE &message = m_recv_message_queue.front(); - - if (message.command.compare(command) == 0 && - message.type.compare(ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY]) == 0) { - ret = true; - values = message.values; - } - handle_recved_message(message); - - m_recv_message_queue.pop(); - } - - pthread_mutex_unlock(&g_ws_server_mutex); - - return ret; -} - -void CWebHelperAgentWebSocket::handle_recved_message(ISE_MESSAGE &message) -{ - static bool _key_event_processing = false; - if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_LOG]) == 0) { - std::string str = ""; - for (unsigned int loop = 0;loop < message.values.size();loop++) { - str += message.values.at(loop).c_str(); - if (loop < message.values.size() - 1) { - str += " "; - } - } - log(str.c_str()); - } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_COMMIT_STRING]) == 0) { - std::string str = ""; - for (unsigned int loop = 0;loop < message.values.size();loop++) { - str += message.values.at(loop).c_str(); - if (loop < message.values.size() - 1) { - str += " "; - } - } - if (_key_event_processing) { - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 50000; - select(0, NULL, NULL, NULL, &tv); - _key_event_processing = false; - } - commit_string(str.c_str()); - } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_PREEDIT_STRING]) == 0) { - std::string str = ""; - for (unsigned int loop = 0;loop < message.values.size();loop++) { - str += message.values.at(loop).c_str(); - if (loop < message.values.size() - 1) { - str += " "; - } - } - update_preedit_string(str.c_str()); - } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SEND_KEY_EVENT]) == 0) { - if (message.values.size() == 1) { - forward_key_event(atoi(message.values.at(0).c_str())); - _key_event_processing = true; - } - } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_KEYBOARD_SIZES]) == 0) { - LOGD("ISE_MESSAGE_COMMAND_SET_KEYBOARD_SIZES"); - int portrait_width, portrait_height; - int landscape_width, landscape_height; - - if (message.values.size() == 4 || message.values.size() == 2) { - portrait_width = atoi(message.values.at(0).c_str()); - portrait_height = atoi(message.values.at(1).c_str()); - if (message.values.size() == 2) { - landscape_width = portrait_width; - landscape_height = portrait_height; - } else { - landscape_width = atoi(message.values.at(2).c_str()); - landscape_height = atoi(message.values.at(3).c_str()); - } - - LOGD("ISE_MESSAGE_COMMAND_SET_KEYBOARD_SIZES : %d %d %d %d", - portrait_width, portrait_height, landscape_width, landscape_height); - -#ifdef WAYLAND - /* Since the full screen IME makes the client application fully obscured, - * when it hides the client receives resume command and try to show IME again. - * So here we are adjusting the height value when the requested keyboard size - * is the same with the screen size, as a workaround */ - int scr_w = 0, scr_h = 0; - ecore_wl2_sync(); - Ecore_Wl2_Display *ewd = NULL; - if ((ewd = ecore_wl2_connected_display_get(NULL))) { - ecore_wl2_display_screen_size_get(ewd, &scr_w, &scr_h); - - if (scr_w == portrait_width && scr_h == portrait_height) { - portrait_height -= 1; - } - if (scr_h == landscape_width && scr_w == landscape_height) { - landscape_height -= 1; - } - } -#endif - - set_keyboard_sizes( - portrait_width, portrait_height, landscape_width, landscape_height); - } - } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_SELECTION]) == 0) { - LOGD("ISE_MESSAGE_COMMAND_SET_SELECTION"); - if (message.values.size() == 2) { - LOGD("ISE_MESSAGE_COMMAND_SET_SELECTION : %d %d", - atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str())); - set_selection( - atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str())); - } - } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_SELECTION]) == 0) { - if (message.values.size() == 0) { - get_selection(); - } - } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_SURROUNDING_TEXT]) == 0) { - LOGD("ISE_MESSAGE_COMMAND_GET_SURROUNDING_TEXT"); - if (message.values.size() == 2) { - LOGD("ISE_MESSAGE_COMMAND_GET_SURROUNDING_TEXT : %d %d", - atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str())); - get_surrounding_text( - atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str())); - } - } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_DELETE_SURROUNDING_TEXT]) == 0) { - LOGD("ISE_MESSAGE_COMMAND_DELETE_SURROUNDING_TEXT"); - if (message.values.size() == 2) { - LOGD("ISE_MESSAGE_COMMAND_DELETE_SURROUNDING_TEXT : %d %d", - atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str())); - delete_surrounding_text( - atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str())); - } - } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_LOGIN]) == 0) { - if (g_ws_server_context) { - lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); - } else { - LOGD("WARNING : g_ws_server_context is NULL"); - } - } -} diff --git a/src/legacy_support/websocket.h b/src/legacy_support/websocket.h deleted file mode 100644 index 0be56b4..0000000 --- a/src/legacy_support/websocket.h +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Copyright (c) 2012 - 2016 Samsung Electronics Co., Ltd All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the License); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifndef _WEB_HELPER_AGENT_WEBSOCKET_H_ -#define _WEB_HELPER_AGENT_WEBSOCKET_H_ - -#include "web_helper_agent.h" - -#include - -#include -#include -#include - -/* Wait for at most 1 second */ -const struct timeval REPLY_TIMEOUT = {1, 0}; - -typedef enum { - ISE_MESSAGE_TYPE_PLAIN, - ISE_MESSAGE_TYPE_QUERY, - ISE_MESSAGE_TYPE_REPLY, - - ISE_MESSAGE_TYPES_NUM, -} ISE_MESSAGE_TYPES; - -const std::string ISE_MESSAGE_TYPE_STRINGS[] = { - "plain", // ISE_MESSAGE_TYPE_PLAIN, - "query", // ISE_MESSAGE_TYPE_QUERY - "reply", // ISE_MESSAGE_TYPE_REPLY -}; - -typedef enum { - ISE_MESSAGE_COMMAND_INIT, - ISE_MESSAGE_COMMAND_EXIT, - - ISE_MESSAGE_COMMAND_FOCUS_IN, - ISE_MESSAGE_COMMAND_FOCUS_OUT, - ISE_MESSAGE_COMMAND_SHOW, - ISE_MESSAGE_COMMAND_HIDE, - ISE_MESSAGE_COMMAND_SET_ROTATION, - ISE_MESSAGE_COMMAND_UPDATE_CURSOR_POSITION, - ISE_MESSAGE_COMMAND_UPDATE_SURROUNDING_TEXT, - ISE_MESSAGE_COMMAND_UPDATE_SELECTION, - ISE_MESSAGE_COMMAND_SET_LANGUAGE, - ISE_MESSAGE_COMMAND_SET_IMDATA, - ISE_MESSAGE_COMMAND_GET_IMDATA, - ISE_MESSAGE_COMMAND_SET_RETURN_KEY_TYPE, - ISE_MESSAGE_COMMAND_GET_RETURN_KEY_TYPE, - ISE_MESSAGE_COMMAND_SET_RETURN_KEY_DISABLE, - ISE_MESSAGE_COMMAND_GET_RETURN_KEY_DISABLE, - ISE_MESSAGE_COMMAND_SET_LAYOUT, - ISE_MESSAGE_COMMAND_GET_LAYOUT, - ISE_MESSAGE_COMMAND_RESET_INPUT_CONTEXT, - ISE_MESSAGE_COMMAND_PROCESS_KEY_EVENT, - - ISE_MESSAGE_COMMAND_LOG, - ISE_MESSAGE_COMMAND_COMMIT_STRING, - ISE_MESSAGE_COMMAND_UPDATE_PREEDIT_STRING, - ISE_MESSAGE_COMMAND_SEND_KEY_EVENT, - ISE_MESSAGE_COMMAND_FORWARD_KEY_EVENT, - ISE_MESSAGE_COMMAND_SET_KEYBOARD_SIZES, - ISE_MESSAGE_COMMAND_SET_SELECTION, - ISE_MESSAGE_COMMAND_GET_SELECTION, - ISE_MESSAGE_COMMAND_GET_SURROUNDING_TEXT, - ISE_MESSAGE_COMMAND_DELETE_SURROUNDING_TEXT, - ISE_MESSAGE_COMMAND_LOGIN, - - ISE_MESSAGE_COMMANDS_NUM, -} ISE_MESSAGE_COMMANDS; - -const std::string ISE_MESSAGE_COMMAND_STRINGS[] = { - "init", // ISE_MESSAGE_COMMAND_INIT, - "exit", // ISE_MESSAGE_COMMAND_EXIT, - - "focus_in", // ISE_MESSAGE_COMMAND_FOCUS_IN, - "focus_out", // ISE_MESSAGE_COMMAND_FOCUS_OUT, - "show", // ISE_MESSAGE_COMMAND_SHOW, - "hide", // ISE_MESSAGE_COMMAND_HIDE, - "set_rotation", // ISE_MESSAGE_COMMAND_SET_ROTATION, - "update_cursor_position", // ISE_MESSAGE_COMMAND_UPDATE_CURSOR_POSITION, - "update_surrounding_text", // ISE_MESSAGE_COMMAND_UPDATE_SURROUNDING_TEXT, - "update_selection", // ISE_MESSAGE_COMMAND_UPDATE_SELECTION - "set_language", // ISE_MESSAGE_COMMAND_SET_LANGUAGE, - "set_imdata", // ISE_MESSAGE_COMMAND_SET_IMDATA, - "get_imdata", // ISE_MESSAGE_COMMAND_GET_IMDATA, - "set_return_key_type", // ISE_MESSAGE_COMMAND_SET_RETURN_KEY_TYPE, - "get_return_key_type", // ISE_MESSAGE_COMMAND_GET_RETURN_KEY_TYPE, - "set_return_key_disable", // ISE_MESSAGE_COMMAND_SET_RETURN_KEY_DISABLE, - "get_return_key_disable", // ISE_MESSAGE_COMMAND_GET_RETURN_KEY_DISABLE, - "set_layout", // ISE_MESSAGE_COMMAND_SET_LAYOUT, - "get_layout", // ISE_MESSAGE_COMMAND_GET_LAYOUT, - "reset_input_context", // ISE_MESSAGE_COMMAND_RESET_INPUT_CONTEXT, - "process_key_event", // ISE_MESSAGE_COMMAND_PROCESS_KEY_EVENT, - - "log", // ISE_MESSAGE_COMMAND_LOG, - "commit_string", // ISE_MESSAGE_COMMAND_COMMIT_STRING, - "update_preedit_string", // ISE_MESSAGE_COMMAND_UPDATE_PREEDIT_STRING, - "send_key_event", // ISE_MESSAGE_COMMAND_SEND_KEY_EVENT, - "forward_key_event", // ISE_MESSAGE_COMMAND_FORWARD_KEY_EVENT, - "set_keyboard_sizes", // ISE_MESSAGE_COMMAND_SET_KEYBOARD_SIZES, - "set_selection", // ISE_MESSAGE_COMMAND_SET_SELECTION, - "get_selection", // ISE_MESSAGE_COMMAND_GET_SELECTION, - "get_surrounding_text", // ISE_MESSAGE_COMMAND_GET_SURROUNDING_TEXT, - "delete_surrounding_text", // ISE_MESSAGE_COMMAND_DELETE_SURROUNDING_TEXT, - "login", // ISE_MESSAGE_COMMAND_LOGIN, -}; - -typedef struct { - std::string type; - std::string command; - std::vector values; -} ISE_MESSAGE; - -typedef struct { - int type_value; - std::string type_string; -} ISE_TYPE_VALUE_STRING; - -const ISE_TYPE_VALUE_STRING ISE_RETURN_KEY_TYPES[] = { - {ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT, "default"}, - {ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DONE, "done"}, - {ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_GO, "go"}, - {ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_JOIN, "join"}, - {ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_LOGIN, "login"}, - {ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_NEXT, "next"}, - {ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEARCH, "search"}, - {ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEND, "send"}, - {ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SIGNIN, "signin"}, -}; - -const ISE_TYPE_VALUE_STRING ISE_LAYOUT_TYPES[] = { - {ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL, "normal"}, - {ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBER, "number"}, - {ECORE_IMF_INPUT_PANEL_LAYOUT_EMAIL, "email"}, - {ECORE_IMF_INPUT_PANEL_LAYOUT_URL, "url"}, - {ECORE_IMF_INPUT_PANEL_LAYOUT_PHONENUMBER, "phonenumber"}, - {ECORE_IMF_INPUT_PANEL_LAYOUT_IP, "ip"}, - {ECORE_IMF_INPUT_PANEL_LAYOUT_MONTH, "month"}, - {ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY, "numberonly"}, - {ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD, "password"}, - {ECORE_IMF_INPUT_PANEL_LAYOUT_DATETIME, "datetime"}, -}; - -const ISE_TYPE_VALUE_STRING ISE_LANGUAGE_TYPES[] = { - {ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC, "automatic"}, - {ECORE_IMF_INPUT_PANEL_LANG_ALPHABET, "alphabet"}, -}; - -/* FIXME : Should consider the case if the boolean value does not match with EINA_TRUE or EINA_FALSE */ -const ISE_TYPE_VALUE_STRING ISE_TRUEFALSE_TYPES[] = { - {EINA_FALSE, "false"}, - {EINA_TRUE, "true"}, -}; - -class CISEMessageSerializer -{ -protected: - /* FIXME : Temporary solution for distinguish commands and values */ - static const char MESSAGE_DELIMETER = ' '; - -public: - static std::string serialize(ISE_MESSAGE message) { - std::string ret; - ret += message.type; - ret += MESSAGE_DELIMETER; - ret += message.command; - for (unsigned int loop = 0;loop < message.values.size();loop++) { - ret += MESSAGE_DELIMETER; - ret += message.values.at(loop); - } - return ret; - } - - static ISE_MESSAGE deserialize(std::string message) { - ISE_MESSAGE ret; - std::vector vec = CStringTokenizer::split(message, MESSAGE_DELIMETER); - if (vec.size() > 1) { - ret.type = vec.at(0); - vec.erase(vec.begin()); - ret.command = vec.at(0); - vec.erase(vec.begin()); - ret.values = vec; - } - return ret; - } - - static bool valid(std::string str) - { - int loop; - - bool valid_type = false; - bool valid_command = false; - - ISE_MESSAGE message; - message = deserialize(str); - - for (loop = 0;!valid_type && loop < ISE_MESSAGE_TYPES_NUM;loop++) { - if (message.type.compare(ISE_MESSAGE_TYPE_STRINGS[loop]) == 0) { - valid_type = true; - } - } - for (loop = 0;!valid_command && loop < ISE_MESSAGE_COMMANDS_NUM;loop++) { - if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[loop]) == 0) { - valid_command = true; - } - } - - return (valid_type && valid_command); - } -}; - -class CWebHelperAgentWebSocket : public CWebHelperAgent { -public: - CWebHelperAgentWebSocket(); - virtual ~CWebHelperAgentWebSocket(); - - bool init(); - bool exit(); - - bool run(); - - bool initialized() { return m_initialized; } - - void signal(int sig); - - void on_init(); - void on_exit(); - - void on_focus_in(int ic); - void on_focus_out(int ic); - - void on_show(int ic); - void on_hide(int ic); - - void on_set_rotation(int degree); - - void on_update_cursor_position(int ic, int cursor_pos); - void on_update_surrounding_text(int ic, const char *text, int cursor); - void on_update_selection(int ic, const char *text); - - void on_set_language(unsigned int language); - - void on_set_imdata(char *buf, unsigned int len); - void on_get_imdata(char **buf, unsigned int *len); - - void on_set_return_key_type(unsigned int type); - void on_get_return_key_type(unsigned int *type); - - void on_set_return_key_disable(unsigned int disabled); - void on_get_return_key_disable(unsigned int *disabled); - - void on_set_layout(unsigned int layout); - void on_get_layout(unsigned int *layout); - - void on_reset_input_context(int ic); - - void on_process_key_event(unsigned int code, unsigned int mask, unsigned int layout, unsigned int *ret); - - std::queue& get_send_message_queue(); - std::queue& get_recv_message_queue(); - Ecore_Pipe* get_message_pipe(); - - void wait_for_reply_message(); - - void process_recved_messages(); - bool process_recved_messages_until_reply_found(std::string command, std::vector &values); - void handle_recved_message(ISE_MESSAGE &message); - - static CWebHelperAgentWebSocket* get_current_instance(); -protected: - static CWebHelperAgentWebSocket *m_current_instance; - - std::queue m_send_message_queue; - std::queue m_recv_message_queue; - - Ecore_Pipe *m_message_pipe; - - bool m_initialized; -}; - -#endif // _WEB_HELPER_AGENT_WEBSOCKET_H_ diff --git a/src/sclconnection-isf.cpp b/src/sclconnection-isf.cpp index d00c7ce..74b13e3 100644 --- a/src/sclconnection-isf.cpp +++ b/src/sclconnection-isf.cpp @@ -21,7 +21,7 @@ #include #ifdef WEBSOCKET -#include "legacy_support/websocket.h" +#include "websocket.h" extern CWebHelperAgentWebSocket g_websocket; #endif diff --git a/src/sclcoreui-efl.h b/src/sclcoreui-efl.h index 82d03af..7358590 100644 --- a/src/sclcoreui-efl.h +++ b/src/sclcoreui-efl.h @@ -23,7 +23,7 @@ #include #ifdef WEBSOCKET -#include "legacy_support/websocket.h" +#include "websocket.h" #endif //SCL_BEGIN_DECLS diff --git a/src/web_helper_agent.cpp b/src/web_helper_agent.cpp new file mode 100644 index 0000000..1d3cfc5 --- /dev/null +++ b/src/web_helper_agent.cpp @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2012 - 2016 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include + +#include "web_helper_agent.h" + +#include "websocket.h" +#include "sclcoreimpl.h" + +using namespace scl; + +typedef struct { + int major_version; + WEB_HELPER_AGENT_TYPE agent_type; +} WEB_HELPER_AGENT_TYPES_FOR_VERSIONS; + +static WEB_HELPER_AGENT_TYPES_FOR_VERSIONS web_helper_agent_types_for_versions[] = { + {1, WEB_HELPER_AGENT_WEBSOCKET}, /* Major version 1 indicates that it uses websocket for communication */ +}; + +static int WEB_HELPER_AGENT_TYPES_FOR_VERSIONS_NUM = \ + sizeof(web_helper_agent_types_for_versions) / sizeof(WEB_HELPER_AGENT_TYPES_FOR_VERSIONS); + +WEB_HELPER_AGENT_TYPE CWebHelperAgent::get_web_helper_agent_type_from_major_version(int version) +{ + for (int loop = 0;loop < WEB_HELPER_AGENT_TYPES_FOR_VERSIONS_NUM;loop++) { + if (web_helper_agent_types_for_versions[loop].major_version == version) { + return web_helper_agent_types_for_versions[loop].agent_type; + } + } + return WEB_HELPER_AGENT_UNKNOWN; +} + +CWebHelperAgent* CWebHelperAgent::create_web_helper_agent(WEB_HELPER_AGENT_TYPE type) +{ + CWebHelperAgent *ret = NULL; + if (type == WEB_HELPER_AGENT_WEBSOCKET) { + ret = new CWebHelperAgentWebSocket; + } + return ret; +} + +void CWebHelperAgent::destroy_web_helper_agent(CWebHelperAgent* agent) +{ + if (agent) delete agent; +} + +CWebHelperAgent::CWebHelperAgent() +{ +} + +CWebHelperAgent::~CWebHelperAgent() +{ +} + +bool CWebHelperAgent::init() +{ + return true; +} + +bool CWebHelperAgent::exit() +{ + return true; +} + +void CWebHelperAgent::signal(int sig) +{ +} + +void CWebHelperAgent::log(const char *str) +{ + CSCLCoreImpl *impl = CSCLCoreImpl::get_instance(); + if (impl) { + //impl->logise_log(str); + } +} + +void CWebHelperAgent::commit_string(const char *str) +{ + CSCLCoreImpl *impl = CSCLCoreImpl::get_instance(); + if (impl) { + impl->commit_string(-1, "", str); + } +} + +void CWebHelperAgent::update_preedit_string(const char *str) +{ + CSCLCoreImpl *impl = CSCLCoreImpl::get_instance(); + if (impl) { + impl->update_preedit_string(-1, "", str); + } +} + +void CWebHelperAgent::send_key_event(unsigned int key, unsigned int key_mask) +{ + CSCLCoreImpl *impl = CSCLCoreImpl::get_instance(); + if (impl) { + impl->send_key_event(-1, "", key, key_mask); + } +} + +void CWebHelperAgent::forward_key_event(unsigned int key) +{ + CSCLCoreImpl *impl = CSCLCoreImpl::get_instance(); + if (impl) { + impl->forward_key_event(-1, "", key, scim::SCIM_KEY_NullMask); + } +} + +void CWebHelperAgent::set_keyboard_sizes(int portrait_width, int portrait_height, int landscape_width, int landscape_height) +{ + CSCLCoreImpl *impl = CSCLCoreImpl::get_instance(); + if (impl) { + SclSize portrait, landscape; + portrait.width = portrait_width; + portrait.height = portrait_height; + landscape.width = landscape_width; + landscape.height = landscape_height; + impl->set_keyboard_size_hints(portrait, landscape); + } +} + +void CWebHelperAgent::set_selection(int start_index, int end_index) +{ + CSCLCoreImpl *impl = CSCLCoreImpl::get_instance(); + if (impl) { + impl->set_selection(start_index, end_index); + } +} + +void CWebHelperAgent::get_selection() +{ + CSCLCoreImpl *impl = CSCLCoreImpl::get_instance(); + if (impl) { + //impl->get_selection(-1, "", ); + } +} + +void CWebHelperAgent::get_surrounding_text(int maxlen_before, int maxlen_after) +{ + CSCLCoreImpl *impl = CSCLCoreImpl::get_instance(); + if (impl) { + impl->get_surrounding_text("", maxlen_before, maxlen_after); + } +} + +void CWebHelperAgent::delete_surrounding_text(int offset, int len) +{ + CSCLCoreImpl *impl = CSCLCoreImpl::get_instance(); + if (impl) { + impl->delete_surrounding_text(offset, len); + } +} + +std::string CMagicKeyManager::get_magic_key() +{ + static std::string current_magic_key; + + /* If we don't have magic key generated yet */ + if (current_magic_key.length() != MAGIC_KEY_LENGTH) { + char magic_key[MAGIC_KEY_LENGTH + 1]; + /* We are going to generate a magic key that contains ascii characters in the range of '0' to 'z' */ + const char magic_key_range_lower = '0'; + const char magic_key_range_upper = 'Z'; + + unsigned int seed = time(NULL); + for (int loop = 0;loop < MAGIC_KEY_LENGTH;loop++) { + magic_key[loop] = (rand_r(&seed) % (magic_key_range_upper - magic_key_range_lower)) + magic_key_range_lower; + } + magic_key[MAGIC_KEY_LENGTH] = '\0'; + + current_magic_key = magic_key; + } + + return current_magic_key; +} diff --git a/src/web_helper_agent.h b/src/web_helper_agent.h new file mode 100644 index 0000000..c05c572 --- /dev/null +++ b/src/web_helper_agent.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2012 - 2016 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _WEB_HELPER_AGENT_H_ +#define _WEB_HELPER_AGENT_H_ + +#define MAGIC_KEY_LENGTH 32 +#define VERSION_DELIMITER '.' +#define VERSION_TOKEN_NUM 2 // We are expecting 2 version tokens : MAJOR and MINOR + +#include +#include +#include + +class CStringTokenizer +{ +public: + static std::vector &split(const std::string &s, char delim, std::vector &elems) { + unsigned int loop = 0; + unsigned int start = 0; + for (loop = 0;loop < s.length();loop++) { + if (s.at(loop) == delim) { + std::string item = s.substr(start, loop - start); + elems.push_back(item); + start = loop + 1; + } + } + std::string item = s.substr(start, loop - start); + elems.push_back(item); + return elems; + } + + static std::vector split(const std::string &s, char delim) { + std::vector elems; + split(s, delim, elems); + return elems; + } +}; + +typedef enum { + WEB_HELPER_AGENT_UNKNOWN, + WEB_HELPER_AGENT_WEBSOCKET, + WEB_HELPER_AGENT_DIRECT, +} WEB_HELPER_AGENT_TYPE; + +class CMagicKeyManager +{ +public: + static std::string get_magic_key(); +}; + +class CWebHelperAgent +{ +public: + CWebHelperAgent(); + virtual ~CWebHelperAgent(); + + virtual bool init(); + virtual bool exit(); + + virtual bool run() { return false; } + virtual void signal(int sig); + + virtual void on_init() {} + virtual void on_exit() {} + + virtual void on_focus_in(int ic) {} + virtual void on_focus_out(int ic) {} + + virtual void on_show(int ic) {} + virtual void on_hide(int ic) {} + + virtual void on_set_rotation(int degree) {} + + virtual void on_update_cursor_position(int ic, int cursor_pos) {} + virtual void on_update_surrounding_text(int ic, const char *text, int cursor) {} + virtual void on_update_selection(int ic, const char *text) {} + + virtual void on_set_language(unsigned int language) {} + + virtual void on_set_imdata(char *buf, unsigned int len) {} + virtual void on_get_imdata(char **buf, unsigned int *len) {} + + virtual void on_set_return_key_type(unsigned int type) {} + virtual void on_get_return_key_type(unsigned int *type) {} + + virtual void on_set_return_key_disable(unsigned int disabled) {} + virtual void on_get_return_key_disable(unsigned int *disabled) {} + + virtual void on_set_layout(unsigned int layout) {} + virtual void on_get_layout(unsigned int *layout) {} + + virtual void on_reset_input_context(int ic) {} + + virtual void on_process_key_event(unsigned int code, unsigned int mask, unsigned int layout, unsigned int *ret) {} + + + virtual void log(const char *str); + virtual void commit_string(const char *str); + virtual void update_preedit_string(const char *str); + virtual void send_key_event(unsigned int key, unsigned int key_mask); + virtual void forward_key_event(unsigned int key); + virtual void set_keyboard_sizes(int portrait_width, int portrait_height, int landscape_width, int landscape_height); + virtual void set_selection(int start_index, int end_index); + virtual void get_selection(); + virtual void get_surrounding_text(int maxlen_before, int maxlen_after); + virtual void delete_surrounding_text(int offset, int len); + +public: + static WEB_HELPER_AGENT_TYPE get_web_helper_agent_type_from_major_version(int version); + static CWebHelperAgent* create_web_helper_agent(WEB_HELPER_AGENT_TYPE type); + static void destroy_web_helper_agent(CWebHelperAgent* agent); +}; + +#endif // _WEB_HELPER_AGENT_H_ diff --git a/src/websocket.cpp b/src/websocket.cpp new file mode 100644 index 0000000..2ae2565 --- /dev/null +++ b/src/websocket.cpp @@ -0,0 +1,1252 @@ +/* + * Copyright (c) 2012 - 2016 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "websocket.h" + +#include +#include + +#include + +#ifdef WAYLAND +#define EFL_BETA_API_SUPPORT +#include +#endif + +#define WEBSOCKET_PORT 7681 + +#define RECVED_MESSAGE "recved" +#define MESSAGE_LEFT "left" + +pthread_t g_ws_server_thread = (pthread_t)NULL; +pthread_mutex_t g_ws_server_mutex = PTHREAD_MUTEX_INITIALIZER; + +pthread_cond_t g_ws_query_condition = PTHREAD_COND_INITIALIZER; +pthread_mutex_t g_ws_query_mutex = PTHREAD_MUTEX_INITIALIZER; + +bool g_ws_server_exit = false; +struct lws_context *g_ws_server_context = NULL; + +CWebHelperAgentWebSocket* CWebHelperAgentWebSocket::m_current_instance = NULL; + +int force_exit = 0; + +enum protocols { + /* always first */ + PROTOCOL_HTTP = 0, + + PROTOCOL_KEYBOARD, + + /* always last */ + MAX_PROTOCOL_COUNT +}; + +struct per_session_data__http { + int fd; +}; + +static int callback_http(struct lws *wsi, + enum lws_callback_reasons reason, + void *user, void *in, size_t len) +{ + return 0; +} + +struct per_session_data__keyboard { + int session_id; + int valid; + int need_init; + int initialized; +}; + +static int callback_keyboard(struct lws *wsi, + enum lws_callback_reasons reason, + void *user, void *in, size_t len); + +static struct lws_protocols protocols[] = { + { + "http-only", + callback_http, + sizeof(struct per_session_data__http), + 0, + }, + { + "keyboard-protocol", + callback_keyboard, + sizeof(struct per_session_data__keyboard), + 32, + }, + { NULL, NULL, 0, 0 } +}; + + +static int callback_client(struct lws *wsi, + enum lws_callback_reasons reason, + void *user, void *in, size_t len) +{ + switch (reason) { + case LWS_CALLBACK_CLIENT_ESTABLISHED: + LOGD("[ClientTest] Connection established"); + break; + + case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: + LOGD("[ClientTest] Connection error"); + break; + + case LWS_CALLBACK_CLOSED: + LOGD("[ClientTest] Connection closed"); + break; + + default: + break; + } + + return 0; +} + +int test_client_connection(void) +{ + struct lws_context *context = NULL; + struct lws_context_creation_info context_info; + struct lws_client_connect_info connect_info; + struct lws *wsi = NULL; + + memset(&context_info, 0, sizeof context_info); + memset(&connect_info, 0, sizeof(connect_info)); + + const int protocols_num = sizeof(protocols) / sizeof(lws_protocols); + static struct lws_protocols client_protocols[protocols_num]; + + memcpy(&client_protocols, protocols, sizeof(protocols)); + for (int loop = 0; loop < protocols_num - 1; loop++) { + client_protocols[loop].callback = callback_client; + } + + context_info.port = CONTEXT_PORT_NO_LISTEN; + context_info.protocols = protocols; + context_info.gid = -1; + context_info.uid = -1; + + context = lws_create_context(&context_info); + LOGD("[ClientTest] create_context : %p", context); + if (context == NULL) { + return -1; + } + + connect_info.address = "localhost"; + connect_info.port = WEBSOCKET_PORT; + connect_info.path = "/"; + connect_info.context = context; + connect_info.ssl_connection = 0; + connect_info.host = connect_info.address; + connect_info.origin = connect_info.address; + connect_info.ietf_version_or_minus_one = -1; + connect_info.protocol = "keyboard-protocol"; + + wsi = lws_client_connect_via_info(&connect_info); + LOGD("[ClientTest] wsi created : %p", wsi); + + if (wsi) { + lws_service(context, 50); + } + + lws_context_destroy(context); + + return 0; +} + +static Ecore_Timer *g_flush_server_recv_buffer_timer = NULL; +static std::string server_recv_buffer; +static Eina_Bool flush_server_recv_buffer_func(void *user) +{ + LOGD("flushing recv buffer"); + CWebHelperAgentWebSocket *agent = CWebHelperAgentWebSocket::get_current_instance(); + struct per_session_data__keyboard *pss = (struct per_session_data__keyboard *)user; + + if (g_flush_server_recv_buffer_timer) + ecore_timer_del(g_flush_server_recv_buffer_timer); + g_flush_server_recv_buffer_timer = NULL; + + if (!agent || !pss) return ECORE_CALLBACK_CANCEL; + + pthread_mutex_lock(&g_ws_server_mutex); + ISE_MESSAGE message = CISEMessageSerializer::deserialize(server_recv_buffer); + server_recv_buffer.clear(); + pthread_mutex_unlock(&g_ws_server_mutex); + + if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_LOGIN]) == 0) { + /* + if (message.values.at(0).compare(CMagicKeyManager::get_magic_key()) == 0) { + LOGD("LOGIN successful, validating client"); + pss->valid = true; + } else { + LOGD("LOGIN failed, invalidating client"); + pss->valid = false; + } + */ + pss->valid = true; + + if (agent->initialized()) { + pss->need_init = true; + ecore_pipe_write(agent->get_message_pipe(), MESSAGE_LEFT, strlen(MESSAGE_LEFT)); + } + } + + /* Ignore valid check since the magic key is not used anymore */ + if (!pss->valid) pss->valid = true; + + if (pss->valid) { + pthread_mutex_lock(&g_ws_server_mutex); + std::queue& messages = agent->get_recv_message_queue(); + messages.push(message); + pthread_mutex_unlock(&g_ws_server_mutex); + + ecore_pipe_write(agent->get_message_pipe(), RECVED_MESSAGE, strlen(RECVED_MESSAGE)); + + /* If we received reply message, let's send signal to wake up our main thread */ + if (message.type.compare(ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY]) == 0) { + pthread_mutex_lock(&g_ws_query_mutex); + pthread_cond_signal(&g_ws_query_condition); + pthread_mutex_unlock(&g_ws_query_mutex); + } + } else { + LOGD("Ignoring data received since client is not valid %d", pss->session_id); + } + + return ECORE_CALLBACK_CANCEL; +} + +static int callback_keyboard(struct lws *wsi, + enum lws_callback_reasons reason, + void *user, void *in, size_t len) +{ + static int last_session_id = 0; + const int bufsize = 512; + int n = 0; + unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + bufsize + + LWS_SEND_BUFFER_POST_PADDING]; + unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING]; + struct per_session_data__keyboard *pss = (struct per_session_data__keyboard *)user; + CWebHelperAgentWebSocket *agent = CWebHelperAgentWebSocket::get_current_instance(); + + switch (reason) { + case LWS_CALLBACK_ESTABLISHED: + pss->session_id = ++last_session_id; + LOGD("LWS_CALLBACK_ESTABLISHED : %p %d", g_ws_server_context, pss->session_id); + pss->valid = false; + pss->need_init = false; + pss->initialized = false; + if (g_ws_server_context) { + ecore_pipe_write(agent->get_message_pipe(), MESSAGE_LEFT, strlen(MESSAGE_LEFT)); + } + break; + + case LWS_CALLBACK_CLOSED: + LOGD("LWS_CALLBACK_CLOSED : %d", pss->session_id); + break; + + case LWS_CALLBACK_SERVER_WRITEABLE: + if (agent) { + /* Ignore valid check since the magic key is not used anymore */ + if (!pss->valid) pss->valid = true; + + /* We allow data tranmission only if this client is guaranteed to be valid */ + if (pss->valid) { + pthread_mutex_lock(&g_ws_server_mutex); + std::queue& messages = agent->get_send_message_queue(); + + if (pss->need_init && !pss->initialized) { + ISE_MESSAGE message; + message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN]; + message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_INIT]; + std::string str = CISEMessageSerializer::serialize(message); + SECURE_LOGD("SEND_WEBSOCKET_MESSAGE : %d %s", pss->session_id, str.c_str()); + n = snprintf((char *)p, bufsize, "%s", str.c_str()); + /* too small for partial */ + n = lws_write(wsi, p, n, LWS_WRITE_TEXT); + pss->need_init = false; + pss->initialized = true; + } else { + /* One write allowed per one writable callback */ + if (messages.size() > 0) { + ISE_MESSAGE &message = messages.front(); + bool drop = false; + if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_INIT]) == 0) { + if (pss->initialized) { + drop = true; + } else { + pss->initialized = true; + } + } + if (!drop) { + std::string str = CISEMessageSerializer::serialize(message); + SECURE_LOGD("SEND_WEBSOCKET_MESSAGE : %d %s", pss->session_id, str.c_str()); + n = snprintf((char *)p, bufsize, "%s", str.c_str()); + /* too small for partial */ + n = lws_write(wsi, p, n, LWS_WRITE_TEXT); + } + messages.pop(); + } + } + if (messages.size() > 0) { + ecore_pipe_write(agent->get_message_pipe(), MESSAGE_LEFT, strlen(MESSAGE_LEFT)); + } + pthread_mutex_unlock(&g_ws_server_mutex); + + if (n < 0) { + LOGE("ERROR %d writing to di socket %d", n, pss->session_id); + } + + if (messages.size() > 0) { + lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); + } + } else { + LOGD("Rejecting data transmission since client is not valid : %d", pss->session_id); + } + } + break; + + case LWS_CALLBACK_RECEIVE: + if (in) { + if (g_flush_server_recv_buffer_timer) { + ecore_thread_main_loop_begin(); + ecore_timer_del(g_flush_server_recv_buffer_timer); + g_flush_server_recv_buffer_timer = NULL; + ecore_thread_main_loop_end(); + } + + std::string str = std::string((const char *)in, len); + if (CISEMessageSerializer::valid(str)) { + LOGD("A valid new message received, flush previous buffer"); + flush_server_recv_buffer_func((void*)pss); + } + + pthread_mutex_lock(&g_ws_server_mutex); + server_recv_buffer += str; + SECURE_LOGD("RECEIVE callback : [%zu] [%s], [%s]", len, str.c_str(), server_recv_buffer.c_str()); + pthread_mutex_unlock(&g_ws_server_mutex); + + ecore_thread_main_loop_begin(); + g_flush_server_recv_buffer_timer = ecore_timer_add(0.05, flush_server_recv_buffer_func, (void*)pss); + SECURE_LOGD("flush timer registered : %p", g_flush_server_recv_buffer_timer); + ecore_thread_main_loop_end(); + } + + break; + default: + break; + } + + return 0; +} + +void *process_ws_server(void *data) +{ + while (!force_exit && !g_ws_server_exit) { + struct timeval tv; + gettimeofday(&tv, NULL); + + if (g_ws_server_context) { + lws_service(g_ws_server_context, 50); + } else { + LOGD("WARNING : g_ws_server_context is NULL"); + } + } + LOGD("process_ws_server exits now"); + return NULL; +} + +void log_func(int level, const char *line) +{ + if (line) { + LOGD("LEVEL : %d , %s", level, line); + } +} + +CWebHelperAgentWebSocket::CWebHelperAgentWebSocket() +{ + if (m_current_instance != NULL) { + LOGD("WARNING : m_current_instance is NOT NULL"); + } + m_current_instance = this; + m_message_pipe = NULL; + m_initialized = false; +} + +CWebHelperAgentWebSocket::~CWebHelperAgentWebSocket() +{ + if (m_current_instance == this) { + m_current_instance = NULL; + } + + if (m_message_pipe) { + ecore_pipe_del(m_message_pipe); + m_message_pipe = NULL; + } +} + +static void message_pipe_handler(void *data, void *buffer, unsigned int nbyte) +{ + if (buffer) { + if (strncmp((const char*)buffer, RECVED_MESSAGE, strlen(RECVED_MESSAGE)) == 0) { + CWebHelperAgentWebSocket *agent = CWebHelperAgentWebSocket::get_current_instance(); + if (agent) { + agent->process_recved_messages(); + } + } else { + if (g_ws_server_context) { + lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); + } else { + LOGD("WARNING : g_ws_server_context is NULL"); + } + } + } +} + +bool CWebHelperAgentWebSocket::init() +{ + bool ret = true; + + struct lws_context_creation_info info; + + memset(&info, 0, sizeof info); + info.port = WEBSOCKET_PORT; + + int log_level = LLL_ERR | LLL_WARN | LLL_DEBUG; + lws_set_log_level(log_level, log_func); + + info.iface = NULL; + info.protocols = protocols; + info.extensions = NULL; + info.ssl_cert_filepath = NULL; + info.ssl_private_key_filepath = NULL; + info.gid = -1; + info.uid = -1; + info.options = 0; + + ecore_init(); + + /* The WebSocket server is running on a separate thread, and let the thread send a message + through this pipe to guarantee thread safety */ + m_message_pipe = ecore_pipe_add(message_pipe_handler, NULL); + + /* Let's retry creating server context for a certain number of times */ + const int max_retry_num = 30; + int retry_num = 0; + + do { + g_ws_server_context = lws_create_context(&info); + LOGD("libwebsocket context : %p", g_ws_server_context); + usleep(100 * 1000); + } while (g_ws_server_context == NULL && retry_num++ < max_retry_num); + + pthread_mutex_init(&g_ws_server_mutex, NULL); + + pthread_mutex_init(&g_ws_query_mutex, NULL); + pthread_cond_init(&g_ws_query_condition, NULL); + + m_initialized = true; + + return ret; +} + +bool CWebHelperAgentWebSocket::exit() +{ + if (g_flush_server_recv_buffer_timer) + ecore_timer_del(g_flush_server_recv_buffer_timer); + g_flush_server_recv_buffer_timer = NULL; + + on_exit(); + + g_ws_server_exit = true; + if (g_ws_server_context) { + lws_cancel_service(g_ws_server_context); + } + + if (m_message_pipe) { + ecore_pipe_del(m_message_pipe); + m_message_pipe = NULL; + } + + if (g_ws_server_thread) { + pthread_join(g_ws_server_thread, NULL); + } + + pthread_cond_destroy(&g_ws_query_condition); + pthread_mutex_destroy(&g_ws_query_mutex); + + pthread_mutex_destroy(&g_ws_server_mutex); + + if (g_ws_server_context) { + lws_context_destroy(g_ws_server_context); + g_ws_server_context = NULL; + } + + ecore_shutdown(); + + return true; +} + +bool CWebHelperAgentWebSocket::run() +{ + if (!m_initialized) { + LOGE("Not initialized"); + return false; + } + + bool ret = false; + if (g_ws_server_context) { + if (pthread_create(&g_ws_server_thread, NULL, &process_ws_server, NULL) != 0) { + g_ws_server_thread = (pthread_t)NULL; + ret = false; + + on_init(); + + test_client_connection(); + } + } else { + LOGE("Failed creating server context : %p", g_ws_server_context); + ret = false; + } + return ret; +} + +void CWebHelperAgentWebSocket::signal(int sig) +{ + force_exit = 1; +} + +template +std::string to_string(T i) +{ + std::stringstream ss; + std::string s; + ss << i; + s = ss.str(); + + return s; +} + +void CWebHelperAgentWebSocket::on_init() +{ + ISE_MESSAGE message; + message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN]; + message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_INIT]; + + pthread_mutex_lock(&g_ws_server_mutex); + m_send_message_queue.push(message); + pthread_mutex_unlock(&g_ws_server_mutex); + + if (g_ws_server_context) { + lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); + } else { + LOGD("WARNING : g_ws_server_context is NULL"); + } +} + +void CWebHelperAgentWebSocket::on_exit() +{ + ISE_MESSAGE message; + message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN]; + message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_EXIT]; + + pthread_mutex_lock(&g_ws_server_mutex); + m_send_message_queue.push(message); + pthread_mutex_unlock(&g_ws_server_mutex); + + if (g_ws_server_context) { + lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); + } else { + LOGD("WARNING : g_ws_server_context is NULL"); + } +} + +void CWebHelperAgentWebSocket::on_focus_in(int ic) +{ + ISE_MESSAGE message; + message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN]; + message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_FOCUS_IN]; + message.values.push_back(to_string(ic)); + + pthread_mutex_lock(&g_ws_server_mutex); + m_send_message_queue.push(message); + pthread_mutex_unlock(&g_ws_server_mutex); + + if (g_ws_server_context) { + lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); + } else { + LOGD("WARNING : g_ws_server_context is NULL"); + } +} + +void CWebHelperAgentWebSocket::on_focus_out(int ic) +{ + ISE_MESSAGE message; + message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN]; + message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_FOCUS_OUT]; + message.values.push_back(to_string(ic)); + + pthread_mutex_lock(&g_ws_server_mutex); + m_send_message_queue.push(message); + pthread_mutex_unlock(&g_ws_server_mutex); + + if (g_ws_server_context) { + lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); + } else { + LOGD("WARNING : g_ws_server_context is NULL"); + } +} + +void CWebHelperAgentWebSocket::on_show(int ic) +{ + ISE_MESSAGE message; + message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN]; + message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SHOW]; + message.values.push_back(to_string(ic)); + + pthread_mutex_lock(&g_ws_server_mutex); + m_send_message_queue.push(message); + pthread_mutex_unlock(&g_ws_server_mutex); + + if (g_ws_server_context) { + lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); + } else { + LOGD("WARNING : g_ws_server_context is NULL"); + } + + LOGD("put into send message buffer"); +} + +void CWebHelperAgentWebSocket::on_hide(int ic) +{ + ISE_MESSAGE message; + message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN]; + message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_HIDE]; + message.values.push_back(to_string(ic)); + + pthread_mutex_lock(&g_ws_server_mutex); + m_send_message_queue.push(message); + pthread_mutex_unlock(&g_ws_server_mutex); + + if (g_ws_server_context) { + lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); + } else { + LOGD("WARNING : g_ws_server_context is NULL"); + } +} + +void CWebHelperAgentWebSocket::on_set_rotation(int degree) +{ + ISE_MESSAGE message; + message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN]; + message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_ROTATION]; + message.values.push_back(to_string(degree)); + + pthread_mutex_lock(&g_ws_server_mutex); + m_send_message_queue.push(message); + pthread_mutex_unlock(&g_ws_server_mutex); + + if (g_ws_server_context) { + lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); + } else { + LOGD("WARNING : g_ws_server_context is NULL"); + } +} + +void CWebHelperAgentWebSocket::on_update_cursor_position(int ic, int cursor_pos) +{ + ISE_MESSAGE message; + message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN]; + message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_CURSOR_POSITION]; + message.values.push_back(to_string(ic)); + message.values.push_back(to_string(cursor_pos)); + + pthread_mutex_lock(&g_ws_server_mutex); + m_send_message_queue.push(message); + pthread_mutex_unlock(&g_ws_server_mutex); + + if (g_ws_server_context) { + lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); + } else { + LOGD("WARNING : g_ws_server_context is NULL"); + } +} + +void CWebHelperAgentWebSocket::on_update_surrounding_text(int ic, const char *text, int cursor) +{ + ISE_MESSAGE message; + message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY]; + message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_SURROUNDING_TEXT]; + message.values.push_back(to_string(cursor)); + message.values.push_back(text); + + pthread_mutex_lock(&g_ws_server_mutex); + m_send_message_queue.push(message); + pthread_mutex_unlock(&g_ws_server_mutex); + + if (g_ws_server_context) { + lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); + } else { + LOGD("WARNING : g_ws_server_context is NULL"); + } +} + +void CWebHelperAgentWebSocket::on_update_selection(int ic, const char *text) +{ + ISE_MESSAGE message; + message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY]; + message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_SELECTION]; + message.values.push_back(text); + + pthread_mutex_lock(&g_ws_server_mutex); + m_send_message_queue.push(message); + pthread_mutex_unlock(&g_ws_server_mutex); + + if (g_ws_server_context) { + lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); + } else { + LOGD("WARNING : g_ws_server_context is NULL"); + } +} + +void CWebHelperAgentWebSocket::on_set_language(unsigned int language) +{ + ISE_MESSAGE message; + message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN]; + message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_LANGUAGE]; + + bool found = false; + for (unsigned int loop = 0;loop < sizeof(ISE_LANGUAGE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) { + if (language == (unsigned int)ISE_LANGUAGE_TYPES[loop].type_value) { + message.values.push_back(ISE_LANGUAGE_TYPES[loop].type_string); + found = true; + } + } + + if (found) { + pthread_mutex_lock(&g_ws_server_mutex); + m_send_message_queue.push(message); + pthread_mutex_unlock(&g_ws_server_mutex); + + if (g_ws_server_context) { + lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); + } else { + LOGD("WARNING : g_ws_server_context is NULL"); + } + } +} + +void CWebHelperAgentWebSocket::on_set_imdata(char *buf, unsigned int len) +{ + ISE_MESSAGE message; + message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN]; + message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_IMDATA]; + message.values.push_back(buf); + + pthread_mutex_lock(&g_ws_server_mutex); + m_send_message_queue.push(message); + pthread_mutex_unlock(&g_ws_server_mutex); + + if (g_ws_server_context) { + lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); + } else { + LOGD("WARNING : g_ws_server_context is NULL"); + } +} + +void CWebHelperAgentWebSocket::on_get_imdata(char **buf, unsigned int *len) +{ + ISE_MESSAGE message; + message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY]; + message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_IMDATA]; + + pthread_mutex_lock(&g_ws_server_mutex); + m_send_message_queue.push(message); + pthread_mutex_unlock(&g_ws_server_mutex); + + if (g_ws_server_context) { + lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); + } else { + LOGD("WARNING : g_ws_server_context is NULL"); + } + + wait_for_reply_message(); + + std::vector values; + /* Check if we received reply for GET_IMDATA message */ + if (process_recved_messages_until_reply_found( + ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_IMDATA], values)) { + if (values.size() > 0 && buf && len) { + int string_length = values.at(0).length(); + (*buf) = new char[string_length + 1]; + if (*buf) { + strncpy(*buf, values.at(0).c_str(), string_length); + /* Make sure this is a null-terminated string */ + *(*buf + string_length) = '\0'; + *len = string_length; + } + } + } else { + LOGD("process_recved_messages_until_reply_found returned FALSE"); + } + /* Now process the rest in the recv buffer */ + process_recved_messages(); +} + +void CWebHelperAgentWebSocket::on_set_return_key_type(unsigned int type) +{ + ISE_MESSAGE message; + message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN]; + message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_RETURN_KEY_TYPE]; + + bool found = false; + for (unsigned int loop = 0;loop < sizeof(ISE_RETURN_KEY_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) { + if (type == (unsigned int)ISE_RETURN_KEY_TYPES[loop].type_value) { + message.values.push_back(ISE_RETURN_KEY_TYPES[loop].type_string); + found = true; + } + } + + if (found) { + pthread_mutex_lock(&g_ws_server_mutex); + m_send_message_queue.push(message); + pthread_mutex_unlock(&g_ws_server_mutex); + + if (g_ws_server_context) { + lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); + } else { + LOGD("WARNING : g_ws_server_context is NULL"); + } + } +} + +void CWebHelperAgentWebSocket::on_get_return_key_type(unsigned int *type) +{ + ISE_MESSAGE message; + message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY]; + message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_TYPE]; + + pthread_mutex_lock(&g_ws_server_mutex); + m_send_message_queue.push(message); + pthread_mutex_unlock(&g_ws_server_mutex); + + if (g_ws_server_context) { + lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); + } else { + LOGD("WARNING : g_ws_server_context is NULL"); + } + + wait_for_reply_message(); + + std::vector values; + /* Check if we received reply for GET_RETURN_KEY_TYPE message */ + if (process_recved_messages_until_reply_found( + ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_TYPE], values)) { + if (type) { + for (unsigned int loop = 0;loop < sizeof(ISE_RETURN_KEY_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) { + if (values.at(0).compare(ISE_RETURN_KEY_TYPES[loop].type_string) == 0) { + *type = ISE_RETURN_KEY_TYPES[loop].type_value; + } + } + } + } + /* Now process the rest in the recv buffer */ + process_recved_messages(); +} + +void CWebHelperAgentWebSocket::on_set_return_key_disable(unsigned int disabled) +{ + ISE_MESSAGE message; + message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN]; + message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_RETURN_KEY_DISABLE]; + + bool found = false; + for (unsigned int loop = 0;loop < sizeof(ISE_TRUEFALSE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) { + if (disabled == (unsigned int)ISE_TRUEFALSE_TYPES[loop].type_value) { + message.values.push_back(ISE_TRUEFALSE_TYPES[loop].type_string); + found = true; + } + } + + if (found) { + pthread_mutex_lock(&g_ws_server_mutex); + m_send_message_queue.push(message); + pthread_mutex_unlock(&g_ws_server_mutex); + + if (g_ws_server_context) { + lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); + } else { + LOGD("WARNING : g_ws_server_context is NULL"); + } + } +} + +void CWebHelperAgentWebSocket::on_get_return_key_disable(unsigned int *disabled) +{ + ISE_MESSAGE message; + message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY]; + message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_DISABLE]; + + pthread_mutex_lock(&g_ws_server_mutex); + m_send_message_queue.push(message); + pthread_mutex_unlock(&g_ws_server_mutex); + + if (g_ws_server_context) { + lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); + } else { + LOGD("WARNING : g_ws_server_context is NULL"); + } + + wait_for_reply_message(); + + std::vector values; + /* Check if we received reply for GET_RETURN_KEY_DISABLE message */ + if (process_recved_messages_until_reply_found( + ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_DISABLE], values)) { + if (disabled) { + for (unsigned int loop = 0;loop < sizeof(ISE_TRUEFALSE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) { + if (values.at(0).compare(ISE_TRUEFALSE_TYPES[loop].type_string) == 0) { + *disabled = ISE_TRUEFALSE_TYPES[loop].type_value; + } + } + } + } + /* Now process the rest in the recv buffer */ + process_recved_messages(); +} + +void CWebHelperAgentWebSocket::on_set_layout(unsigned int layout) +{ + ISE_MESSAGE message; + message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN]; + message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_LAYOUT]; + + bool found = false; + for (unsigned int loop = 0;loop < sizeof(ISE_LAYOUT_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) { + if (layout == (unsigned int)ISE_LAYOUT_TYPES[loop].type_value) { + message.values.push_back(ISE_LAYOUT_TYPES[loop].type_string); + found = true; + } + } + + if (found) { + pthread_mutex_lock(&g_ws_server_mutex); + m_send_message_queue.push(message); + pthread_mutex_unlock(&g_ws_server_mutex); + + if (g_ws_server_context) { + lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); + } else { + LOGD("WARNING : g_ws_server_context is NULL"); + } + } +} + +void CWebHelperAgentWebSocket::on_get_layout(unsigned int *layout) +{ + ISE_MESSAGE message; + message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY]; + message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_LAYOUT]; + + pthread_mutex_lock(&g_ws_server_mutex); + m_send_message_queue.push(message); + pthread_mutex_unlock(&g_ws_server_mutex); + + if (g_ws_server_context) { + lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); + } else { + LOGD("WARNING : g_ws_server_context is NULL"); + } + + wait_for_reply_message(); + + std::vector values; + /* Check if we received reply for GET_LAYOUT message */ + if (process_recved_messages_until_reply_found( + ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_LAYOUT], values)) { + if (layout) { + for (unsigned int loop = 0;loop < sizeof(ISE_LAYOUT_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) { + if (values.at(0).compare(ISE_LAYOUT_TYPES[loop].type_string) == 0) { + *layout = ISE_LAYOUT_TYPES[loop].type_value; + } + } + } + } + /* Now process the rest in the recv buffer */ + process_recved_messages(); +} + +void CWebHelperAgentWebSocket::on_reset_input_context(int ic) +{ + ISE_MESSAGE message; + message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN]; + message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_RESET_INPUT_CONTEXT]; + message.values.push_back(to_string(ic)); + + pthread_mutex_lock(&g_ws_server_mutex); + m_send_message_queue.push(message); + pthread_mutex_unlock(&g_ws_server_mutex); + + if (g_ws_server_context) { + lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); + } else { + LOGD("WARNING : g_ws_server_context is NULL"); + } +} + +void CWebHelperAgentWebSocket::on_process_key_event(unsigned int code, unsigned int mask, unsigned int layout, unsigned int *ret) +{ + ISE_MESSAGE message; + message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY]; + message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_PROCESS_KEY_EVENT]; + message.values.push_back(to_string(code)); + message.values.push_back(to_string(mask)); + message.values.push_back(to_string(layout)); + + pthread_mutex_lock(&g_ws_server_mutex); + m_send_message_queue.push(message); + pthread_mutex_unlock(&g_ws_server_mutex); + + if (g_ws_server_context) { + lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); + } else { + LOGD("WARNING : g_ws_server_context is NULL"); + } + + wait_for_reply_message(); + + std::vector values; + /* Check if we received reply for PROCESS_KEY_EVENT message */ + if (process_recved_messages_until_reply_found( + ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_PROCESS_KEY_EVENT], values)) { + if (ret) { + for (unsigned int loop = 0;loop < sizeof(ISE_TRUEFALSE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) { + if (values.at(0).compare(ISE_TRUEFALSE_TYPES[loop].type_string) == 0) { + *ret = ISE_TRUEFALSE_TYPES[loop].type_value; + } + } + } + } + /* Now process the rest in the recv buffer */ + process_recved_messages(); +} + +CWebHelperAgentWebSocket* CWebHelperAgentWebSocket::get_current_instance() +{ + return m_current_instance; +} + +std::queue& CWebHelperAgentWebSocket::get_send_message_queue() +{ + return m_send_message_queue; +} + +std::queue& CWebHelperAgentWebSocket::get_recv_message_queue() +{ + return m_recv_message_queue; +} + +Ecore_Pipe* CWebHelperAgentWebSocket::get_message_pipe() +{ + return m_message_pipe; +} + +void CWebHelperAgentWebSocket::wait_for_reply_message() +{ + /* Let's wait for at most REPLY_TIMEOUT */ + struct timeval now; + struct timespec timeout; + gettimeofday(&now, NULL); + timeout.tv_sec = now.tv_sec + REPLY_TIMEOUT.tv_sec; + timeout.tv_nsec = (now.tv_usec + REPLY_TIMEOUT.tv_usec) * 1000; + pthread_mutex_lock(&g_ws_query_mutex); + pthread_cond_timedwait(&g_ws_query_condition, &g_ws_query_mutex, &timeout); + pthread_mutex_unlock(&g_ws_query_mutex); +} + +void CWebHelperAgentWebSocket::process_recved_messages() +{ + pthread_mutex_lock(&g_ws_server_mutex); + + while (m_recv_message_queue.size() > 0) { + ISE_MESSAGE &message = m_recv_message_queue.front(); + + handle_recved_message(message); + + m_recv_message_queue.pop(); + } + + pthread_mutex_unlock(&g_ws_server_mutex); +} + +bool CWebHelperAgentWebSocket::process_recved_messages_until_reply_found(std::string command, std::vector &values) +{ + bool ret = false; + + pthread_mutex_lock(&g_ws_server_mutex); + + while (ret == false && m_recv_message_queue.size() > 0) { + ISE_MESSAGE &message = m_recv_message_queue.front(); + + if (message.command.compare(command) == 0 && + message.type.compare(ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY]) == 0) { + ret = true; + values = message.values; + } + handle_recved_message(message); + + m_recv_message_queue.pop(); + } + + pthread_mutex_unlock(&g_ws_server_mutex); + + return ret; +} + +void CWebHelperAgentWebSocket::handle_recved_message(ISE_MESSAGE &message) +{ + static bool _key_event_processing = false; + if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_LOG]) == 0) { + std::string str = ""; + for (unsigned int loop = 0;loop < message.values.size();loop++) { + str += message.values.at(loop).c_str(); + if (loop < message.values.size() - 1) { + str += " "; + } + } + log(str.c_str()); + } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_COMMIT_STRING]) == 0) { + std::string str = ""; + for (unsigned int loop = 0;loop < message.values.size();loop++) { + str += message.values.at(loop).c_str(); + if (loop < message.values.size() - 1) { + str += " "; + } + } + if (_key_event_processing) { + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 50000; + select(0, NULL, NULL, NULL, &tv); + _key_event_processing = false; + } + commit_string(str.c_str()); + } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_PREEDIT_STRING]) == 0) { + std::string str = ""; + for (unsigned int loop = 0;loop < message.values.size();loop++) { + str += message.values.at(loop).c_str(); + if (loop < message.values.size() - 1) { + str += " "; + } + } + update_preedit_string(str.c_str()); + } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SEND_KEY_EVENT]) == 0) { + if (message.values.size() == 1) { + forward_key_event(atoi(message.values.at(0).c_str())); + _key_event_processing = true; + } + } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_KEYBOARD_SIZES]) == 0) { + LOGD("ISE_MESSAGE_COMMAND_SET_KEYBOARD_SIZES"); + int portrait_width, portrait_height; + int landscape_width, landscape_height; + + if (message.values.size() == 4 || message.values.size() == 2) { + portrait_width = atoi(message.values.at(0).c_str()); + portrait_height = atoi(message.values.at(1).c_str()); + if (message.values.size() == 2) { + landscape_width = portrait_width; + landscape_height = portrait_height; + } else { + landscape_width = atoi(message.values.at(2).c_str()); + landscape_height = atoi(message.values.at(3).c_str()); + } + + LOGD("ISE_MESSAGE_COMMAND_SET_KEYBOARD_SIZES : %d %d %d %d", + portrait_width, portrait_height, landscape_width, landscape_height); + +#ifdef WAYLAND + /* Since the full screen IME makes the client application fully obscured, + * when it hides the client receives resume command and try to show IME again. + * So here we are adjusting the height value when the requested keyboard size + * is the same with the screen size, as a workaround */ + int scr_w = 0, scr_h = 0; + ecore_wl2_sync(); + Ecore_Wl2_Display *ewd = NULL; + if ((ewd = ecore_wl2_connected_display_get(NULL))) { + ecore_wl2_display_screen_size_get(ewd, &scr_w, &scr_h); + + if (scr_w == portrait_width && scr_h == portrait_height) { + portrait_height -= 1; + } + if (scr_h == landscape_width && scr_w == landscape_height) { + landscape_height -= 1; + } + } +#endif + + set_keyboard_sizes( + portrait_width, portrait_height, landscape_width, landscape_height); + } + } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_SELECTION]) == 0) { + LOGD("ISE_MESSAGE_COMMAND_SET_SELECTION"); + if (message.values.size() == 2) { + LOGD("ISE_MESSAGE_COMMAND_SET_SELECTION : %d %d", + atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str())); + set_selection( + atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str())); + } + } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_SELECTION]) == 0) { + if (message.values.size() == 0) { + get_selection(); + } + } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_SURROUNDING_TEXT]) == 0) { + LOGD("ISE_MESSAGE_COMMAND_GET_SURROUNDING_TEXT"); + if (message.values.size() == 2) { + LOGD("ISE_MESSAGE_COMMAND_GET_SURROUNDING_TEXT : %d %d", + atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str())); + get_surrounding_text( + atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str())); + } + } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_DELETE_SURROUNDING_TEXT]) == 0) { + LOGD("ISE_MESSAGE_COMMAND_DELETE_SURROUNDING_TEXT"); + if (message.values.size() == 2) { + LOGD("ISE_MESSAGE_COMMAND_DELETE_SURROUNDING_TEXT : %d %d", + atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str())); + delete_surrounding_text( + atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str())); + } + } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_LOGIN]) == 0) { + if (g_ws_server_context) { + lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]); + } else { + LOGD("WARNING : g_ws_server_context is NULL"); + } + } +} diff --git a/src/websocket.h b/src/websocket.h new file mode 100644 index 0000000..0be56b4 --- /dev/null +++ b/src/websocket.h @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2012 - 2016 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _WEB_HELPER_AGENT_WEBSOCKET_H_ +#define _WEB_HELPER_AGENT_WEBSOCKET_H_ + +#include "web_helper_agent.h" + +#include + +#include +#include +#include + +/* Wait for at most 1 second */ +const struct timeval REPLY_TIMEOUT = {1, 0}; + +typedef enum { + ISE_MESSAGE_TYPE_PLAIN, + ISE_MESSAGE_TYPE_QUERY, + ISE_MESSAGE_TYPE_REPLY, + + ISE_MESSAGE_TYPES_NUM, +} ISE_MESSAGE_TYPES; + +const std::string ISE_MESSAGE_TYPE_STRINGS[] = { + "plain", // ISE_MESSAGE_TYPE_PLAIN, + "query", // ISE_MESSAGE_TYPE_QUERY + "reply", // ISE_MESSAGE_TYPE_REPLY +}; + +typedef enum { + ISE_MESSAGE_COMMAND_INIT, + ISE_MESSAGE_COMMAND_EXIT, + + ISE_MESSAGE_COMMAND_FOCUS_IN, + ISE_MESSAGE_COMMAND_FOCUS_OUT, + ISE_MESSAGE_COMMAND_SHOW, + ISE_MESSAGE_COMMAND_HIDE, + ISE_MESSAGE_COMMAND_SET_ROTATION, + ISE_MESSAGE_COMMAND_UPDATE_CURSOR_POSITION, + ISE_MESSAGE_COMMAND_UPDATE_SURROUNDING_TEXT, + ISE_MESSAGE_COMMAND_UPDATE_SELECTION, + ISE_MESSAGE_COMMAND_SET_LANGUAGE, + ISE_MESSAGE_COMMAND_SET_IMDATA, + ISE_MESSAGE_COMMAND_GET_IMDATA, + ISE_MESSAGE_COMMAND_SET_RETURN_KEY_TYPE, + ISE_MESSAGE_COMMAND_GET_RETURN_KEY_TYPE, + ISE_MESSAGE_COMMAND_SET_RETURN_KEY_DISABLE, + ISE_MESSAGE_COMMAND_GET_RETURN_KEY_DISABLE, + ISE_MESSAGE_COMMAND_SET_LAYOUT, + ISE_MESSAGE_COMMAND_GET_LAYOUT, + ISE_MESSAGE_COMMAND_RESET_INPUT_CONTEXT, + ISE_MESSAGE_COMMAND_PROCESS_KEY_EVENT, + + ISE_MESSAGE_COMMAND_LOG, + ISE_MESSAGE_COMMAND_COMMIT_STRING, + ISE_MESSAGE_COMMAND_UPDATE_PREEDIT_STRING, + ISE_MESSAGE_COMMAND_SEND_KEY_EVENT, + ISE_MESSAGE_COMMAND_FORWARD_KEY_EVENT, + ISE_MESSAGE_COMMAND_SET_KEYBOARD_SIZES, + ISE_MESSAGE_COMMAND_SET_SELECTION, + ISE_MESSAGE_COMMAND_GET_SELECTION, + ISE_MESSAGE_COMMAND_GET_SURROUNDING_TEXT, + ISE_MESSAGE_COMMAND_DELETE_SURROUNDING_TEXT, + ISE_MESSAGE_COMMAND_LOGIN, + + ISE_MESSAGE_COMMANDS_NUM, +} ISE_MESSAGE_COMMANDS; + +const std::string ISE_MESSAGE_COMMAND_STRINGS[] = { + "init", // ISE_MESSAGE_COMMAND_INIT, + "exit", // ISE_MESSAGE_COMMAND_EXIT, + + "focus_in", // ISE_MESSAGE_COMMAND_FOCUS_IN, + "focus_out", // ISE_MESSAGE_COMMAND_FOCUS_OUT, + "show", // ISE_MESSAGE_COMMAND_SHOW, + "hide", // ISE_MESSAGE_COMMAND_HIDE, + "set_rotation", // ISE_MESSAGE_COMMAND_SET_ROTATION, + "update_cursor_position", // ISE_MESSAGE_COMMAND_UPDATE_CURSOR_POSITION, + "update_surrounding_text", // ISE_MESSAGE_COMMAND_UPDATE_SURROUNDING_TEXT, + "update_selection", // ISE_MESSAGE_COMMAND_UPDATE_SELECTION + "set_language", // ISE_MESSAGE_COMMAND_SET_LANGUAGE, + "set_imdata", // ISE_MESSAGE_COMMAND_SET_IMDATA, + "get_imdata", // ISE_MESSAGE_COMMAND_GET_IMDATA, + "set_return_key_type", // ISE_MESSAGE_COMMAND_SET_RETURN_KEY_TYPE, + "get_return_key_type", // ISE_MESSAGE_COMMAND_GET_RETURN_KEY_TYPE, + "set_return_key_disable", // ISE_MESSAGE_COMMAND_SET_RETURN_KEY_DISABLE, + "get_return_key_disable", // ISE_MESSAGE_COMMAND_GET_RETURN_KEY_DISABLE, + "set_layout", // ISE_MESSAGE_COMMAND_SET_LAYOUT, + "get_layout", // ISE_MESSAGE_COMMAND_GET_LAYOUT, + "reset_input_context", // ISE_MESSAGE_COMMAND_RESET_INPUT_CONTEXT, + "process_key_event", // ISE_MESSAGE_COMMAND_PROCESS_KEY_EVENT, + + "log", // ISE_MESSAGE_COMMAND_LOG, + "commit_string", // ISE_MESSAGE_COMMAND_COMMIT_STRING, + "update_preedit_string", // ISE_MESSAGE_COMMAND_UPDATE_PREEDIT_STRING, + "send_key_event", // ISE_MESSAGE_COMMAND_SEND_KEY_EVENT, + "forward_key_event", // ISE_MESSAGE_COMMAND_FORWARD_KEY_EVENT, + "set_keyboard_sizes", // ISE_MESSAGE_COMMAND_SET_KEYBOARD_SIZES, + "set_selection", // ISE_MESSAGE_COMMAND_SET_SELECTION, + "get_selection", // ISE_MESSAGE_COMMAND_GET_SELECTION, + "get_surrounding_text", // ISE_MESSAGE_COMMAND_GET_SURROUNDING_TEXT, + "delete_surrounding_text", // ISE_MESSAGE_COMMAND_DELETE_SURROUNDING_TEXT, + "login", // ISE_MESSAGE_COMMAND_LOGIN, +}; + +typedef struct { + std::string type; + std::string command; + std::vector values; +} ISE_MESSAGE; + +typedef struct { + int type_value; + std::string type_string; +} ISE_TYPE_VALUE_STRING; + +const ISE_TYPE_VALUE_STRING ISE_RETURN_KEY_TYPES[] = { + {ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT, "default"}, + {ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DONE, "done"}, + {ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_GO, "go"}, + {ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_JOIN, "join"}, + {ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_LOGIN, "login"}, + {ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_NEXT, "next"}, + {ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEARCH, "search"}, + {ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEND, "send"}, + {ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SIGNIN, "signin"}, +}; + +const ISE_TYPE_VALUE_STRING ISE_LAYOUT_TYPES[] = { + {ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL, "normal"}, + {ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBER, "number"}, + {ECORE_IMF_INPUT_PANEL_LAYOUT_EMAIL, "email"}, + {ECORE_IMF_INPUT_PANEL_LAYOUT_URL, "url"}, + {ECORE_IMF_INPUT_PANEL_LAYOUT_PHONENUMBER, "phonenumber"}, + {ECORE_IMF_INPUT_PANEL_LAYOUT_IP, "ip"}, + {ECORE_IMF_INPUT_PANEL_LAYOUT_MONTH, "month"}, + {ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY, "numberonly"}, + {ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD, "password"}, + {ECORE_IMF_INPUT_PANEL_LAYOUT_DATETIME, "datetime"}, +}; + +const ISE_TYPE_VALUE_STRING ISE_LANGUAGE_TYPES[] = { + {ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC, "automatic"}, + {ECORE_IMF_INPUT_PANEL_LANG_ALPHABET, "alphabet"}, +}; + +/* FIXME : Should consider the case if the boolean value does not match with EINA_TRUE or EINA_FALSE */ +const ISE_TYPE_VALUE_STRING ISE_TRUEFALSE_TYPES[] = { + {EINA_FALSE, "false"}, + {EINA_TRUE, "true"}, +}; + +class CISEMessageSerializer +{ +protected: + /* FIXME : Temporary solution for distinguish commands and values */ + static const char MESSAGE_DELIMETER = ' '; + +public: + static std::string serialize(ISE_MESSAGE message) { + std::string ret; + ret += message.type; + ret += MESSAGE_DELIMETER; + ret += message.command; + for (unsigned int loop = 0;loop < message.values.size();loop++) { + ret += MESSAGE_DELIMETER; + ret += message.values.at(loop); + } + return ret; + } + + static ISE_MESSAGE deserialize(std::string message) { + ISE_MESSAGE ret; + std::vector vec = CStringTokenizer::split(message, MESSAGE_DELIMETER); + if (vec.size() > 1) { + ret.type = vec.at(0); + vec.erase(vec.begin()); + ret.command = vec.at(0); + vec.erase(vec.begin()); + ret.values = vec; + } + return ret; + } + + static bool valid(std::string str) + { + int loop; + + bool valid_type = false; + bool valid_command = false; + + ISE_MESSAGE message; + message = deserialize(str); + + for (loop = 0;!valid_type && loop < ISE_MESSAGE_TYPES_NUM;loop++) { + if (message.type.compare(ISE_MESSAGE_TYPE_STRINGS[loop]) == 0) { + valid_type = true; + } + } + for (loop = 0;!valid_command && loop < ISE_MESSAGE_COMMANDS_NUM;loop++) { + if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[loop]) == 0) { + valid_command = true; + } + } + + return (valid_type && valid_command); + } +}; + +class CWebHelperAgentWebSocket : public CWebHelperAgent { +public: + CWebHelperAgentWebSocket(); + virtual ~CWebHelperAgentWebSocket(); + + bool init(); + bool exit(); + + bool run(); + + bool initialized() { return m_initialized; } + + void signal(int sig); + + void on_init(); + void on_exit(); + + void on_focus_in(int ic); + void on_focus_out(int ic); + + void on_show(int ic); + void on_hide(int ic); + + void on_set_rotation(int degree); + + void on_update_cursor_position(int ic, int cursor_pos); + void on_update_surrounding_text(int ic, const char *text, int cursor); + void on_update_selection(int ic, const char *text); + + void on_set_language(unsigned int language); + + void on_set_imdata(char *buf, unsigned int len); + void on_get_imdata(char **buf, unsigned int *len); + + void on_set_return_key_type(unsigned int type); + void on_get_return_key_type(unsigned int *type); + + void on_set_return_key_disable(unsigned int disabled); + void on_get_return_key_disable(unsigned int *disabled); + + void on_set_layout(unsigned int layout); + void on_get_layout(unsigned int *layout); + + void on_reset_input_context(int ic); + + void on_process_key_event(unsigned int code, unsigned int mask, unsigned int layout, unsigned int *ret); + + std::queue& get_send_message_queue(); + std::queue& get_recv_message_queue(); + Ecore_Pipe* get_message_pipe(); + + void wait_for_reply_message(); + + void process_recved_messages(); + bool process_recved_messages_until_reply_found(std::string command, std::vector &values); + void handle_recved_message(ISE_MESSAGE &message); + + static CWebHelperAgentWebSocket* get_current_instance(); +protected: + static CWebHelperAgentWebSocket *m_current_instance; + + std::queue m_send_message_queue; + std::queue m_recv_message_queue; + + Ecore_Pipe *m_message_pipe; + + bool m_initialized; +}; + +#endif // _WEB_HELPER_AGENT_WEBSOCKET_H_