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 pthread_t g_ws_server_thread = (pthread_t)NULL;
39 pthread_mutex_t g_ws_server_mutex = PTHREAD_MUTEX_INITIALIZER;
41 pthread_cond_t g_ws_query_condition = PTHREAD_COND_INITIALIZER;
42 pthread_mutex_t g_ws_query_mutex = PTHREAD_MUTEX_INITIALIZER;
44 bool g_ws_server_exit = false;
45 struct lws_context *g_ws_server_context = NULL;
47 CWebHelperAgentWebSocket* CWebHelperAgentWebSocket::m_current_instance = NULL;
61 struct per_session_data__http {
65 static int callback_http(struct lws *wsi,
66 enum lws_callback_reasons reason,
67 void *user, void *in, size_t len)
72 struct per_session_data__keyboard {
79 static int callback_keyboard(struct lws *wsi,
80 enum lws_callback_reasons reason,
81 void *user, void *in, size_t len);
83 static struct lws_protocols protocols[] = {
87 sizeof(struct per_session_data__http),
93 sizeof(struct per_session_data__keyboard),
99 static int callback_keyboard(struct lws *wsi,
100 enum lws_callback_reasons reason,
101 void *user, void *in, size_t len)
103 static int last_session_id = 0;
104 const int bufsize = 512;
106 unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + bufsize +
107 LWS_SEND_BUFFER_POST_PADDING];
108 unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
109 struct per_session_data__keyboard *pss = (struct per_session_data__keyboard *)user;
110 CWebHelperAgentWebSocket *agent = CWebHelperAgentWebSocket::get_current_instance();
113 case LWS_CALLBACK_ESTABLISHED:
114 pss->session_id = ++last_session_id;
115 LOGD("LWS_CALLBACK_ESTABLISHED : %p %d", g_ws_server_context, pss->session_id);
117 pss->need_init = false;
118 pss->initialized = false;
119 if (g_ws_server_context) {
120 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
124 case LWS_CALLBACK_CLOSED:
125 LOGD("LWS_CALLBACK_CLOSED : %d", pss->session_id);
128 case LWS_CALLBACK_SERVER_WRITEABLE:
130 /* Ignore valid check since the magic key is not used anymore */
131 if (!pss->valid) pss->valid = true;
133 /* We allow data tranmission only if this client is guaranteed to be valid */
135 pthread_mutex_lock(&g_ws_server_mutex);
136 std::queue<ISE_MESSAGE>& messages = agent->get_send_message_queue();
138 if (pss->need_init && !pss->initialized) {
140 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
141 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_INIT];
142 std::string str = CISEMessageSerializer::serialize(message);
143 LOGD("SEND_WEBSOCKET_MESSAGE : %d %s", pss->session_id, str.c_str());
144 n = snprintf((char *)p, bufsize, "%s", str.c_str());
145 /* too small for partial */
146 n = lws_write(wsi, p, n, LWS_WRITE_TEXT);
147 pss->need_init = false;
148 pss->initialized = true;
150 if (messages.size() > 0) {
151 ISE_MESSAGE &message = messages.front();
153 if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_INIT]) == 0) {
154 if (pss->initialized) {
157 pss->initialized = true;
161 std::string str = CISEMessageSerializer::serialize(message);
162 LOGD("SEND_WEBSOCKET_MESSAGE : %d %s", pss->session_id, str.c_str());
163 n = snprintf((char *)p, bufsize, "%s", str.c_str());
164 /* too small for partial */
165 n = lws_write(wsi, p, n, LWS_WRITE_TEXT);
172 LOGE("ERROR %d writing to di socket %d", n, pss->session_id);
176 if (messages.size() > 0) {
177 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
179 pthread_mutex_unlock(&g_ws_server_mutex);
181 LOGD("Rejecting data transmission since client is not valid : %d", pss->session_id);
186 case LWS_CALLBACK_RECEIVE:
188 std::string str = (const char *)in;
189 ISE_MESSAGE message = CISEMessageSerializer::deserialize(str);
191 if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_LOGIN]) == 0) {
193 if (message.values.at(0).compare(CMagicKeyManager::get_magic_key()) == 0) {
194 LOGD("LOGIN successful, validating client");
197 LOGD("LOGIN failed, invalidating client");
203 if (agent->initalized()) {
204 pss->need_init = true;
205 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
209 /* Ignore valid check since the magic key is not used anymore */
210 if (!pss->valid) pss->valid = true;
213 pthread_mutex_lock(&g_ws_server_mutex);
214 std::queue<ISE_MESSAGE>& messages = agent->get_recv_message_queue();
215 messages.push(message);
216 pthread_mutex_unlock(&g_ws_server_mutex);
218 const char *recved_message = "recved";
219 ecore_pipe_write(agent->get_recv_message_pipe(), recved_message, strlen(recved_message));
221 /* If we received reply message, let's send signal to wake up our main thread */
222 if (message.type.compare(ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY]) == 0) {
223 pthread_mutex_lock(&g_ws_query_mutex);
224 pthread_cond_signal(&g_ws_query_condition);
225 pthread_mutex_unlock(&g_ws_query_mutex);
228 LOGD("Ignoring data received since client is not valid %d", pss->session_id);
240 void *process_ws_server(void *data)
242 while (!force_exit && !g_ws_server_exit) {
244 gettimeofday(&tv, NULL);
246 if (g_ws_server_context) {
247 lws_service(g_ws_server_context, 50);
249 LOGD("WARNING : g_ws_server_context is NULL");
255 void log_func(int level, const char *line)
258 LOGD("LEVEL : %d , %s", level, line);
262 CWebHelperAgentWebSocket::CWebHelperAgentWebSocket()
264 if (m_current_instance != NULL) {
265 LOGD("WARNING : m_current_instance is NOT NULL");
267 m_current_instance = this;
268 m_recv_message_pipe = NULL;
269 m_initialized = false;
272 CWebHelperAgentWebSocket::~CWebHelperAgentWebSocket()
274 if (m_current_instance == this) {
275 m_current_instance = NULL;
278 if (m_recv_message_pipe) {
279 ecore_pipe_del(m_recv_message_pipe);
280 m_recv_message_pipe = NULL;
284 static void recv_message_pipe_handler(void *data, void *buffer, unsigned int nbyte)
286 CWebHelperAgentWebSocket *agent = CWebHelperAgentWebSocket::get_current_instance();
288 agent->process_recved_messages();
292 bool CWebHelperAgentWebSocket::init()
296 struct lws_context_creation_info info;
298 memset(&info, 0, sizeof info);
301 int debug_level = LLL_DEBUG;
302 lws_set_log_level(debug_level, log_func);
305 info.protocols = protocols;
306 info.extensions = NULL;
307 info.ssl_cert_filepath = NULL;
308 info.ssl_private_key_filepath = NULL;
315 /* The WebSocket server is running on a separate thread, and let the thread send a message
316 through this pipe to guarantee thread safety */
317 m_recv_message_pipe = ecore_pipe_add(recv_message_pipe_handler, NULL);
319 /* Let's retry creating server context for a certain number of times */
320 const int max_retry_num = 10;
324 g_ws_server_context = lws_create_context(&info);
325 LOGD("libwebsocket context : %p", g_ws_server_context);
327 } while (g_ws_server_context == NULL && retry_num++ < max_retry_num);
329 pthread_mutex_init(&g_ws_server_mutex, NULL);
331 pthread_mutex_init(&g_ws_query_mutex, NULL);
332 pthread_cond_init(&g_ws_query_condition, NULL);
334 if (g_ws_server_context) {
335 if (pthread_create(&g_ws_server_thread, NULL, &process_ws_server, NULL) != 0) {
336 g_ws_server_thread = (pthread_t)NULL;
345 m_initialized = true;
350 bool CWebHelperAgentWebSocket::exit()
354 g_ws_server_exit = true;
356 if (m_recv_message_pipe) {
357 ecore_pipe_del(m_recv_message_pipe);
358 m_recv_message_pipe = NULL;
361 if (g_ws_server_thread) {
362 pthread_join(g_ws_server_thread, NULL);
365 pthread_cond_destroy(&g_ws_query_condition);
366 pthread_mutex_destroy(&g_ws_query_mutex);
368 pthread_mutex_destroy(&g_ws_server_mutex);
370 if (g_ws_server_context) {
371 lws_context_destroy(g_ws_server_context);
372 g_ws_server_context = NULL;
380 void CWebHelperAgentWebSocket::signal(int sig)
386 std::string to_string(T i)
388 std::stringstream ss;
396 void CWebHelperAgentWebSocket::on_init()
399 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
400 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_INIT];
402 pthread_mutex_lock(&g_ws_server_mutex);
403 m_send_message_queue.push(message);
404 pthread_mutex_unlock(&g_ws_server_mutex);
406 if (g_ws_server_context) {
407 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
409 LOGD("WARNING : g_ws_server_context is NULL");
413 void CWebHelperAgentWebSocket::on_exit()
416 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
417 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_EXIT];
419 pthread_mutex_lock(&g_ws_server_mutex);
420 m_send_message_queue.push(message);
421 pthread_mutex_unlock(&g_ws_server_mutex);
423 if (g_ws_server_context) {
424 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
426 LOGD("WARNING : g_ws_server_context is NULL");
430 void CWebHelperAgentWebSocket::on_focus_in(int ic)
433 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
434 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_FOCUS_IN];
435 message.values.push_back(to_string(ic));
437 pthread_mutex_lock(&g_ws_server_mutex);
438 m_send_message_queue.push(message);
439 pthread_mutex_unlock(&g_ws_server_mutex);
441 if (g_ws_server_context) {
442 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
444 LOGD("WARNING : g_ws_server_context is NULL");
448 void CWebHelperAgentWebSocket::on_focus_out(int ic)
451 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
452 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_FOCUS_OUT];
453 message.values.push_back(to_string(ic));
455 pthread_mutex_lock(&g_ws_server_mutex);
456 m_send_message_queue.push(message);
457 pthread_mutex_unlock(&g_ws_server_mutex);
459 if (g_ws_server_context) {
460 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
462 LOGD("WARNING : g_ws_server_context is NULL");
466 void CWebHelperAgentWebSocket::on_show(int ic)
469 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
470 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SHOW];
471 message.values.push_back(to_string(ic));
473 pthread_mutex_lock(&g_ws_server_mutex);
474 m_send_message_queue.push(message);
475 pthread_mutex_unlock(&g_ws_server_mutex);
477 if (g_ws_server_context) {
478 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
480 LOGD("WARNING : g_ws_server_context is NULL");
483 LOGD("put into send message buffer");
486 void CWebHelperAgentWebSocket::on_hide(int ic)
489 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
490 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_HIDE];
491 message.values.push_back(to_string(ic));
493 pthread_mutex_lock(&g_ws_server_mutex);
494 m_send_message_queue.push(message);
495 pthread_mutex_unlock(&g_ws_server_mutex);
497 if (g_ws_server_context) {
498 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
500 LOGD("WARNING : g_ws_server_context is NULL");
504 void CWebHelperAgentWebSocket::on_set_rotation(int degree)
507 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
508 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_ROTATION];
509 message.values.push_back(to_string(degree));
511 pthread_mutex_lock(&g_ws_server_mutex);
512 m_send_message_queue.push(message);
513 pthread_mutex_unlock(&g_ws_server_mutex);
515 if (g_ws_server_context) {
516 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
518 LOGD("WARNING : g_ws_server_context is NULL");
522 void CWebHelperAgentWebSocket::on_update_cursor_position(int ic, int cursor_pos)
525 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
526 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_CURSOR_POSITION];
527 message.values.push_back(to_string(ic));
528 message.values.push_back(to_string(cursor_pos));
530 pthread_mutex_lock(&g_ws_server_mutex);
531 m_send_message_queue.push(message);
532 pthread_mutex_unlock(&g_ws_server_mutex);
534 if (g_ws_server_context) {
535 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
537 LOGD("WARNING : g_ws_server_context is NULL");
541 void CWebHelperAgentWebSocket::on_update_surrounding_text(int ic, const char *text, int cursor)
544 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY];
545 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_SURROUNDING_TEXT];
546 message.values.push_back(to_string(cursor));
547 message.values.push_back(text);
549 pthread_mutex_lock(&g_ws_server_mutex);
550 m_send_message_queue.push(message);
551 pthread_mutex_unlock(&g_ws_server_mutex);
553 if (g_ws_server_context) {
554 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
556 LOGD("WARNING : g_ws_server_context is NULL");
560 void CWebHelperAgentWebSocket::on_update_selection(int ic, const char *text)
563 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY];
564 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_SELECTION];
565 message.values.push_back(text);
567 pthread_mutex_lock(&g_ws_server_mutex);
568 m_send_message_queue.push(message);
569 pthread_mutex_unlock(&g_ws_server_mutex);
571 if (g_ws_server_context) {
572 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
574 LOGD("WARNING : g_ws_server_context is NULL");
578 void CWebHelperAgentWebSocket::on_set_language(unsigned int language)
581 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
582 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_LANGUAGE];
585 for (unsigned int loop = 0;loop < sizeof(ISE_LANGUAGE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
586 if (language == (unsigned int)ISE_LANGUAGE_TYPES[loop].type_value) {
587 message.values.push_back(ISE_LANGUAGE_TYPES[loop].type_string);
593 pthread_mutex_lock(&g_ws_server_mutex);
594 m_send_message_queue.push(message);
595 pthread_mutex_unlock(&g_ws_server_mutex);
597 if (g_ws_server_context) {
598 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
600 LOGD("WARNING : g_ws_server_context is NULL");
605 void CWebHelperAgentWebSocket::on_set_imdata(char *buf, unsigned int len)
608 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
609 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_IMDATA];
610 message.values.push_back(buf);
612 pthread_mutex_lock(&g_ws_server_mutex);
613 m_send_message_queue.push(message);
614 pthread_mutex_unlock(&g_ws_server_mutex);
616 if (g_ws_server_context) {
617 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
619 LOGD("WARNING : g_ws_server_context is NULL");
623 void CWebHelperAgentWebSocket::on_get_imdata(char **buf, unsigned int *len)
626 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY];
627 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_IMDATA];
629 pthread_mutex_lock(&g_ws_server_mutex);
630 m_send_message_queue.push(message);
631 pthread_mutex_unlock(&g_ws_server_mutex);
633 if (g_ws_server_context) {
634 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
636 LOGD("WARNING : g_ws_server_context is NULL");
639 wait_for_reply_message();
641 std::vector<std::string> values;
642 /* Check if we received reply for GET_IMDATA message */
643 if (process_recved_messages_until_reply_found(
644 ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_IMDATA], values)) {
645 if (values.size() > 0 && buf && len) {
646 int string_length = values.at(0).length();
647 (*buf) = new char[string_length + 1];
649 strncpy(*buf, values.at(0).c_str(), string_length);
650 /* Make sure this is a null-terminated string */
651 *(*buf + string_length) = '\0';
652 *len = string_length;
656 LOGD("process_recved_messages_until_reply_found returned FALSE");
658 /* Now process the rest in the recv buffer */
659 process_recved_messages();
662 void CWebHelperAgentWebSocket::on_set_return_key_type(unsigned int type)
665 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
666 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_RETURN_KEY_TYPE];
669 for (unsigned int loop = 0;loop < sizeof(ISE_RETURN_KEY_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
670 if (type == (unsigned int)ISE_RETURN_KEY_TYPES[loop].type_value) {
671 message.values.push_back(ISE_RETURN_KEY_TYPES[loop].type_string);
677 pthread_mutex_lock(&g_ws_server_mutex);
678 m_send_message_queue.push(message);
679 pthread_mutex_unlock(&g_ws_server_mutex);
681 if (g_ws_server_context) {
682 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
684 LOGD("WARNING : g_ws_server_context is NULL");
689 void CWebHelperAgentWebSocket::on_get_return_key_type(unsigned int *type)
692 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY];
693 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_TYPE];
695 pthread_mutex_lock(&g_ws_server_mutex);
696 m_send_message_queue.push(message);
697 pthread_mutex_unlock(&g_ws_server_mutex);
699 if (g_ws_server_context) {
700 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
702 LOGD("WARNING : g_ws_server_context is NULL");
705 wait_for_reply_message();
707 std::vector<std::string> values;
708 /* Check if we received reply for GET_RETURN_KEY_TYPE message */
709 if (process_recved_messages_until_reply_found(
710 ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_TYPE], values)) {
712 for (unsigned int loop = 0;loop < sizeof(ISE_RETURN_KEY_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
713 if (values.at(0).compare(ISE_RETURN_KEY_TYPES[loop].type_string) == 0) {
714 *type = ISE_RETURN_KEY_TYPES[loop].type_value;
719 /* Now process the rest in the recv buffer */
720 process_recved_messages();
723 void CWebHelperAgentWebSocket::on_set_return_key_disable(unsigned int disabled)
726 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
727 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_RETURN_KEY_DISABLE];
730 for (unsigned int loop = 0;loop < sizeof(ISE_TRUEFALSE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
731 if (disabled == (unsigned int)ISE_TRUEFALSE_TYPES[loop].type_value) {
732 message.values.push_back(ISE_TRUEFALSE_TYPES[loop].type_string);
738 pthread_mutex_lock(&g_ws_server_mutex);
739 m_send_message_queue.push(message);
740 pthread_mutex_unlock(&g_ws_server_mutex);
742 if (g_ws_server_context) {
743 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
745 LOGD("WARNING : g_ws_server_context is NULL");
750 void CWebHelperAgentWebSocket::on_get_return_key_disable(unsigned int *disabled)
753 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY];
754 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_DISABLE];
756 pthread_mutex_lock(&g_ws_server_mutex);
757 m_send_message_queue.push(message);
758 pthread_mutex_unlock(&g_ws_server_mutex);
760 if (g_ws_server_context) {
761 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
763 LOGD("WARNING : g_ws_server_context is NULL");
766 wait_for_reply_message();
768 std::vector<std::string> values;
769 /* Check if we received reply for GET_RETURN_KEY_DISABLE message */
770 if (process_recved_messages_until_reply_found(
771 ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_DISABLE], values)) {
773 for (unsigned int loop = 0;loop < sizeof(ISE_TRUEFALSE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
774 if (values.at(0).compare(ISE_TRUEFALSE_TYPES[loop].type_string) == 0) {
775 *disabled = ISE_TRUEFALSE_TYPES[loop].type_value;
780 /* Now process the rest in the recv buffer */
781 process_recved_messages();
784 void CWebHelperAgentWebSocket::on_set_layout(unsigned int layout)
787 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
788 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_LAYOUT];
791 for (unsigned int loop = 0;loop < sizeof(ISE_LAYOUT_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
792 if (layout == (unsigned int)ISE_LAYOUT_TYPES[loop].type_value) {
793 message.values.push_back(ISE_LAYOUT_TYPES[loop].type_string);
799 pthread_mutex_lock(&g_ws_server_mutex);
800 m_send_message_queue.push(message);
801 pthread_mutex_unlock(&g_ws_server_mutex);
803 if (g_ws_server_context) {
804 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
806 LOGD("WARNING : g_ws_server_context is NULL");
811 void CWebHelperAgentWebSocket::on_get_layout(unsigned int *layout)
814 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY];
815 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_LAYOUT];
817 pthread_mutex_lock(&g_ws_server_mutex);
818 m_send_message_queue.push(message);
819 pthread_mutex_unlock(&g_ws_server_mutex);
821 if (g_ws_server_context) {
822 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
824 LOGD("WARNING : g_ws_server_context is NULL");
827 wait_for_reply_message();
829 std::vector<std::string> values;
830 /* Check if we received reply for GET_LAYOUT message */
831 if (process_recved_messages_until_reply_found(
832 ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_LAYOUT], values)) {
834 for (unsigned int loop = 0;loop < sizeof(ISE_LAYOUT_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
835 if (values.at(0).compare(ISE_LAYOUT_TYPES[loop].type_string) == 0) {
836 *layout = ISE_LAYOUT_TYPES[loop].type_value;
841 /* Now process the rest in the recv buffer */
842 process_recved_messages();
845 void CWebHelperAgentWebSocket::on_reset_input_context(int ic)
848 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
849 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_RESET_INPUT_CONTEXT];
850 message.values.push_back(to_string(ic));
852 pthread_mutex_lock(&g_ws_server_mutex);
853 m_send_message_queue.push(message);
854 pthread_mutex_unlock(&g_ws_server_mutex);
856 if (g_ws_server_context) {
857 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
859 LOGD("WARNING : g_ws_server_context is NULL");
863 void CWebHelperAgentWebSocket::on_process_key_event(unsigned int code, unsigned int mask, unsigned int layout, unsigned int *ret)
866 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY];
867 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_PROCESS_KEY_EVENT];
868 message.values.push_back(to_string(code));
869 message.values.push_back(to_string(mask));
870 message.values.push_back(to_string(layout));
872 pthread_mutex_lock(&g_ws_server_mutex);
873 m_send_message_queue.push(message);
874 pthread_mutex_unlock(&g_ws_server_mutex);
876 if (g_ws_server_context) {
877 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
879 LOGD("WARNING : g_ws_server_context is NULL");
882 wait_for_reply_message();
884 std::vector<std::string> values;
885 /* Check if we received reply for PROCESS_KEY_EVENT message */
886 if (process_recved_messages_until_reply_found(
887 ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_PROCESS_KEY_EVENT], values)) {
889 for (unsigned int loop = 0;loop < sizeof(ISE_TRUEFALSE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
890 if (values.at(0).compare(ISE_TRUEFALSE_TYPES[loop].type_string) == 0) {
891 *ret = ISE_TRUEFALSE_TYPES[loop].type_value;
896 /* Now process the rest in the recv buffer */
897 process_recved_messages();
900 CWebHelperAgentWebSocket* CWebHelperAgentWebSocket::get_current_instance()
902 return m_current_instance;
905 std::queue<ISE_MESSAGE>& CWebHelperAgentWebSocket::get_send_message_queue()
907 return m_send_message_queue;
910 std::queue<ISE_MESSAGE>& CWebHelperAgentWebSocket::get_recv_message_queue()
912 return m_recv_message_queue;
915 Ecore_Pipe* CWebHelperAgentWebSocket::get_recv_message_pipe()
917 return m_recv_message_pipe;
920 void CWebHelperAgentWebSocket::wait_for_reply_message()
922 /* Let's wait for at most REPLY_TIMEOUT */
924 struct timespec timeout;
925 gettimeofday(&now, NULL);
926 timeout.tv_sec = now.tv_sec + REPLY_TIMEOUT.tv_sec;
927 timeout.tv_nsec = (now.tv_usec + REPLY_TIMEOUT.tv_usec) * 1000;
928 pthread_mutex_lock(&g_ws_query_mutex);
929 pthread_cond_timedwait(&g_ws_query_condition, &g_ws_query_mutex, &timeout);
930 pthread_mutex_unlock(&g_ws_query_mutex);
933 void CWebHelperAgentWebSocket::process_recved_messages()
935 pthread_mutex_lock(&g_ws_server_mutex);
937 while (m_recv_message_queue.size() > 0) {
938 ISE_MESSAGE &message = m_recv_message_queue.front();
940 handle_recved_message(message);
942 m_recv_message_queue.pop();
945 pthread_mutex_unlock(&g_ws_server_mutex);
948 bool CWebHelperAgentWebSocket::process_recved_messages_until_reply_found(std::string command, std::vector<std::string> &values)
952 pthread_mutex_lock(&g_ws_server_mutex);
954 while (ret == false && m_recv_message_queue.size() > 0) {
955 ISE_MESSAGE &message = m_recv_message_queue.front();
957 if (message.command.compare(command) == 0 &&
958 message.type.compare(ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY]) == 0) {
960 values = message.values;
962 handle_recved_message(message);
964 m_recv_message_queue.pop();
967 pthread_mutex_unlock(&g_ws_server_mutex);
972 void CWebHelperAgentWebSocket::handle_recved_message(ISE_MESSAGE &message)
974 if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_LOG]) == 0) {
975 std::string str = "";
976 for (unsigned int loop = 0;loop < message.values.size();loop++) {
977 str += message.values.at(loop).c_str();
978 if (loop < message.values.size() - 1) {
983 } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_COMMIT_STRING]) == 0) {
984 send_key_event(0xff6b, 0); // Temporarily reset keyboard engine
986 std::string str = "";
987 for (unsigned int loop = 0;loop < message.values.size();loop++) {
988 str += message.values.at(loop).c_str();
989 if (loop < message.values.size() - 1) {
993 commit_string(str.c_str());
994 } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_PREEDIT_STRING]) == 0) {
995 std::string str = "";
996 for (unsigned int loop = 0;loop < message.values.size();loop++) {
997 str += message.values.at(loop).c_str();
998 if (loop < message.values.size() - 1) {
1002 update_preedit_string(str.c_str());
1003 } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SEND_KEY_EVENT]) == 0) {
1004 if (message.values.size() == 1) {
1005 send_key_event(atoi(message.values.at(0).c_str()), 0);
1007 } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_KEYBOARD_SIZES]) == 0) {
1008 LOGD("ISE_MESSAGE_COMMAND_SET_KEYBOARD_SIZES");
1009 int portrait_width, portrait_height;
1010 int landscape_width, landscape_height;
1012 if (message.values.size() == 4 || message.values.size() == 2) {
1013 portrait_width = atoi(message.values.at(0).c_str());
1014 portrait_height = atoi(message.values.at(1).c_str());
1015 if (message.values.size() == 2) {
1016 landscape_width = portrait_width;
1017 landscape_height = portrait_height;
1019 landscape_width = atoi(message.values.at(2).c_str());
1020 landscape_height = atoi(message.values.at(3).c_str());
1023 LOGD("ISE_MESSAGE_COMMAND_SET_KEYBOARD_SIZES : %d %d %d %d",
1024 portrait_width, portrait_height, landscape_width, landscape_height);
1026 portrait_width, portrait_height, landscape_width, landscape_height);
1028 } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_SELECTION]) == 0) {
1029 LOGD("ISE_MESSAGE_COMMAND_SET_SELECTION");
1030 if (message.values.size() == 2) {
1031 LOGD("ISE_MESSAGE_COMMAND_SET_SELECTION : %d %d",
1032 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1034 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1036 } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_SELECTION]) == 0) {
1037 if (message.values.size() == 0) {
1040 } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_SURROUNDING_TEXT]) == 0) {
1041 LOGD("ISE_MESSAGE_COMMAND_GET_SURROUNDING_TEXT");
1042 if (message.values.size() == 2) {
1043 LOGD("ISE_MESSAGE_COMMAND_GET_SURROUNDING_TEXT : %d %d",
1044 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1045 get_surrounding_text(
1046 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1048 } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_DELETE_SURROUNDING_TEXT]) == 0) {
1049 LOGD("ISE_MESSAGE_COMMAND_DELETE_SURROUNDING_TEXT");
1050 if (message.values.size() == 2) {
1051 LOGD("ISE_MESSAGE_COMMAND_DELETE_SURROUNDING_TEXT : %d %d",
1052 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1053 delete_surrounding_text(
1054 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1056 } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_LOGIN]) == 0) {
1057 if (g_ws_server_context) {
1058 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
1060 LOGD("WARNING : g_ws_server_context is NULL");