QWO4: some tweaks with diagonals
[mokosuite2:mokowm.git] / src / vkbd.c
1 /*
2  * Mokosuite
3  * Virtual keyboard input window
4  * Copyright (C) 2009-2010 Daniele Ricci <daniele.athome@gmail.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 #include <Edje.h>
22 #include <Evas.h>
23 #include <Ecore_X.h>
24 #include <fakekey/fakekey.h>
25 #include <ctype.h>
26
27 #include "vkbd.h"
28
29 #define LANDSCAPE_INPUT_WIDTH     640
30 #define LANDSCAPE_INPUT_HEIGHT    254 //234
31 #define LANDSCAPE_INPUT_X         0
32 #define LANDSCAPE_INPUT_Y         (480 - LANDSCAPE_INPUT_HEIGHT)
33
34 #define PORTRAIT_INPUT_WIDTH     480
35 #define PORTRAIT_INPUT_HEIGHT    254 //234
36 #define PORTRAIT_INPUT_X         0
37 #define PORTRAIT_INPUT_Y         (640 - PORTRAIT_INPUT_HEIGHT)
38
39 typedef struct {
40     gboolean is_shift_down;
41     gboolean is_mouse_down;
42
43     Evas_Object* kbd;
44     FakeKey* fk;
45     GHashTable* pressed_keys;
46 } vkbd_private_data;
47
48
49 static void each_release_key(gpointer key, gpointer value, gpointer data)
50 {
51     edje_object_signal_emit((Evas_Object *) data, "release_key", (char*) key);
52 }
53
54 static void kbd_key_down(void *data, Evas_Object *obj, const char *emission, const char *source)
55 {
56     wm_input_client* ic = data;
57     vkbd_private_data* priv = ic->private;
58
59     char* key = NULL;
60     char* work = g_strdup(source);
61
62     key = strstr(work, ":");
63     if (!key)
64         key = (char *)work;
65     else
66         key++;
67
68     if (!strcmp(key, "enter")) {
69         // TODO press_shift();
70         // key press!!
71         fakekey_press_keysym(priv->fk, XK_Return, 0);
72         fakekey_release(priv->fk);
73     }
74
75     else if (!strcmp(key, "backspace")) {
76         // key press!!
77         fakekey_press_keysym(priv->fk, XK_BackSpace, 0);
78         fakekey_release(priv->fk);
79     }
80
81     else if (!strcmp(key, "shift")) {
82         // TODO toggle_shift();
83     }
84
85     else if (!strcmp(key, ".?123") || !strcmp(key, "ABC") || !strcmp(key, "#+=") || !strcmp(key, ".?12")) {
86         // lol
87         //pass
88     }
89
90     else if (!strcmp(key, "&")) {
91         //g_string_append(text, "&amp;");
92         //edje_object_part_text_set(obj, "field", text->str);
93         // TODO
94     }
95
96     else if (!strcmp(key, "<")) {
97         //g_string_append(text, "&lt;");
98         //edje_object_part_text_set(obj, "field", text->str);
99         // TODO
100     }
101
102     else if (!strcmp(key, ">")) {
103         //g_string_append(text, "&gt;");
104         //edje_object_part_text_set(obj, "field", text->str);
105         // TODO
106     }
107
108     else {
109         if (priv->is_shift_down) {
110             // TODO release_shift();
111             key[0] = toupper(key[0]);
112         } else {
113             key[0] = tolower(key[0]);
114         }
115
116         // key press!!!
117         g_debug("Sending key press: %s (%c)", key, key[0]);
118         fakekey_press(priv->fk, (unsigned char *) key, 1, 0);
119         fakekey_release(priv->fk);
120     }
121
122     g_free(work);
123 }
124
125 static void kbd_mouse_over_key(void *data, Evas_Object *obj, const char *emission, const char *source)
126 {
127     wm_input_client* ic = data;
128     vkbd_private_data* priv = ic->private;
129
130     // mmm...
131     if (!priv->is_mouse_down || !strstr(source, ":")) return;
132
133     char *work = g_strdup(source);
134     char *part = NULL, *subpart = NULL;
135
136     // sottoparte
137     subpart = (strstr(work, ":") + 1);
138
139     // parte
140     *(subpart-1) = '\0';
141     part = (char *) work;
142
143     if (g_hash_table_lookup(priv->pressed_keys, subpart))
144         return;
145
146     #if 0
147     for k in self.pressed_keys.values():
148         o.signal_emit("release_key", k)
149     self.pressed_keys.clear()
150     self.pressed_keys[subpart] = subpart
151     o.signal_emit("press_key", subpart)
152     #else
153     Evas_Object* part_obj = edje_object_part_swallow_get(obj, part);
154
155     g_hash_table_foreach(priv->pressed_keys, each_release_key, part_obj);
156     g_hash_table_remove_all(priv->pressed_keys);
157     g_hash_table_insert(priv->pressed_keys, g_strdup(subpart), GINT_TO_POINTER(1));
158
159     edje_object_signal_emit(part_obj, "press_key", subpart);
160     #endif
161 }
162
163 static void kbd_mouse_out_key(void *data, Evas_Object *obj, const char *emission, const char *source)
164 {
165     wm_input_client* ic = data;
166     vkbd_private_data* priv = ic->private;
167
168     // mmm...
169     if (!priv->is_mouse_down || !strstr(source, ":")) return;
170
171     char *work = g_strdup(source);
172     char *part = NULL, *subpart = NULL;
173
174     // sottoparte
175     subpart = (strstr(work, ":") + 1);
176
177     // parte
178     *(subpart-1) = '\0';
179     part = (char *) work;
180
181     Evas_Object* part_obj = edje_object_part_swallow_get(obj, part);
182
183     #if 0
184     if subpart in self.pressed_keys:
185         del self.pressed_keys[subpart]
186         o.signal_emit("release_key", subpart)
187     #else
188     if (g_hash_table_lookup(priv->pressed_keys, subpart)) {
189         g_hash_table_remove(priv->pressed_keys, subpart);
190         edje_object_signal_emit(part_obj, "release_key", subpart);
191     }
192     #endif
193 }
194
195 static void kbd_mouse_down_key(void *data, Evas_Object *obj, const char *emission, const char *source)
196 {
197     wm_input_client* ic = data;
198     vkbd_private_data* priv = ic->private;
199
200     // mmm...
201     if (!strstr(source, ":")) return;
202
203     char *work = g_strdup(source);
204     char *part = NULL, *subpart = NULL;
205
206     // sottoparte
207     subpart = (strstr(work, ":") + 1);
208
209     // parte
210     *(subpart-1) = '\0';
211     part = (char *) work;
212
213     priv->is_mouse_down = TRUE;
214
215     if (g_hash_table_lookup(priv->pressed_keys, subpart))
216         return;
217
218     // TODO
219     #if 0
220     for k in self.pressed_keys.values():
221         o.signal_emit("release_key", k)
222     self.pressed_keys.clear()
223     self.pressed_keys[subpart] = subpart
224     #else
225     Evas_Object* part_obj = edje_object_part_swallow_get(obj, part);
226
227     g_hash_table_foreach(priv->pressed_keys, each_release_key, part_obj);
228     g_hash_table_remove_all(priv->pressed_keys);
229     g_hash_table_insert(priv->pressed_keys, g_strdup(subpart), GINT_TO_POINTER(1));
230     #endif
231
232     edje_object_signal_emit(part_obj, "press_key", subpart);
233
234     g_free(work);
235 }
236
237 static void kbd_mouse_up_key(void *data, Evas_Object *obj, const char *emission, const char *source)
238 {
239     wm_input_client* ic = data;
240     vkbd_private_data* priv = ic->private;
241
242     // mmm...
243     if (!strstr(source, ":")) return;
244
245     char *work = g_strdup(source);
246     char *part = NULL, *subpart = NULL;
247
248     // sottoparte
249     subpart = (strstr(work, ":") + 1);
250
251     // parte
252     *(subpart-1) = '\0';
253     part = (char *) work;
254
255     Evas_Object* part_obj = edje_object_part_swallow_get(obj, part);
256
257     priv->is_mouse_down = FALSE;
258
259     // TODO
260     #if 0
261     if subpart in self.pressed_keys:
262         del self.pressed_keys[subpart]
263         o.signal_emit("release_key", subpart)
264         o.signal_emit("activated_key", subpart)
265     #else
266     if (g_hash_table_lookup(priv->pressed_keys, subpart)) {
267         g_hash_table_remove(priv->pressed_keys, subpart);
268
269         edje_object_signal_emit(part_obj, "release_key", subpart);
270         edje_object_signal_emit(part_obj, "activated_key", subpart);
271     }
272     #endif
273 }
274
275 void vkbd_show(wm_input_client* ic)
276 {
277     ecore_evas_show(ic->window);
278 }
279
280 void vkbd_hide(wm_input_client* ic)
281 {
282     ecore_evas_hide(ic->window);
283 }
284
285 /* orientation change */
286 void vkbd_set_orientation(wm_input_client* ic, bool landscape)
287 {
288     g_debug("[%s] old_landscape=%s, new_landscape=%s",
289         __func__, ic->landscape ? "true" : "false", landscape ? "true" : "false");
290
291     if (ic->landscape != landscape) {
292         ic->landscape = landscape;
293
294         if (landscape) {
295             ic->width = LANDSCAPE_INPUT_WIDTH;
296             ic->height = LANDSCAPE_INPUT_HEIGHT;
297             ic->x = LANDSCAPE_INPUT_X;
298             ic->y = LANDSCAPE_INPUT_Y;
299         }
300         else {
301             ic->width = PORTRAIT_INPUT_WIDTH;
302             ic->height = PORTRAIT_INPUT_HEIGHT;
303             ic->x = PORTRAIT_INPUT_X;
304             ic->y = PORTRAIT_INPUT_Y;
305         }
306
307         g_debug("[%s] resizing input window to %dx%d and moving to %dx%d",
308                 __func__, ic->width, ic->height, ic->x, ic->y);
309         ecore_evas_move_resize(ic->window, ic->x, ic->y, ic->width, ic->height);
310
311         vkbd_private_data* priv = ic->private;
312
313         char* edjfile = g_strdup_printf(DATADIR "/mokosuite/wm/vkbd.%s.edj", landscape ? "landscape" : "portrait");
314         edje_object_file_set(priv->kbd, edjfile, "main");
315         g_free(edjfile);
316
317         evas_object_hide(priv->kbd);
318         evas_object_resize(priv->kbd, ic->width, ic->height);
319         evas_object_show(priv->kbd);
320     }
321 }
322
323 wm_input_client* vkbd_create(wm_client* client, bool landscape)
324 {
325     wm_input_client* ic = g_new0(wm_input_client, 1);
326     vkbd_private_data* priv = g_new0(vkbd_private_data, 1);
327
328     ic->client = client;
329     ic->landscape = landscape;
330     ic->private = priv;
331
332     ic->set_orientation = vkbd_set_orientation;
333     ic->show = vkbd_show;
334     ic->hide = vkbd_hide;
335
336     if (landscape) {
337         ic->width = LANDSCAPE_INPUT_WIDTH;
338         ic->height = LANDSCAPE_INPUT_HEIGHT;
339         ic->x = LANDSCAPE_INPUT_X;
340         ic->y = LANDSCAPE_INPUT_Y;
341     }
342     else {
343         ic->width = PORTRAIT_INPUT_WIDTH;
344         ic->height = PORTRAIT_INPUT_HEIGHT;
345         ic->x = PORTRAIT_INPUT_X;
346         ic->y = PORTRAIT_INPUT_Y;
347     }
348
349     g_debug("[%s] Creating input window", __func__);
350     ic->window = ecore_evas_new(NULL, ic->x, ic->y, ic->width, ic->height, NULL);
351     if (!ic->window) {
352         g_warning("[%s] Unable to create input window canvas", __func__);
353         g_free(ic->private);
354         g_free(ic);
355         return NULL;
356     }
357
358     ecore_x_netwm_window_type_set(ecore_evas_software_x11_window_get(ic->window),
359         ECORE_X_WINDOW_TYPE_UTILITY);
360
361     Evas* evas = ecore_evas_get(ic->window);
362
363     priv->kbd = edje_object_add(evas);
364
365     char* edjfile = g_strdup_printf(DATADIR "/mokosuite/wm/vkbd.%s.edj", landscape ? "landscape" : "portrait");
366     edje_object_file_set(priv->kbd, edjfile, "main");
367     g_free(edjfile);
368
369     evas_object_resize(priv->kbd, ic->width, ic->height);
370     evas_object_show(priv->kbd);
371
372     // eventi sulla tastiera
373     edje_object_signal_callback_add(priv->kbd, "key_down", "*", kbd_key_down, ic);
374     edje_object_signal_callback_add(priv->kbd, "mouse_over_key", "*", kbd_mouse_over_key, ic);
375     edje_object_signal_callback_add(priv->kbd, "mouse_out_key", "*", kbd_mouse_out_key, ic);
376     edje_object_signal_callback_add(priv->kbd, "mouse,down,1", "*", kbd_mouse_down_key, ic);
377     edje_object_signal_callback_add(priv->kbd, "mouse,down,1,*", "*", kbd_mouse_down_key, ic);
378     edje_object_signal_callback_add(priv->kbd, "mouse,up,1", "*", kbd_mouse_up_key, ic);
379
380     ecore_evas_title_set(ic->window, "Virtual keyboard");
381     // NON MOSTRARE SUBITO
382
383     /*
384     TODO
385     self.on_mouse_down_add(self.on_mouse_down)
386     self.on_mouse_up_add(self.on_mouse_up)
387     self.on_key_down_add(self.on_key_down)
388     */
389
390     // inizializza fakekey
391     priv->fk = fakekey_init(ecore_x_display_get());
392     g_debug("[%s] FakeKey instance created (%p)", __func__, priv->fk);
393
394     // array tasti premuti
395     priv->pressed_keys = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
396
397     return ic;
398 }