| Flutter Linux Embedder |

fl_key_channel_responder.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "flutter/shell/platform/linux/fl_key_channel_responder.h"
6
7 #include <gtk/gtk.h>
8 #include <cinttypes>
9
10 #include "flutter/shell/platform/linux/public/flutter_linux/fl_basic_message_channel.h"
11 #include "flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h"
12
13 static constexpr char kChannelName[] = "flutter/keyevent";
14 static constexpr char kTypeKey[] = "type";
15 static constexpr char kTypeValueUp[] = "keyup";
16 static constexpr char kTypeValueDown[] = "keydown";
17 static constexpr char kKeymapKey[] = "keymap";
18 static constexpr char kKeyCodeKey[] = "keyCode";
19 static constexpr char kScanCodeKey[] = "scanCode";
20 static constexpr char kModifiersKey[] = "modifiers";
21 static constexpr char kToolkitKey[] = "toolkit";
22 static constexpr char kSpecifiedLogicalKey[] = "specifiedLogicalKey";
23 static constexpr char kUnicodeScalarValuesKey[] = "unicodeScalarValues";
24
25 static constexpr char kGtkToolkit[] = "gtk";
26 static constexpr char kLinuxKeymap[] = "linux";
27
28 /* Declare and define FlKeyChannelUserData */
29
30 /**
31 * FlKeyChannelUserData:
32 * The user_data used when #FlKeyChannelResponder sends message through the
33 * channel.
34 */
35 G_DECLARE_FINAL_TYPE(FlKeyChannelUserData,
36 fl_key_channel_user_data,
37 FL,
38 KEY_CHANNEL_USER_DATA,
39 GObject);
40
41 struct _FlKeyChannelUserData {
42 GObject parent_instance;
43
44 // The current responder.
45 FlKeyChannelResponder* responder;
46 // The callback provided by the caller #FlKeyboardManager.
47 FlKeyResponderAsyncCallback callback;
48 // The user_data provided by the caller #FlKeyboardManager.
49 gpointer user_data;
50 };
51
52 // Definition for FlKeyChannelUserData private class.
53 G_DEFINE_TYPE(FlKeyChannelUserData, fl_key_channel_user_data, G_TYPE_OBJECT)
54
55 // Dispose method for FlKeyChannelUserData private class.
56 static void fl_key_channel_user_data_dispose(GObject* object) {
57 g_return_if_fail(FL_IS_KEY_CHANNEL_USER_DATA(object));
58 FlKeyChannelUserData* self = FL_KEY_CHANNEL_USER_DATA(object);
59 if (self->responder != nullptr) {
60 g_object_remove_weak_pointer(
61 G_OBJECT(self->responder),
62 reinterpret_cast<gpointer*>(&(self->responder)));
63 self->responder = nullptr;
64 }
65 }
66
67 // Class initialization method for FlKeyChannelUserData private class.
68 static void fl_key_channel_user_data_class_init(
69 FlKeyChannelUserDataClass* klass) {
70 G_OBJECT_CLASS(klass)->dispose = fl_key_channel_user_data_dispose;
71 }
72
73 // Instance initialization method for FlKeyChannelUserData private class.
74 static void fl_key_channel_user_data_init(FlKeyChannelUserData* self) {}
75
76 // Creates a new FlKeyChannelUserData private class with all information.
77 //
78 // The callback and the user_data might be nullptr.
79 static FlKeyChannelUserData* fl_key_channel_user_data_new(
80 FlKeyChannelResponder* responder,
81 FlKeyResponderAsyncCallback callback,
82 gpointer user_data) {
83 FlKeyChannelUserData* self = FL_KEY_CHANNEL_USER_DATA(
84 g_object_new(fl_key_channel_user_data_get_type(), nullptr));
85
86 self->responder = responder;
87 // Add a weak pointer so we can know if the key event responder disappeared
88 // while the framework was responding.
89 g_object_add_weak_pointer(G_OBJECT(responder),
90 reinterpret_cast<gpointer*>(&(self->responder)));
91 self->callback = callback;
92 self->user_data = user_data;
93 return self;
94 }
95
96 /* Define FlKeyChannelResponder */
97
98 // Definition of the FlKeyChannelResponder GObject class.
99 struct _FlKeyChannelResponder {
100 GObject parent_instance;
101
102 FlBasicMessageChannel* channel;
103
104 FlKeyChannelResponderMock* mock;
105 };
106
107 static void fl_key_channel_responder_iface_init(FlKeyResponderInterface* iface);
108
109 G_DEFINE_TYPE_WITH_CODE(
110 FlKeyChannelResponder,
111 fl_key_channel_responder,
112 G_TYPE_OBJECT,
113 G_IMPLEMENT_INTERFACE(FL_TYPE_KEY_RESPONDER,
114 fl_key_channel_responder_iface_init))
115
116 static void fl_key_channel_responder_handle_event(
117 FlKeyResponder* responder,
118 FlKeyEvent* event,
119 uint64_t specified_logical_key,
120 FlKeyResponderAsyncCallback callback,
121 gpointer user_data);
122
123 static void fl_key_channel_responder_iface_init(
124 FlKeyResponderInterface* iface) {
125 iface->handle_event = fl_key_channel_responder_handle_event;
126 }
127
128 /* Implement FlKeyChannelResponder */
129
130 // Handles a response from the method channel to a key event sent to the
131 // framework earlier.
132 static void handle_response(GObject* object,
133 GAsyncResult* result,
134 gpointer user_data) {
135 g_autoptr(FlKeyChannelUserData) data = FL_KEY_CHANNEL_USER_DATA(user_data);
136
137 // This is true if the weak pointer has been destroyed.
138 if (data->responder == nullptr) {
139 return;
140 }
141
142 FlKeyChannelResponder* self = data->responder;
143
144 g_autoptr(GError) error = nullptr;
145 FlBasicMessageChannel* messageChannel = FL_BASIC_MESSAGE_CHANNEL(object);
146 FlValue* message =
147 fl_basic_message_channel_send_finish(messageChannel, result, &error);
148 if (self->mock != nullptr && self->mock->value_converter != nullptr) {
149 message = self->mock->value_converter(message);
150 }
151 bool handled = false;
152 if (error != nullptr) {
153 g_warning("Unable to retrieve framework response: %s", error->message);
154 } else {
155 g_autoptr(FlValue) handled_value =
156 fl_value_lookup_string(message, "handled");
157 handled = fl_value_get_bool(handled_value);
158 }
159
160 data->callback(handled, data->user_data);
161 }
162
163 // Disposes of an FlKeyChannelResponder instance.
164 static void fl_key_channel_responder_dispose(GObject* object) {
165 FlKeyChannelResponder* self = FL_KEY_CHANNEL_RESPONDER(object);
166
167 g_clear_object(&self->channel);
168
169 G_OBJECT_CLASS(fl_key_channel_responder_parent_class)->dispose(object);
170 }
171
172 // Initializes the FlKeyChannelResponder class methods.
173 static void fl_key_channel_responder_class_init(
174 FlKeyChannelResponderClass* klass) {
175 G_OBJECT_CLASS(klass)->dispose = fl_key_channel_responder_dispose;
176 }
177
178 // Initializes an FlKeyChannelResponder instance.
179 static void fl_key_channel_responder_init(FlKeyChannelResponder* self) {}
180
181 // Creates a new FlKeyChannelResponder instance, with a messenger used to send
182 // messages to the framework, and an FlTextInputPlugin that is used to handle
183 // key events that the framework doesn't handle. Mainly for testing purposes, it
184 // also takes an optional callback to call when a response is received, and an
185 // optional channel name to use when sending messages.
186 FlKeyChannelResponder* fl_key_channel_responder_new(
187 FlBinaryMessenger* messenger,
188 FlKeyChannelResponderMock* mock) {
189 g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr);
190
191 FlKeyChannelResponder* self = FL_KEY_CHANNEL_RESPONDER(
192 g_object_new(fl_key_channel_responder_get_type(), nullptr));
193 self->mock = mock;
194
195 g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new();
196 const char* channel_name =
197 mock == nullptr ? kChannelName : mock->channel_name;
198 self->channel = fl_basic_message_channel_new(messenger, channel_name,
199 FL_MESSAGE_CODEC(codec));
200
201 return self;
202 }
203
204 // Sends a key event to the framework.
205 static void fl_key_channel_responder_handle_event(
206 FlKeyResponder* responder,
207 FlKeyEvent* event,
208 uint64_t specified_logical_key,
209 FlKeyResponderAsyncCallback callback,
210 gpointer user_data) {
211 FlKeyChannelResponder* self = FL_KEY_CHANNEL_RESPONDER(responder);
212 g_return_if_fail(event != nullptr);
213 g_return_if_fail(callback != nullptr);
214
215 const gchar* type = event->is_press ? kTypeValueDown : kTypeValueUp;
216 int64_t scan_code = event->keycode;
217 int64_t unicode_scarlar_values = gdk_keyval_to_unicode(event->keyval);
218
219 // For most modifier keys, GTK keeps track of the "pressed" state of the
220 // modifier keys. Flutter uses this information to keep modifier keys from
221 // being "stuck" when a key-up event is lost because it happens after the app
222 // loses focus.
223 //
224 // For Lock keys (ShiftLock, CapsLock, NumLock), however, GTK keeps track of
225 // the state of the locks themselves, not the "pressed" state of the key.
226 //
227 // Since Flutter expects the "pressed" state of the modifier keys, the lock
228 // state for these keys is discarded here, and it is substituted for the
229 // pressed state of the key.
230 //
231 // This code has the flaw that if a key event is missed due to the app losing
232 // focus, then this state will still think the key is pressed when it isn't,
233 // but that is no worse than for "regular" keys until we implement the
234 // sync/cancel events on app focus changes.
235 //
236 // This is necessary to do here instead of in the framework because Flutter
237 // does modifier key syncing in the framework, and will turn on/off these keys
238 // as being "pressed" whenever the lock is on, which breaks a lot of
239 // interactions (for example, if shift-lock is on, tab traversal is broken).
240
241 // Remove lock states from state mask.
242 guint state = event->state & ~(GDK_LOCK_MASK | GDK_MOD2_MASK);
243
244 static bool shift_lock_pressed = FALSE;
245 static bool caps_lock_pressed = FALSE;
246 static bool num_lock_pressed = FALSE;
247 switch (event->keyval) {
248 case GDK_KEY_Num_Lock:
249 num_lock_pressed = event->is_press;
250 break;
251 case GDK_KEY_Caps_Lock:
252 caps_lock_pressed = event->is_press;
253 break;
254 case GDK_KEY_Shift_Lock:
255 shift_lock_pressed = event->is_press;
256 break;
257 }
258
259 // Add back in the state matching the actual pressed state of the lock keys,
260 // not the lock states.
261 state |= (shift_lock_pressed || caps_lock_pressed) ? GDK_LOCK_MASK : 0x0;
262 state |= num_lock_pressed ? GDK_MOD2_MASK : 0x0;
263
264 g_autoptr(FlValue) message = fl_value_new_map();
265 fl_value_set_string_take(message, kTypeKey, fl_value_new_string(type));
266 fl_value_set_string_take(message, kKeymapKey,
267 fl_value_new_string(kLinuxKeymap));
268 fl_value_set_string_take(message, kScanCodeKey, fl_value_new_int(scan_code));
269 fl_value_set_string_take(message, kToolkitKey,
270 fl_value_new_string(kGtkToolkit));
271 fl_value_set_string_take(message, kKeyCodeKey,
272 fl_value_new_int(event->keyval));
273 fl_value_set_string_take(message, kModifiersKey, fl_value_new_int(state));
274 if (unicode_scarlar_values != 0) {
275 fl_value_set_string_take(message, kUnicodeScalarValuesKey,
276 fl_value_new_int(unicode_scarlar_values));
277 }
278
279 if (specified_logical_key != 0) {
280 fl_value_set_string_take(message, kSpecifiedLogicalKey,
281 fl_value_new_int(specified_logical_key));
282 }
283
284 FlKeyChannelUserData* data =
285 fl_key_channel_user_data_new(self, callback, user_data);
286 // Send the message off to the framework for handling (or not).
287 fl_basic_message_channel_send(self->channel, message, nullptr,
288 handle_response, data);
289 }
event
FlKeyEvent * event
Definition: fl_key_channel_responder.cc:118
fl_key_channel_user_data_dispose
static void fl_key_channel_user_data_dispose(GObject *object)
Definition: fl_key_channel_responder.cc:56
kLinuxKeymap
static constexpr char kLinuxKeymap[]
Definition: fl_key_channel_responder.cc:26
kKeyCodeKey
static constexpr char kKeyCodeKey[]
Definition: fl_key_channel_responder.cc:18
fl_key_channel_user_data_new
static FlKeyChannelUserData * fl_key_channel_user_data_new(FlKeyChannelResponder *responder, FlKeyResponderAsyncCallback callback, gpointer user_data)
Definition: fl_key_channel_responder.cc:79
fl_value_set_string_take
G_MODULE_EXPORT void fl_value_set_string_take(FlValue *self, const gchar *key, FlValue *value)
Definition: fl_value.cc:610
fl_basic_message_channel_send
G_MODULE_EXPORT void fl_basic_message_channel_send(FlBasicMessageChannel *self, FlValue *message, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
Definition: fl_basic_message_channel.cc:226
kChannelName
static constexpr char kChannelName[]
Definition: fl_key_channel_responder.cc:13
fl_key_channel_responder_init
static void fl_key_channel_responder_init(FlKeyChannelResponder *self)
Definition: fl_key_channel_responder.cc:179
kTypeValueDown
static constexpr char kTypeValueDown[]
Definition: fl_key_channel_responder.cc:16
handle_response
static void handle_response(GObject *object, GAsyncResult *result, gpointer user_data)
Definition: fl_key_channel_responder.cc:132
FlValue
typedefG_BEGIN_DECLS struct _FlValue FlValue
Definition: fl_value.h:40
fl_json_message_codec_new
G_MODULE_EXPORT FlJsonMessageCodec * fl_json_message_codec_new()
Definition: fl_json_message_codec.cc:306
fl_json_message_codec.h
user_data
FlKeyEvent uint64_t FlKeyResponderAsyncCallback gpointer user_data
Definition: fl_key_channel_responder.cc:121
_FlKeyChannelResponder::mock
FlKeyChannelResponderMock * mock
Definition: fl_key_channel_responder.cc:104
_FlKeyChannelUserData::parent_instance
GObject parent_instance
Definition: fl_key_channel_responder.cc:42
fl_value_get_bool
G_MODULE_EXPORT bool fl_value_get_bool(FlValue *self)
Definition: fl_value.cc:621
fl_value_lookup_string
G_MODULE_EXPORT FlValue * fl_value_lookup_string(FlValue *self, const gchar *key)
Definition: fl_value.cc:770
fl_basic_message_channel.h
fl_value_new_int
G_MODULE_EXPORT FlValue * fl_value_new_int(int64_t value)
Definition: fl_value.cc:251
fl_key_channel_responder_dispose
static void fl_key_channel_responder_dispose(GObject *object)
Definition: fl_key_channel_responder.cc:164
_FlKeyEvent
Definition: fl_key_event.h:31
state
AtkStateType state
Definition: fl_accessible_node.cc:10
fl_key_channel_responder_new
FlKeyChannelResponder * fl_key_channel_responder_new(FlBinaryMessenger *messenger, FlKeyChannelResponderMock *mock)
Definition: fl_key_channel_responder.cc:186
kModifiersKey
static constexpr char kModifiersKey[]
Definition: fl_key_channel_responder.cc:20
kTypeValueUp
static constexpr char kTypeValueUp[]
Definition: fl_key_channel_responder.cc:15
_FlKeyChannelResponder
Definition: fl_key_channel_responder.cc:99
_FlKeyChannelUserData
Definition: fl_key_channel_responder.cc:41
kScanCodeKey
static constexpr char kScanCodeKey[]
Definition: fl_key_channel_responder.cc:19
_FlKeyChannelResponderMock::channel_name
const char * channel_name
Definition: fl_key_channel_responder.h:35
fl_value_new_map
G_MODULE_EXPORT FlValue * fl_value_new_map()
Definition: fl_value.cc:355
FL_TYPE_KEY_RESPONDER
#define FL_TYPE_KEY_RESPONDER
Definition: fl_key_responder.h:30
kSpecifiedLogicalKey
static constexpr char kSpecifiedLogicalKey[]
Definition: fl_key_channel_responder.cc:22
FlKeyResponderAsyncCallback
void(* FlKeyResponderAsyncCallback)(bool handled, gpointer user_data)
Definition: fl_key_responder.h:28
G_DEFINE_TYPE
G_DEFINE_TYPE(FlBasicMessageChannelResponseHandle, fl_basic_message_channel_response_handle, G_TYPE_OBJECT) static void fl_basic_message_channel_response_handle_dispose(GObject *object)
Definition: fl_basic_message_channel.cc:37
kGtkToolkit
static constexpr char kGtkToolkit[]
Definition: fl_key_channel_responder.cc:25
fl_key_channel_responder_class_init
static void fl_key_channel_responder_class_init(FlKeyChannelResponderClass *klass)
Definition: fl_key_channel_responder.cc:173
g_object_add_weak_pointer
g_object_add_weak_pointer(G_OBJECT(self), reinterpret_cast< gpointer * >(&self->engine))
_FlKeyEvent::keyval
guint keyval
Definition: fl_key_event.h:39
kTypeKey
static constexpr char kTypeKey[]
Definition: fl_key_channel_responder.cc:14
FL
FL
Definition: fl_binary_messenger.cc:27
_FlKeyChannelUserData::callback
FlKeyResponderAsyncCallback callback
Definition: fl_key_channel_responder.cc:47
kKeymapKey
static constexpr char kKeymapKey[]
Definition: fl_key_channel_responder.cc:17
self
GdkEvent FlView * self
Definition: fl_view.cc:100
result
GAsyncResult * result
Definition: fl_text_input_plugin.cc:106
G_DEFINE_TYPE_WITH_CODE
G_DEFINE_TYPE_WITH_CODE(FlKeyChannelResponder, fl_key_channel_responder, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE(FL_TYPE_KEY_RESPONDER, fl_key_channel_responder_iface_init)) static void fl_key_channel_responder_handle_event(FlKeyResponder *responder
fl_key_channel_user_data_init
static void fl_key_channel_user_data_init(FlKeyChannelUserData *self)
Definition: fl_key_channel_responder.cc:74
_FlKeyChannelUserData::responder
FlKeyChannelResponder * responder
Definition: fl_key_channel_responder.cc:45
error
const uint8_t uint32_t uint32_t GError ** error
Definition: fl_pixel_buffer_texture_test.cc:40
fl_key_channel_responder_iface_init
static void fl_key_channel_responder_iface_init(FlKeyResponderInterface *iface)
Definition: fl_key_channel_responder.cc:123
fl_key_channel_user_data_class_init
static void fl_key_channel_user_data_class_init(FlKeyChannelUserDataClass *klass)
Definition: fl_key_channel_responder.cc:68
_FlKeyChannelResponder::channel
FlBasicMessageChannel * channel
Definition: fl_key_channel_responder.cc:102
_FlKeyChannelResponderMock
Definition: fl_key_channel_responder.h:23
specified_logical_key
FlKeyEvent uint64_t specified_logical_key
Definition: fl_key_channel_responder.cc:119
kToolkitKey
static constexpr char kToolkitKey[]
Definition: fl_key_channel_responder.cc:21
fl_key_channel_responder_handle_event
static void fl_key_channel_responder_handle_event(FlKeyResponder *responder, FlKeyEvent *event, uint64_t specified_logical_key, FlKeyResponderAsyncCallback callback, gpointer user_data)
Definition: fl_key_channel_responder.cc:205
_FlKeyChannelUserData::user_data
gpointer user_data
Definition: fl_key_channel_responder.cc:49
callback
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
Definition: fl_key_channel_responder.cc:120
kUnicodeScalarValuesKey
static constexpr char kUnicodeScalarValuesKey[]
Definition: fl_key_channel_responder.cc:23
fl_key_channel_responder.h
fl_basic_message_channel_send_finish
G_MODULE_EXPORT FlValue * fl_basic_message_channel_send_finish(FlBasicMessageChannel *self, GAsyncResult *result, GError **error)
Definition: fl_basic_message_channel.cc:253
fl_basic_message_channel_new
G_MODULE_EXPORT FlBasicMessageChannel * fl_basic_message_channel_new(FlBinaryMessenger *messenger, const gchar *name, FlMessageCodec *codec)
Definition: fl_basic_message_channel.cc:154
_FlKeyChannelResponder::parent_instance
GObject parent_instance
Definition: fl_key_channel_responder.cc:100
G_DECLARE_FINAL_TYPE
G_DECLARE_FINAL_TYPE(FlKeyChannelUserData, fl_key_channel_user_data, FL, KEY_CHANNEL_USER_DATA, GObject)
fl_value_new_string
G_MODULE_EXPORT FlValue * fl_value_new_string(const gchar *value)
Definition: fl_value.cc:265