1 /**************************************************************************/
2 /*  Klavaro - a flexible touch typing tutor                               */
3 /*  Copyright (C) from 2005 until 2008 Felipe Castro                      */
4 /*  Copyright (C) from 2009 until 2019 The Free Software Foundation       */
5 /*                                                                        */
6 /*  This program is free software, licensed under the terms of the GNU    */
7 /*  General Public License as published by the Free Software Foundation,  */
8 /*  either version 3 of the License, or (at your option) any later        */
9 /*  version. You should have received a copy of the GNU General Public    */
10 /*  License along with this program. If not,                              */
11 /*  see <https://www.gnu.org/licenses/>.                                  */
12 /**************************************************************************/
13 
14 /* Functions to implement and manage the keyboard editing operations
15  */
16 #include <errno.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <glib.h>
21 #include <glib/gstdio.h>
22 #include <gtk/gtk.h>
23 
24 #include "auxiliar.h"
25 #include "main.h"
26 #include "callbacks.h"
27 #include "translation.h"
28 #include "keyboard.h"
29 
30 #define KEY_DX 35
31 #define KEY_DY 35
32 
33 extern gchar *KEYB_CUSTOM;
34 extern gchar *KEYB_EDIT;
35 
36 //static GtkCssProvider *keyb_css = NULL;
37 GtkCssProvider *keyb_css = NULL;
38 
39 static struct
40 {
41 	gchar *name;
42 	gchar *name_last;
43 	gboolean modified_status;
44 	gunichar lochars[4][KEY_LINE_LEN + 1];
45 	gunichar upchars[4][KEY_LINE_LEN + 1];
46 	GtkWidget *but[4][KEY_LINE_LEN - 1];
47 	GtkWidget *lab[4][KEY_LINE_LEN - 1];
48 	GtkWidget *entry;
49 	struct
50 	{
51 		guint i;
52 		guint j;
53 	} pos;
54 	gint cmb_n;
55 	gint intro_step;
56 } keyb;
57 static guint x0[4] = {0, 49, 59, 43};
58 
59 static struct
60 {
61 	KeybLayout *orig; // Original layouts already defined
62 	gint n_orig;
63 	KeybLayout *cust; // Custom layouts created by the user
64 	gint n_cust;
65 } layouts;
66 
67 /* Constants
68  */
69 const gunichar vowels[] = {
70 	L'a', L'e', L'i', L'o', L'u',
71 	(gunichar) 945,
72 	(gunichar) 949,
73 	(gunichar) 953,
74 	(gunichar) 959,
75 	(gunichar) 965,
76 	(gunichar) 1072,
77 	(gunichar) 1077,
78 	(gunichar) 1080,
79 	(gunichar) 1086,
80 	(gunichar) 1091,
81 	// Tibetan vowels
82 	(gunichar) 0x0F72,
83 	(gunichar) 0x0F74,
84 	(gunichar) 0x0F7A,
85 	(gunichar) 0x0F7C,
86 	L'\0'
87 };
88 
89 /* Diacritic chars should never appear one after another
90  */
91 const gunichar diacritics[] = {
92 	// Urdu diacritics
93 	(gunichar) 0x0640,
94 	(gunichar) 0x064B,
95 	(gunichar) 0x064E,
96 	(gunichar) 0x064F,
97 	(gunichar) 0x0650,
98 	(gunichar) 0x0651,
99 	(gunichar) 0x0654,
100 	(gunichar) 0x0670,
101 	// Tibetan diacritics
102 	(gunichar) 0x0F35,
103 	(gunichar) 0x0F37,
104 	(gunichar) 0x0F71,
105 	(gunichar) 0x0F72,
106 	(gunichar) 0x0F74,
107 	(gunichar) 0x0F7A,
108 	(gunichar) 0x0F7B,
109 	(gunichar) 0x0F7C,
110 	(gunichar) 0x0F7D,
111 	(gunichar) 0x0F7E,
112 	(gunichar) 0x0F80,
113 	(gunichar) 0x0F83,
114 	(gunichar) 0x0F90,
115 	(gunichar) 0x0F91,
116 	(gunichar) 0x0F92,
117 	(gunichar) 0x0F94,
118 	(gunichar) 0x0F95,
119 	(gunichar) 0x0F96,
120 	(gunichar) 0x0F97,
121 	(gunichar) 0x0F98,
122 	(gunichar) 0x0F99,
123 	(gunichar) 0x0F9A,
124 	(gunichar) 0x0F9F,
125 	(gunichar) 0x0FA0,
126 	(gunichar) 0x0FA1,
127 	(gunichar) 0x0FA3,
128 	(gunichar) 0x0FA4,
129 	(gunichar) 0x0FA5,
130 	(gunichar) 0x0FA6,
131 	(gunichar) 0x0FA8,
132 	(gunichar) 0x0FA9,
133 	(gunichar) 0x0FAA,
134 	(gunichar) 0x0FAB,
135 	(gunichar) 0x0FAD,
136 	(gunichar) 0x0FAE,
137 	(gunichar) 0x0FAF,
138 	(gunichar) 0x0FB0,
139 	(gunichar) 0x0FB1,
140 	(gunichar) 0x0FB2,
141 	(gunichar) 0x0FB3,
142 	(gunichar) 0x0FB4,
143 	(gunichar) 0x0FB6,
144 	(gunichar) 0x0FB7,
145 	(gunichar) 0x0FB8,
146 	(gunichar) 0x0FBA,
147 	(gunichar) 0x0FBB,
148 	// Other arabic diacritics
149 	(gunichar) 0x0610,
150 	(gunichar) 0x0611,
151 	(gunichar) 0x0612,
152 	(gunichar) 0x0613,
153 	(gunichar) 0x0614,
154 	(gunichar) 0x0615,
155 	(gunichar) 0x0616,
156 	(gunichar) 0x0617,
157 	(gunichar) 0x0618,
158 	(gunichar) 0x0619,
159 	(gunichar) 0x061A,
160 	(gunichar) 0x064C,
161 	(gunichar) 0x064D,
162 	(gunichar) 0x0652,
163 	(gunichar) 0x0653,
164 	(gunichar) 0x0655,
165 	(gunichar) 0x0656,
166 	(gunichar) 0x0657,
167 	(gunichar) 0x0658,
168 	(gunichar) 0x0659,
169 	(gunichar) 0x065A,
170 	(gunichar) 0x065B,
171 	(gunichar) 0x065C,
172 	(gunichar) 0x065D,
173 	(gunichar) 0x065E,
174 	(gunichar) 0x06D6,
175 	(gunichar) 0x06D7,
176 	(gunichar) 0x06D8,
177 	(gunichar) 0x06D9,
178 	(gunichar) 0x06DA,
179 	(gunichar) 0x06DB,
180 	(gunichar) 0x06DC,
181 	(gunichar) 0x06DF,
182 	(gunichar) 0x06E0,
183 	(gunichar) 0x06E1,
184 	(gunichar) 0x06E2,
185 	(gunichar) 0x06E3,
186 	(gunichar) 0x06E4,
187 	(gunichar) 0x06E7,
188 	(gunichar) 0x06E8,
189 	(gunichar) 0x06EA,
190 	(gunichar) 0x06EB,
191 	(gunichar) 0x06EC,
192 	(gunichar) 0x06ED,
193 	L'\0'
194 };
195 
196 /*******************************************************************************
197  * Interface functions
198  */
199 gchar *
keyb_get_name()200 keyb_get_name ()
201 {
202 	return (keyb.name);
203 }
204 
205 gchar *
keyb_get_name_last()206 keyb_get_name_last ()
207 {
208 	return (keyb.name_last);
209 }
210 
211 void
keyb_set_name(const gchar * name)212 keyb_set_name (const gchar * name)
213 {
214 	g_free (keyb.name_last);
215 	keyb.name_last = g_strdup (keyb.name);
216 	g_free (keyb.name);
217 	keyb.name = g_strdup (name);
218 }
219 
220 void
keyb_init_name(const gchar * name)221 keyb_init_name (const gchar * name)
222 {
223 	keyb.name = g_strdup (name);
224 	keyb.name_last = g_strdup (name);
225 }
226 
227 gunichar
keyb_get_lochars(gint i,gint j)228 keyb_get_lochars (gint i, gint j)
229 {
230 	return (keyb.lochars[i][j]);
231 }
232 
233 gunichar
keyb_get_upchars(gint i,gint j)234 keyb_get_upchars (gint i, gint j)
235 {
236 	return (keyb.upchars[i][j]);
237 }
238 
239 gboolean
keyb_get_modified_status()240 keyb_get_modified_status ()
241 {
242 	return (keyb.modified_status);
243 }
244 
245 void
keyb_set_modified_status(gboolean new_status)246 keyb_set_modified_status (gboolean new_status)
247 {
248 	gtk_widget_set_sensitive (get_wg ("combobox_keyboard_country"), ! new_status);
249 	gtk_widget_set_sensitive (get_wg ("combobox_keyboard_variant"), ! new_status);
250 	gtk_widget_set_sensitive (get_wg ("button_kb_save"), new_status);
251 	keyb.modified_status = new_status;
252 	if (new_status)
253 	{
254 		callbacks_shield_set (TRUE);
255 		gtk_combo_box_set_active (GTK_COMBO_BOX (get_wg ("combobox_keyboard_country")), 0);
256 		gtk_combo_box_set_active (GTK_COMBO_BOX (get_wg ("combobox_keyboard_variant")), -1);
257 		callbacks_shield_set (FALSE);
258 	}
259 }
260 
261 void
keyb_create_virtual_keys()262 keyb_create_virtual_keys ()
263 {
264 	gint i, j;
265 	gchar *hlp;
266 	GtkFixed *fix;
267 	GdkRGBA color;
268 	gchar *css_text;
269 	gchar *tmp;
270 	gchar *tmp2;
271 	gchar chcd;
272 	GtkStyleContext *sc;
273 
274 	/* Set color of keys
275 	 */
276 	if (main_preferences_exist ("colors", "key_fg"))
277 		hlp = main_preferences_get_string ("colors", "key_fg");
278 	else
279 		hlp = g_strdup (KEYB_BLACK);
280 	if (keyb_css == NULL)
281 	{
282 		keyb_css = gtk_css_provider_new ();
283 		css_text = g_strdup ("");
284 		for (chcd = '1'; chcd <= '9'; chcd++)
285 		{
286 			tmp = g_strdup_printf (".key-but%c {background-image: none; background-color: %s; color: %s} "
287 					       ".key-but%c:hover {background-image: none; background-color: white; color: black} "
288 					       ".key-but%c:active {background-image: none; background-color: black; color: white} ",
289 				               chcd, hints_color_from_charcode (chcd), hlp, chcd, chcd);
290 			css_text = g_strdup_printf ("%s%s", css_text, tmp);
291 			g_free (tmp);
292 		}
293 		gtk_css_provider_load_from_data (keyb_css, css_text, -1, NULL);
294 		g_free (css_text);
295 	}
296 	g_free (hlp);
297 
298 	/* Set space key
299 	 */
300 	sc = gtk_widget_get_style_context (get_wg ("but_space"));
301 	gtk_style_context_add_provider (sc, GTK_STYLE_PROVIDER (keyb_css), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
302 	gtk_style_context_add_class (sc, "key-but5");
303 
304 	/* Create and position buttons and labels
305 	 */
306 	fix = GTK_FIXED (get_wg ("fixed_keyboard"));
307 	for (i = 0; i < 4; i++)
308 	{
309 		for (j = 0; j < KEY_LINE_LEN - 1; j++)
310 		{
311 			keyb.but[i][j] = gtk_button_new ();
312 			gtk_fixed_put (fix, keyb.but[i][j], x0[i] + j * KEY_DX, i * KEY_DY);
313 			gtk_widget_set_size_request (keyb.but[i][j], 32, 32);
314   			g_signal_connect_after ((gpointer) keyb.but[i][j], "clicked",
315 				       	G_CALLBACK (on_virtual_key_clicked), NULL);
316   			g_signal_connect_after ((gpointer) keyb.but[i][j], "grab-focus",
317 				       	G_CALLBACK (on_virtual_key_grab_focus), NULL);
318 			keyb.lab[i][j] = gtk_label_new ("0");
319 			gtk_container_add (GTK_CONTAINER (keyb.but[i][j]), keyb.lab[i][j]);
320 
321 			if (i > 0)
322 			{
323 				if (i == 1)
324 				{
325 					if (j > 12)
326 						continue;
327 				}
328 				else
329 				{
330 					if (j > 11)
331 						continue;
332 				}
333 			}
334 			gtk_widget_show (keyb.but[i][j]);
335 			gtk_widget_show (keyb.lab[i][j]);
336 		}
337 	}
338 	gtk_widget_set_size_request (keyb.but[1][12], 53, 32);
339 
340 	/* Key entry little evil
341 	 */
342   	keyb.entry = gtk_entry_new ();
343   	gtk_fixed_put (fix, keyb.entry, 2, 2);
344 	gtk_entry_set_width_chars (GTK_ENTRY (keyb.entry), 1);
345 	gtk_entry_set_max_length (GTK_ENTRY (keyb.entry), 1);
346 	gtk_entry_set_alignment (GTK_ENTRY (keyb.entry), 0.5);
347 	gtk_widget_set_size_request (keyb.entry, 28, 28);
348 	g_object_set (G_OBJECT (keyb.entry), "shadow-type", GTK_SHADOW_NONE, NULL);
349   	g_signal_connect_after ((gpointer) keyb.entry, "changed", G_CALLBACK (on_virtual_key_changed), NULL);
350 }
351 
352 /**********************************************************************
353  * Read the character sets (keyb.lochars[] & keyb.upchars[])
354  * for the keyboard currently selected.
355  */
356 void
keyb_set_chars()357 keyb_set_chars ()
358 {
359 	gint i;
360 	gchar *tmp_name = NULL;
361 	gchar tmp_str[6 * KEY_LINE_LEN + 1];
362 	glong n_itens;
363 	gunichar *uchs;
364 	FILE *fh;
365 
366 	/* Search at home
367 	 */
368 	tmp_name = g_strconcat (main_path_user (), G_DIR_SEPARATOR_S, keyb.name, ".kbd", NULL);
369 	fh = (FILE *) g_fopen (tmp_name, "r");
370 	if (fh == NULL)
371 	{
372 		/* Search at data
373 		 */
374 		g_free (tmp_name);
375 		tmp_name = g_strconcat (main_path_data (), G_DIR_SEPARATOR_S, keyb.name, ".kbd", NULL);
376 		fh = (FILE *) g_fopen (tmp_name, "r");
377 	}
378 	g_free (tmp_name);
379 
380 	/* Success */
381 	if (fh)
382 	{
383 		for (i = 0; i < 4; i++)
384 		{
385 			tmp_name = fgets (tmp_str, 6 * KEY_LINE_LEN + 1, fh);
386 			tmp_str[6 * KEY_LINE_LEN] = '\0';
387 			uchs = g_utf8_to_ucs4_fast (tmp_str, -1, &n_itens);
388 			if (n_itens > KEY_LINE_LEN)
389 				g_error ("invalid keyboard layout: %s\n"
390 					 "invalid line: %i\n"
391 					 "invalid number of chars: %li", keyb.name, i + 1, n_itens);
392 			memcpy (keyb.lochars[i], uchs, (n_itens - 1) * sizeof (gunichar));
393 			g_free (uchs);
394 			for (; n_itens < KEY_LINE_LEN; n_itens++)
395 				keyb.lochars[i][n_itens] = L' ';
396 		}
397 		for (i = 0; i < 4; i++)
398 		{
399 			tmp_name = fgets (tmp_str, 6 * KEY_LINE_LEN + 1, fh);
400 			tmp_str[6 * KEY_LINE_LEN] = '\0';
401 			uchs = g_utf8_to_ucs4_fast (tmp_str, -1, &n_itens);
402 			if (n_itens > KEY_LINE_LEN)
403 				g_error ("invalid keyboard layout: %s\n"
404 					 "invalid line: %i\n"
405 					 "invalid number of chars: %li", keyb.name, i + 5, n_itens);
406 			memcpy (keyb.upchars[i], uchs, (n_itens - 1) * sizeof (gunichar));
407 			g_free (uchs);
408 			for (; n_itens < KEY_LINE_LEN; n_itens++)
409 				keyb.upchars[i][n_itens] = L' ';
410 		}
411 		fclose (fh);
412 
413 		keyb_set_modified_status (FALSE);
414 	}
415 	/*
416 	 * Recursively try defaults
417 	 */
418 	else
419 	{
420 		if (g_str_equal (keyb.name, trans_get_default_keyboard ()))
421 		{
422 			main_preferences_remove ("tutor", "keyboard");
423 			g_error ("couldn't open the default keyboard layout: [%s]", trans_get_default_keyboard ());
424 		}
425 
426 		g_message ("couldn't find the keyboard layout: \"%s\"\n"
427 			   " Opening the default one: \"%s\"", keyb.name, trans_get_default_keyboard ());
428 		main_preferences_set_string ("tutor", "keyboard", trans_get_default_keyboard());
429 		keyb_set_name (trans_get_default_keyboard ());
430 		keyb_set_chars ();
431 		return;
432 	}
433 }
434 
435 /**********************************************************************
436  * Test if chr belongs to the current key set
437  */
keyb_is_inset(gunichar chr)438 gboolean keyb_is_inset (gunichar chr)
439 {
440 	register gint i, j;
441 
442 	for (i = 0; i < 4; i++)
443 		for (j = 0; j <= KEY_LINE_LEN; j++)
444 			if (chr == keyb.lochars[i][j])
445 				return (TRUE);
446 
447 	for (i = 0; i < 4; i++)
448 		for (j = 0; j <= KEY_LINE_LEN; j++)
449 			if (chr == keyb.upchars[i][j])
450 				return (TRUE);
451 	return (FALSE);
452 }
453 
454 /**********************************************************************
455  * Test if chr is a vowel
456  */
457 gboolean
keyb_is_vowel(gunichar chr)458 keyb_is_vowel (gunichar chr)
459 {
460 	gint i;
461 
462 	for (i = 0; vowels[i] != L'\0'; i++)
463 		if (g_unichar_tolower (chr) == vowels[i])
464 			return (TRUE);
465 	return (FALSE);
466 }
467 
468 /**********************************************************************
469  * Test if chr is a diacritic character
470  */
471 gboolean
keyb_is_diacritic(gunichar chr)472 keyb_is_diacritic (gunichar chr)
473 {
474 	gint i;
475 	gunichar *diac_array;
476 
477 	for (i = 0; diacritics[i] != L'\0'; i++)
478 		if (chr == diacritics[i])
479 			return (TRUE);
480 	return (FALSE);
481 }
482 
483 /**********************************************************************
484  * Get the set of available vowels of the keyboard
485  */
486 gint
keyb_get_vowels(gunichar * vows)487 keyb_get_vowels (gunichar * vows)
488 {
489 	gint i;
490 	gint j;
491 	gint k = 0;
492 
493 	for (i = 0; i < 4; i++)
494 		for (j = 0; j < KEY_LINE_LEN; j++)
495 		{
496 			if (keyb_is_vowel (keyb.lochars[i][j]))
497 				vows[k++] = keyb.lochars[i][j];
498 			if (k == 20)
499 				break;
500 		}
501 	if (k == 0)
502 		for (i = j = 0, k = 5; i < 5 && j < 10; i++, j++)
503 		{
504 			for (; keyb_is_diacritic (keyb.lochars[2][j]) && j < 12; j++);
505 			vows[i] = keyb.lochars[2][j];
506 		}
507 	return (k);
508 }
509 
510 /**********************************************************************
511  * Get the set of available consonants of the keyboard
512  */
513 gint
keyb_get_consonants(gunichar * consonants)514 keyb_get_consonants (gunichar * consonants)
515 {
516 	gint i, j;
517 	gint k = 0;
518 	gunichar chr;
519 
520 	for (i = 0; i < 4; i++)
521 		for (j = 0; j < KEY_LINE_LEN; j++)
522 		{
523 			chr = keyb.lochars[i][j];
524 			if (g_unichar_isalpha (chr) && (!keyb_is_vowel (chr)))
525 				consonants[k++] = chr;
526 
527 			chr = g_unichar_tolower (keyb.upchars[i][j]);
528 			if (g_unichar_isalpha (chr) && (!keyb_is_vowel (chr))
529 			    && (chr != keyb.lochars[i][j]))
530 				consonants[k++] = chr;
531 		}
532 	return (k);
533 }
534 
535 /**********************************************************************
536  * Get the set of available symbols of the keyboard
537  */
538 gint
keyb_get_symbols(gunichar * symbols)539 keyb_get_symbols (gunichar * symbols)
540 {
541 	gint i, j;
542 	gint k = 0;
543 	gunichar chr;
544 
545 	for (i = 0; i < 4; i++)
546 		for (j = 0; j < KEY_LINE_LEN; j++)
547 		{
548 			chr = keyb.lochars[i][j];
549 			if (g_unichar_ispunct (chr))
550 				symbols[k++] = chr;
551 
552 			chr = keyb.upchars[i][j];
553 			if (g_unichar_ispunct (chr))
554 				symbols[k++] = chr;
555 		}
556 	return (k);
557 }
558 
559 /**********************************************************************
560  * Get the set of available non-arabic digits in the keyboard
561  */
562 gint
keyb_get_altnums(gunichar * altnums)563 keyb_get_altnums (gunichar * altnums)
564 {
565 	gint i, j;
566 	gint k = 0;
567 	gunichar chr;
568 
569 	for (i = 0; i < 4; i++)
570 		for (j = 0; j < KEY_LINE_LEN; j++)
571 		{
572 			chr = keyb.lochars[i][j];
573 			if (g_unichar_isdigit (chr) && chr > 255)
574 				altnums[k++] = chr;
575 
576 			chr = keyb.upchars[i][j];
577 			if (g_unichar_isdigit (chr) && chr > 255)
578 				altnums[k++] = chr;
579 		}
580 	return (k);
581 }
582 
583 /**********************************************************************
584  * Get the upper case of a letter, only if it's included in the keyboard (by shift)
585  */
586 gunichar
keyb_unichar_toupper(gunichar uchar)587 keyb_unichar_toupper (gunichar uchar)
588 {
589 	gint i,j;
590 	gunichar Uchar;
591 
592 	Uchar = g_unichar_toupper (uchar);
593 	for (i = 0; i < 4; i++)
594 		for (j = 0; j < KEY_LINE_LEN; j++)
595 			if (uchar == keyb.lochars[i][j] && Uchar == keyb.upchars[i][j])
596 				return Uchar;
597 	return uchar;
598 }
599 
600 /**********************************************************************
601  * Save the custom keyboard layout created by the user
602  */
603 void
keyb_save_new_layout()604 keyb_save_new_layout ()
605 {
606 	gint i;
607 	gchar *tmp_name = NULL;
608 	FILE *fh;
609 
610 	assert_user_dir ();
611 	tmp_name = g_strconcat (main_path_user (), G_DIR_SEPARATOR_S, keyb.name, ".kbd", NULL);
612 	fh = (FILE *) g_fopen (tmp_name, "w");
613 	g_free (tmp_name);
614 
615 	for (i = 0; i < 4; i++)
616 	{
617 		tmp_name = g_ucs4_to_utf8 (keyb.lochars[i], KEY_LINE_LEN - 1, NULL, NULL, NULL);
618 		fprintf (fh, "%s\n", tmp_name);
619 		g_free (tmp_name);
620 	}
621 	for (i = 0; i < 4; i++)
622 	{
623 		tmp_name = g_ucs4_to_utf8 (keyb.upchars[i], KEY_LINE_LEN - 1, NULL, NULL, NULL);
624 		fprintf (fh, "%s\n", tmp_name);
625 		g_free (tmp_name);
626 	}
627 	fclose (fh);
628 
629 	keyb_set_modified_status (FALSE);
630 }
631 
632 /**********************************************************************
633  * Remove custom keyboard layout created by the user
634  */
635 void
keyb_remove_user_layout()636 keyb_remove_user_layout ()
637 {
638 	guint active;
639 	gchar *aux;
640 	gchar *tmp_name;
641 	GtkComboBox *cmb;
642 
643 	callbacks_shield_set (TRUE);
644 
645 	cmb = GTK_COMBO_BOX (get_wg ("combobox_keyboard_variant"));
646 	aux = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (cmb));
647 	active = gtk_combo_box_get_active (cmb);
648 	gtk_combo_box_text_remove (GTK_COMBO_BOX_TEXT (cmb), active);
649 
650 	tmp_name = g_strconcat (main_path_user (), G_DIR_SEPARATOR_S, aux, ".kbd", NULL);
651 	g_unlink (tmp_name);
652 	g_free (tmp_name);
653 
654 	keyb_set_keyboard_layouts ();
655 
656 	gtk_combo_box_set_active (cmb, -1);
657 
658 	callbacks_shield_set (FALSE);
659 }
660 
661 
662 /**********************************************************************
663  * Update the virtual keyboard accordingly to its character set and
664  * shift key state.
665  */
666 void
keyb_update_virtual_layout()667 keyb_update_virtual_layout ()
668 {
669 	gint i, j;
670 	gchar ut8[7];
671 	gunichar uch;
672 	gboolean tog_state;
673 	GtkWidget *wg;
674 
675 	wg = get_wg ("toggle_shift1");
676 	tog_state = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (wg));
677 	for (i = 0; i < 4; i++)
678 	{
679 		for (j = 0; j < KEY_LINE_LEN - (i == 0 ? 1 : (i == 1 ? 2 : 3)); j++)
680 		{
681 			uch = tog_state ? keyb.upchars[i][j] : keyb.lochars[i][j];
682 			if (g_unichar_isalpha (uch)
683 			    && g_unichar_tolower (keyb.upchars[i][j]) == keyb.lochars[i][j])
684 				uch = g_unichar_toupper (uch);
685 			ut8[g_unichar_to_utf8 (uch, ut8)] = '\0';
686 			gtk_label_set_text (GTK_LABEL (keyb.lab[i][j]), ut8);
687 		}
688 	}
689 }
690 
691 /* Get a list of .kbd file names in the subdir path, stripping their .kbd extensions
692  */
693 GList *
keyb_get_layout_list_from_path(gchar * path)694 keyb_get_layout_list_from_path (gchar *path)
695 {
696 	gsize name_len;
697 	GDir *dir = NULL;
698 	gchar *dentry = NULL;
699 	GList *files = NULL;
700 
701 	dir = g_dir_open (path, 0, NULL);
702 	if (dir == NULL)
703 		g_error ("keyb_get_layout_list_from_path ():\n\tCould not find this directory:\n\t%s\n", path);
704 
705 	while ( (dentry = g_strdup (g_dir_read_name (dir))) )
706 	{
707 		name_len = strlen (dentry);
708 		if (name_len > 255 || name_len < 5)
709 		{
710 			g_free (dentry);
711 			continue;
712 		}
713 
714 		if (! g_str_has_suffix (dentry, ".kbd"))
715 		{
716 			g_free (dentry);
717 			continue;
718 		}
719 
720 		dentry[name_len - 4] = '\0';
721 		if (g_str_equal (dentry, ".tmp"))
722 		{
723 			g_free (dentry);
724 			continue;
725 		}
726 		files = g_list_insert_sorted (files, dentry, compare_string_function);
727 	}
728 	g_dir_close (dir);
729 
730 	return (files);
731 }
732 
733 /* Get the country code from a keyboard name
734  */
735 gchar *
keyb_get_country_code(const gchar * kbd)736 keyb_get_country_code (const gchar *kbd)
737 {
738 	gchar *code = NULL;
739 
740 	code = strchr (kbd, '_');
741 	if (code)
742 		code = strdup (code + 1);
743 	else
744 		code = strdup ("xx");
745 	code[2] = '\0';
746 
747 	return code;
748 }
749 
750 
751 /* Get the country from a keyboard name
752  */
753 gchar *
keyb_get_country(const gchar * kbd)754 keyb_get_country (const gchar *kbd)
755 {
756 	gchar *country = NULL;
757 	gchar *code = NULL;
758 
759 	code = keyb_get_country_code (kbd);
760 	country = g_strdup (trans_code_to_country (code));
761 	g_free (code);
762 
763 	return country;
764 }
765 
766 /* Get the variant from a keyboard name
767  */
768 gchar *
keyb_get_variant(const gchar * kbd)769 keyb_get_variant (const gchar *kbd)
770 {
771 	gchar *begin;
772 	gchar *end;
773 
774 	begin = g_strdup (kbd);
775 	end = strchr (begin, '_');
776 	if (end == NULL)
777 		return begin;
778 	*end = '\0';
779 	end++;
780 	end = strchr (end, '_');
781 	if (end == NULL)
782 		return begin;
783 	end = g_strconcat (begin, end, NULL);
784 	g_free (begin);
785 
786 	return end;
787 }
788 
789 /* Set the array of available keyboard layouts
790  */
791 #define LAYOUT_BLOCK 64
792 void
keyb_set_keyboard_layouts()793 keyb_set_keyboard_layouts ()
794 {
795 	static gboolean init = FALSE;
796 	gchar *data;
797 	gint i;
798 	GList *files;
799 
800 	if (! init)
801 	{
802 
803 		/* Read original layouts just once, now.
804 		 */
805 		files = keyb_get_layout_list_from_path (main_path_data ());
806 		layouts.n_orig = g_list_length (files);
807 		layouts.orig = g_malloc (layouts.n_orig * sizeof (KeybLayout));
808 		//g_printf ("==> Data dir: %s\n", main_path_data ());
809 		for (i = 0; i < layouts.n_orig; i++)
810 		{
811 			data = g_list_nth_data (files, i);
812 			//g_printf ("kb(%i): %s\n", i, data);
813 			layouts.orig[i].name = data;
814 			layouts.orig[i].country = keyb_get_country (data);
815 			layouts.orig[i].variant = keyb_get_variant (data);
816 			//g_printf ("kb(%i): %s\t", i, layouts.orig[i].name);
817 			//g_printf ("%s\t", layouts.orig[i].country);
818 			//g_printf ("%s\n", layouts.orig[i].variant);
819 		}
820 		g_list_free (files);
821 
822 		init = TRUE;
823 		layouts.n_cust = 0;
824 		layouts.cust = g_malloc (LAYOUT_BLOCK * sizeof (KeybLayout));
825 	}
826 
827 	/*
828 	 * Reads the list of custom files
829 	 */
830 	for (i = 0; i < layouts.n_cust; i++)
831 		g_free (layouts.cust[i].name);
832 	assert_user_dir ();
833 	files = keyb_get_layout_list_from_path (main_path_user ());
834 	layouts.n_cust = g_list_length (files);
835 	if (layouts.n_cust == 0)
836 		return;
837 	if (layouts.n_cust > LAYOUT_BLOCK)
838 		layouts.cust = g_realloc (layouts.cust, layouts.n_cust * sizeof (KeybLayout));
839 	for (i = 0; i < layouts.n_cust; i++)
840 	{
841 		data = g_list_nth_data (files, i);
842 		layouts.cust[i].name = data;
843 		//g_printf ("kb(%i): %s\n", i, layouts.cust[i].name);
844 	}
845 	g_list_free (files);
846 }
847 
848 void
keyb_update_from_variant(gchar * cmb_country,gchar * cmb_variant)849 keyb_update_from_variant (gchar *cmb_country, gchar *cmb_variant)
850 {
851 	gint i;
852 	gchar *country;
853 	gchar *variant;
854 	GtkComboBox *cmb;
855 
856 	cmb = GTK_COMBO_BOX (get_wg (cmb_country));
857 	country = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (cmb));
858 	if (country == NULL)
859 		return;
860 
861 	cmb = GTK_COMBO_BOX (get_wg (cmb_variant));
862 	variant = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (cmb));
863 	if (variant == NULL)
864 	{
865 		g_free (country);
866 		return;
867 	}
868 
869 	callbacks_shield_set (TRUE);
870 
871 	if (g_str_equal (country, KEYB_CUSTOM))
872 	{
873 		/* Update the keyboard for a custom layout
874 		 */
875 		if (! g_str_equal (variant, KEYB_EDIT))
876 		{
877 			keyb_set_name (variant);
878 			keyb_set_chars ();
879 			keyb_update_virtual_layout ();
880 		}
881 	}
882 	else
883 	{
884 		/* Update it for a original layout
885 		 */
886 		for (i = 0; i < layouts.n_orig; i++)
887 		{
888 			if (g_str_equal (layouts.orig[i].country, country))
889 				if (g_str_equal (layouts.orig[i].variant, variant))
890 					break;
891 		}
892 
893 		if (i == layouts.n_orig)
894 			g_warning ("selected unavailable keyboard layout.");
895 		else
896 		{
897 			keyb_set_name (layouts.orig[i].name);
898 			keyb_set_chars ();
899 			keyb_update_virtual_layout ();
900 		}
901 	}
902 
903 	g_free (country);
904 	g_free (variant);
905 
906 	callbacks_shield_set (FALSE);
907 }
908 
909 void
keyb_set_combo_kbd_variant(gchar * cmb_country,gchar * cmb_variant)910 keyb_set_combo_kbd_variant (gchar *cmb_country, gchar *cmb_variant)
911 {
912 	gint i;
913 	gint n;
914 	gchar *country_txt;
915 	gboolean valid;
916 	GtkComboBox *cmb;
917 	GtkTreeModel *tmd;
918 	GtkTreeIter iter;
919 
920 	callbacks_shield_set (TRUE);
921 
922 	/* Clear the combo variant
923 	 */
924 	cmb = GTK_COMBO_BOX (get_wg (cmb_variant));
925 	tmd = gtk_combo_box_get_model (cmb);
926 	n = 0;
927 	valid = gtk_tree_model_get_iter_first (tmd, &iter);
928 	while (valid)
929 	{
930 		n++;
931 		valid = gtk_tree_model_iter_next (tmd, &iter);
932 	}
933 	for (i = 0; i < n; i++)
934 		gtk_combo_box_text_remove (GTK_COMBO_BOX_TEXT (cmb), 0);
935 
936 	/* Get the selected country text
937 	 */
938 	country_txt = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (get_wg (cmb_country)));
939 	if (country_txt == NULL)
940 	{
941 		g_warning ("Country combo not set, so nothing done with variant combo.");
942 		callbacks_shield_set (FALSE);
943 		return;
944 	}
945 
946 	/* Set the original variants for the selected country */
947 	if (! g_str_equal (country_txt, KEYB_CUSTOM))
948 	{
949 		gchar *current;
950 
951 		n = 0;
952 		for (i = 0; i < layouts.n_orig; i++)
953 		{
954 			if (g_str_equal (layouts.orig[i].country, country_txt))
955 			{
956 				gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (cmb), layouts.orig[i].variant);
957 				n++;
958 			}
959 		}
960 
961 		current = keyb_get_variant (keyb.name);
962 		for (i = 0; i < n; i++)
963 		{
964 			gchar *variant;
965 
966 			gtk_combo_box_set_active (cmb, i);
967 			variant = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (cmb));
968 			if (g_str_equal (variant, current))
969 			{
970 				g_free (variant);
971 				break;
972 			}
973 			g_free (variant);
974 		}
975 
976 		if (i == n)
977 		{
978 			if (n > 0)
979 				gtk_combo_box_set_active (cmb, 0);
980 			else
981 				gtk_combo_box_set_active (cmb, -1);
982 		}
983 
984 		if (n > 1)
985 			gtk_widget_set_sensitive (get_wg (cmb_variant), TRUE);
986 		else
987 			gtk_widget_set_sensitive (get_wg (cmb_variant), FALSE);
988 
989 		g_free (current);
990 
991 	}
992 	/* Set custom layouts in the variant combo */
993 	else
994 	{
995 		n = 0;
996 		if (g_str_equal (cmb_variant, "combobox_kbd_variant"))
997 		{
998 			gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (cmb), KEYB_EDIT);
999 			n++;
1000 		}
1001 		for (i = 0; i < layouts.n_cust; i++)
1002 		{
1003 			gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (cmb), layouts.cust[i].name);
1004 			n++;
1005 		}
1006 
1007 		for (i = 0; i < n; i++)
1008 		{
1009 			gchar *variant;
1010 
1011 			gtk_combo_box_set_active (cmb, i);
1012 			variant = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (cmb));
1013 			if (g_str_equal (variant, keyb.name))
1014 			{
1015 				g_free (variant);
1016 				break;
1017 			}
1018 			g_free (variant);
1019 		}
1020 
1021 		if (i == n)
1022 		{
1023 			if (n > 1)
1024 				gtk_combo_box_set_active (cmb, 1);
1025 			else if (! gtk_widget_get_visible (get_wg ("window_keyboard")))
1026 			{
1027 				gtk_combo_box_set_active (cmb, 0);
1028 				keyb_mode_edit ();
1029 			}
1030 		}
1031 
1032 		if (layouts.n_cust > 0)
1033 			gtk_widget_set_sensitive (get_wg (cmb_variant), TRUE);
1034 		else
1035 			gtk_widget_set_sensitive (get_wg (cmb_variant), FALSE);
1036 	}
1037 	g_free (country_txt);
1038 
1039 	keyb_update_from_variant (cmb_country, cmb_variant);
1040 
1041 	callbacks_shield_set (FALSE);
1042 }
1043 
1044 void
keyb_set_combo_kbd(gchar * cmb_country,gchar * cmb_variant)1045 keyb_set_combo_kbd (gchar *cmb_country, gchar *cmb_variant)
1046 {
1047 	static gboolean init = FALSE;
1048 	gchar *tmp;
1049 	gint i, j;
1050 	GtkComboBox *cmb;
1051 
1052 	callbacks_shield_set (TRUE);
1053 
1054 	if (! main_preferences_exist ("tutor", "keyboard"))
1055 		main_preferences_set_string ("tutor", "keyboard", trans_get_default_keyboard ());
1056 
1057 	if (init == FALSE)
1058 	{
1059 		tmp = main_preferences_get_string ("tutor", "keyboard");
1060 		if (tmp == NULL)
1061 			g_error ("Unexpected keyboard layout, NULL");
1062 		keyb_init_name (tmp);
1063 		keyb_set_chars ();
1064 		init = TRUE;
1065 		g_free (tmp);
1066 	}
1067 
1068 	keyb_set_keyboard_layouts (); // if already initialized, this sets only the custom layouts
1069 
1070 	cmb = GTK_COMBO_BOX (get_wg (cmb_country));
1071 	gtk_combo_box_text_remove (GTK_COMBO_BOX_TEXT (cmb), 0);
1072 	keyb.cmb_n = 0;
1073 	for (i = 0; i < layouts.n_orig; i++)
1074 	{
1075 		j = i - 1;
1076 		while (j >= 0)
1077 		{
1078 			if (g_str_equal (layouts.orig[i].country, layouts.orig[j].country))
1079 				break;
1080 			j--;
1081 		}
1082 		if (j < 0)
1083 		{
1084 			gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (cmb), layouts.orig[i].country);
1085 			keyb.cmb_n++;
1086 		}
1087 	}
1088 	gtk_combo_box_text_prepend_text (GTK_COMBO_BOX_TEXT (cmb), KEYB_CUSTOM);
1089 	keyb.cmb_n++;
1090 
1091 	keyb_update_combos (cmb_country, cmb_variant);
1092 
1093 	callbacks_shield_set (FALSE);
1094 }
1095 
1096 void
keyb_update_combos(gchar * cmb_country,gchar * cmb_variant)1097 keyb_update_combos (gchar *cmb_country, gchar *cmb_variant)
1098 {
1099 	gint i;
1100 	GtkComboBox *cmb;
1101 
1102 	callbacks_shield_set (TRUE);
1103 
1104 	cmb = GTK_COMBO_BOX (get_wg (cmb_country));
1105 
1106 	for (i = 0; i < layouts.n_orig; i++)
1107 	{
1108 		if (g_str_equal (keyb.name, layouts.orig[i].name))
1109 			break;
1110 	}
1111 	if (i < layouts.n_orig)
1112 	{
1113 		gchar *country;
1114 		gchar *current;
1115 
1116 		/* Set original */
1117 		for (i = 1; i < keyb.cmb_n; i++)
1118 		{
1119 
1120 			gtk_combo_box_set_active (cmb, i);
1121 			country = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (cmb));
1122 			current = keyb_get_country (keyb.name);
1123 			if (g_str_equal (country, current))
1124 			{
1125 				g_free (country);
1126 				g_free (current);
1127 				break;
1128 			}
1129 			g_free (country);
1130 			g_free (current);
1131 		}
1132 		if (i == keyb.cmb_n)
1133 			gtk_combo_box_set_active (cmb, 0);
1134 	}
1135 	else 	/* Set custom */
1136 		gtk_combo_box_set_active (cmb, 0);
1137 
1138 	keyb_set_combo_kbd_variant (cmb_country, cmb_variant);
1139 
1140 	callbacks_shield_set (FALSE);
1141 }
1142 
1143 void
keyb_intro_step_next()1144 keyb_intro_step_next ()
1145 {
1146 	if (keyb.intro_step < 7)
1147 		keyb_intro_step (++keyb.intro_step);
1148 }
1149 
1150 void
keyb_intro_step_previous()1151 keyb_intro_step_previous ()
1152 {
1153 	if (keyb.intro_step > 0)
1154 		keyb_intro_step (--keyb.intro_step);
1155 }
1156 
1157 void
keyb_intro_step(gint step)1158 keyb_intro_step (gint step)
1159 {
1160 	gchar *intro00;
1161 	GtkLabel *tit;
1162 	GtkLabel *tx1;
1163 	GtkLabel *tx2;
1164 	GtkTextBuffer *buffer;
1165 	GtkWidget *wg;
1166 
1167 	static gchar *intro01 = NULL;
1168 	static gchar *intro02 = NULL;
1169 	static gchar *intro03 = NULL;
1170 	static gchar *intro04 = NULL;
1171 	static gchar *intro05 = NULL;
1172 	static gchar *intro06 = NULL;
1173 	static gchar *intro07 = NULL;
1174 	static gchar *intro08 = NULL;
1175 	static gchar *intro09 = NULL;
1176 	static gchar *intro10 = NULL;
1177 	static gchar *intro11 = NULL;
1178 
1179 	if (intro01 == NULL)
1180 	{
1181 		intro01 = g_strdup (_("Correct positioning of the hands and fingers is very important to efficient typing. "
1182 	"You will learn faster and type better if you follow the next recommendations."));
1183 		intro02 = g_strdup (_(
1184 	"The index-finger tips rest over each of the two keys which have a small raised mark, "
1185 	"in the center of the keyboard."));
1186 		intro03 = g_strdup (_(
1187 	"These marks function as 'tactile hooks' for your fingers to remain at the correct position. "
1188 	"This way, with a little experience, you will not need to look at the keyboard to see if your "
1189 	"fingers are properly positioned."));
1190 		intro04 = g_strdup (_(
1191 	"The tips of the other fingers lie naturally beside the index ones, "
1192 	"over the keys on the same row of the keyboard."));
1193 		intro05 = g_strdup (_(
1194 	"The outside edges of your thumbs rest over the space bar."));
1195 		intro06 = g_strdup (_(
1196 	"The part of the hands closest to the wrist (the base) rest over the table, "
1197 	"outside the keyboard. Without this kind of support the arms would quickly tire."));
1198 		intro07 = g_strdup (_(
1199 	"This is referred to as the home position for the hands. "
1200 	"From it the fingers move all over the keyboard, "
1201 	"reaching all the keys as naturally and quickly as possible. "
1202 	"To reach this goal one uses a specific relation between each key and finger. "
1203 	"This relation will be learned gradually as you complete the basic course."));
1204 		intro08 = g_strdup (_(
1205 	"When learning the relation between fingers and keys, "
1206 	"it is very important that you only move the finger which must press the key "
1207 	"and allow all other fingers to remain in the home position."));
1208 		intro09 = g_strdup (_(
1209 	"After memorizing this relationship, you can relax the previous rule some, "
1210 	"so that you can attain greater speed while typing."));
1211 		intro10 = g_strdup (_(
1212 	"The shift keys are used for capital letters and for some symbols. "
1213 	"To get a shifted key input you should first use the small finger of the opposite hand. "
1214 	"Just keep it in the closest Shift while reaching the target key with the other hand."));
1215 		intro11 = g_strdup (_(
1216 	"You should be prepared to start training with the basic course. "
1217 	"It will take effort and patience to be successful as a typist. "
1218 	"We trust you have these and look forward to your success!"));
1219 	}
1220 
1221 	tit = GTK_LABEL (get_wg ("label_keyboard_title"));
1222 	tx1 = GTK_LABEL (get_wg ("label_keyboard_text_1"));
1223 	tx2 = GTK_LABEL (get_wg ("label_keyboard_text_2"));
1224 
1225 	buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (get_wg ("textview_keyboard")));
1226 
1227 	intro00 = g_strdup_printf (_("Step %i"), step);
1228 	switch (step)
1229 	{
1230 	case 0:	/* Recommendations */
1231 		gtk_label_set_text (tit, _("To position the hands"));
1232         	gtk_text_buffer_set_text (buffer, intro01, -1);
1233 		gtk_widget_grab_focus (get_wg ("button_keyboard_next"));
1234 		keyb_set_sensitive (TRUE);
1235 		hints_demo_fingers (0);
1236 		break;
1237 	case 1: /* Index fingers */
1238 		gtk_label_set_text (tit, intro00);
1239         	gtk_text_buffer_set_text (buffer, intro02, -1);
1240         	gtk_text_buffer_insert_at_cursor (buffer, "\n", -1);
1241         	gtk_text_buffer_insert_at_cursor (buffer, intro03, -1);
1242 		keyb_set_sensitive (FALSE);
1243 		gtk_widget_set_sensitive (keyb.but[2][3], TRUE);
1244 		gtk_widget_set_sensitive (keyb.but[2][6], TRUE);
1245 		hints_demo_fingers (1000);
1246 		break;
1247 	case 2: /* Fingers beside index */
1248 		gtk_label_set_text (tit, intro00);
1249         	gtk_text_buffer_set_text (buffer, intro04, -1);
1250 		keyb_set_sensitive (FALSE);
1251 		gtk_widget_set_sensitive (keyb.but[2][0], TRUE);
1252 		gtk_widget_set_sensitive (keyb.but[2][1], TRUE);
1253 		gtk_widget_set_sensitive (keyb.but[2][2], TRUE);
1254 		gtk_widget_set_sensitive (keyb.but[2][7], TRUE);
1255 		gtk_widget_set_sensitive (keyb.but[2][8], TRUE);
1256 		gtk_widget_set_sensitive (keyb.but[2][9], TRUE);
1257 		hints_demo_fingers (1000/3);
1258 		break;
1259 	case 3: /* Thumbs and wrists */
1260 		gtk_label_set_text (tit, intro00);
1261         	gtk_text_buffer_set_text (buffer, intro05, -1);
1262         	gtk_text_buffer_insert_at_cursor (buffer, "\n", -1);
1263         	gtk_text_buffer_insert_at_cursor (buffer, intro06, -1);
1264 		keyb_set_sensitive (FALSE);
1265 		gtk_widget_set_sensitive (get_wg ("but_space"), TRUE);
1266 		hints_demo_fingers (0);
1267 		gtk_widget_grab_focus (get_wg ("but_space"));
1268 		hints_update_from_button (GTK_BUTTON (get_wg ("but_space")));
1269 		break;
1270 	case 4: /* The home position */
1271 		gtk_label_set_text (tit, intro00);
1272         	gtk_text_buffer_set_text (buffer, intro07, -1);
1273 		keyb_set_sensitive (FALSE);
1274 		gtk_widget_set_sensitive (keyb.but[2][0], TRUE);
1275 		gtk_widget_set_sensitive (keyb.but[2][1], TRUE);
1276 		gtk_widget_set_sensitive (keyb.but[2][2], TRUE);
1277 		gtk_widget_set_sensitive (keyb.but[2][3], TRUE);
1278 		gtk_widget_set_sensitive (keyb.but[2][6], TRUE);
1279 		gtk_widget_set_sensitive (keyb.but[2][7], TRUE);
1280 		gtk_widget_set_sensitive (keyb.but[2][8], TRUE);
1281 		gtk_widget_set_sensitive (keyb.but[2][9], TRUE);
1282 		hints_demo_fingers (1000/4);
1283 		break;
1284 	case 5: /* Reaching keys */
1285 		gtk_label_set_text (tit, intro00);
1286         	gtk_text_buffer_set_text (buffer, intro08, -1);
1287         	gtk_text_buffer_insert_at_cursor (buffer, "\n", -1);
1288         	gtk_text_buffer_insert_at_cursor (buffer, intro09, -1);
1289 		keyb_set_sensitive (TRUE);
1290 		gtk_widget_set_sensitive (keyb.but[2][0], FALSE);
1291 		gtk_widget_set_sensitive (keyb.but[2][1], FALSE);
1292 		gtk_widget_set_sensitive (keyb.but[2][2], FALSE);
1293 		gtk_widget_set_sensitive (keyb.but[2][3], FALSE);
1294 		gtk_widget_set_sensitive (keyb.but[2][6], FALSE);
1295 		gtk_widget_set_sensitive (keyb.but[2][7], FALSE);
1296 		gtk_widget_set_sensitive (keyb.but[2][8], FALSE);
1297 		gtk_widget_set_sensitive (keyb.but[2][9], FALSE);
1298 		gtk_widget_set_sensitive (get_wg ("but_space"), FALSE);
1299 		gtk_widget_set_sensitive (get_wg ("toggle_shift1"), FALSE);
1300 		gtk_widget_set_sensitive (get_wg ("toggle_shift2"), FALSE);
1301 		hints_demo_fingers (1000/5);
1302 		break;
1303 	case 6: /* Shift key */
1304 		gtk_label_set_text (tit, intro00);
1305         	gtk_text_buffer_set_text (buffer, intro10, -1);
1306 		keyb_set_sensitive (FALSE);
1307 		gtk_widget_set_sensitive (keyb.but[0][0], TRUE);
1308 		gtk_widget_set_sensitive (keyb.but[0][13], TRUE);
1309 		gtk_widget_set_sensitive (get_wg ("toggle_shift1"), TRUE);
1310 		gtk_widget_set_sensitive (get_wg ("toggle_shift2"), TRUE);
1311 		hints_demo_fingers (1000/2);
1312 		break;
1313 	case 7: /* Final words */
1314 		gtk_label_set_text (tit, _("Go ahead!"));
1315         	gtk_text_buffer_set_text (buffer, intro11, -1);
1316 		gtk_widget_grab_focus (get_wg ("button_keyboard_close"));
1317 		keyb_set_sensitive (TRUE);
1318 		hints_demo_fingers (0);
1319 		break;
1320 	default:
1321 		g_free (intro00);
1322 		intro00 = g_strdup (_("Click on any key to see which finger you must use:"));
1323 		gtk_label_set_text (tit, _("Relation between fingers and keys"));
1324 		gtk_label_set_text (tx1, _("Click on any key to see which finger you must use:"));
1325 		gtk_label_set_text (tx2, "");
1326         	gtk_text_buffer_set_text (buffer, intro00, -1);
1327 		keyb_set_sensitive (TRUE);
1328 		hints_demo_fingers (0);
1329 	}
1330 	g_free (intro00);
1331 
1332 	/* Blind people want no fancy autonomous buttons jumping around */
1333 	wg = get_wg ("checkbutton_speech");
1334 	if (gtk_widget_get_visible (wg) && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (wg)))
1335 		hints_demo_fingers (0);
1336 
1337 	if (step == 0)
1338 		gtk_widget_set_sensitive (get_wg ("button_keyboard_previous"), FALSE);
1339 	else
1340 		gtk_widget_set_sensitive (get_wg ("button_keyboard_previous"), TRUE);
1341 
1342 	if (step == 7)
1343 		gtk_widget_set_sensitive (get_wg ("button_keyboard_next"), FALSE);
1344 	else
1345 		gtk_widget_set_sensitive (get_wg ("button_keyboard_next"), TRUE);
1346 
1347 	if (step >= 0 && step <= 7)
1348 		keyb.intro_step = step;
1349 	else
1350 		keyb.intro_step = 0;
1351 }
1352 
1353 gchar *
keyb_mode_get_name()1354 keyb_mode_get_name ()
1355 {
1356 	gchar *country;
1357 	gchar *variant;
1358 	static gchar *kbname = NULL;
1359 
1360 	if (kbname != NULL)
1361 		g_free (kbname);
1362 
1363 	country = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (get_wg ("combobox_kbd_country")));
1364 	variant = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (get_wg ("combobox_kbd_variant")));
1365 	kbname = g_strdup_printf ("%s - %s", country, variant);
1366 	g_free (country);
1367 	g_free (variant);
1368 
1369 	return (kbname);
1370 }
1371 
1372 void
keyb_mode_intro()1373 keyb_mode_intro ()
1374 {
1375 	gchar *tit;
1376 
1377 	keyb_update_virtual_layout ();
1378 	gtk_widget_hide (get_wg ("window_hints"));
1379 	keyb_edit_none ();
1380 
1381 	tit = g_strdup_printf ("%s - %s: %s", _("Introduction"), _("Keyboard"), keyb_mode_get_name ());
1382 	gtk_window_set_title (get_win ("window_keyboard"), tit);
1383 	g_free (tit);
1384 
1385 	gtk_window_set_resizable (get_win ("window_keyboard"), TRUE);
1386 	gtk_widget_set_size_request (get_wg ("window_keyboard"), -1, 420);
1387 	gtk_widget_hide (get_wg ("label_keyboard_text_1"));
1388 	gtk_widget_hide (get_wg ("button_kb_save"));
1389 	gtk_widget_hide (get_wg ("button_keyboard_hands"));
1390 	gtk_widget_hide (get_wg ("button_keyboard_cancel"));
1391 	gtk_widget_hide (get_wg ("hbox_keyboard_selector"));
1392 	gtk_widget_hide (get_wg ("hbox_keyboard_saveas"));
1393 	gtk_widget_show (get_wg ("label_keyboard_spacer"));
1394 	gtk_widget_show (get_wg ("scrolledwindow_keyboard"));
1395 	gtk_widget_show (get_wg ("button_keyboard_close"));
1396 	gtk_widget_show (get_wg ("button_keyboard_previous"));
1397 	gtk_widget_show (get_wg ("button_keyboard_next"));
1398 	gtk_widget_show (get_wg ("hbox_keyboard_hints"));
1399 
1400 	hints_set_tips ();
1401 	keyb_intro_step (0);
1402 
1403 	gtk_widget_show (get_wg ("window_keyboard"));
1404 }
1405 
1406 void
keyb_mode_hint()1407 keyb_mode_hint ()
1408 {
1409 	gchar *tit;
1410 
1411 	keyb_update_virtual_layout ();
1412 	gtk_widget_hide (get_wg ("window_hints"));
1413 	keyb_edit_none ();
1414 
1415 	tit = g_strdup_printf ("%s: %s", _("Keyboard"), keyb_mode_get_name ());
1416 	gtk_window_set_title (get_win ("window_keyboard"), tit);
1417 	g_free (tit);
1418 
1419 	gtk_window_set_resizable (get_win ("window_keyboard"), FALSE);
1420 	gtk_widget_set_size_request (get_wg ("window_keyboard"), -1, -1);
1421 	gtk_widget_hide (get_wg ("label_keyboard_spacer"));
1422 	gtk_widget_hide (get_wg ("scrolledwindow_keyboard"));
1423 	gtk_widget_hide (get_wg ("button_kb_save"));
1424 	gtk_widget_hide (get_wg ("button_keyboard_cancel"));
1425 	gtk_widget_hide (get_wg ("button_keyboard_previous"));
1426 	gtk_widget_hide (get_wg ("button_keyboard_next"));
1427 	gtk_widget_hide (get_wg ("hbox_keyboard_selector"));
1428 	gtk_widget_hide (get_wg ("hbox_keyboard_saveas"));
1429 	gtk_widget_show (get_wg ("label_keyboard_text_1"));
1430 	gtk_widget_show (get_wg ("button_keyboard_hands"));
1431 	gtk_widget_show (get_wg ("button_keyboard_close"));
1432 	gtk_widget_show (get_wg ("hbox_keyboard_hints"));
1433 
1434 	hints_set_tips ();
1435 	keyb_intro_step (-1);
1436 	gtk_widget_grab_focus (get_wg ("button_keyboard_close"));
1437 
1438 	gtk_widget_show (get_wg ("window_keyboard"));
1439 }
1440 
1441 void
keyb_mode_edit()1442 keyb_mode_edit ()
1443 {
1444 	gchar *tmp;
1445 
1446 	/* Save the current name as 'name_last' */
1447 	tmp = g_strdup (keyb.name);
1448 	keyb_set_name (tmp);
1449 	g_free (tmp);
1450 
1451 	keyb_set_modified_status (FALSE);
1452 	if (layouts.n_cust == 0)
1453 		gtk_widget_set_sensitive (get_wg ("button_kb_remove"), FALSE);
1454 	else
1455 		gtk_widget_set_sensitive (get_wg ("button_kb_remove"), TRUE);
1456 
1457 	keyb_update_combos ("combobox_keyboard_country", "combobox_keyboard_variant");
1458 
1459 	keyb_update_virtual_layout ();
1460 	keyb_edit_none ();
1461 
1462 	gtk_window_set_title (get_win ("window_keyboard"), _("Create or modify a custom keyboard layout"));
1463 	gtk_window_set_resizable (get_win ("window_keyboard"), FALSE);
1464 	gtk_widget_set_size_request (get_wg ("window_keyboard"), -1, -1);
1465 	gtk_widget_hide (get_wg ("button_keyboard_hands"));
1466 	gtk_widget_hide (get_wg ("button_keyboard_close"));
1467 	gtk_widget_hide (get_wg ("button_keyboard_previous"));
1468 	gtk_widget_hide (get_wg ("button_keyboard_next"));
1469 	gtk_widget_hide (get_wg ("hbox_keyboard_hints"));
1470 	gtk_widget_show (get_wg ("button_keyboard_cancel"));
1471 	gtk_widget_show (get_wg ("hbox_keyboard_selector"));
1472 	gtk_widget_show (get_wg ("hbox_keyboard_saveas"));
1473 	gtk_widget_show (get_wg ("button_kb_save"));
1474 
1475 	keyb_set_sensitive (TRUE);
1476 	gtk_widget_set_sensitive (get_wg ("but_space"), FALSE);
1477 
1478 	hints_set_tips ();
1479 	gtk_widget_grab_focus (get_wg ("button_keyboard_cancel"));
1480 
1481 	gtk_widget_show (get_wg ("window_keyboard"));
1482 }
1483 
1484 void
keyb_set_sensitive(gboolean state)1485 keyb_set_sensitive (gboolean state)
1486 {
1487 	gint i, j;
1488 	gint j_max;
1489 
1490 	for (i = 0; i < 4; i++)
1491 	{
1492 		j_max = KEY_LINE_LEN - (i == 0 ? 1 : (i == 1 ? 2 : 3));
1493 		for (j = 0; j < j_max; j++)
1494 			gtk_widget_set_sensitive (keyb.but[i][j], state);
1495 	}
1496 	gtk_widget_set_sensitive (get_wg ("but_space"), state);
1497 	gtk_widget_set_sensitive (get_wg ("toggle_shift1"), state);
1498 	gtk_widget_set_sensitive (get_wg ("toggle_shift2"), state);
1499 }
1500 
1501 gboolean
keyb_button_match(GtkButton * button)1502 keyb_button_match (GtkButton * button)
1503 {
1504 	gint i, j;
1505 	gint j_max;
1506 
1507 	for (i = 0; i < 4; i++)
1508 	{
1509 		j_max = KEY_LINE_LEN - (i == 0 ? 1 : (i == 1 ? 2 : 3));
1510 		for (j = 0; j < j_max; j++)
1511 		{
1512 			if (keyb.but[i][j] == GTK_WIDGET (button))
1513 			{
1514 				keyb.pos.i = i;
1515 				keyb.pos.j = j;
1516 				return TRUE;
1517 			}
1518 		}
1519 	}
1520 	return FALSE;
1521 }
1522 
1523 /**********************************************************************
1524  * Moves the entry widget to get a real key pressed and
1525  * writes the name of the virtual one.
1526  */
1527 void
keyb_edit_button(GtkButton * button)1528 keyb_edit_button (GtkButton * button)
1529 {
1530 	if (! keyb_button_match (button))
1531 		return;
1532 
1533 	callbacks_shield_set (TRUE);
1534 
1535 	gtk_widget_grab_focus (GTK_WIDGET (button));
1536 	gtk_entry_set_text (GTK_ENTRY (keyb.entry),
1537 		       	gtk_label_get_text (GTK_LABEL (keyb.lab[keyb.pos.i][keyb.pos.j])));
1538 	gtk_fixed_move (GTK_FIXED (get_wg ("fixed_keyboard")), keyb.entry,
1539 		       	2 + x0[keyb.pos.i] + KEY_DX * keyb.pos.j,
1540 		       	2 + KEY_DY * keyb.pos.i);
1541 	if (keyb.pos.i == 1 && keyb.pos.j == 12)
1542 		gtk_widget_set_size_request (keyb.entry, 49, 28);
1543 	else
1544 		gtk_widget_set_size_request (keyb.entry, 28, 28);
1545 	gtk_editable_select_region (GTK_EDITABLE (keyb.entry), 0, 1);
1546 	gtk_widget_show (keyb.entry);
1547 	gtk_widget_grab_focus (keyb.entry);
1548 
1549 	callbacks_shield_set (FALSE);
1550 }
1551 
1552 void
keyb_edit_none(void)1553 keyb_edit_none (void)
1554 {
1555 	gtk_widget_hide (keyb.entry);
1556 }
1557 
1558 gboolean
keyb_edit_next(void)1559 keyb_edit_next (void)
1560 {
1561 	keyb.pos.j++;
1562 
1563 	switch (keyb.pos.i)
1564 	{
1565 	case 0:
1566 		if (keyb.pos.j > 13)
1567 		{
1568 			keyb.pos.i++;
1569 			keyb.pos.j = 0;
1570 		}
1571 		break;
1572 	case 1:
1573 		if (keyb.pos.j > 12)
1574 		{
1575 			keyb.pos.i++;
1576 			keyb.pos.j = 0;
1577 		}
1578 		break;
1579 	default:
1580 		if (keyb.pos.j > 11)
1581 		{
1582 			keyb.pos.i++;
1583 			keyb.pos.j = 0;
1584 		}
1585 	}
1586 
1587 	if (keyb.pos.i > 3)
1588 		keyb.pos.i = 0;
1589 
1590 	gtk_widget_hide (keyb.entry);
1591 	if (gtk_widget_get_sensitive (keyb.but[keyb.pos.i][keyb.pos.j]))
1592 	{
1593 		gtk_widget_grab_focus (keyb.but[keyb.pos.i][keyb.pos.j]);
1594 		return TRUE;
1595 	}
1596 	else
1597 		return FALSE;
1598 }
1599 
1600 /**********************************************************************
1601  * Apply the key pressed to the virtual keyboard
1602  * and to the upper or lower character sets
1603  */
1604 void
keyb_change_key(gunichar real_key)1605 keyb_change_key (gunichar real_key)
1606 {
1607 	gint key_lin, key_col;
1608 	gunichar str_char;
1609 	gchar tmp_utf8[7];
1610 	gboolean tog_state;
1611 	GtkWidget *wg;
1612 
1613 	key_lin = keyb.pos.i;
1614 	key_col = keyb.pos.j;
1615 
1616 	str_char = g_unichar_toupper (real_key);
1617 	tmp_utf8[g_unichar_to_utf8 (str_char, tmp_utf8)] = '\0';
1618 	gtk_label_set_text (GTK_LABEL (keyb.lab[key_lin][key_col]), tmp_utf8);
1619 
1620 	wg = get_wg ("toggle_shift1");
1621 	tog_state = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (wg));
1622 	if (tog_state)
1623 	{
1624 		keyb.upchars[key_lin][key_col] = str_char;
1625 		if (str_char >= L'A' && str_char <= L'Z')
1626 			keyb.lochars[key_lin][key_col] = g_unichar_tolower (str_char);
1627 	}
1628 	else
1629 	{
1630 		keyb.lochars[key_lin][key_col] = g_unichar_tolower (str_char);
1631 		if (str_char >= L'A' && str_char <= L'Z')
1632 			keyb.upchars[key_lin][key_col] = str_char;
1633 	}
1634 
1635 	keyb_set_modified_status (TRUE);
1636 	gtk_widget_set_sensitive (get_wg ("button_kb_save"), TRUE);
1637 	gtk_widget_set_sensitive (get_wg ("combobox_keyboard_country"), FALSE);
1638 	gtk_widget_set_sensitive (get_wg ("combobox_keyboard_variant"), FALSE);
1639 }
1640 
1641 /*******************************************************************************
1642  * Get an utf8 string for the par symbol
1643  */
1644 gchar *
keyb_get_utf8_paragraph_symbol()1645 keyb_get_utf8_paragraph_symbol ()
1646 {
1647 	static gchar parsym[7] = {0, 0, 0, 0, 0, 0, 0};
1648 	static gboolean is_initialized = FALSE;
1649 
1650 	if (is_initialized == FALSE)
1651 	{
1652 		is_initialized = TRUE;
1653 		g_unichar_to_utf8 (UPSYM, parsym);
1654 	}
1655 	return (parsym);
1656 }
1657 
1658 /*******************************************************************************
1659  * Initialize the hints mapping array
1660  */
1661 static gchar hints[4][KEY_LINE_LEN + 1];
1662 static gboolean hints_is_initialized = FALSE;
1663 
1664 void
hints_init()1665 hints_init ()
1666 {
1667 	gint i;
1668 	gchar *tmp_name;
1669 	gchar *tmp;
1670 	FILE *fh;
1671 
1672 	if (hints_is_initialized == TRUE)
1673 		return;
1674 
1675 	tmp_name = g_build_filename ("/etc/klavaro/fingers_position.txt", NULL);
1676 	if (!g_file_test (tmp_name, G_FILE_TEST_IS_REGULAR))
1677 	{
1678 		g_free (tmp_name);
1679 		tmp_name = g_build_filename (main_path_user (), "fingers_position.txt", NULL);
1680 	}
1681 	if (!g_file_test (tmp_name, G_FILE_TEST_IS_REGULAR))
1682 	{
1683 		g_free (tmp_name);
1684 		tmp_name = g_build_filename (main_path_data (), "fingers_position.txt", NULL);
1685 	}
1686 	fh = (FILE *) g_fopen (tmp_name, "r");
1687 	if (fh)
1688 	{
1689 		hints_is_initialized = TRUE;
1690 		for (i = 0; i < 4; i++)
1691 			tmp = fgets (hints[i], KEY_LINE_LEN + 1, fh);
1692 		fclose (fh);
1693 		hints_set_tips ();
1694 		hints_set_colors ();
1695 	}
1696 	else
1697 		g_warning ("couldn't open the file:\n %s", tmp_name);
1698 	g_free (tmp_name);
1699 
1700 }
1701 
1702 gchar *
hints_string_from_charcode(gchar charcode)1703 hints_string_from_charcode (gchar charcode)
1704 {
1705 	gchar *fingerhint = NULL;
1706 
1707 	switch (charcode)
1708 	{
1709 	case '1':
1710 		fingerhint = g_strdup (_("small finger"));
1711 		break;
1712 	case '2':
1713 		fingerhint = g_strdup (_("ring finger"));
1714 		break;
1715 	case '3':
1716 		fingerhint = g_strdup (_("middle finger"));
1717 		break;
1718 	case '4':
1719 		fingerhint = g_strdup (_("index finger"));
1720 		break;
1721 	case '5':
1722 		fingerhint = g_strdup (_("thumbs"));
1723 		break;
1724 	case '6':
1725 		fingerhint = g_strdup (_("index finger"));
1726 		break;
1727 	case '7':
1728 		fingerhint = g_strdup (_("middle finger"));
1729 		break;
1730 	case '8':
1731 		fingerhint = g_strdup (_("ring finger"));
1732 		break;
1733 	case '9':
1734 		fingerhint = g_strdup (_("small finger"));
1735 		break;
1736 	default:
1737 		fingerhint = g_strdup ("???");
1738 	}
1739 	return (fingerhint);
1740 }
1741 
1742 gchar *
hints_color_from_charcode(gchar charcode)1743 hints_color_from_charcode (gchar charcode)
1744 {
1745 	static gchar *hlp = NULL;
1746 
1747 	g_free (hlp);
1748 
1749 	switch (charcode)
1750 	{
1751 	case '1':
1752 		if (main_preferences_exist ("colors", "key_1"))
1753 			hlp = main_preferences_get_string ("colors", "key_1");
1754 		else
1755 			hlp = g_strdup (KEYB_BLUE);
1756 		break;
1757 	case '2':
1758 		if (main_preferences_exist ("colors", "key_2"))
1759 			hlp = main_preferences_get_string ("colors", "key_2");
1760 		else
1761 			hlp = g_strdup (KEYB_RED);
1762 		break;
1763 	case '3':
1764 		if (main_preferences_exist ("colors", "key_3"))
1765 			hlp = main_preferences_get_string ("colors", "key_3");
1766 		else
1767 			hlp = g_strdup (KEYB_GREEN);
1768 		break;
1769 	case '4':
1770 		if (main_preferences_exist ("colors", "key_4"))
1771 			hlp = main_preferences_get_string ("colors", "key_4");
1772 		else
1773 			hlp = g_strdup (KEYB_YELLOW);
1774 		break;
1775 	case '5':
1776 		if (main_preferences_exist ("colors", "key_5"))
1777 			hlp = main_preferences_get_string ("colors", "key_5");
1778 		else
1779 			hlp = g_strdup (KEYB_PURPLE);
1780 		break;
1781 	case '6':
1782 		if (main_preferences_exist ("colors", "key_6"))
1783 			hlp = main_preferences_get_string ("colors", "key_6");
1784 		else
1785 			hlp = g_strdup (KEYB_ORANGE);
1786 		break;
1787 	case '7':
1788 		if (main_preferences_exist ("colors", "key_7"))
1789 			hlp = main_preferences_get_string ("colors", "key_7");
1790 		else
1791 			hlp = g_strdup (KEYB_GREEN);
1792 		break;
1793 	case '8':
1794 		if (main_preferences_exist ("colors", "key_8"))
1795 			hlp = main_preferences_get_string ("colors", "key_8");
1796 		else
1797 			hlp = g_strdup (KEYB_RED);
1798 		break;
1799 	case '9':
1800 		if (main_preferences_exist ("colors", "key_9"))
1801 			hlp = main_preferences_get_string ("colors", "key_9");
1802 		else
1803 			hlp = g_strdup (KEYB_BLUE);
1804 		break;
1805 	default:
1806 		hlp = g_strdup ("#AFAFAF");
1807 	}
1808 	return hlp;
1809 }
1810 
1811 void
hints_set_tips()1812 hints_set_tips ()
1813 {
1814 	static gchar *editme = NULL;
1815 	gint i, j;
1816 	gint j_max;
1817 	gchar *tmp;
1818 
1819 	if (editme == NULL)
1820 	       editme = g_strdup (_("Press and edit me"));
1821 
1822 	if (hints_is_initialized == FALSE)
1823 	{
1824 		g_warning ("Not able to set keyboard tips without initializing the hints");
1825 		return;
1826 	}
1827 
1828 	for (i = 0; i < 4; i++)
1829 	{
1830 		j_max = KEY_LINE_LEN - (i == 0 ? 1 : (i == 1 ? 2 : 3));
1831 		for (j = 0; j < j_max; j++)
1832 		{
1833 			tmp = hints_string_from_charcode (hints[i][j]);
1834 			if (! gtk_widget_get_visible (get_wg ("hbox_keyboard_hints")))
1835 				gtk_widget_set_tooltip_text (keyb.but[i][j], editme);
1836 			else
1837 				gtk_widget_set_tooltip_text (keyb.but[i][j], tmp);
1838 			g_free (tmp);
1839 		}
1840 	}
1841 }
1842 
1843 void
hints_set_colors()1844 hints_set_colors ()
1845 {
1846 	gint i, j;
1847 	gint j_max;
1848 	GdkRGBA color;
1849 	GtkStyleContext *sc;
1850 	gchar *tmp;
1851 
1852 	if (hints_is_initialized == FALSE)
1853 	{
1854 		g_warning ("Not able to set keyboard colors without initializing the hints");
1855 		return;
1856 	}
1857 
1858 	for (i = 0; i < 4; i++)
1859 	{
1860 		j_max = KEY_LINE_LEN - (i == 0 ? 1 : (i == 1 ? 2 : 3));
1861 		for (j = 0; j < j_max; j++)
1862 		{
1863 			sc = gtk_widget_get_style_context (keyb.but[i][j]);
1864 			gtk_style_context_add_provider (sc, GTK_STYLE_PROVIDER (keyb_css), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
1865 			tmp = g_strdup_printf ("key-but%c", hints[i][j]);
1866 			gtk_style_context_add_class (sc, tmp);
1867 			g_free (tmp);
1868 		}
1869 	}
1870 }
1871 
1872 /* Update the image of the window_keyboard
1873  * Maps the button to the file which shows the finger associated with its key
1874  */
1875 void
hints_update_from_button(GtkButton * button)1876 hints_update_from_button (GtkButton *button)
1877 {
1878 	gchar *pix_name;
1879 	gchar ch;
1880 
1881 	hints_init (); // if already initialized, do nothing
1882 
1883 	if (keyb_button_match (button))
1884 	{
1885 		pix_name = g_strdup ("hands_0.png");
1886 		ch = hints[keyb.pos.i][keyb.pos.j];
1887 		if (ch >= '1' && ch <= '9')
1888 			pix_name[6] = ch;
1889 	}
1890 	else if ( button == GTK_BUTTON (get_wg ("but_space")) )
1891 		pix_name = g_strdup ("hands_5.png");
1892 	else if ( button == GTK_BUTTON (get_wg ("toggle_shift1")) )
1893 		pix_name = g_strdup ("hands_1.png");
1894 	else if ( button == GTK_BUTTON (get_wg ("toggle_shift2")) )
1895 		pix_name = g_strdup ("hands_9.png");
1896 	else
1897 		pix_name = g_strdup ("hands_0.png");
1898 
1899 	set_pixmap ("pixmap_hints_fixed", pix_name);
1900 	g_free (pix_name);
1901 }
1902 
1903 /* Update the image of the window_hints
1904  * Maps the character to the file which shows the finger associated with that key
1905  */
1906 void
hints_update_from_char(gunichar character)1907 hints_update_from_char (gunichar character)
1908 {
1909 	gchar file_name[32];
1910 	gint i, j;
1911 
1912 	if (! gtk_widget_get_visible (get_wg ("window_hints")))
1913 		return;
1914 
1915 	strcpy (file_name, "hands_0.png");
1916 	if (character == UPSYM)
1917 		strcpy (file_name, "hands_9.png");
1918 	else if (character == L' ')
1919 		strcpy (file_name, "hands_5.png");
1920 	else if (character != 0)
1921 	{
1922 		hints_init (); // if already initialized, do nothing
1923 
1924 		for (i = 3; i >= 0; i--)
1925 			for (j = 0; j < 15; j++)
1926 				if (character == keyb.lochars[i][j])
1927 				{
1928 					file_name[6] = hints[i][j];
1929 					set_pixmap ("pixmap_hints", file_name);
1930 					return;
1931 				}
1932 
1933 		for (i = 3; i >= 0; i--)
1934 			for (j = 0; j < 15; j++)
1935 				if (character == keyb.upchars[i][j])
1936 				{
1937 					file_name[6] = hints[i][j];
1938 					set_pixmap ("pixmap_hints", file_name);
1939 					return;
1940 				}
1941 		file_name[6] = '0';
1942 	}
1943 
1944 	set_pixmap ("pixmap_hints", file_name);
1945 }
1946 
1947 gboolean
hints_demo_fingers_move(gpointer data)1948 hints_demo_fingers_move (gpointer data)
1949 {
1950 	static int i = 0;
1951 
1952 	if (data)
1953 	{
1954 		keyb.pos.i = 0;
1955 		keyb.pos.j = 0;
1956 	}
1957 
1958 	for (i = 0; i < 500; i++)
1959 		if (keyb_edit_next ())
1960 			break;
1961 	return TRUE;
1962 }
1963 
1964 void
hints_demo_fingers(guint msec)1965 hints_demo_fingers (guint msec)
1966 {
1967 	static GSource *source = NULL;
1968 	guint id;
1969 
1970 	if (source != NULL)
1971 		g_source_destroy (source);
1972 	source = NULL;
1973 	hints_demo_fingers_move (&msec);
1974 
1975 	if (msec != 0)
1976 	{
1977 		id = g_timeout_add (msec, hints_demo_fingers_move, NULL);
1978 		source = g_main_context_find_source_by_id (NULL, id);
1979 	}
1980 }
1981 
1982 gchar *
hints_finger_name_from_char(gunichar uch)1983 hints_finger_name_from_char (gunichar uch)
1984 {
1985 	gint i, j;
1986 
1987 	if (uch == UPSYM || uch == L'\n' || uch == L'\r')
1988 		return (hints_string_from_charcode ('9'));
1989 	if (uch == L' ')
1990 		return (hints_string_from_charcode ('5'));
1991 
1992 	hints_init (); // if already initialized, do nothing
1993 
1994 	for (i = 3; i >= 0; i--)
1995 		for (j = 0; j < 15; j++)
1996 			if (uch == keyb.lochars[i][j])
1997 				return (hints_string_from_charcode (hints[i][j]));
1998 
1999 	for (i = 3; i >= 0; i--)
2000 		for (j = 0; j < 15; j++)
2001 			if (uch == keyb.upchars[i][j])
2002 				return (hints_string_from_charcode (hints[i][j]));
2003 
2004 	return (g_strdup (" "));
2005 }
2006 
2007