"Fossies" - the Fresh Open Source Software Archive

Member "klavaro-3.13/src/keyboard.c" (18 Apr 2021, 50888 Bytes) of package /linux/privat/klavaro-3.13.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "keyboard.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.12_vs_3.13.

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