1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2017, Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16  *
17  * Author(s): Carlos Garnacho <carlosg@gnome.org>
18  */
19 
20 /**
21  * SECTION:gtkeventcontrollerkey
22  * @Short_description: Event controller for key events
23  * @Title: GtkEventControllerKey
24  * @See_also: #GtkEventController
25  *
26  * #GtkEventControllerKey is an event controller meant for situations
27  * where you need access to key events.
28  *
29  * This object was added in 3.24.
30  **/
31 
32 #include "config.h"
33 
34 #include "gtkintl.h"
35 #include "gtkmarshalers.h"
36 #include "gtkprivate.h"
37 #include "gtkwidgetprivate.h"
38 #include "gtkeventcontrollerprivate.h"
39 #include "gtkeventcontrollerkey.h"
40 #include "gtkbindings.h"
41 
42 #include <gdk/gdk.h>
43 
44 struct _GtkEventControllerKey
45 {
46   GtkEventController parent_instance;
47   GtkIMContext *im_context;
48   GHashTable *pressed_keys;
49 
50   GdkModifierType state;
51 
52   const GdkEvent *current_event;
53 };
54 
55 struct _GtkEventControllerKeyClass
56 {
57   GtkEventControllerClass parent_class;
58 };
59 
60 enum {
61   KEY_PRESSED,
62   KEY_RELEASED,
63   MODIFIERS,
64   IM_UPDATE,
65   FOCUS_IN,
66   FOCUS_OUT,
67   N_SIGNALS
68 };
69 
70 static guint signals[N_SIGNALS] = { 0 };
71 
G_DEFINE_TYPE(GtkEventControllerKey,gtk_event_controller_key,GTK_TYPE_EVENT_CONTROLLER)72 G_DEFINE_TYPE (GtkEventControllerKey, gtk_event_controller_key,
73                GTK_TYPE_EVENT_CONTROLLER)
74 
75 static void
76 gtk_event_controller_finalize (GObject *object)
77 {
78   GtkEventControllerKey *key = GTK_EVENT_CONTROLLER_KEY (object);
79 
80   g_hash_table_destroy (key->pressed_keys);
81   g_clear_object (&key->im_context);
82 
83   G_OBJECT_CLASS (gtk_event_controller_key_parent_class)->finalize (object);
84 }
85 
86 static gboolean
gtk_event_controller_key_handle_event(GtkEventController * controller,const GdkEvent * event)87 gtk_event_controller_key_handle_event (GtkEventController *controller,
88                                        const GdkEvent     *event)
89 {
90   GtkEventControllerKey *key = GTK_EVENT_CONTROLLER_KEY (controller);
91   GdkEventType event_type = gdk_event_get_event_type (event);
92   GdkModifierType state;
93   guint16 keycode;
94   guint keyval;
95   gboolean handled = FALSE;
96 
97   if (event_type == GDK_FOCUS_CHANGE)
98     {
99       if (event->focus_change.in)
100         g_signal_emit (controller, signals[FOCUS_IN], 0);
101       else
102         g_signal_emit (controller, signals[FOCUS_OUT], 0);
103 
104       return FALSE;
105     }
106 
107   if (event_type != GDK_KEY_PRESS && event_type != GDK_KEY_RELEASE)
108     return FALSE;
109 
110   if (key->im_context &&
111       gtk_im_context_filter_keypress (key->im_context, (GdkEventKey *) event))
112     {
113       g_signal_emit (controller, signals[IM_UPDATE], 0);
114       return TRUE;
115     }
116 
117   key->current_event = event;
118 
119   gdk_event_get_state (event, &state);
120   if (key->state != state)
121     {
122       gboolean unused;
123 
124       key->state = state;
125       g_signal_emit (controller, signals[MODIFIERS], 0, state, &unused);
126     }
127 
128   gdk_event_get_keycode (event, &keycode);
129   gdk_event_get_keyval (event, &keyval);
130 
131   if (event_type == GDK_KEY_PRESS)
132     {
133       g_signal_emit (controller, signals[KEY_PRESSED], 0,
134                      keyval, keycode, state, &handled);
135       if (handled)
136         g_hash_table_add (key->pressed_keys, GUINT_TO_POINTER (keyval));
137     }
138   else if (event_type == GDK_KEY_RELEASE)
139     {
140       g_signal_emit (controller, signals[KEY_RELEASED], 0,
141                      keyval, keycode, state);
142 
143       handled = g_hash_table_lookup (key->pressed_keys, GUINT_TO_POINTER (keyval)) != NULL;
144       g_hash_table_remove (key->pressed_keys, GUINT_TO_POINTER (keyval));
145     }
146   else
147     handled = FALSE;
148 
149   key->current_event = NULL;
150 
151   return handled;
152 }
153 
154 static void
gtk_event_controller_key_class_init(GtkEventControllerKeyClass * klass)155 gtk_event_controller_key_class_init (GtkEventControllerKeyClass *klass)
156 {
157   GtkEventControllerClass *controller_class = GTK_EVENT_CONTROLLER_CLASS (klass);
158   GObjectClass *object_class = G_OBJECT_CLASS (klass);
159 
160   object_class->finalize = gtk_event_controller_finalize;
161   controller_class->handle_event = gtk_event_controller_key_handle_event;
162 
163   /**
164    * GtkEventControllerKey::key-pressed:
165    * @controller: the object which received the signal.
166    * @keyval: the pressed key.
167    * @keycode: the raw code of the pressed key.
168    * @state: the bitmask, representing the state of modifier keys and pointer buttons. See #GdkModifierType.
169    *
170    * This signal is emitted whenever a key is pressed.
171    *
172    * Returns: %TRUE if the key press was handled, %FALSE otherwise.
173    *
174    * Since: 3.24
175    */
176   signals[KEY_PRESSED] =
177     g_signal_new (I_("key-pressed"),
178                   GTK_TYPE_EVENT_CONTROLLER_KEY,
179                   G_SIGNAL_RUN_LAST,
180                   0, _gtk_boolean_handled_accumulator, NULL,
181                   _gtk_marshal_BOOLEAN__UINT_UINT_FLAGS,
182                   G_TYPE_BOOLEAN, 3, G_TYPE_UINT, G_TYPE_UINT, GDK_TYPE_MODIFIER_TYPE);
183   g_signal_set_va_marshaller (signals[KEY_PRESSED],
184                               G_TYPE_FROM_CLASS (klass),
185                               _gtk_marshal_BOOLEAN__UINT_UINT_FLAGSv);
186 
187   /**
188    * GtkEventControllerKey::key-released:
189    * @controller: the object which received the signal.
190    * @keyval: the released key.
191    * @keycode: the raw code of the released key.
192    * @state: the bitmask, representing the state of modifier keys and pointer buttons. See #GdkModifierType.
193    *
194    * This signal is emitted whenever a key is released.
195    *
196    * Since: 3.24
197    */
198   signals[KEY_RELEASED] =
199     g_signal_new (I_("key-released"),
200                   GTK_TYPE_EVENT_CONTROLLER_KEY,
201                   G_SIGNAL_RUN_LAST,
202                   0, NULL, NULL,
203                   _gtk_marshal_VOID__UINT_UINT_FLAGS,
204                   G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_UINT, GDK_TYPE_MODIFIER_TYPE);
205   g_signal_set_va_marshaller (signals[KEY_RELEASED],
206                               G_TYPE_FROM_CLASS (klass),
207                               _gtk_marshal_VOID__UINT_UINT_FLAGSv);
208 
209   signals[MODIFIERS] =
210     g_signal_new (I_("modifiers"),
211                   GTK_TYPE_EVENT_CONTROLLER_KEY,
212                   G_SIGNAL_RUN_LAST,
213                   0, NULL,
214                   NULL,
215                   _gtk_marshal_BOOLEAN__FLAGS,
216                   G_TYPE_BOOLEAN, 1, GDK_TYPE_MODIFIER_TYPE);
217   g_signal_set_va_marshaller (signals[MODIFIERS],
218                               G_TYPE_FROM_CLASS (klass),
219                               _gtk_marshal_BOOLEAN__FLAGSv);
220 
221   signals[IM_UPDATE] =
222     g_signal_new (I_("im-update"),
223                   GTK_TYPE_EVENT_CONTROLLER_KEY,
224                   G_SIGNAL_RUN_LAST,
225                   0, NULL, NULL,
226                   NULL,
227                   G_TYPE_NONE, 0);
228   signals[FOCUS_IN] =
229     g_signal_new (I_("focus-in"),
230                   GTK_TYPE_EVENT_CONTROLLER_KEY,
231                   G_SIGNAL_RUN_LAST,
232                   0, NULL, NULL,
233                   NULL,
234                   G_TYPE_NONE, 0);
235   signals[FOCUS_OUT] =
236     g_signal_new (I_("focus-out"),
237                   GTK_TYPE_EVENT_CONTROLLER_KEY,
238                   G_SIGNAL_RUN_LAST,
239                   0, NULL, NULL,
240                   NULL,
241                   G_TYPE_NONE, 0);
242 }
243 
244 static void
gtk_event_controller_key_init(GtkEventControllerKey * controller)245 gtk_event_controller_key_init (GtkEventControllerKey *controller)
246 {
247   controller->pressed_keys = g_hash_table_new (NULL, NULL);
248 }
249 
250 GtkEventController *
gtk_event_controller_key_new(GtkWidget * widget)251 gtk_event_controller_key_new (GtkWidget *widget)
252 {
253   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
254 
255   return g_object_new (GTK_TYPE_EVENT_CONTROLLER_KEY,
256                        "widget", widget,
257                        NULL);
258 }
259 
260 void
gtk_event_controller_key_set_im_context(GtkEventControllerKey * controller,GtkIMContext * im_context)261 gtk_event_controller_key_set_im_context (GtkEventControllerKey *controller,
262                                          GtkIMContext          *im_context)
263 {
264   g_return_if_fail (GTK_IS_EVENT_CONTROLLER_KEY (controller));
265   g_return_if_fail (!im_context || GTK_IS_IM_CONTEXT (im_context));
266 
267   if (controller->im_context)
268     gtk_im_context_reset (controller->im_context);
269 
270   g_set_object (&controller->im_context, im_context);
271 }
272 
273 /**
274  * gtk_event_controller_key_get_im_context:
275  * @controller: a #GtkEventControllerKey
276  *
277  * Gets the IM context of a key controller.
278  *
279  * Returns: (transfer none): the IM context
280  *
281  * Since: 3.24
282  **/
283 GtkIMContext *
gtk_event_controller_key_get_im_context(GtkEventControllerKey * controller)284 gtk_event_controller_key_get_im_context (GtkEventControllerKey *controller)
285 {
286   g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_KEY (controller), NULL);
287 
288   return controller->im_context;
289 }
290 
291 gboolean
gtk_event_controller_key_forward(GtkEventControllerKey * controller,GtkWidget * widget)292 gtk_event_controller_key_forward (GtkEventControllerKey *controller,
293                                   GtkWidget             *widget)
294 {
295   g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_KEY (controller), FALSE);
296   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
297   g_return_val_if_fail (controller->current_event != NULL, FALSE);
298 
299   if (!gtk_widget_get_realized (widget))
300     gtk_widget_realize (widget);
301 
302   if (_gtk_widget_captured_event (widget, (GdkEvent *) controller->current_event))
303     return TRUE;
304   if (gtk_widget_event (widget, (GdkEvent *) controller->current_event))
305     return TRUE;
306 
307   return FALSE;
308 }
309 
310 guint
gtk_event_controller_key_get_group(GtkEventControllerKey * controller)311 gtk_event_controller_key_get_group (GtkEventControllerKey *controller)
312 {
313   g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_KEY (controller), FALSE);
314   g_return_val_if_fail (controller->current_event != NULL, FALSE);
315 
316   return controller->current_event->key.group;
317 }
318