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