2 * Copyright (c) 2012 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
28 #include <Ecore_IMF.h>
31 #include "websocket.h"
36 #include <libwebsockets.h>
38 #define WEBSOCKET_PORT 7681
40 pthread_t g_ws_server_thread = (pthread_t)NULL;
41 pthread_mutex_t g_ws_server_mutex = PTHREAD_MUTEX_INITIALIZER;
43 pthread_cond_t g_ws_query_condition = PTHREAD_COND_INITIALIZER;
44 pthread_mutex_t g_ws_query_mutex = PTHREAD_MUTEX_INITIALIZER;
46 bool g_ws_server_exit = false;
47 struct lws_context *g_ws_server_context = NULL;
49 CWebHelperAgentWebSocket* CWebHelperAgentWebSocket::m_current_instance = NULL;
63 struct per_session_data__http {
67 static int callback_http(struct lws *wsi,
68 enum lws_callback_reasons reason,
69 void *user, void *in, size_t len)
74 struct per_session_data__keyboard {
81 static int callback_keyboard(struct lws *wsi,
82 enum lws_callback_reasons reason,
83 void *user, void *in, size_t len);
85 static struct lws_protocols protocols[] = {
89 sizeof(struct per_session_data__http),
95 sizeof(struct per_session_data__keyboard),
102 static int callback_client(struct lws *wsi,
103 enum lws_callback_reasons reason,
104 void *user, void *in, size_t len)
107 case LWS_CALLBACK_CLIENT_ESTABLISHED:
108 LOGD("[ClientTest] Connection established");
111 case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
112 LOGD("[ClientTest] Connection error");
115 case LWS_CALLBACK_CLOSED:
116 LOGD("[ClientTest] Connection closed");
126 int test_client_connection(void)
128 struct lws_context *context = NULL;
129 struct lws_context_creation_info context_info;
130 struct lws_client_connect_info connect_info;
131 struct lws *wsi = NULL;
133 memset(&context_info, 0, sizeof context_info);
134 memset(&connect_info, 0, sizeof(connect_info));
136 const int protocols_num = sizeof(protocols) / sizeof(lws_protocols);
137 static struct lws_protocols client_protocols[protocols_num];
139 memcpy(&client_protocols, protocols, sizeof(protocols));
140 for (int loop = 0; loop < protocols_num - 1; loop++) {
141 client_protocols[loop].callback = callback_client;
144 context_info.port = CONTEXT_PORT_NO_LISTEN;
145 context_info.protocols = protocols;
146 context_info.gid = -1;
147 context_info.uid = -1;
149 context = lws_create_context(&context_info);
150 LOGD("[ClientTest] create_context : %p", context);
151 if (context == NULL) {
155 connect_info.address = "localhost";
156 connect_info.port = WEBSOCKET_PORT;
157 connect_info.path = "/";
158 connect_info.context = context;
159 connect_info.ssl_connection = 0;
160 connect_info.host = connect_info.address;
161 connect_info.origin = connect_info.address;
162 connect_info.ietf_version_or_minus_one = -1;
163 connect_info.protocol = "keyboard-protocol";
165 wsi = lws_client_connect_via_info(&connect_info);
166 LOGD("[ClientTest] wsi created : %p", wsi);
169 lws_service(context, 50);
172 lws_context_destroy(context);
177 static int callback_keyboard(struct lws *wsi,
178 enum lws_callback_reasons reason,
179 void *user, void *in, size_t len)
181 static int last_session_id = 0;
182 const int bufsize = 512;
184 unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + bufsize +
185 LWS_SEND_BUFFER_POST_PADDING];
186 unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
187 struct per_session_data__keyboard *pss = (struct per_session_data__keyboard *)user;
188 CWebHelperAgentWebSocket *agent = CWebHelperAgentWebSocket::get_current_instance();
191 case LWS_CALLBACK_ESTABLISHED:
192 pss->session_id = ++last_session_id;
193 LOGD("LWS_CALLBACK_ESTABLISHED : %p %d", g_ws_server_context, pss->session_id);
195 pss->need_init = false;
196 pss->initialized = false;
197 if (g_ws_server_context) {
198 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
202 case LWS_CALLBACK_CLOSED:
203 LOGD("LWS_CALLBACK_CLOSED : %d", pss->session_id);
206 case LWS_CALLBACK_SERVER_WRITEABLE:
208 /* Ignore valid check since the magic key is not used anymore */
209 if (!pss->valid) pss->valid = true;
211 /* We allow data tranmission only if this client is guaranteed to be valid */
213 pthread_mutex_lock(&g_ws_server_mutex);
214 std::queue<ISE_MESSAGE>& messages = agent->get_send_message_queue();
216 if (pss->need_init && !pss->initialized) {
218 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
219 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_INIT];
220 std::string str = CISEMessageSerializer::serialize(message);
221 SECURE_LOGD("SEND_WEBSOCKET_MESSAGE : %d %s", pss->session_id, str.c_str());
222 n = snprintf((char *)p, bufsize, "%s", str.c_str());
223 /* too small for partial */
224 n = lws_write(wsi, p, n, LWS_WRITE_TEXT);
225 pss->need_init = false;
226 pss->initialized = true;
228 if (messages.size() > 0) {
229 ISE_MESSAGE &message = messages.front();
231 if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_INIT]) == 0) {
232 if (pss->initialized) {
235 pss->initialized = true;
239 std::string str = CISEMessageSerializer::serialize(message);
240 SECURE_LOGD("SEND_WEBSOCKET_MESSAGE : %d %s", pss->session_id, str.c_str());
241 n = snprintf((char *)p, bufsize, "%s", str.c_str());
242 /* too small for partial */
243 n = lws_write(wsi, p, n, LWS_WRITE_TEXT);
250 LOGE("ERROR %d writing to di socket %d", n, pss->session_id);
253 if (messages.size() > 0) {
254 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
256 pthread_mutex_unlock(&g_ws_server_mutex);
258 LOGD("Rejecting data transmission since client is not valid : %d", pss->session_id);
263 case LWS_CALLBACK_RECEIVE:
265 std::string str = (const char *)in;
266 ISE_MESSAGE message = CISEMessageSerializer::deserialize(str);
268 if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_LOGIN]) == 0) {
270 if (message.values.at(0).compare(CMagicKeyManager::get_magic_key()) == 0) {
271 LOGD("LOGIN successful, validating client");
274 LOGD("LOGIN failed, invalidating client");
280 if (agent->initalized()) {
281 pss->need_init = true;
282 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
286 /* Ignore valid check since the magic key is not used anymore */
287 if (!pss->valid) pss->valid = true;
290 pthread_mutex_lock(&g_ws_server_mutex);
291 std::queue<ISE_MESSAGE>& messages = agent->get_recv_message_queue();
292 messages.push(message);
293 pthread_mutex_unlock(&g_ws_server_mutex);
295 const char *recved_message = "recved";
296 ecore_pipe_write(agent->get_recv_message_pipe(), recved_message, strlen(recved_message));
298 /* If we received reply message, let's send signal to wake up our main thread */
299 if (message.type.compare(ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY]) == 0) {
300 pthread_mutex_lock(&g_ws_query_mutex);
301 pthread_cond_signal(&g_ws_query_condition);
302 pthread_mutex_unlock(&g_ws_query_mutex);
305 LOGD("Ignoring data received since client is not valid %d", pss->session_id);
317 void *process_ws_server(void *data)
319 while (!force_exit && !g_ws_server_exit) {
321 gettimeofday(&tv, NULL);
323 if (g_ws_server_context) {
324 lws_service(g_ws_server_context, 50);
326 LOGD("WARNING : g_ws_server_context is NULL");
332 void log_func(int level, const char *line)
335 LOGD("LEVEL : %d , %s", level, line);
339 CWebHelperAgentWebSocket::CWebHelperAgentWebSocket()
341 if (m_current_instance != NULL) {
342 LOGD("WARNING : m_current_instance is NOT NULL");
344 m_current_instance = this;
345 m_recv_message_pipe = NULL;
346 m_initialized = false;
349 CWebHelperAgentWebSocket::~CWebHelperAgentWebSocket()
351 if (m_current_instance == this) {
352 m_current_instance = NULL;
355 if (m_recv_message_pipe) {
356 ecore_pipe_del(m_recv_message_pipe);
357 m_recv_message_pipe = NULL;
361 static void recv_message_pipe_handler(void *data, void *buffer, unsigned int nbyte)
363 CWebHelperAgentWebSocket *agent = CWebHelperAgentWebSocket::get_current_instance();
365 agent->process_recved_messages();
369 bool CWebHelperAgentWebSocket::init()
373 struct lws_context_creation_info info;
375 memset(&info, 0, sizeof info);
376 info.port = WEBSOCKET_PORT;
378 int debug_level = LLL_DEBUG;
379 lws_set_log_level(debug_level, log_func);
382 info.protocols = protocols;
383 info.extensions = NULL;
384 info.ssl_cert_filepath = NULL;
385 info.ssl_private_key_filepath = NULL;
392 /* The WebSocket server is running on a separate thread, and let the thread send a message
393 through this pipe to guarantee thread safety */
394 m_recv_message_pipe = ecore_pipe_add(recv_message_pipe_handler, NULL);
396 /* Let's retry creating server context for a certain number of times */
397 const int max_retry_num = 30;
401 g_ws_server_context = lws_create_context(&info);
402 LOGD("libwebsocket context : %p", g_ws_server_context);
404 } while (g_ws_server_context == NULL && retry_num++ < max_retry_num);
406 pthread_mutex_init(&g_ws_server_mutex, NULL);
408 pthread_mutex_init(&g_ws_query_mutex, NULL);
409 pthread_cond_init(&g_ws_query_condition, NULL);
411 if (g_ws_server_context) {
412 if (pthread_create(&g_ws_server_thread, NULL, &process_ws_server, NULL) != 0) {
413 g_ws_server_thread = (pthread_t)NULL;
417 LOGE("Failed creating server context : %p", g_ws_server_context);
423 m_initialized = true;
425 test_client_connection();
430 bool CWebHelperAgentWebSocket::exit()
434 g_ws_server_exit = true;
436 if (m_recv_message_pipe) {
437 ecore_pipe_del(m_recv_message_pipe);
438 m_recv_message_pipe = NULL;
441 if (g_ws_server_thread) {
442 pthread_join(g_ws_server_thread, NULL);
445 pthread_cond_destroy(&g_ws_query_condition);
446 pthread_mutex_destroy(&g_ws_query_mutex);
448 pthread_mutex_destroy(&g_ws_server_mutex);
450 if (g_ws_server_context) {
451 lws_cancel_service(g_ws_server_context);
452 lws_context_destroy(g_ws_server_context);
453 g_ws_server_context = NULL;
461 void CWebHelperAgentWebSocket::signal(int sig)
467 std::string to_string(T i)
469 std::stringstream ss;
477 void CWebHelperAgentWebSocket::on_init()
480 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
481 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_INIT];
483 pthread_mutex_lock(&g_ws_server_mutex);
484 m_send_message_queue.push(message);
485 pthread_mutex_unlock(&g_ws_server_mutex);
487 if (g_ws_server_context) {
488 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
490 LOGD("WARNING : g_ws_server_context is NULL");
494 void CWebHelperAgentWebSocket::on_exit()
497 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
498 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_EXIT];
500 pthread_mutex_lock(&g_ws_server_mutex);
501 m_send_message_queue.push(message);
502 pthread_mutex_unlock(&g_ws_server_mutex);
504 if (g_ws_server_context) {
505 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
507 LOGD("WARNING : g_ws_server_context is NULL");
511 void CWebHelperAgentWebSocket::on_focus_in(int ic)
514 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
515 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_FOCUS_IN];
516 message.values.push_back(to_string(ic));
518 pthread_mutex_lock(&g_ws_server_mutex);
519 m_send_message_queue.push(message);
520 pthread_mutex_unlock(&g_ws_server_mutex);
522 if (g_ws_server_context) {
523 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
525 LOGD("WARNING : g_ws_server_context is NULL");
529 void CWebHelperAgentWebSocket::on_focus_out(int ic)
532 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
533 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_FOCUS_OUT];
534 message.values.push_back(to_string(ic));
536 pthread_mutex_lock(&g_ws_server_mutex);
537 m_send_message_queue.push(message);
538 pthread_mutex_unlock(&g_ws_server_mutex);
540 if (g_ws_server_context) {
541 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
543 LOGD("WARNING : g_ws_server_context is NULL");
547 void CWebHelperAgentWebSocket::on_show(int ic)
550 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
551 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SHOW];
552 message.values.push_back(to_string(ic));
554 pthread_mutex_lock(&g_ws_server_mutex);
555 m_send_message_queue.push(message);
556 pthread_mutex_unlock(&g_ws_server_mutex);
558 if (g_ws_server_context) {
559 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
561 LOGD("WARNING : g_ws_server_context is NULL");
564 LOGD("put into send message buffer");
567 void CWebHelperAgentWebSocket::on_hide(int ic)
570 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
571 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_HIDE];
572 message.values.push_back(to_string(ic));
574 pthread_mutex_lock(&g_ws_server_mutex);
575 m_send_message_queue.push(message);
576 pthread_mutex_unlock(&g_ws_server_mutex);
578 if (g_ws_server_context) {
579 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
581 LOGD("WARNING : g_ws_server_context is NULL");
585 void CWebHelperAgentWebSocket::on_set_rotation(int degree)
588 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
589 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_ROTATION];
590 message.values.push_back(to_string(degree));
592 pthread_mutex_lock(&g_ws_server_mutex);
593 m_send_message_queue.push(message);
594 pthread_mutex_unlock(&g_ws_server_mutex);
596 if (g_ws_server_context) {
597 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
599 LOGD("WARNING : g_ws_server_context is NULL");
603 void CWebHelperAgentWebSocket::on_update_cursor_position(int ic, int cursor_pos)
606 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
607 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_CURSOR_POSITION];
608 message.values.push_back(to_string(ic));
609 message.values.push_back(to_string(cursor_pos));
611 pthread_mutex_lock(&g_ws_server_mutex);
612 m_send_message_queue.push(message);
613 pthread_mutex_unlock(&g_ws_server_mutex);
615 if (g_ws_server_context) {
616 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
618 LOGD("WARNING : g_ws_server_context is NULL");
622 void CWebHelperAgentWebSocket::on_update_surrounding_text(int ic, const char *text, int cursor)
625 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY];
626 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_SURROUNDING_TEXT];
627 message.values.push_back(to_string(cursor));
628 message.values.push_back(text);
630 pthread_mutex_lock(&g_ws_server_mutex);
631 m_send_message_queue.push(message);
632 pthread_mutex_unlock(&g_ws_server_mutex);
634 if (g_ws_server_context) {
635 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
637 LOGD("WARNING : g_ws_server_context is NULL");
641 void CWebHelperAgentWebSocket::on_update_selection(int ic, const char *text)
644 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY];
645 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_SELECTION];
646 message.values.push_back(text);
648 pthread_mutex_lock(&g_ws_server_mutex);
649 m_send_message_queue.push(message);
650 pthread_mutex_unlock(&g_ws_server_mutex);
652 if (g_ws_server_context) {
653 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
655 LOGD("WARNING : g_ws_server_context is NULL");
659 void CWebHelperAgentWebSocket::on_set_language(unsigned int language)
662 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
663 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_LANGUAGE];
666 for (unsigned int loop = 0;loop < sizeof(ISE_LANGUAGE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
667 if (language == (unsigned int)ISE_LANGUAGE_TYPES[loop].type_value) {
668 message.values.push_back(ISE_LANGUAGE_TYPES[loop].type_string);
674 pthread_mutex_lock(&g_ws_server_mutex);
675 m_send_message_queue.push(message);
676 pthread_mutex_unlock(&g_ws_server_mutex);
678 if (g_ws_server_context) {
679 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
681 LOGD("WARNING : g_ws_server_context is NULL");
686 void CWebHelperAgentWebSocket::on_set_imdata(char *buf, unsigned int len)
689 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
690 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_IMDATA];
691 message.values.push_back(buf);
693 pthread_mutex_lock(&g_ws_server_mutex);
694 m_send_message_queue.push(message);
695 pthread_mutex_unlock(&g_ws_server_mutex);
697 if (g_ws_server_context) {
698 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
700 LOGD("WARNING : g_ws_server_context is NULL");
704 void CWebHelperAgentWebSocket::on_get_imdata(char **buf, unsigned int *len)
707 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY];
708 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_IMDATA];
710 pthread_mutex_lock(&g_ws_server_mutex);
711 m_send_message_queue.push(message);
712 pthread_mutex_unlock(&g_ws_server_mutex);
714 if (g_ws_server_context) {
715 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
717 LOGD("WARNING : g_ws_server_context is NULL");
720 wait_for_reply_message();
722 std::vector<std::string> values;
723 /* Check if we received reply for GET_IMDATA message */
724 if (process_recved_messages_until_reply_found(
725 ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_IMDATA], values)) {
726 if (values.size() > 0 && buf && len) {
727 int string_length = values.at(0).length();
728 (*buf) = new char[string_length + 1];
730 strncpy(*buf, values.at(0).c_str(), string_length);
731 /* Make sure this is a null-terminated string */
732 *(*buf + string_length) = '\0';
733 *len = string_length;
737 LOGD("process_recved_messages_until_reply_found returned FALSE");
739 /* Now process the rest in the recv buffer */
740 process_recved_messages();
743 void CWebHelperAgentWebSocket::on_set_return_key_type(unsigned int type)
746 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
747 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_RETURN_KEY_TYPE];
750 for (unsigned int loop = 0;loop < sizeof(ISE_RETURN_KEY_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
751 if (type == (unsigned int)ISE_RETURN_KEY_TYPES[loop].type_value) {
752 message.values.push_back(ISE_RETURN_KEY_TYPES[loop].type_string);
758 pthread_mutex_lock(&g_ws_server_mutex);
759 m_send_message_queue.push(message);
760 pthread_mutex_unlock(&g_ws_server_mutex);
762 if (g_ws_server_context) {
763 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
765 LOGD("WARNING : g_ws_server_context is NULL");
770 void CWebHelperAgentWebSocket::on_get_return_key_type(unsigned int *type)
773 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY];
774 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_TYPE];
776 pthread_mutex_lock(&g_ws_server_mutex);
777 m_send_message_queue.push(message);
778 pthread_mutex_unlock(&g_ws_server_mutex);
780 if (g_ws_server_context) {
781 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
783 LOGD("WARNING : g_ws_server_context is NULL");
786 wait_for_reply_message();
788 std::vector<std::string> values;
789 /* Check if we received reply for GET_RETURN_KEY_TYPE message */
790 if (process_recved_messages_until_reply_found(
791 ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_TYPE], values)) {
793 for (unsigned int loop = 0;loop < sizeof(ISE_RETURN_KEY_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
794 if (values.at(0).compare(ISE_RETURN_KEY_TYPES[loop].type_string) == 0) {
795 *type = ISE_RETURN_KEY_TYPES[loop].type_value;
800 /* Now process the rest in the recv buffer */
801 process_recved_messages();
804 void CWebHelperAgentWebSocket::on_set_return_key_disable(unsigned int disabled)
807 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
808 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_RETURN_KEY_DISABLE];
811 for (unsigned int loop = 0;loop < sizeof(ISE_TRUEFALSE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
812 if (disabled == (unsigned int)ISE_TRUEFALSE_TYPES[loop].type_value) {
813 message.values.push_back(ISE_TRUEFALSE_TYPES[loop].type_string);
819 pthread_mutex_lock(&g_ws_server_mutex);
820 m_send_message_queue.push(message);
821 pthread_mutex_unlock(&g_ws_server_mutex);
823 if (g_ws_server_context) {
824 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
826 LOGD("WARNING : g_ws_server_context is NULL");
831 void CWebHelperAgentWebSocket::on_get_return_key_disable(unsigned int *disabled)
834 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY];
835 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_DISABLE];
837 pthread_mutex_lock(&g_ws_server_mutex);
838 m_send_message_queue.push(message);
839 pthread_mutex_unlock(&g_ws_server_mutex);
841 if (g_ws_server_context) {
842 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
844 LOGD("WARNING : g_ws_server_context is NULL");
847 wait_for_reply_message();
849 std::vector<std::string> values;
850 /* Check if we received reply for GET_RETURN_KEY_DISABLE message */
851 if (process_recved_messages_until_reply_found(
852 ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_DISABLE], values)) {
854 for (unsigned int loop = 0;loop < sizeof(ISE_TRUEFALSE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
855 if (values.at(0).compare(ISE_TRUEFALSE_TYPES[loop].type_string) == 0) {
856 *disabled = ISE_TRUEFALSE_TYPES[loop].type_value;
861 /* Now process the rest in the recv buffer */
862 process_recved_messages();
865 void CWebHelperAgentWebSocket::on_set_layout(unsigned int layout)
868 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
869 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_LAYOUT];
872 for (unsigned int loop = 0;loop < sizeof(ISE_LAYOUT_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
873 if (layout == (unsigned int)ISE_LAYOUT_TYPES[loop].type_value) {
874 message.values.push_back(ISE_LAYOUT_TYPES[loop].type_string);
880 pthread_mutex_lock(&g_ws_server_mutex);
881 m_send_message_queue.push(message);
882 pthread_mutex_unlock(&g_ws_server_mutex);
884 if (g_ws_server_context) {
885 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
887 LOGD("WARNING : g_ws_server_context is NULL");
892 void CWebHelperAgentWebSocket::on_get_layout(unsigned int *layout)
895 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY];
896 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_LAYOUT];
898 pthread_mutex_lock(&g_ws_server_mutex);
899 m_send_message_queue.push(message);
900 pthread_mutex_unlock(&g_ws_server_mutex);
902 if (g_ws_server_context) {
903 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
905 LOGD("WARNING : g_ws_server_context is NULL");
908 wait_for_reply_message();
910 std::vector<std::string> values;
911 /* Check if we received reply for GET_LAYOUT message */
912 if (process_recved_messages_until_reply_found(
913 ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_LAYOUT], values)) {
915 for (unsigned int loop = 0;loop < sizeof(ISE_LAYOUT_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
916 if (values.at(0).compare(ISE_LAYOUT_TYPES[loop].type_string) == 0) {
917 *layout = ISE_LAYOUT_TYPES[loop].type_value;
922 /* Now process the rest in the recv buffer */
923 process_recved_messages();
926 void CWebHelperAgentWebSocket::on_reset_input_context(int ic)
929 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
930 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_RESET_INPUT_CONTEXT];
931 message.values.push_back(to_string(ic));
933 pthread_mutex_lock(&g_ws_server_mutex);
934 m_send_message_queue.push(message);
935 pthread_mutex_unlock(&g_ws_server_mutex);
937 if (g_ws_server_context) {
938 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
940 LOGD("WARNING : g_ws_server_context is NULL");
944 void CWebHelperAgentWebSocket::on_process_key_event(unsigned int code, unsigned int mask, unsigned int layout, unsigned int *ret)
947 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY];
948 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_PROCESS_KEY_EVENT];
949 message.values.push_back(to_string(code));
950 message.values.push_back(to_string(mask));
951 message.values.push_back(to_string(layout));
953 pthread_mutex_lock(&g_ws_server_mutex);
954 m_send_message_queue.push(message);
955 pthread_mutex_unlock(&g_ws_server_mutex);
957 if (g_ws_server_context) {
958 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
960 LOGD("WARNING : g_ws_server_context is NULL");
963 wait_for_reply_message();
965 std::vector<std::string> values;
966 /* Check if we received reply for PROCESS_KEY_EVENT message */
967 if (process_recved_messages_until_reply_found(
968 ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_PROCESS_KEY_EVENT], values)) {
970 for (unsigned int loop = 0;loop < sizeof(ISE_TRUEFALSE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
971 if (values.at(0).compare(ISE_TRUEFALSE_TYPES[loop].type_string) == 0) {
972 *ret = ISE_TRUEFALSE_TYPES[loop].type_value;
977 /* Now process the rest in the recv buffer */
978 process_recved_messages();
981 CWebHelperAgentWebSocket* CWebHelperAgentWebSocket::get_current_instance()
983 return m_current_instance;
986 std::queue<ISE_MESSAGE>& CWebHelperAgentWebSocket::get_send_message_queue()
988 return m_send_message_queue;
991 std::queue<ISE_MESSAGE>& CWebHelperAgentWebSocket::get_recv_message_queue()
993 return m_recv_message_queue;
996 Ecore_Pipe* CWebHelperAgentWebSocket::get_recv_message_pipe()
998 return m_recv_message_pipe;
1001 void CWebHelperAgentWebSocket::wait_for_reply_message()
1003 /* Let's wait for at most REPLY_TIMEOUT */
1005 struct timespec timeout;
1006 gettimeofday(&now, NULL);
1007 timeout.tv_sec = now.tv_sec + REPLY_TIMEOUT.tv_sec;
1008 timeout.tv_nsec = (now.tv_usec + REPLY_TIMEOUT.tv_usec) * 1000;
1009 pthread_mutex_lock(&g_ws_query_mutex);
1010 pthread_cond_timedwait(&g_ws_query_condition, &g_ws_query_mutex, &timeout);
1011 pthread_mutex_unlock(&g_ws_query_mutex);
1014 void CWebHelperAgentWebSocket::process_recved_messages()
1016 pthread_mutex_lock(&g_ws_server_mutex);
1018 while (m_recv_message_queue.size() > 0) {
1019 ISE_MESSAGE &message = m_recv_message_queue.front();
1021 handle_recved_message(message);
1023 m_recv_message_queue.pop();
1026 pthread_mutex_unlock(&g_ws_server_mutex);
1029 bool CWebHelperAgentWebSocket::process_recved_messages_until_reply_found(std::string command, std::vector<std::string> &values)
1033 pthread_mutex_lock(&g_ws_server_mutex);
1035 while (ret == false && m_recv_message_queue.size() > 0) {
1036 ISE_MESSAGE &message = m_recv_message_queue.front();
1038 if (message.command.compare(command) == 0 &&
1039 message.type.compare(ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY]) == 0) {
1041 values = message.values;
1043 handle_recved_message(message);
1045 m_recv_message_queue.pop();
1048 pthread_mutex_unlock(&g_ws_server_mutex);
1053 void CWebHelperAgentWebSocket::handle_recved_message(ISE_MESSAGE &message)
1055 if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_LOG]) == 0) {
1056 std::string str = "";
1057 for (unsigned int loop = 0;loop < message.values.size();loop++) {
1058 str += message.values.at(loop).c_str();
1059 if (loop < message.values.size() - 1) {
1064 } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_COMMIT_STRING]) == 0) {
1065 send_key_event(0xff6b, 0); // Temporarily reset keyboard engine
1067 std::string str = "";
1068 for (unsigned int loop = 0;loop < message.values.size();loop++) {
1069 str += message.values.at(loop).c_str();
1070 if (loop < message.values.size() - 1) {
1074 commit_string(str.c_str());
1075 } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_PREEDIT_STRING]) == 0) {
1076 std::string str = "";
1077 for (unsigned int loop = 0;loop < message.values.size();loop++) {
1078 str += message.values.at(loop).c_str();
1079 if (loop < message.values.size() - 1) {
1083 update_preedit_string(str.c_str());
1084 } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SEND_KEY_EVENT]) == 0) {
1085 if (message.values.size() == 1) {
1086 send_key_event(atoi(message.values.at(0).c_str()), 0);
1088 } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_KEYBOARD_SIZES]) == 0) {
1089 LOGD("ISE_MESSAGE_COMMAND_SET_KEYBOARD_SIZES");
1090 int portrait_width, portrait_height;
1091 int landscape_width, landscape_height;
1093 if (message.values.size() == 4 || message.values.size() == 2) {
1094 portrait_width = atoi(message.values.at(0).c_str());
1095 portrait_height = atoi(message.values.at(1).c_str());
1096 if (message.values.size() == 2) {
1097 landscape_width = portrait_width;
1098 landscape_height = portrait_height;
1100 landscape_width = atoi(message.values.at(2).c_str());
1101 landscape_height = atoi(message.values.at(3).c_str());
1104 LOGD("ISE_MESSAGE_COMMAND_SET_KEYBOARD_SIZES : %d %d %d %d",
1105 portrait_width, portrait_height, landscape_width, landscape_height);
1107 portrait_width, portrait_height, landscape_width, landscape_height);
1109 } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_SELECTION]) == 0) {
1110 LOGD("ISE_MESSAGE_COMMAND_SET_SELECTION");
1111 if (message.values.size() == 2) {
1112 LOGD("ISE_MESSAGE_COMMAND_SET_SELECTION : %d %d",
1113 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1115 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1117 } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_SELECTION]) == 0) {
1118 if (message.values.size() == 0) {
1121 } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_SURROUNDING_TEXT]) == 0) {
1122 LOGD("ISE_MESSAGE_COMMAND_GET_SURROUNDING_TEXT");
1123 if (message.values.size() == 2) {
1124 LOGD("ISE_MESSAGE_COMMAND_GET_SURROUNDING_TEXT : %d %d",
1125 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1126 get_surrounding_text(
1127 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1129 } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_DELETE_SURROUNDING_TEXT]) == 0) {
1130 LOGD("ISE_MESSAGE_COMMAND_DELETE_SURROUNDING_TEXT");
1131 if (message.values.size() == 2) {
1132 LOGD("ISE_MESSAGE_COMMAND_DELETE_SURROUNDING_TEXT : %d %d",
1133 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1134 delete_surrounding_text(
1135 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1137 } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_LOGIN]) == 0) {
1138 if (g_ws_server_context) {
1139 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
1141 LOGD("WARNING : g_ws_server_context is NULL");