"Fossies" - the Fresh Open Source Software Archive

Member "gambas-3.16.3/gb.gtk/src/gkey.cpp" (7 Sep 2021, 13109 Bytes) of package /linux/misc/gambas-3.16.3.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 "gkey.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.16.2_vs_3.16.3.

    1 /***************************************************************************
    2 
    3   gkey.cpp
    4 
    5   (c) 2004-2006 - Daniel Campos Fernández <dcamposf@gmail.com>
    6   (c) 2000-2017 Benoît Minisini <g4mba5@gmail.com>
    7 
    8   This program is free software; you can redistribute it and/or modify
    9   it under the terms of the GNU General Public License as published by
   10   the Free Software Foundation; either version 2, or (at your option)
   11   any later version.
   12 
   13   This program is distributed in the hope that it will be useful,
   14   but WITHOUT ANY WARRANTY; without even the implied warranty of
   15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16   GNU General Public License for more details.
   17 
   18   You should have received a copy of the GNU General Public License
   19   along with this program; if not, write to the Free Software
   20   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
   21   MA 02110-1301, USA.
   22 
   23 ***************************************************************************/
   24 
   25 #define __GKEY_CPP
   26 
   27 #include <ctype.h>
   28 #include <time.h>
   29 #include <unistd.h>
   30 
   31 #include "widgets.h"
   32 #include "gapplication.h"
   33 #include "gtrayicon.h"
   34 #include "gdesktop.h"
   35 #include "gmainwindow.h"
   36 #include "gkey.h"
   37 
   38 //#define DEBUG_IM 1
   39 
   40 /*************************************************************************
   41 
   42 gKey
   43 
   44 **************************************************************************/
   45 
   46 int gKey::_valid = 0;
   47 bool gKey::_canceled = false;
   48 GdkEventKey gKey::_event;
   49 int gKey::_last_key_press = 0;
   50 int gKey::_last_key_release = 0;
   51 
   52 static GtkIMContext *_im_context = NULL;
   53 static char *_im_default_slave = NULL;
   54 static bool _im_has_input_method = FALSE;
   55 static gControl *_im_control = NULL;
   56 static bool _im_no_commit = false;
   57 static GdkWindow *_im_window = NULL;
   58 static bool _im_is_xim = FALSE;
   59 static bool _im_ignore_event = FALSE;
   60 static bool _im_got_commit = FALSE;
   61 
   62 //#define MAX_CODE 16
   63 //static uint _key_code[MAX_CODE] = { 0 };
   64 
   65 
   66 //char *_im_text = NULL;
   67 
   68 const char *gKey::text()
   69 {
   70     if (!_valid) 
   71         return 0;
   72     else
   73         return _event.string;
   74 }
   75 
   76 int gKey::code()
   77 {
   78     if (!_valid)
   79         return 0;
   80     
   81     int code = _event.keyval;
   82     
   83     if (code >= GDK_a && code <= GDK_z)
   84         code += GDK_A - GDK_a;
   85     else if (code == GDK_Alt_R)
   86         code = GDK_Alt_L;
   87     else if (code == GDK_Control_R)
   88         code = GDK_Control_L;
   89     else if (code == GDK_Meta_R)
   90         code = GDK_Meta_L;
   91     else if (code == GDK_Shift_R)
   92         code = GDK_Shift_L;
   93     else
   94     {
   95         int unicode = gdk_keyval_to_unicode(code);
   96         if (unicode >= 32 && unicode < 127)
   97             code = unicode;
   98     }
   99 
  100     return code;
  101 }
  102 
  103 int gKey::state()
  104 {
  105     if (!_valid)
  106         return 0;
  107     else
  108         return _event.state;
  109 }
  110 
  111 bool gKey::alt()
  112 {
  113     return state() & GDK_MOD1_MASK; // || _event.keyval == GDK_Alt_L || _event.keyval == GDK_Alt_R;
  114 }
  115 
  116 bool gKey::control()
  117 {
  118     return state() & GDK_CONTROL_MASK; // || _event.keyval == GDK_Control_L || _event.keyval == GDK_Control_R;
  119 }
  120 
  121 bool gKey::meta()
  122 {
  123     return state() & GDK_META_MASK; // || _event.keyval == GDK_Meta_L || _event.keyval == GDK_Meta_R;
  124 }
  125 
  126 bool gKey::normal()
  127 {
  128     return (state() & (GDK_MOD1_MASK | GDK_CONTROL_MASK | GDK_META_MASK | GDK_SHIFT_MASK)) == 0;
  129 }
  130 
  131 bool gKey::shift()
  132 {
  133     return state() & GDK_SHIFT_MASK; // || _event.keyval == GDK_Shift_L || _event.keyval == GDK_Shift_R;
  134 }
  135 
  136 int gKey::fromString(const char *str)
  137 {
  138     char *lstr;
  139     int key;
  140     
  141     if (!str || !*str)
  142         return 0;
  143     
  144     lstr = g_ascii_strup(str, -1);
  145     key = gdk_keyval_from_name(lstr);
  146     g_free(lstr);
  147     if (key) return key;
  148 
  149     lstr = g_ascii_strdown(str, -1);
  150     key = gdk_keyval_from_name(lstr);
  151     g_free(lstr);
  152     if (key) return key;
  153 
  154     key = gdk_keyval_from_name(str);
  155     if (key) return key;
  156 
  157     if (!str[1] && isascii(str[0]))
  158         return str[0];
  159     else
  160         return 0;
  161 }
  162 
  163 void gKey::disable()
  164 {
  165     _valid--;
  166     if (_valid)
  167         return;
  168     
  169     _valid = false;
  170     _event.keyval = 0;
  171     _event.state = 0;
  172     //g_free(_event.string);
  173 }
  174 
  175 bool gKey::enable(gControl *control, GdkEventKey *event)
  176 {
  177     bool f = false;
  178     
  179     _valid++;
  180     _canceled = false;
  181 
  182     if (event)
  183     {
  184         _im_no_commit = false;
  185 
  186         _event = *event;
  187         _event.window = _im_window;
  188 
  189         if (gKey::mustIgnoreEvent(event))
  190             return true;
  191 
  192         if (control == _im_control)
  193         {
  194             #if DEBUG_IM
  195             fprintf(stderr, "gKey::enable: [%p] flag = %d event->string = %d\n", event, (event->state & (1 << 25)) != 0, *event->string);
  196             #endif
  197 
  198 #if 0
  199             if (_im_slave_is_xim)
  200             {
  201                 /*if (_im_xim_abort == 2)
  202                 {
  203                     f = true;
  204                     _im_xim_abort = 0;
  205                 }
  206                 else*/
  207                 {
  208                     GdkEventKey save = *event;
  209                     if (save.string)
  210                         save.string = g_strdup(save.string);
  211 
  212                     f = gtk_im_context_filter_keypress(_im_context, event);
  213                     *event = save;
  214                     _im_xim_abort++;
  215                 }
  216             }
  217             else
  218                 f = gtk_im_context_filter_keypress(_im_context, event);
  219 #endif
  220 
  221             if (!_im_has_input_method)
  222             {
  223                 initContext();
  224                 f = gtk_im_context_filter_keypress(_im_context, event);
  225             }
  226 
  227             #if DEBUG_IM
  228             fprintf(stderr, "gKey::enable: [%p] filter -> %d\n", event, f);
  229             #endif
  230         }
  231     }
  232 
  233   return f || _canceled;
  234 }
  235 
  236 bool gKey::mustIgnoreEvent(GdkEventKey *event)
  237 {
  238     if (!_im_has_input_method)
  239         return false;
  240     else
  241         return (event->type == GDK_KEY_PRESS) && (event->keyval == 0 || !event->string || ((uchar)*event->string >= 32 && ((event->keyval & 0xFF00) != 0xFF00)));
  242 }
  243 
  244 void gcb_im_commit(GtkIMContext *context, const char *str, gControl *control)
  245 {
  246     bool disable = false;
  247 
  248     if (!control)
  249         control = _im_control;
  250     
  251     // Not called from a key press event!
  252     if (!control)
  253         return;
  254 
  255     #if DEBUG_IM
  256     fprintf(stderr, "cb_im_commit: \"%s\"  _im_no_commit = %d  gKey::valid = %d\n", str, _im_no_commit, gKey::isValid());
  257     #endif
  258     
  259     if (!gKey::isValid())
  260     {
  261         gKey::enable(control, NULL);
  262         gKey::_event.keyval = gKey::_last_key_press;
  263         disable = true;
  264     }
  265 
  266     gKey::_canceled = gKey::raiseEvent(gEvent_KeyPress, control, str);
  267 #if DEBUG_IM
  268     fprintf(stderr, "cb_im_commit: canceled = %d\n", gKey::_canceled);
  269 #endif
  270 
  271     if (disable)
  272         gKey::disable();
  273 
  274     _im_no_commit = true;
  275 }
  276 
  277 static gboolean hook_commit(GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, gpointer data)
  278 {
  279     _im_got_commit = TRUE;
  280     return true;
  281 }
  282 
  283 void gKey::initContext()
  284 {
  285     if (_im_context)
  286         return;
  287 
  288     _im_context = gtk_im_multicontext_new();
  289     gtk_im_context_set_client_window (_im_context, _im_window);
  290 
  291     _im_default_slave = g_strdup(gtk_im_multicontext_get_context_id(GTK_IM_MULTICONTEXT(_im_context)));
  292 
  293   g_signal_connect(_im_context, "commit", G_CALLBACK(gcb_im_commit), NULL);
  294 
  295     g_signal_add_emission_hook(g_signal_lookup("commit", GTK_TYPE_IM_CONTEXT), (GQuark)0, hook_commit, (gpointer)0, NULL);
  296 }
  297 
  298 void gKey::init()
  299 {
  300     GdkWindowAttr attr;
  301 
  302     attr.event_mask = GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK;
  303     attr.width = attr.height = 10;
  304     attr.wclass = GDK_INPUT_OUTPUT;
  305     attr.window_type = GDK_WINDOW_TOPLEVEL;
  306 
  307     _im_window = gdk_window_new(NULL, &attr, 0);
  308 }
  309 
  310 void gKey::exit()
  311 {
  312     disable();
  313     if (_im_context)
  314     {
  315         g_free(_im_default_slave);
  316         g_object_unref(_im_context);
  317     }
  318 }
  319 
  320 void gKey::setActiveControl(gControl *control)
  321 {
  322     const char *slave;
  323     GtkIMContext *context;
  324 
  325     if (_im_control)
  326     {
  327 #if DEBUG_IM
  328         fprintf(stderr, "gtk_im_context_focus_out\n");
  329 #endif
  330         if (!_im_has_input_method)
  331         {
  332             initContext();
  333             gtk_im_context_reset(_im_context);
  334             gtk_im_context_set_client_window (_im_context, 0);
  335             gtk_im_context_reset(_im_context);
  336             gtk_im_context_focus_out(_im_context);
  337             gtk_im_context_reset(_im_context);
  338         }
  339 
  340         _im_control = NULL;
  341     }
  342     
  343     if (control)
  344     {
  345         _im_control = control;
  346         
  347         if (!control->hasInputMethod())
  348         {
  349             initContext();
  350             _im_has_input_method = FALSE;
  351             gtk_im_context_reset(_im_context);
  352             gtk_im_context_set_client_window (_im_context, gtk_widget_get_window(control->widget));
  353             gtk_im_context_reset(_im_context);
  354             gtk_im_context_focus_in(_im_context);
  355             gtk_im_context_reset(_im_context);
  356             //slave = gtk_im_multicontext_get_context_id(GTK_IM_MULTICONTEXT(_im_context));
  357             _im_is_xim = FALSE;
  358         }
  359         else
  360         {
  361             _im_has_input_method = TRUE;
  362             context = control->getInputMethod();
  363             if (context && GTK_IS_IM_MULTICONTEXT(context))
  364             {
  365                 slave = gtk_im_multicontext_get_context_id(GTK_IM_MULTICONTEXT(context));
  366                 _im_is_xim = slave && strcmp(slave, "xim") == 0;
  367             }
  368             else
  369             {
  370                 _im_is_xim = FALSE;
  371             }
  372         }
  373 
  374         _im_ignore_event = FALSE;
  375 
  376 #if DEBUG_IM
  377         fprintf(stderr,"\n------------------------\n");
  378         fprintf(stderr, "gtk_im_context_focus_in: %s _im_has_input_method = %d\n", control ? control->name() : "-", _im_has_input_method);
  379 #endif
  380     }
  381 }
  382 
  383 static bool raise_key_event_to_parent_window(gControl *control, int type)
  384 {
  385     gMainWindow *win;
  386 
  387     while (control->parent())
  388     {
  389         win = control->parent()->window();
  390         if (win->onKeyEvent && win->canRaise(win, type))
  391         {
  392             //fprintf(stderr, "onKeyEvent: %d %p %s\n", type, win, win->name());
  393             if (win->onKeyEvent(win, type))
  394                 return true;
  395         }
  396 
  397         control = win;
  398     }
  399 
  400     return false;
  401 }
  402 
  403 #if 0
  404 static bool can_raise(GdkEventKey *event)
  405 {
  406     int i;
  407 
  408     if (event->type == GDK_KEY_PRESS)
  409     {
  410         for (i = 0; i < MAX_CODE; i++)
  411         {
  412             if (event->keyval == _key_code[i])
  413                 return false;
  414         }
  415         for (i = 0; i < MAX_CODE; i++)
  416         {
  417             if (!_key_code[i])
  418             {
  419                 //fprintf(stderr, "store key %d\n", event->keyval);
  420                 _key_code[i] = event->keyval;
  421                 break;
  422             }
  423         }
  424         return true;
  425     }
  426     else
  427     {
  428         for (i = 0; i < MAX_CODE; i++)
  429         {
  430             if (event->keyval == _key_code[i])
  431             {
  432                 //fprintf(stderr, "remove key %d\n", event->keyval);
  433                 _key_code[i] = 0;
  434                 return true;
  435             }
  436         }
  437         return false;
  438     }
  439 }
  440 #endif
  441 
  442 bool gKey::raiseEvent(int type, gControl *control, const char *text)
  443 {
  444     bool parent_got_it = false;
  445     bool cancel = false;
  446     bool handled = false;
  447 
  448 #if DEBUG_IM
  449     fprintf(stderr, "gKey::raiseEvent %s to %p %s\n", type == gEvent_KeyPress ? "KeyPress" : "KeyRelease", control, control->name());
  450 #endif
  451                     
  452     if (text)
  453         _event.string = (gchar *)text;
  454 
  455     //if (!can_raise(&_event))
  456     //  return false;
  457 
  458 __KEY_TRY_PROXY:
  459 
  460     if (!parent_got_it)
  461     {
  462         parent_got_it = true;
  463 
  464         if (gApplication::onKeyEvent)
  465             cancel = gApplication::onKeyEvent(type);
  466 
  467         if (!cancel)
  468             cancel = raise_key_event_to_parent_window(control, type);
  469     }
  470 
  471     if (!cancel && control->onKeyEvent && control->canRaise(control, type))
  472     {
  473         //fprintf(stderr, "gEvent_KeyPress on %p %s\n", control, control->name());
  474         //fprintf(stderr, "onKeyEvent: %p %d %p %s\n", event, type, control, control->name());
  475         #if DEBUG_IM
  476             fprintf(stderr, "--> %s\n", control->name());
  477         #endif
  478         handled = true;
  479         cancel = control->onKeyEvent(control, type);
  480     }
  481 
  482     if (cancel)
  483     {
  484         #if DEBUG_IM
  485             fprintf(stderr, "--> cancel\n");
  486         #endif
  487         return true;
  488     }
  489 
  490     if (control->_proxy_for)
  491     {
  492         control = control->_proxy_for;
  493         goto __KEY_TRY_PROXY;
  494     }
  495 
  496     if (!handled)
  497     {
  498         control = control->parent();
  499         if (control && !control->isWindow())
  500             goto __KEY_TRY_PROXY;
  501     }
  502     
  503     return false;
  504 }
  505 
  506 static bool check_button(gControl *w)
  507 {
  508     return w && w->isReallyVisible() && w->isEnabled();
  509 }
  510 
  511 gboolean gcb_key_event(GtkWidget *widget, GdkEvent *event, gControl *control)
  512 {
  513     gMainWindow *win;
  514     int type;
  515     bool cancel;
  516 
  517 #if DEBUG_IM
  518     fprintf(stderr, "gcb_key_event: %s for %p %s / active = %p %s\n", event->type == GDK_KEY_PRESS ? "GDK_KEY_PRESS" : "GDK_KEY_RELEASE", control, control->name(), gApplication::activeControl(), gApplication::activeControl() ? gApplication::activeControl()->name() : "-");
  519 #endif
  520 
  521     /*if (!control->_grab && gApplication::activeControl())
  522         control = gApplication::activeControl();*/
  523     if (!control || control != gApplication::activeControl())
  524         return false;
  525     
  526 #if DEBUG_IM
  527     fprintf(stderr, "handle it\n");
  528 #endif
  529 
  530     //if (event->type == GDK_KEY_PRESS)
  531     //  fprintf(stderr, "GDK_KEY_PRESS: control = %p %s %p %08X\n", control, control ? control->name() : "", event, event->key.state);
  532 
  533     if (_im_is_xim)
  534     {
  535         _im_ignore_event = !_im_ignore_event;
  536         if (_im_ignore_event)
  537             return false;
  538     }
  539 
  540     type =  (event->type == GDK_KEY_PRESS) ? gEvent_KeyPress : gEvent_KeyRelease;
  541 
  542     if (gKey::enable(control, &event->key))
  543     {
  544         gKey::disable();
  545         return gKey::canceled() || !_im_has_input_method;
  546     }
  547 
  548     if (gKey::mustIgnoreEvent(&event->key))
  549     {
  550         gKey::disable();
  551         return true;
  552     }
  553 
  554     cancel = gKey::raiseEvent(type, control, NULL);
  555     gKey::disable();
  556 
  557     if (cancel)
  558         return true;
  559 
  560     win = control->window();
  561     
  562     for(;;)
  563     {
  564         if (event->key.keyval == GDK_Escape)
  565         {
  566             if (control->_grab)
  567             {
  568                 gApplication::exitLoop(control);
  569                 return true;
  570             }
  571 
  572             if (check_button(win->_cancel))
  573             {
  574                 #if DEBUG_IM
  575                     fprintf(stderr, "gcb_key_event: cancel button\n");
  576                 #endif
  577                 //win->_cancel->setFocus();
  578                 win->_cancel->animateClick(type == gEvent_KeyRelease);
  579                 return true;
  580             }
  581         }
  582         else if (event->key.keyval == GDK_Return || event->key.keyval == GDK_KP_Enter)
  583         {
  584             if (check_button(win->_default) && !control->eatReturnKey())
  585             {
  586                 #if DEBUG_IM
  587                     fprintf(stderr, "gcb_key_event: default button\n");
  588                 #endif
  589                 //win->_default->setFocus();
  590                 win->_default->animateClick(type == gEvent_KeyRelease);
  591                 return true;
  592             }
  593         }
  594         
  595         if (win->isTopLevel())
  596             break;
  597         
  598         win = win->parent()->window();
  599     }
  600 
  601     if (control->_grab)
  602         return true;
  603 
  604     return false;
  605 }
  606 
  607 bool gKey::gotCommit()
  608 {
  609     bool ret = _im_got_commit;
  610     _im_got_commit = FALSE;
  611     return ret;
  612 }