4bc9f878b2a6f2d8bfa15ff415d26a4c4dc4e389
[platform/core/uifw/libscl-core.git] / src / legacy_support / websocket.cpp
1 /*
2  * Copyright (c) 2012 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <getopt.h>
22 #include <string.h>
23 #include <sys/time.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <assert.h>
27 #include <Ecore.h>
28 #include <Ecore_IMF.h>
29 #include <dlog.h>
30
31 #include "websocket.h"
32
33 #include <syslog.h>
34 #include <signal.h>
35
36 #include <libwebsockets.h>
37
38 #ifdef WAYLAND
39 #define EFL_BETA_API_SUPPORT
40 #include <Ecore_Wl2.h>
41 #endif
42
43 #define WEBSOCKET_PORT 7681
44
45 #define RECVED_MESSAGE "recved"
46 #define MESSAGE_LEFT "left"
47
48 pthread_t g_ws_server_thread = (pthread_t)NULL;
49 pthread_mutex_t g_ws_server_mutex = PTHREAD_MUTEX_INITIALIZER;
50
51 pthread_cond_t g_ws_query_condition = PTHREAD_COND_INITIALIZER;
52 pthread_mutex_t g_ws_query_mutex = PTHREAD_MUTEX_INITIALIZER;
53
54 bool g_ws_server_exit = false;
55 struct lws_context *g_ws_server_context = NULL;
56
57 CWebHelperAgentWebSocket* CWebHelperAgentWebSocket::m_current_instance = NULL;
58
59 int force_exit = 0;
60
61 enum protocols {
62     /* always first */
63     PROTOCOL_HTTP = 0,
64
65     PROTOCOL_KEYBOARD,
66
67     /* always last */
68     MAX_PROTOCOL_COUNT
69 };
70
71 struct per_session_data__http {
72     int fd;
73 };
74
75 static int callback_http(struct lws *wsi,
76         enum lws_callback_reasons reason,
77         void *user, void *in, size_t len)
78 {
79     return 0;
80 }
81
82 struct per_session_data__keyboard {
83     int session_id;
84     int valid;
85     int need_init;
86     int initialized;
87 };
88
89 static int callback_keyboard(struct lws *wsi,
90         enum lws_callback_reasons reason,
91         void *user, void *in, size_t len);
92
93 static struct lws_protocols protocols[] = {
94     {
95         "http-only",
96         callback_http,
97         sizeof(struct per_session_data__http),
98         0,
99     },
100     {
101         "keyboard-protocol",
102         callback_keyboard,
103         sizeof(struct per_session_data__keyboard),
104         32,
105     },
106     { NULL, NULL, 0, 0 }
107 };
108
109
110 static int callback_client(struct lws *wsi,
111     enum lws_callback_reasons reason,
112     void *user, void *in, size_t len)
113 {
114     switch (reason) {
115     case LWS_CALLBACK_CLIENT_ESTABLISHED:
116         LOGD("[ClientTest] Connection established");
117         break;
118
119     case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
120         LOGD("[ClientTest] Connection error");
121         break;
122
123     case LWS_CALLBACK_CLOSED:
124         LOGD("[ClientTest] Connection closed");
125         break;
126
127     default:
128         break;
129     }
130
131     return 0;
132 }
133
134 int test_client_connection(void)
135 {
136     struct lws_context *context = NULL;
137     struct lws_context_creation_info context_info;
138     struct lws_client_connect_info connect_info;
139     struct lws *wsi = NULL;
140
141     memset(&context_info, 0, sizeof context_info);
142     memset(&connect_info, 0, sizeof(connect_info));
143
144     const int protocols_num = sizeof(protocols) / sizeof(lws_protocols);
145     static struct lws_protocols client_protocols[protocols_num];
146
147     memcpy(&client_protocols, protocols, sizeof(protocols));
148     for (int loop = 0; loop < protocols_num - 1; loop++) {
149         client_protocols[loop].callback = callback_client;
150     }
151
152     context_info.port = CONTEXT_PORT_NO_LISTEN;
153     context_info.protocols = protocols;
154     context_info.gid = -1;
155     context_info.uid = -1;
156
157     context = lws_create_context(&context_info);
158     LOGD("[ClientTest] create_context : %p", context);
159     if (context == NULL) {
160         return -1;
161     }
162
163     connect_info.address = "localhost";
164     connect_info.port = WEBSOCKET_PORT;
165     connect_info.path = "/";
166     connect_info.context = context;
167     connect_info.ssl_connection = 0;
168     connect_info.host = connect_info.address;
169     connect_info.origin = connect_info.address;
170     connect_info.ietf_version_or_minus_one = -1;
171     connect_info.protocol = "keyboard-protocol";
172
173     wsi = lws_client_connect_via_info(&connect_info);
174     LOGD("[ClientTest] wsi created : %p", wsi);
175
176     if (wsi) {
177         lws_service(context, 50);
178     }
179
180     lws_context_destroy(context);
181
182     return 0;
183 }
184
185 static Ecore_Timer *g_flush_server_recv_buffer_timer = NULL;
186 static std::string server_recv_buffer;
187 static Eina_Bool flush_server_recv_buffer_func(void *user)
188 {
189     LOGD("");
190     CWebHelperAgentWebSocket *agent = CWebHelperAgentWebSocket::get_current_instance();
191     struct per_session_data__keyboard *pss = (struct per_session_data__keyboard *)user;
192
193     if (g_flush_server_recv_buffer_timer)
194         ecore_timer_del(g_flush_server_recv_buffer_timer);
195     g_flush_server_recv_buffer_timer = NULL;
196
197     if (!agent || !pss) return ECORE_CALLBACK_CANCEL;
198
199     pthread_mutex_lock(&g_ws_server_mutex);
200     ISE_MESSAGE message = CISEMessageSerializer::deserialize(server_recv_buffer);
201     server_recv_buffer.clear();
202     pthread_mutex_unlock(&g_ws_server_mutex);
203
204     if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_LOGIN]) == 0) {
205         /*
206            if (message.values.at(0).compare(CMagicKeyManager::get_magic_key()) == 0) {
207            LOGD("LOGIN successful, validating client");
208            pss->valid = true;
209            } else {
210            LOGD("LOGIN failed, invalidating client");
211            pss->valid = false;
212            }
213            */
214         pss->valid = true;
215
216         if (agent->initalized()) {
217             pss->need_init = true;
218             ecore_pipe_write(agent->get_message_pipe(), MESSAGE_LEFT, strlen(MESSAGE_LEFT));
219         }
220     }
221
222     /* Ignore valid check since the magic key is not used anymore */
223     if (!pss->valid) pss->valid = true;
224
225     if (pss->valid) {
226         pthread_mutex_lock(&g_ws_server_mutex);
227         std::queue<ISE_MESSAGE>& messages = agent->get_recv_message_queue();
228         messages.push(message);
229         pthread_mutex_unlock(&g_ws_server_mutex);
230
231         ecore_pipe_write(agent->get_message_pipe(), RECVED_MESSAGE, strlen(RECVED_MESSAGE));
232
233         /* If we received reply message, let's send signal to wake up our main thread */
234         if (message.type.compare(ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY]) == 0) {
235             pthread_mutex_lock(&g_ws_query_mutex);
236             pthread_cond_signal(&g_ws_query_condition);
237             pthread_mutex_unlock(&g_ws_query_mutex);
238         }
239     } else {
240         LOGD("Ignoring data received since client is not valid %d", pss->session_id);
241     }
242
243     return ECORE_CALLBACK_CANCEL;
244 }
245
246 static int callback_keyboard(struct lws *wsi,
247         enum lws_callback_reasons reason,
248         void *user, void *in, size_t len)
249 {
250     static int last_session_id = 0;
251     const int bufsize = 512;
252     int n = 0;
253     unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + bufsize +
254                           LWS_SEND_BUFFER_POST_PADDING];
255     unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
256     struct per_session_data__keyboard *pss = (struct per_session_data__keyboard *)user;
257     CWebHelperAgentWebSocket *agent = CWebHelperAgentWebSocket::get_current_instance();
258
259     switch (reason) {
260     case LWS_CALLBACK_ESTABLISHED:
261         pss->session_id = ++last_session_id;
262         LOGD("LWS_CALLBACK_ESTABLISHED : %p %d", g_ws_server_context, pss->session_id);
263         pss->valid = false;
264         pss->need_init = false;
265         pss->initialized = false;
266         if (g_ws_server_context) {
267             ecore_pipe_write(agent->get_message_pipe(), MESSAGE_LEFT, strlen(MESSAGE_LEFT));
268         }
269         break;
270
271     case LWS_CALLBACK_CLOSED:
272         LOGD("LWS_CALLBACK_CLOSED : %d", pss->session_id);
273         break;
274
275     case LWS_CALLBACK_SERVER_WRITEABLE:
276         if (agent) {
277             /* Ignore valid check since the magic key is not used anymore */
278             if (!pss->valid) pss->valid = true;
279
280             /* We allow data tranmission only if this client is guaranteed to be valid */
281             if (pss->valid) {
282                 pthread_mutex_lock(&g_ws_server_mutex);
283                 std::queue<ISE_MESSAGE>& messages = agent->get_send_message_queue();
284
285                 if (pss->need_init && !pss->initialized) {
286                     ISE_MESSAGE message;
287                     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
288                     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_INIT];
289                     std::string str = CISEMessageSerializer::serialize(message);
290                     SECURE_LOGD("SEND_WEBSOCKET_MESSAGE : %d %s", pss->session_id, str.c_str());
291                     n = snprintf((char *)p, bufsize, "%s", str.c_str());
292                     /* too small for partial */
293                     n = lws_write(wsi, p, n, LWS_WRITE_TEXT);
294                     pss->need_init = false;
295                     pss->initialized = true;
296                 } else {
297                     /* One write allowed per one writable callback */
298                     if (messages.size() > 0) {
299                         ISE_MESSAGE &message = messages.front();
300                         bool drop = false;
301                         if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_INIT]) == 0) {
302                             if (pss->initialized) {
303                                 drop = true;
304                             } else {
305                                 pss->initialized = true;
306                             }
307                         }
308                         if (!drop) {
309                             std::string str = CISEMessageSerializer::serialize(message);
310                             SECURE_LOGD("SEND_WEBSOCKET_MESSAGE : %d %s", pss->session_id, str.c_str());
311                             n = snprintf((char *)p, bufsize, "%s", str.c_str());
312                             /* too small for partial */
313                             n = lws_write(wsi, p, n, LWS_WRITE_TEXT);
314                         }
315                         messages.pop();
316                     }
317                 }
318                 if (messages.size() > 0) {
319                     ecore_pipe_write(agent->get_message_pipe(), MESSAGE_LEFT, strlen(MESSAGE_LEFT));
320                 }
321                 pthread_mutex_unlock(&g_ws_server_mutex);
322
323                 if (n < 0) {
324                     LOGE("ERROR %d writing to di socket %d", n, pss->session_id);
325                 }
326
327                 if (messages.size() > 0) {
328                     lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
329                 }
330             } else {
331                 LOGD("Rejecting data transmission since client is not valid : %d", pss->session_id);
332             }
333         }
334         break;
335
336     case LWS_CALLBACK_RECEIVE:
337         if (in) {
338             if (g_flush_server_recv_buffer_timer)
339                 ecore_timer_del(g_flush_server_recv_buffer_timer);
340
341             std::string str = (const char *)in;
342             if (CISEMessageSerializer::valid(str)) {
343                 LOGD("A valid new message received, flush previous buffer");
344                 flush_server_recv_buffer_func((void*)pss);
345             }
346
347             pthread_mutex_lock(&g_ws_server_mutex);
348             server_recv_buffer += str;
349             pthread_mutex_unlock(&g_ws_server_mutex);
350
351             g_flush_server_recv_buffer_timer = ecore_timer_add(0.05, flush_server_recv_buffer_func, (void*)pss);
352         }
353
354         break;
355     default:
356         break;
357     }
358
359     return 0;
360 }
361
362 void *process_ws_server(void *data)
363 {
364     while (!force_exit && !g_ws_server_exit) {
365         struct timeval tv;
366         gettimeofday(&tv, NULL);
367
368         if (g_ws_server_context) {
369             lws_service(g_ws_server_context, 50);
370         } else {
371             LOGD("WARNING : g_ws_server_context is NULL");
372         }
373     }
374     return NULL;
375 }
376
377 void log_func(int level, const char *line)
378 {
379     if (line) {
380         LOGD("LEVEL : %d , %s", level, line);
381     }
382 }
383
384 CWebHelperAgentWebSocket::CWebHelperAgentWebSocket()
385 {
386     if (m_current_instance != NULL) {
387         LOGD("WARNING : m_current_instance is NOT NULL");
388     }
389     m_current_instance = this;
390     m_message_pipe = NULL;
391     m_initialized = false;
392 }
393
394 CWebHelperAgentWebSocket::~CWebHelperAgentWebSocket()
395 {
396     if (m_current_instance == this) {
397         m_current_instance = NULL;
398     }
399
400     if (m_message_pipe) {
401         ecore_pipe_del(m_message_pipe);
402         m_message_pipe = NULL;
403     }
404 }
405
406 static void message_pipe_handler(void *data, void *buffer, unsigned int nbyte)
407 {
408     if (buffer) {
409         if (strncmp((const char*)buffer, RECVED_MESSAGE, strlen(RECVED_MESSAGE)) == 0) {
410             CWebHelperAgentWebSocket *agent = CWebHelperAgentWebSocket::get_current_instance();
411             if (agent) {
412                 agent->process_recved_messages();
413             }
414         } else {
415             if (g_ws_server_context) {
416                 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
417             } else {
418                 LOGD("WARNING : g_ws_server_context is NULL");
419             }
420         }
421     }
422 }
423
424 bool CWebHelperAgentWebSocket::init()
425 {
426     bool ret = true;
427
428     struct lws_context_creation_info info;
429
430     memset(&info, 0, sizeof info);
431     info.port = WEBSOCKET_PORT;
432
433     int log_level = LLL_ERR | LLL_WARN | LLL_DEBUG;
434     lws_set_log_level(log_level, log_func);
435
436     info.iface = NULL;
437     info.protocols = protocols;
438     info.extensions = NULL;
439     info.ssl_cert_filepath = NULL;
440     info.ssl_private_key_filepath = NULL;
441     info.gid = -1;
442     info.uid = -1;
443     info.options = 0;
444
445     ecore_init();
446
447     /* The WebSocket server is running on a separate thread, and let the thread send a message
448         through this pipe to guarantee thread safety */
449     m_message_pipe = ecore_pipe_add(message_pipe_handler, NULL);
450
451     /* Let's retry creating server context for a certain number of times */
452     const int max_retry_num = 30;
453     int retry_num = 0;
454
455     do {
456         g_ws_server_context = lws_create_context(&info);
457         LOGD("libwebsocket context : %p", g_ws_server_context);
458         usleep(100 * 1000);
459     } while (g_ws_server_context == NULL && retry_num++ < max_retry_num);
460
461     pthread_mutex_init(&g_ws_server_mutex, NULL);
462
463     pthread_mutex_init(&g_ws_query_mutex, NULL);
464     pthread_cond_init(&g_ws_query_condition, NULL);
465
466     if (g_ws_server_context) {
467         if (pthread_create(&g_ws_server_thread, NULL, &process_ws_server, NULL) != 0) {
468             g_ws_server_thread = (pthread_t)NULL;
469             ret = false;
470         }
471     } else {
472         LOGE("Failed creating server context : %p", g_ws_server_context);
473         ret = false;
474     }
475
476     on_init();
477
478     m_initialized = true;
479
480     test_client_connection();
481
482     return ret;
483 }
484
485 bool CWebHelperAgentWebSocket::exit()
486 {
487     if (g_flush_server_recv_buffer_timer)
488         ecore_timer_del(g_flush_server_recv_buffer_timer);
489     g_flush_server_recv_buffer_timer = NULL;
490
491     on_exit();
492
493     g_ws_server_exit = true;
494
495     if (m_message_pipe) {
496         ecore_pipe_del(m_message_pipe);
497         m_message_pipe = NULL;
498     }
499
500     if (g_ws_server_thread) {
501         pthread_join(g_ws_server_thread, NULL);
502     }
503
504     pthread_cond_destroy(&g_ws_query_condition);
505     pthread_mutex_destroy(&g_ws_query_mutex);
506
507     pthread_mutex_destroy(&g_ws_server_mutex);
508
509     if (g_ws_server_context) {
510         lws_cancel_service(g_ws_server_context);
511         lws_context_destroy(g_ws_server_context);
512         g_ws_server_context = NULL;
513     }
514
515     ecore_shutdown();
516
517     return true;
518 }
519
520 void CWebHelperAgentWebSocket::signal(int sig)
521 {
522     force_exit = 1;
523 }
524
525 template<class T>
526 std::string to_string(T i)
527 {
528     std::stringstream ss;
529     std::string s;
530     ss << i;
531     s = ss.str();
532
533     return s;
534 }
535
536 void CWebHelperAgentWebSocket::on_init()
537 {
538     ISE_MESSAGE message;
539     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
540     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_INIT];
541
542     pthread_mutex_lock(&g_ws_server_mutex);
543     m_send_message_queue.push(message);
544     pthread_mutex_unlock(&g_ws_server_mutex);
545
546     if (g_ws_server_context) {
547         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
548     } else {
549         LOGD("WARNING : g_ws_server_context is NULL");
550     }
551 }
552
553 void CWebHelperAgentWebSocket::on_exit()
554 {
555     ISE_MESSAGE message;
556     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
557     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_EXIT];
558
559     pthread_mutex_lock(&g_ws_server_mutex);
560     m_send_message_queue.push(message);
561     pthread_mutex_unlock(&g_ws_server_mutex);
562
563     if (g_ws_server_context) {
564         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
565     } else {
566         LOGD("WARNING : g_ws_server_context is NULL");
567     }
568 }
569
570 void CWebHelperAgentWebSocket::on_focus_in(int ic)
571 {
572     ISE_MESSAGE message;
573     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
574     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_FOCUS_IN];
575     message.values.push_back(to_string(ic));
576
577     pthread_mutex_lock(&g_ws_server_mutex);
578     m_send_message_queue.push(message);
579     pthread_mutex_unlock(&g_ws_server_mutex);
580
581     if (g_ws_server_context) {
582         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
583     } else {
584         LOGD("WARNING : g_ws_server_context is NULL");
585     }
586 }
587
588 void CWebHelperAgentWebSocket::on_focus_out(int ic)
589 {
590     ISE_MESSAGE message;
591     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
592     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_FOCUS_OUT];
593     message.values.push_back(to_string(ic));
594
595     pthread_mutex_lock(&g_ws_server_mutex);
596     m_send_message_queue.push(message);
597     pthread_mutex_unlock(&g_ws_server_mutex);
598
599     if (g_ws_server_context) {
600         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
601     } else {
602         LOGD("WARNING : g_ws_server_context is NULL");
603     }
604 }
605
606 void CWebHelperAgentWebSocket::on_show(int ic)
607 {
608     ISE_MESSAGE message;
609     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
610     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SHOW];
611     message.values.push_back(to_string(ic));
612
613     pthread_mutex_lock(&g_ws_server_mutex);
614     m_send_message_queue.push(message);
615     pthread_mutex_unlock(&g_ws_server_mutex);
616
617     if (g_ws_server_context) {
618         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
619     } else {
620         LOGD("WARNING : g_ws_server_context is NULL");
621     }
622
623     LOGD("put into send message buffer");
624 }
625
626 void CWebHelperAgentWebSocket::on_hide(int ic)
627 {
628     ISE_MESSAGE message;
629     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
630     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_HIDE];
631     message.values.push_back(to_string(ic));
632
633     pthread_mutex_lock(&g_ws_server_mutex);
634     m_send_message_queue.push(message);
635     pthread_mutex_unlock(&g_ws_server_mutex);
636
637     if (g_ws_server_context) {
638         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
639     } else {
640         LOGD("WARNING : g_ws_server_context is NULL");
641     }
642 }
643
644 void CWebHelperAgentWebSocket::on_set_rotation(int degree)
645 {
646     ISE_MESSAGE message;
647     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
648     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_ROTATION];
649     message.values.push_back(to_string(degree));
650
651     pthread_mutex_lock(&g_ws_server_mutex);
652     m_send_message_queue.push(message);
653     pthread_mutex_unlock(&g_ws_server_mutex);
654
655     if (g_ws_server_context) {
656         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
657     } else {
658         LOGD("WARNING : g_ws_server_context is NULL");
659     }
660 }
661
662 void CWebHelperAgentWebSocket::on_update_cursor_position(int ic, int cursor_pos)
663 {
664     ISE_MESSAGE message;
665     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
666     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_CURSOR_POSITION];
667     message.values.push_back(to_string(ic));
668     message.values.push_back(to_string(cursor_pos));
669
670     pthread_mutex_lock(&g_ws_server_mutex);
671     m_send_message_queue.push(message);
672     pthread_mutex_unlock(&g_ws_server_mutex);
673
674     if (g_ws_server_context) {
675         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
676     } else {
677         LOGD("WARNING : g_ws_server_context is NULL");
678     }
679 }
680
681 void CWebHelperAgentWebSocket::on_update_surrounding_text(int ic, const char *text, int cursor)
682 {
683     ISE_MESSAGE message;
684     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY];
685     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_SURROUNDING_TEXT];
686     message.values.push_back(to_string(cursor));
687     message.values.push_back(text);
688
689     pthread_mutex_lock(&g_ws_server_mutex);
690     m_send_message_queue.push(message);
691     pthread_mutex_unlock(&g_ws_server_mutex);
692
693     if (g_ws_server_context) {
694         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
695     } else {
696         LOGD("WARNING : g_ws_server_context is NULL");
697     }
698 }
699
700 void CWebHelperAgentWebSocket::on_update_selection(int ic, const char *text)
701 {
702     ISE_MESSAGE message;
703     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY];
704     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_SELECTION];
705     message.values.push_back(text);
706
707     pthread_mutex_lock(&g_ws_server_mutex);
708     m_send_message_queue.push(message);
709     pthread_mutex_unlock(&g_ws_server_mutex);
710
711     if (g_ws_server_context) {
712         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
713     } else {
714         LOGD("WARNING : g_ws_server_context is NULL");
715     }
716 }
717
718 void CWebHelperAgentWebSocket::on_set_language(unsigned int language)
719 {
720     ISE_MESSAGE message;
721     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
722     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_LANGUAGE];
723
724     bool found = false;
725     for (unsigned int loop = 0;loop < sizeof(ISE_LANGUAGE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
726         if (language == (unsigned int)ISE_LANGUAGE_TYPES[loop].type_value) {
727             message.values.push_back(ISE_LANGUAGE_TYPES[loop].type_string);
728             found = true;
729         }
730     }
731
732     if (found) {
733         pthread_mutex_lock(&g_ws_server_mutex);
734         m_send_message_queue.push(message);
735         pthread_mutex_unlock(&g_ws_server_mutex);
736
737         if (g_ws_server_context) {
738             lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
739         } else {
740             LOGD("WARNING : g_ws_server_context is NULL");
741         }
742     }
743 }
744
745 void CWebHelperAgentWebSocket::on_set_imdata(char *buf, unsigned int len)
746 {
747     ISE_MESSAGE message;
748     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
749     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_IMDATA];
750     message.values.push_back(buf);
751
752     pthread_mutex_lock(&g_ws_server_mutex);
753     m_send_message_queue.push(message);
754     pthread_mutex_unlock(&g_ws_server_mutex);
755
756     if (g_ws_server_context) {
757         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
758     } else {
759         LOGD("WARNING : g_ws_server_context is NULL");
760     }
761 }
762
763 void CWebHelperAgentWebSocket::on_get_imdata(char **buf, unsigned int *len)
764 {
765     ISE_MESSAGE message;
766     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY];
767     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_IMDATA];
768
769     pthread_mutex_lock(&g_ws_server_mutex);
770     m_send_message_queue.push(message);
771     pthread_mutex_unlock(&g_ws_server_mutex);
772
773     if (g_ws_server_context) {
774         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
775     } else {
776         LOGD("WARNING : g_ws_server_context is NULL");
777     }
778
779     wait_for_reply_message();
780
781     std::vector<std::string> values;
782     /* Check if we received reply for GET_IMDATA message */
783     if (process_recved_messages_until_reply_found(
784         ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_IMDATA], values)) {
785             if (values.size() > 0 && buf && len) {
786                 int string_length = values.at(0).length();
787                 (*buf) = new char[string_length + 1];
788                 if (*buf) {
789                     strncpy(*buf, values.at(0).c_str(), string_length);
790                     /* Make sure this is a null-terminated string */
791                     *(*buf + string_length) = '\0';
792                     *len = string_length;
793                 }
794             }
795     } else {
796         LOGD("process_recved_messages_until_reply_found returned FALSE");
797     }
798     /* Now process the rest in the recv buffer */
799     process_recved_messages();
800 }
801
802 void CWebHelperAgentWebSocket::on_set_return_key_type(unsigned int type)
803 {
804     ISE_MESSAGE message;
805     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
806     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_RETURN_KEY_TYPE];
807
808     bool found = false;
809     for (unsigned int loop = 0;loop < sizeof(ISE_RETURN_KEY_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
810         if (type == (unsigned int)ISE_RETURN_KEY_TYPES[loop].type_value) {
811             message.values.push_back(ISE_RETURN_KEY_TYPES[loop].type_string);
812             found = true;
813         }
814     }
815
816     if (found) {
817         pthread_mutex_lock(&g_ws_server_mutex);
818         m_send_message_queue.push(message);
819         pthread_mutex_unlock(&g_ws_server_mutex);
820
821         if (g_ws_server_context) {
822             lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
823         } else {
824             LOGD("WARNING : g_ws_server_context is NULL");
825         }
826     }
827 }
828
829 void CWebHelperAgentWebSocket::on_get_return_key_type(unsigned int *type)
830 {
831     ISE_MESSAGE message;
832     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY];
833     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_TYPE];
834
835     pthread_mutex_lock(&g_ws_server_mutex);
836     m_send_message_queue.push(message);
837     pthread_mutex_unlock(&g_ws_server_mutex);
838
839     if (g_ws_server_context) {
840         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
841     } else {
842         LOGD("WARNING : g_ws_server_context is NULL");
843     }
844
845     wait_for_reply_message();
846
847     std::vector<std::string> values;
848     /* Check if we received reply for GET_RETURN_KEY_TYPE message */
849     if (process_recved_messages_until_reply_found(
850         ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_TYPE], values)) {
851             if (type) {
852                 for (unsigned int loop = 0;loop < sizeof(ISE_RETURN_KEY_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
853                     if (values.at(0).compare(ISE_RETURN_KEY_TYPES[loop].type_string) == 0) {
854                         *type = ISE_RETURN_KEY_TYPES[loop].type_value;
855                     }
856                 }
857             }
858     }
859     /* Now process the rest in the recv buffer */
860     process_recved_messages();
861 }
862
863 void CWebHelperAgentWebSocket::on_set_return_key_disable(unsigned int disabled)
864 {
865     ISE_MESSAGE message;
866     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
867     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_RETURN_KEY_DISABLE];
868
869     bool found = false;
870     for (unsigned int loop = 0;loop < sizeof(ISE_TRUEFALSE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
871         if (disabled == (unsigned int)ISE_TRUEFALSE_TYPES[loop].type_value) {
872             message.values.push_back(ISE_TRUEFALSE_TYPES[loop].type_string);
873             found = true;
874         }
875     }
876
877     if (found) {
878         pthread_mutex_lock(&g_ws_server_mutex);
879         m_send_message_queue.push(message);
880         pthread_mutex_unlock(&g_ws_server_mutex);
881
882         if (g_ws_server_context) {
883             lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
884         } else {
885             LOGD("WARNING : g_ws_server_context is NULL");
886         }
887     }
888 }
889
890 void CWebHelperAgentWebSocket::on_get_return_key_disable(unsigned int *disabled)
891 {
892     ISE_MESSAGE message;
893     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY];
894     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_DISABLE];
895
896     pthread_mutex_lock(&g_ws_server_mutex);
897     m_send_message_queue.push(message);
898     pthread_mutex_unlock(&g_ws_server_mutex);
899
900     if (g_ws_server_context) {
901         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
902     } else {
903         LOGD("WARNING : g_ws_server_context is NULL");
904     }
905
906     wait_for_reply_message();
907
908     std::vector<std::string> values;
909     /* Check if we received reply for GET_RETURN_KEY_DISABLE message */
910     if (process_recved_messages_until_reply_found(
911         ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_DISABLE], values)) {
912             if (disabled) {
913                 for (unsigned int loop = 0;loop < sizeof(ISE_TRUEFALSE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
914                     if (values.at(0).compare(ISE_TRUEFALSE_TYPES[loop].type_string) == 0) {
915                         *disabled = ISE_TRUEFALSE_TYPES[loop].type_value;
916                     }
917                 }
918             }
919     }
920     /* Now process the rest in the recv buffer */
921     process_recved_messages();
922 }
923
924 void CWebHelperAgentWebSocket::on_set_layout(unsigned int layout)
925 {
926     ISE_MESSAGE message;
927     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
928     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_LAYOUT];
929
930     bool found = false;
931     for (unsigned int loop = 0;loop < sizeof(ISE_LAYOUT_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
932         if (layout == (unsigned int)ISE_LAYOUT_TYPES[loop].type_value) {
933             message.values.push_back(ISE_LAYOUT_TYPES[loop].type_string);
934             found = true;
935         }
936     }
937
938     if (found) {
939         pthread_mutex_lock(&g_ws_server_mutex);
940         m_send_message_queue.push(message);
941         pthread_mutex_unlock(&g_ws_server_mutex);
942
943         if (g_ws_server_context) {
944             lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
945         } else {
946             LOGD("WARNING : g_ws_server_context is NULL");
947         }
948     }
949 }
950
951 void CWebHelperAgentWebSocket::on_get_layout(unsigned int *layout)
952 {
953     ISE_MESSAGE message;
954     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY];
955     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_LAYOUT];
956
957     pthread_mutex_lock(&g_ws_server_mutex);
958     m_send_message_queue.push(message);
959     pthread_mutex_unlock(&g_ws_server_mutex);
960
961     if (g_ws_server_context) {
962         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
963     } else {
964         LOGD("WARNING : g_ws_server_context is NULL");
965     }
966
967     wait_for_reply_message();
968
969     std::vector<std::string> values;
970     /* Check if we received reply for GET_LAYOUT message */
971     if (process_recved_messages_until_reply_found(
972         ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_LAYOUT], values)) {
973             if (layout) {
974                 for (unsigned int loop = 0;loop < sizeof(ISE_LAYOUT_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
975                     if (values.at(0).compare(ISE_LAYOUT_TYPES[loop].type_string) == 0) {
976                         *layout = ISE_LAYOUT_TYPES[loop].type_value;
977                     }
978                 }
979             }
980     }
981     /* Now process the rest in the recv buffer */
982     process_recved_messages();
983 }
984
985 void CWebHelperAgentWebSocket::on_reset_input_context(int ic)
986 {
987     ISE_MESSAGE message;
988     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
989     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_RESET_INPUT_CONTEXT];
990     message.values.push_back(to_string(ic));
991
992     pthread_mutex_lock(&g_ws_server_mutex);
993     m_send_message_queue.push(message);
994     pthread_mutex_unlock(&g_ws_server_mutex);
995
996     if (g_ws_server_context) {
997         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
998     } else {
999         LOGD("WARNING : g_ws_server_context is NULL");
1000     }
1001 }
1002
1003 void CWebHelperAgentWebSocket::on_process_key_event(unsigned int code, unsigned int mask, unsigned int layout, unsigned int *ret)
1004 {
1005     ISE_MESSAGE message;
1006     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY];
1007     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_PROCESS_KEY_EVENT];
1008     message.values.push_back(to_string(code));
1009     message.values.push_back(to_string(mask));
1010     message.values.push_back(to_string(layout));
1011
1012     pthread_mutex_lock(&g_ws_server_mutex);
1013     m_send_message_queue.push(message);
1014     pthread_mutex_unlock(&g_ws_server_mutex);
1015
1016     if (g_ws_server_context) {
1017         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
1018     } else {
1019         LOGD("WARNING : g_ws_server_context is NULL");
1020     }
1021
1022     wait_for_reply_message();
1023
1024     std::vector<std::string> values;
1025     /* Check if we received reply for PROCESS_KEY_EVENT message */
1026     if (process_recved_messages_until_reply_found(
1027         ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_PROCESS_KEY_EVENT], values)) {
1028             if (ret) {
1029                 for (unsigned int loop = 0;loop < sizeof(ISE_TRUEFALSE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
1030                     if (values.at(0).compare(ISE_TRUEFALSE_TYPES[loop].type_string) == 0) {
1031                         *ret = ISE_TRUEFALSE_TYPES[loop].type_value;
1032                     }
1033                 }
1034             }
1035     }
1036     /* Now process the rest in the recv buffer */
1037     process_recved_messages();
1038 }
1039
1040 CWebHelperAgentWebSocket* CWebHelperAgentWebSocket::get_current_instance()
1041 {
1042     return m_current_instance;
1043 }
1044
1045 std::queue<ISE_MESSAGE>& CWebHelperAgentWebSocket::get_send_message_queue()
1046 {
1047     return m_send_message_queue;
1048 }
1049
1050 std::queue<ISE_MESSAGE>& CWebHelperAgentWebSocket::get_recv_message_queue()
1051 {
1052     return m_recv_message_queue;
1053 }
1054
1055 Ecore_Pipe* CWebHelperAgentWebSocket::get_message_pipe()
1056 {
1057     return m_message_pipe;
1058 }
1059
1060 void CWebHelperAgentWebSocket::wait_for_reply_message()
1061 {
1062     /* Let's wait for at most REPLY_TIMEOUT */
1063     struct timeval now;
1064     struct timespec timeout;
1065     gettimeofday(&now, NULL);
1066     timeout.tv_sec = now.tv_sec + REPLY_TIMEOUT.tv_sec;
1067     timeout.tv_nsec = (now.tv_usec + REPLY_TIMEOUT.tv_usec) * 1000;
1068     pthread_mutex_lock(&g_ws_query_mutex);
1069     pthread_cond_timedwait(&g_ws_query_condition, &g_ws_query_mutex, &timeout);
1070     pthread_mutex_unlock(&g_ws_query_mutex);
1071 }
1072
1073 void CWebHelperAgentWebSocket::process_recved_messages()
1074 {
1075     pthread_mutex_lock(&g_ws_server_mutex);
1076
1077     while (m_recv_message_queue.size() > 0) {
1078         ISE_MESSAGE &message = m_recv_message_queue.front();
1079
1080         handle_recved_message(message);
1081
1082         m_recv_message_queue.pop();
1083     }
1084
1085     pthread_mutex_unlock(&g_ws_server_mutex);
1086 }
1087
1088 bool CWebHelperAgentWebSocket::process_recved_messages_until_reply_found(std::string command, std::vector<std::string> &values)
1089 {
1090     bool ret = false;
1091
1092     pthread_mutex_lock(&g_ws_server_mutex);
1093
1094     while (ret == false && m_recv_message_queue.size() > 0) {
1095         ISE_MESSAGE &message = m_recv_message_queue.front();
1096
1097         if (message.command.compare(command) == 0 &&
1098             message.type.compare(ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY]) == 0) {
1099             ret = true;
1100             values = message.values;
1101         }
1102         handle_recved_message(message);
1103
1104         m_recv_message_queue.pop();
1105     }
1106
1107     pthread_mutex_unlock(&g_ws_server_mutex);
1108
1109     return ret;
1110 }
1111
1112 void CWebHelperAgentWebSocket::handle_recved_message(ISE_MESSAGE &message)
1113 {
1114     static bool _key_event_processing = false;
1115     if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_LOG]) == 0) {
1116         std::string str = "";
1117         for (unsigned int loop = 0;loop < message.values.size();loop++) {
1118             str += message.values.at(loop).c_str();
1119             if (loop < message.values.size() - 1) {
1120                 str += " ";
1121             }
1122         }
1123         log(str.c_str());
1124     } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_COMMIT_STRING]) == 0) {
1125         std::string str = "";
1126         for (unsigned int loop = 0;loop < message.values.size();loop++) {
1127             str += message.values.at(loop).c_str();
1128             if (loop < message.values.size() - 1) {
1129                 str += " ";
1130             }
1131         }
1132         if (_key_event_processing) {
1133             struct timeval tv;
1134             tv.tv_sec = 0;
1135             tv.tv_usec = 50000;
1136             select(0, NULL, NULL, NULL, &tv);
1137             _key_event_processing = false;
1138         }
1139         commit_string(str.c_str());
1140     } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_PREEDIT_STRING]) == 0) {
1141         std::string str = "";
1142         for (unsigned int loop = 0;loop < message.values.size();loop++) {
1143             str += message.values.at(loop).c_str();
1144             if (loop < message.values.size() - 1) {
1145                 str += " ";
1146             }
1147         }
1148         update_preedit_string(str.c_str());
1149     } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SEND_KEY_EVENT]) == 0) {
1150         if (message.values.size() == 1) {
1151             forward_key_event(atoi(message.values.at(0).c_str()));
1152             _key_event_processing = true;
1153         }
1154     } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_KEYBOARD_SIZES]) == 0) {
1155         LOGD("ISE_MESSAGE_COMMAND_SET_KEYBOARD_SIZES");
1156         int portrait_width, portrait_height;
1157         int landscape_width, landscape_height;
1158
1159         if (message.values.size() == 4 || message.values.size() == 2) {
1160             portrait_width = atoi(message.values.at(0).c_str());
1161             portrait_height = atoi(message.values.at(1).c_str());
1162             if (message.values.size() == 2) {
1163                 landscape_width = portrait_width;
1164                 landscape_height = portrait_height;
1165             } else {
1166                 landscape_width = atoi(message.values.at(2).c_str());
1167                 landscape_height = atoi(message.values.at(3).c_str());
1168             }
1169
1170             LOGD("ISE_MESSAGE_COMMAND_SET_KEYBOARD_SIZES : %d %d %d %d",
1171                 portrait_width, portrait_height, landscape_width, landscape_height);
1172
1173 #ifdef WAYLAND
1174             /* Since the full screen IME makes the client application fully obscured,
1175              * when it hides the client receives resume command and try to show IME again.
1176              * So here we are adjusting the height value when the requested keyboard size
1177              * is the same with the screen size, as a workaround */
1178             int scr_w = 0, scr_h = 0;
1179             ecore_wl2_sync();
1180             Ecore_Wl2_Display *ewd = NULL;
1181             if ((ewd = ecore_wl2_connected_display_get(NULL))) {
1182                 ecore_wl2_display_screen_size_get(ewd, &scr_w, &scr_h);
1183
1184                 if (scr_w == portrait_width && scr_h == portrait_height) {
1185                     portrait_height -= 1;
1186                 }
1187                 if (scr_h == landscape_width && scr_w == landscape_height) {
1188                     landscape_height -= 1;
1189                 }
1190             }
1191 #endif
1192
1193             set_keyboard_sizes(
1194                 portrait_width, portrait_height, landscape_width, landscape_height);
1195         }
1196     } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_SELECTION]) == 0) {
1197         LOGD("ISE_MESSAGE_COMMAND_SET_SELECTION");
1198         if (message.values.size() == 2) {
1199             LOGD("ISE_MESSAGE_COMMAND_SET_SELECTION : %d %d",
1200                 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1201             set_selection(
1202                 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1203         }
1204     } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_SELECTION]) == 0) {
1205         if (message.values.size() == 0) {
1206             get_selection();
1207         }
1208     } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_SURROUNDING_TEXT]) == 0) {
1209         LOGD("ISE_MESSAGE_COMMAND_GET_SURROUNDING_TEXT");
1210         if (message.values.size() == 2) {
1211             LOGD("ISE_MESSAGE_COMMAND_GET_SURROUNDING_TEXT : %d %d",
1212                 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1213             get_surrounding_text(
1214                 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1215         }
1216     } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_DELETE_SURROUNDING_TEXT]) == 0) {
1217         LOGD("ISE_MESSAGE_COMMAND_DELETE_SURROUNDING_TEXT");
1218         if (message.values.size() == 2) {
1219             LOGD("ISE_MESSAGE_COMMAND_DELETE_SURROUNDING_TEXT : %d %d",
1220                 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1221             delete_surrounding_text(
1222                 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1223         }
1224     } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_LOGIN]) == 0) {
1225         if (g_ws_server_context) {
1226             lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
1227         } else {
1228             LOGD("WARNING : g_ws_server_context is NULL");
1229         }
1230     }
1231 }