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 #define RECVED_MESSAGE "recved"
41 #define MESSAGE_LEFT "left"
43 pthread_t g_ws_server_thread = (pthread_t)NULL;
44 pthread_mutex_t g_ws_server_mutex = PTHREAD_MUTEX_INITIALIZER;
46 pthread_cond_t g_ws_query_condition = PTHREAD_COND_INITIALIZER;
47 pthread_mutex_t g_ws_query_mutex = PTHREAD_MUTEX_INITIALIZER;
49 bool g_ws_server_exit = false;
50 struct lws_context *g_ws_server_context = NULL;
52 CWebHelperAgentWebSocket* CWebHelperAgentWebSocket::m_current_instance = NULL;
66 struct per_session_data__http {
70 static int callback_http(struct lws *wsi,
71 enum lws_callback_reasons reason,
72 void *user, void *in, size_t len)
77 struct per_session_data__keyboard {
84 static int callback_keyboard(struct lws *wsi,
85 enum lws_callback_reasons reason,
86 void *user, void *in, size_t len);
88 static struct lws_protocols protocols[] = {
92 sizeof(struct per_session_data__http),
98 sizeof(struct per_session_data__keyboard),
105 static int callback_client(struct lws *wsi,
106 enum lws_callback_reasons reason,
107 void *user, void *in, size_t len)
110 case LWS_CALLBACK_CLIENT_ESTABLISHED:
111 LOGD("[ClientTest] Connection established");
114 case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
115 LOGD("[ClientTest] Connection error");
118 case LWS_CALLBACK_CLOSED:
119 LOGD("[ClientTest] Connection closed");
129 int test_client_connection(void)
131 struct lws_context *context = NULL;
132 struct lws_context_creation_info context_info;
133 struct lws_client_connect_info connect_info;
134 struct lws *wsi = NULL;
136 memset(&context_info, 0, sizeof context_info);
137 memset(&connect_info, 0, sizeof(connect_info));
139 const int protocols_num = sizeof(protocols) / sizeof(lws_protocols);
140 static struct lws_protocols client_protocols[protocols_num];
142 memcpy(&client_protocols, protocols, sizeof(protocols));
143 for (int loop = 0; loop < protocols_num - 1; loop++) {
144 client_protocols[loop].callback = callback_client;
147 context_info.port = CONTEXT_PORT_NO_LISTEN;
148 context_info.protocols = protocols;
149 context_info.gid = -1;
150 context_info.uid = -1;
152 context = lws_create_context(&context_info);
153 LOGD("[ClientTest] create_context : %p", context);
154 if (context == NULL) {
158 connect_info.address = "localhost";
159 connect_info.port = WEBSOCKET_PORT;
160 connect_info.path = "/";
161 connect_info.context = context;
162 connect_info.ssl_connection = 0;
163 connect_info.host = connect_info.address;
164 connect_info.origin = connect_info.address;
165 connect_info.ietf_version_or_minus_one = -1;
166 connect_info.protocol = "keyboard-protocol";
168 wsi = lws_client_connect_via_info(&connect_info);
169 LOGD("[ClientTest] wsi created : %p", wsi);
172 lws_service(context, 50);
175 lws_context_destroy(context);
180 static int callback_keyboard(struct lws *wsi,
181 enum lws_callback_reasons reason,
182 void *user, void *in, size_t len)
184 static int last_session_id = 0;
185 const int bufsize = 512;
187 unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + bufsize +
188 LWS_SEND_BUFFER_POST_PADDING];
189 unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
190 struct per_session_data__keyboard *pss = (struct per_session_data__keyboard *)user;
191 CWebHelperAgentWebSocket *agent = CWebHelperAgentWebSocket::get_current_instance();
194 case LWS_CALLBACK_ESTABLISHED:
195 pss->session_id = ++last_session_id;
196 LOGD("LWS_CALLBACK_ESTABLISHED : %p %d", g_ws_server_context, pss->session_id);
198 pss->need_init = false;
199 pss->initialized = false;
200 if (g_ws_server_context) {
201 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
205 case LWS_CALLBACK_CLOSED:
206 LOGD("LWS_CALLBACK_CLOSED : %d", pss->session_id);
209 case LWS_CALLBACK_SERVER_WRITEABLE:
211 /* Ignore valid check since the magic key is not used anymore */
212 if (!pss->valid) pss->valid = true;
214 /* We allow data tranmission only if this client is guaranteed to be valid */
216 pthread_mutex_lock(&g_ws_server_mutex);
217 std::queue<ISE_MESSAGE>& messages = agent->get_send_message_queue();
219 if (pss->need_init && !pss->initialized) {
221 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
222 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_INIT];
223 std::string str = CISEMessageSerializer::serialize(message);
224 SECURE_LOGD("SEND_WEBSOCKET_MESSAGE : %d %s", pss->session_id, str.c_str());
225 n = snprintf((char *)p, bufsize, "%s", str.c_str());
226 /* too small for partial */
227 n = lws_write(wsi, p, n, LWS_WRITE_TEXT);
228 pss->need_init = false;
229 pss->initialized = true;
231 /* One write allowed per one writable callback */
232 if (messages.size() > 0) {
233 ISE_MESSAGE &message = messages.front();
235 if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_INIT]) == 0) {
236 if (pss->initialized) {
239 pss->initialized = true;
243 std::string str = CISEMessageSerializer::serialize(message);
244 SECURE_LOGD("SEND_WEBSOCKET_MESSAGE : %d %s", pss->session_id, str.c_str());
245 n = snprintf((char *)p, bufsize, "%s", str.c_str());
246 /* too small for partial */
247 n = lws_write(wsi, p, n, LWS_WRITE_TEXT);
252 if (messages.size() > 0) {
253 ecore_pipe_write(agent->get_message_pipe(), MESSAGE_LEFT, strlen(MESSAGE_LEFT));
255 pthread_mutex_unlock(&g_ws_server_mutex);
258 LOGE("ERROR %d writing to di socket %d", n, pss->session_id);
261 if (messages.size() > 0) {
262 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
265 LOGD("Rejecting data transmission since client is not valid : %d", pss->session_id);
270 case LWS_CALLBACK_RECEIVE:
272 std::string str = (const char *)in;
273 ISE_MESSAGE message = CISEMessageSerializer::deserialize(str);
275 if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_LOGIN]) == 0) {
277 if (message.values.at(0).compare(CMagicKeyManager::get_magic_key()) == 0) {
278 LOGD("LOGIN successful, validating client");
281 LOGD("LOGIN failed, invalidating client");
287 if (agent->initalized()) {
288 pss->need_init = true;
289 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
293 /* Ignore valid check since the magic key is not used anymore */
294 if (!pss->valid) pss->valid = true;
297 pthread_mutex_lock(&g_ws_server_mutex);
298 std::queue<ISE_MESSAGE>& messages = agent->get_recv_message_queue();
299 messages.push(message);
300 pthread_mutex_unlock(&g_ws_server_mutex);
302 ecore_pipe_write(agent->get_message_pipe(), RECVED_MESSAGE, strlen(RECVED_MESSAGE));
304 /* If we received reply message, let's send signal to wake up our main thread */
305 if (message.type.compare(ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY]) == 0) {
306 pthread_mutex_lock(&g_ws_query_mutex);
307 pthread_cond_signal(&g_ws_query_condition);
308 pthread_mutex_unlock(&g_ws_query_mutex);
311 LOGD("Ignoring data received since client is not valid %d", pss->session_id);
323 void *process_ws_server(void *data)
325 while (!force_exit && !g_ws_server_exit) {
327 gettimeofday(&tv, NULL);
329 if (g_ws_server_context) {
330 lws_service(g_ws_server_context, 50);
332 LOGD("WARNING : g_ws_server_context is NULL");
338 void log_func(int level, const char *line)
341 LOGD("LEVEL : %d , %s", level, line);
345 CWebHelperAgentWebSocket::CWebHelperAgentWebSocket()
347 if (m_current_instance != NULL) {
348 LOGD("WARNING : m_current_instance is NOT NULL");
350 m_current_instance = this;
351 m_message_pipe = NULL;
352 m_initialized = false;
355 CWebHelperAgentWebSocket::~CWebHelperAgentWebSocket()
357 if (m_current_instance == this) {
358 m_current_instance = NULL;
361 if (m_message_pipe) {
362 ecore_pipe_del(m_message_pipe);
363 m_message_pipe = NULL;
367 static void message_pipe_handler(void *data, void *buffer, unsigned int nbyte)
370 if (strncmp((const char*)buffer, RECVED_MESSAGE, strlen(RECVED_MESSAGE)) == 0) {
371 CWebHelperAgentWebSocket *agent = CWebHelperAgentWebSocket::get_current_instance();
373 agent->process_recved_messages();
376 if (g_ws_server_context) {
377 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
379 LOGD("WARNING : g_ws_server_context is NULL");
385 bool CWebHelperAgentWebSocket::init()
389 struct lws_context_creation_info info;
391 memset(&info, 0, sizeof info);
392 info.port = WEBSOCKET_PORT;
394 int log_level = LLL_ERR | LLL_WARN | LLL_DEBUG;
395 lws_set_log_level(log_level, log_func);
398 info.protocols = protocols;
399 info.extensions = NULL;
400 info.ssl_cert_filepath = NULL;
401 info.ssl_private_key_filepath = NULL;
408 /* The WebSocket server is running on a separate thread, and let the thread send a message
409 through this pipe to guarantee thread safety */
410 m_message_pipe = ecore_pipe_add(message_pipe_handler, NULL);
412 /* Let's retry creating server context for a certain number of times */
413 const int max_retry_num = 30;
417 g_ws_server_context = lws_create_context(&info);
418 LOGD("libwebsocket context : %p", g_ws_server_context);
420 } while (g_ws_server_context == NULL && retry_num++ < max_retry_num);
422 pthread_mutex_init(&g_ws_server_mutex, NULL);
424 pthread_mutex_init(&g_ws_query_mutex, NULL);
425 pthread_cond_init(&g_ws_query_condition, NULL);
427 if (g_ws_server_context) {
428 if (pthread_create(&g_ws_server_thread, NULL, &process_ws_server, NULL) != 0) {
429 g_ws_server_thread = (pthread_t)NULL;
433 LOGE("Failed creating server context : %p", g_ws_server_context);
439 m_initialized = true;
441 test_client_connection();
446 bool CWebHelperAgentWebSocket::exit()
450 g_ws_server_exit = true;
452 if (m_message_pipe) {
453 ecore_pipe_del(m_message_pipe);
454 m_message_pipe = NULL;
457 if (g_ws_server_thread) {
458 pthread_join(g_ws_server_thread, NULL);
461 pthread_cond_destroy(&g_ws_query_condition);
462 pthread_mutex_destroy(&g_ws_query_mutex);
464 pthread_mutex_destroy(&g_ws_server_mutex);
466 if (g_ws_server_context) {
467 lws_cancel_service(g_ws_server_context);
468 lws_context_destroy(g_ws_server_context);
469 g_ws_server_context = NULL;
477 void CWebHelperAgentWebSocket::signal(int sig)
483 std::string to_string(T i)
485 std::stringstream ss;
493 void CWebHelperAgentWebSocket::on_init()
496 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
497 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_INIT];
499 pthread_mutex_lock(&g_ws_server_mutex);
500 m_send_message_queue.push(message);
501 pthread_mutex_unlock(&g_ws_server_mutex);
503 if (g_ws_server_context) {
504 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
506 LOGD("WARNING : g_ws_server_context is NULL");
510 void CWebHelperAgentWebSocket::on_exit()
513 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
514 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_EXIT];
516 pthread_mutex_lock(&g_ws_server_mutex);
517 m_send_message_queue.push(message);
518 pthread_mutex_unlock(&g_ws_server_mutex);
520 if (g_ws_server_context) {
521 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
523 LOGD("WARNING : g_ws_server_context is NULL");
527 void CWebHelperAgentWebSocket::on_focus_in(int ic)
530 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
531 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_FOCUS_IN];
532 message.values.push_back(to_string(ic));
534 pthread_mutex_lock(&g_ws_server_mutex);
535 m_send_message_queue.push(message);
536 pthread_mutex_unlock(&g_ws_server_mutex);
538 if (g_ws_server_context) {
539 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
541 LOGD("WARNING : g_ws_server_context is NULL");
545 void CWebHelperAgentWebSocket::on_focus_out(int ic)
548 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
549 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_FOCUS_OUT];
550 message.values.push_back(to_string(ic));
552 pthread_mutex_lock(&g_ws_server_mutex);
553 m_send_message_queue.push(message);
554 pthread_mutex_unlock(&g_ws_server_mutex);
556 if (g_ws_server_context) {
557 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
559 LOGD("WARNING : g_ws_server_context is NULL");
563 void CWebHelperAgentWebSocket::on_show(int ic)
566 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
567 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SHOW];
568 message.values.push_back(to_string(ic));
570 pthread_mutex_lock(&g_ws_server_mutex);
571 m_send_message_queue.push(message);
572 pthread_mutex_unlock(&g_ws_server_mutex);
574 if (g_ws_server_context) {
575 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
577 LOGD("WARNING : g_ws_server_context is NULL");
580 LOGD("put into send message buffer");
583 void CWebHelperAgentWebSocket::on_hide(int ic)
586 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
587 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_HIDE];
588 message.values.push_back(to_string(ic));
590 pthread_mutex_lock(&g_ws_server_mutex);
591 m_send_message_queue.push(message);
592 pthread_mutex_unlock(&g_ws_server_mutex);
594 if (g_ws_server_context) {
595 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
597 LOGD("WARNING : g_ws_server_context is NULL");
601 void CWebHelperAgentWebSocket::on_set_rotation(int degree)
604 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
605 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_ROTATION];
606 message.values.push_back(to_string(degree));
608 pthread_mutex_lock(&g_ws_server_mutex);
609 m_send_message_queue.push(message);
610 pthread_mutex_unlock(&g_ws_server_mutex);
612 if (g_ws_server_context) {
613 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
615 LOGD("WARNING : g_ws_server_context is NULL");
619 void CWebHelperAgentWebSocket::on_update_cursor_position(int ic, int cursor_pos)
622 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
623 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_CURSOR_POSITION];
624 message.values.push_back(to_string(ic));
625 message.values.push_back(to_string(cursor_pos));
627 pthread_mutex_lock(&g_ws_server_mutex);
628 m_send_message_queue.push(message);
629 pthread_mutex_unlock(&g_ws_server_mutex);
631 if (g_ws_server_context) {
632 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
634 LOGD("WARNING : g_ws_server_context is NULL");
638 void CWebHelperAgentWebSocket::on_update_surrounding_text(int ic, const char *text, int cursor)
641 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY];
642 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_SURROUNDING_TEXT];
643 message.values.push_back(to_string(cursor));
644 message.values.push_back(text);
646 pthread_mutex_lock(&g_ws_server_mutex);
647 m_send_message_queue.push(message);
648 pthread_mutex_unlock(&g_ws_server_mutex);
650 if (g_ws_server_context) {
651 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
653 LOGD("WARNING : g_ws_server_context is NULL");
657 void CWebHelperAgentWebSocket::on_update_selection(int ic, const char *text)
660 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY];
661 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_SELECTION];
662 message.values.push_back(text);
664 pthread_mutex_lock(&g_ws_server_mutex);
665 m_send_message_queue.push(message);
666 pthread_mutex_unlock(&g_ws_server_mutex);
668 if (g_ws_server_context) {
669 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
671 LOGD("WARNING : g_ws_server_context is NULL");
675 void CWebHelperAgentWebSocket::on_set_language(unsigned int language)
678 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
679 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_LANGUAGE];
682 for (unsigned int loop = 0;loop < sizeof(ISE_LANGUAGE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
683 if (language == (unsigned int)ISE_LANGUAGE_TYPES[loop].type_value) {
684 message.values.push_back(ISE_LANGUAGE_TYPES[loop].type_string);
690 pthread_mutex_lock(&g_ws_server_mutex);
691 m_send_message_queue.push(message);
692 pthread_mutex_unlock(&g_ws_server_mutex);
694 if (g_ws_server_context) {
695 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
697 LOGD("WARNING : g_ws_server_context is NULL");
702 void CWebHelperAgentWebSocket::on_set_imdata(char *buf, unsigned int len)
705 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
706 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_IMDATA];
707 message.values.push_back(buf);
709 pthread_mutex_lock(&g_ws_server_mutex);
710 m_send_message_queue.push(message);
711 pthread_mutex_unlock(&g_ws_server_mutex);
713 if (g_ws_server_context) {
714 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
716 LOGD("WARNING : g_ws_server_context is NULL");
720 void CWebHelperAgentWebSocket::on_get_imdata(char **buf, unsigned int *len)
723 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY];
724 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_IMDATA];
726 pthread_mutex_lock(&g_ws_server_mutex);
727 m_send_message_queue.push(message);
728 pthread_mutex_unlock(&g_ws_server_mutex);
730 if (g_ws_server_context) {
731 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
733 LOGD("WARNING : g_ws_server_context is NULL");
736 wait_for_reply_message();
738 std::vector<std::string> values;
739 /* Check if we received reply for GET_IMDATA message */
740 if (process_recved_messages_until_reply_found(
741 ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_IMDATA], values)) {
742 if (values.size() > 0 && buf && len) {
743 int string_length = values.at(0).length();
744 (*buf) = new char[string_length + 1];
746 strncpy(*buf, values.at(0).c_str(), string_length);
747 /* Make sure this is a null-terminated string */
748 *(*buf + string_length) = '\0';
749 *len = string_length;
753 LOGD("process_recved_messages_until_reply_found returned FALSE");
755 /* Now process the rest in the recv buffer */
756 process_recved_messages();
759 void CWebHelperAgentWebSocket::on_set_return_key_type(unsigned int type)
762 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
763 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_RETURN_KEY_TYPE];
766 for (unsigned int loop = 0;loop < sizeof(ISE_RETURN_KEY_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
767 if (type == (unsigned int)ISE_RETURN_KEY_TYPES[loop].type_value) {
768 message.values.push_back(ISE_RETURN_KEY_TYPES[loop].type_string);
774 pthread_mutex_lock(&g_ws_server_mutex);
775 m_send_message_queue.push(message);
776 pthread_mutex_unlock(&g_ws_server_mutex);
778 if (g_ws_server_context) {
779 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
781 LOGD("WARNING : g_ws_server_context is NULL");
786 void CWebHelperAgentWebSocket::on_get_return_key_type(unsigned int *type)
789 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY];
790 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_TYPE];
792 pthread_mutex_lock(&g_ws_server_mutex);
793 m_send_message_queue.push(message);
794 pthread_mutex_unlock(&g_ws_server_mutex);
796 if (g_ws_server_context) {
797 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
799 LOGD("WARNING : g_ws_server_context is NULL");
802 wait_for_reply_message();
804 std::vector<std::string> values;
805 /* Check if we received reply for GET_RETURN_KEY_TYPE message */
806 if (process_recved_messages_until_reply_found(
807 ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_TYPE], values)) {
809 for (unsigned int loop = 0;loop < sizeof(ISE_RETURN_KEY_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
810 if (values.at(0).compare(ISE_RETURN_KEY_TYPES[loop].type_string) == 0) {
811 *type = ISE_RETURN_KEY_TYPES[loop].type_value;
816 /* Now process the rest in the recv buffer */
817 process_recved_messages();
820 void CWebHelperAgentWebSocket::on_set_return_key_disable(unsigned int disabled)
823 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
824 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_RETURN_KEY_DISABLE];
827 for (unsigned int loop = 0;loop < sizeof(ISE_TRUEFALSE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
828 if (disabled == (unsigned int)ISE_TRUEFALSE_TYPES[loop].type_value) {
829 message.values.push_back(ISE_TRUEFALSE_TYPES[loop].type_string);
835 pthread_mutex_lock(&g_ws_server_mutex);
836 m_send_message_queue.push(message);
837 pthread_mutex_unlock(&g_ws_server_mutex);
839 if (g_ws_server_context) {
840 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
842 LOGD("WARNING : g_ws_server_context is NULL");
847 void CWebHelperAgentWebSocket::on_get_return_key_disable(unsigned int *disabled)
850 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY];
851 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_DISABLE];
853 pthread_mutex_lock(&g_ws_server_mutex);
854 m_send_message_queue.push(message);
855 pthread_mutex_unlock(&g_ws_server_mutex);
857 if (g_ws_server_context) {
858 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
860 LOGD("WARNING : g_ws_server_context is NULL");
863 wait_for_reply_message();
865 std::vector<std::string> values;
866 /* Check if we received reply for GET_RETURN_KEY_DISABLE message */
867 if (process_recved_messages_until_reply_found(
868 ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_DISABLE], values)) {
870 for (unsigned int loop = 0;loop < sizeof(ISE_TRUEFALSE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
871 if (values.at(0).compare(ISE_TRUEFALSE_TYPES[loop].type_string) == 0) {
872 *disabled = ISE_TRUEFALSE_TYPES[loop].type_value;
877 /* Now process the rest in the recv buffer */
878 process_recved_messages();
881 void CWebHelperAgentWebSocket::on_set_layout(unsigned int layout)
884 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
885 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_LAYOUT];
888 for (unsigned int loop = 0;loop < sizeof(ISE_LAYOUT_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
889 if (layout == (unsigned int)ISE_LAYOUT_TYPES[loop].type_value) {
890 message.values.push_back(ISE_LAYOUT_TYPES[loop].type_string);
896 pthread_mutex_lock(&g_ws_server_mutex);
897 m_send_message_queue.push(message);
898 pthread_mutex_unlock(&g_ws_server_mutex);
900 if (g_ws_server_context) {
901 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
903 LOGD("WARNING : g_ws_server_context is NULL");
908 void CWebHelperAgentWebSocket::on_get_layout(unsigned int *layout)
911 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY];
912 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_LAYOUT];
914 pthread_mutex_lock(&g_ws_server_mutex);
915 m_send_message_queue.push(message);
916 pthread_mutex_unlock(&g_ws_server_mutex);
918 if (g_ws_server_context) {
919 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
921 LOGD("WARNING : g_ws_server_context is NULL");
924 wait_for_reply_message();
926 std::vector<std::string> values;
927 /* Check if we received reply for GET_LAYOUT message */
928 if (process_recved_messages_until_reply_found(
929 ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_LAYOUT], values)) {
931 for (unsigned int loop = 0;loop < sizeof(ISE_LAYOUT_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
932 if (values.at(0).compare(ISE_LAYOUT_TYPES[loop].type_string) == 0) {
933 *layout = ISE_LAYOUT_TYPES[loop].type_value;
938 /* Now process the rest in the recv buffer */
939 process_recved_messages();
942 void CWebHelperAgentWebSocket::on_reset_input_context(int ic)
945 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
946 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_RESET_INPUT_CONTEXT];
947 message.values.push_back(to_string(ic));
949 pthread_mutex_lock(&g_ws_server_mutex);
950 m_send_message_queue.push(message);
951 pthread_mutex_unlock(&g_ws_server_mutex);
953 if (g_ws_server_context) {
954 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
956 LOGD("WARNING : g_ws_server_context is NULL");
960 void CWebHelperAgentWebSocket::on_process_key_event(unsigned int code, unsigned int mask, unsigned int layout, unsigned int *ret)
963 message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY];
964 message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_PROCESS_KEY_EVENT];
965 message.values.push_back(to_string(code));
966 message.values.push_back(to_string(mask));
967 message.values.push_back(to_string(layout));
969 pthread_mutex_lock(&g_ws_server_mutex);
970 m_send_message_queue.push(message);
971 pthread_mutex_unlock(&g_ws_server_mutex);
973 if (g_ws_server_context) {
974 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
976 LOGD("WARNING : g_ws_server_context is NULL");
979 wait_for_reply_message();
981 std::vector<std::string> values;
982 /* Check if we received reply for PROCESS_KEY_EVENT message */
983 if (process_recved_messages_until_reply_found(
984 ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_PROCESS_KEY_EVENT], values)) {
986 for (unsigned int loop = 0;loop < sizeof(ISE_TRUEFALSE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
987 if (values.at(0).compare(ISE_TRUEFALSE_TYPES[loop].type_string) == 0) {
988 *ret = ISE_TRUEFALSE_TYPES[loop].type_value;
993 /* Now process the rest in the recv buffer */
994 process_recved_messages();
997 CWebHelperAgentWebSocket* CWebHelperAgentWebSocket::get_current_instance()
999 return m_current_instance;
1002 std::queue<ISE_MESSAGE>& CWebHelperAgentWebSocket::get_send_message_queue()
1004 return m_send_message_queue;
1007 std::queue<ISE_MESSAGE>& CWebHelperAgentWebSocket::get_recv_message_queue()
1009 return m_recv_message_queue;
1012 Ecore_Pipe* CWebHelperAgentWebSocket::get_message_pipe()
1014 return m_message_pipe;
1017 void CWebHelperAgentWebSocket::wait_for_reply_message()
1019 /* Let's wait for at most REPLY_TIMEOUT */
1021 struct timespec timeout;
1022 gettimeofday(&now, NULL);
1023 timeout.tv_sec = now.tv_sec + REPLY_TIMEOUT.tv_sec;
1024 timeout.tv_nsec = (now.tv_usec + REPLY_TIMEOUT.tv_usec) * 1000;
1025 pthread_mutex_lock(&g_ws_query_mutex);
1026 pthread_cond_timedwait(&g_ws_query_condition, &g_ws_query_mutex, &timeout);
1027 pthread_mutex_unlock(&g_ws_query_mutex);
1030 void CWebHelperAgentWebSocket::process_recved_messages()
1032 pthread_mutex_lock(&g_ws_server_mutex);
1034 while (m_recv_message_queue.size() > 0) {
1035 ISE_MESSAGE &message = m_recv_message_queue.front();
1037 handle_recved_message(message);
1039 m_recv_message_queue.pop();
1042 pthread_mutex_unlock(&g_ws_server_mutex);
1045 bool CWebHelperAgentWebSocket::process_recved_messages_until_reply_found(std::string command, std::vector<std::string> &values)
1049 pthread_mutex_lock(&g_ws_server_mutex);
1051 while (ret == false && m_recv_message_queue.size() > 0) {
1052 ISE_MESSAGE &message = m_recv_message_queue.front();
1054 if (message.command.compare(command) == 0 &&
1055 message.type.compare(ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY]) == 0) {
1057 values = message.values;
1059 handle_recved_message(message);
1061 m_recv_message_queue.pop();
1064 pthread_mutex_unlock(&g_ws_server_mutex);
1069 void CWebHelperAgentWebSocket::handle_recved_message(ISE_MESSAGE &message)
1071 if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_LOG]) == 0) {
1072 std::string str = "";
1073 for (unsigned int loop = 0;loop < message.values.size();loop++) {
1074 str += message.values.at(loop).c_str();
1075 if (loop < message.values.size() - 1) {
1080 } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_COMMIT_STRING]) == 0) {
1081 send_key_event(0xff6b, 0); // Temporarily reset keyboard engine
1083 std::string str = "";
1084 for (unsigned int loop = 0;loop < message.values.size();loop++) {
1085 str += message.values.at(loop).c_str();
1086 if (loop < message.values.size() - 1) {
1090 commit_string(str.c_str());
1091 } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_PREEDIT_STRING]) == 0) {
1092 std::string str = "";
1093 for (unsigned int loop = 0;loop < message.values.size();loop++) {
1094 str += message.values.at(loop).c_str();
1095 if (loop < message.values.size() - 1) {
1099 update_preedit_string(str.c_str());
1100 } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SEND_KEY_EVENT]) == 0) {
1101 if (message.values.size() == 1) {
1102 send_key_event(atoi(message.values.at(0).c_str()), 0);
1104 } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_KEYBOARD_SIZES]) == 0) {
1105 LOGD("ISE_MESSAGE_COMMAND_SET_KEYBOARD_SIZES");
1106 int portrait_width, portrait_height;
1107 int landscape_width, landscape_height;
1109 if (message.values.size() == 4 || message.values.size() == 2) {
1110 portrait_width = atoi(message.values.at(0).c_str());
1111 portrait_height = atoi(message.values.at(1).c_str());
1112 if (message.values.size() == 2) {
1113 landscape_width = portrait_width;
1114 landscape_height = portrait_height;
1116 landscape_width = atoi(message.values.at(2).c_str());
1117 landscape_height = atoi(message.values.at(3).c_str());
1120 LOGD("ISE_MESSAGE_COMMAND_SET_KEYBOARD_SIZES : %d %d %d %d",
1121 portrait_width, portrait_height, landscape_width, landscape_height);
1123 portrait_width, portrait_height, landscape_width, landscape_height);
1125 } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_SELECTION]) == 0) {
1126 LOGD("ISE_MESSAGE_COMMAND_SET_SELECTION");
1127 if (message.values.size() == 2) {
1128 LOGD("ISE_MESSAGE_COMMAND_SET_SELECTION : %d %d",
1129 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1131 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1133 } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_SELECTION]) == 0) {
1134 if (message.values.size() == 0) {
1137 } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_SURROUNDING_TEXT]) == 0) {
1138 LOGD("ISE_MESSAGE_COMMAND_GET_SURROUNDING_TEXT");
1139 if (message.values.size() == 2) {
1140 LOGD("ISE_MESSAGE_COMMAND_GET_SURROUNDING_TEXT : %d %d",
1141 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1142 get_surrounding_text(
1143 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1145 } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_DELETE_SURROUNDING_TEXT]) == 0) {
1146 LOGD("ISE_MESSAGE_COMMAND_DELETE_SURROUNDING_TEXT");
1147 if (message.values.size() == 2) {
1148 LOGD("ISE_MESSAGE_COMMAND_DELETE_SURROUNDING_TEXT : %d %d",
1149 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1150 delete_surrounding_text(
1151 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1153 } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_LOGIN]) == 0) {
1154 if (g_ws_server_context) {
1155 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
1157 LOGD("WARNING : g_ws_server_context is NULL");