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 
6 
7 #include <gtk/gtk.h>
8 #include <cinttypes>
9 
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 
42  GObject parent_instance;
43 
44  // The current responder.
45  FlKeyChannelResponder* responder;
46  // The callback provided by the caller #FlKeyboardHandler.
48  // The user_data provided by the caller #FlKeyboardHandler.
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.
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,
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.
101 
102  FlBasicMessageChannel* channel;
103 
105 };
106 
107 static void fl_key_channel_responder_iface_init(FlKeyResponderInterface* iface);
108 
110  FlKeyChannelResponder,
111  fl_key_channel_responder,
112  G_TYPE_OBJECT,
113  G_IMPLEMENT_INTERFACE(FL_TYPE_KEY_RESPONDER,
115 
117  FlKeyResponder* responder,
118  FlKeyEvent* event,
121  gpointer user_data);
122 
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 =
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.
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 FlTextInputHandler 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,
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.
206  FlKeyResponder* responder,
207  FlKeyEvent* event,
208  uint64_t specified_logical_key,
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 =
217  int64_t scan_code = fl_key_event_get_keycode(event);
218  int64_t unicode_scarlar_values =
219  gdk_keyval_to_unicode(fl_key_event_get_keyval(event));
220 
221  // For most modifier keys, GTK keeps track of the "pressed" state of the
222  // modifier keys. Flutter uses this information to keep modifier keys from
223  // being "stuck" when a key-up event is lost because it happens after the app
224  // loses focus.
225  //
226  // For Lock keys (ShiftLock, CapsLock, NumLock), however, GTK keeps track of
227  // the state of the locks themselves, not the "pressed" state of the key.
228  //
229  // Since Flutter expects the "pressed" state of the modifier keys, the lock
230  // state for these keys is discarded here, and it is substituted for the
231  // pressed state of the key.
232  //
233  // This code has the flaw that if a key event is missed due to the app losing
234  // focus, then this state will still think the key is pressed when it isn't,
235  // but that is no worse than for "regular" keys until we implement the
236  // sync/cancel events on app focus changes.
237  //
238  // This is necessary to do here instead of in the framework because Flutter
239  // does modifier key syncing in the framework, and will turn on/off these keys
240  // as being "pressed" whenever the lock is on, which breaks a lot of
241  // interactions (for example, if shift-lock is on, tab traversal is broken).
242 
243  // Remove lock states from state mask.
244  guint state =
245  fl_key_event_get_state(event) & ~(GDK_LOCK_MASK | GDK_MOD2_MASK);
246 
247  static bool shift_lock_pressed = FALSE;
248  static bool caps_lock_pressed = FALSE;
249  static bool num_lock_pressed = FALSE;
250  switch (fl_key_event_get_keyval(event)) {
251  case GDK_KEY_Num_Lock:
252  num_lock_pressed = fl_key_event_get_is_press(event);
253  break;
254  case GDK_KEY_Caps_Lock:
255  caps_lock_pressed = fl_key_event_get_is_press(event);
256  break;
257  case GDK_KEY_Shift_Lock:
258  shift_lock_pressed = fl_key_event_get_is_press(event);
259  break;
260  }
261 
262  // Add back in the state matching the actual pressed state of the lock keys,
263  // not the lock states.
264  state |= (shift_lock_pressed || caps_lock_pressed) ? GDK_LOCK_MASK : 0x0;
265  state |= num_lock_pressed ? GDK_MOD2_MASK : 0x0;
266 
267  g_autoptr(FlValue) message = fl_value_new_map();
277  if (unicode_scarlar_values != 0) {
279  fl_value_new_int(unicode_scarlar_values));
280  }
281 
282  if (specified_logical_key != 0) {
285  }
286 
287  FlKeyChannelUserData* data =
289  // Send the message off to the framework for handling (or not).
290  fl_basic_message_channel_send(self->channel, message, nullptr,
291  handle_response, data);
292 }
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
type
uint8_t type
Definition: fl_standard_message_codec_test.cc:1115
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:650
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:42
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:661
fl_value_lookup_string
G_MODULE_EXPORT FlValue * fl_value_lookup_string(FlValue *self, const gchar *key)
Definition: fl_value.cc:811
fl_basic_message_channel.h
fl_value_new_int
G_MODULE_EXPORT FlValue * fl_value_new_int(int64_t value)
Definition: fl_value.cc:262
fl_key_channel_responder_dispose
static void fl_key_channel_responder_dispose(GObject *object)
Definition: fl_key_channel_responder.cc:164
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_key_event_get_keyval
guint fl_key_event_get_keyval(FlKeyEvent *self)
Definition: fl_key_event.cc:94
fl_value_new_map
G_MODULE_EXPORT FlValue * fl_value_new_map()
Definition: fl_value.cc:366
FL_TYPE_KEY_RESPONDER
#define FL_TYPE_KEY_RESPONDER
Definition: fl_key_responder.h:28
kSpecifiedLogicalKey
static constexpr char kSpecifiedLogicalKey[]
Definition: fl_key_channel_responder.cc:22
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
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
FlKeyResponderAsyncCallback
G_BEGIN_DECLS typedef void(* FlKeyResponderAsyncCallback)(bool handled, gpointer user_data)
Definition: fl_key_responder.h:26
result
GAsyncResult * result
Definition: fl_text_input_handler.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_event_get_state
GdkModifierType fl_key_event_get_state(FlKeyEvent *self)
Definition: fl_key_event.cc:99
fl_key_channel_user_data_init
static void fl_key_channel_user_data_init(FlKeyChannelUserData *self)
Definition: fl_key_channel_responder.cc:74
fl_key_event_get_keycode
guint16 fl_key_event_get_keycode(FlKeyEvent *self)
Definition: fl_key_event.cc:89
_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_event_get_is_press
gboolean fl_key_event_get_is_press(FlKeyEvent *self)
Definition: fl_key_event.cc:84
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:276