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 
11 
13  GObject parent_instance;
14 
15  FlKeyEventChannel* channel;
16 };
17 
18 G_DEFINE_TYPE(FlKeyChannelResponder, fl_key_channel_responder, G_TYPE_OBJECT)
19 
20 // Handles a response from the method channel to a key event sent to the
21 // framework earlier.
22 static void handle_response(GObject* object,
23  GAsyncResult* result,
24  gpointer user_data) {
25  g_autoptr(GTask) task = G_TASK(user_data);
26 
27  gboolean handled = FALSE;
28  g_autoptr(GError) error = nullptr;
29  if (!fl_key_event_channel_send_finish(object, result, &handled, &error)) {
30  g_warning("Unable to retrieve framework response: %s", error->message);
31  }
32 
33  gboolean* return_value = g_new0(gboolean, 1);
34  *return_value = handled;
35  g_task_return_pointer(task, return_value, g_free);
36 }
37 
38 // Disposes of an FlKeyChannelResponder instance.
39 static void fl_key_channel_responder_dispose(GObject* object) {
40  FlKeyChannelResponder* self = FL_KEY_CHANNEL_RESPONDER(object);
41 
42  g_clear_object(&self->channel);
43 
44  G_OBJECT_CLASS(fl_key_channel_responder_parent_class)->dispose(object);
45 }
46 
47 // Initializes the FlKeyChannelResponder class methods.
49  FlKeyChannelResponderClass* klass) {
50  G_OBJECT_CLASS(klass)->dispose = fl_key_channel_responder_dispose;
51 }
52 
53 // Initializes an FlKeyChannelResponder instance.
54 static void fl_key_channel_responder_init(FlKeyChannelResponder* self) {}
55 
56 // Creates a new FlKeyChannelResponder instance, with a messenger used to send
57 // messages to the framework, and an FlTextInputHandler that is used to handle
58 // key events that the framework doesn't handle.
59 FlKeyChannelResponder* fl_key_channel_responder_new(
60  FlBinaryMessenger* messenger) {
61  g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr);
62 
63  FlKeyChannelResponder* self = FL_KEY_CHANNEL_RESPONDER(
64  g_object_new(fl_key_channel_responder_get_type(), nullptr));
65 
66  self->channel = fl_key_event_channel_new(messenger);
67 
68  return self;
69 }
70 
71 void fl_key_channel_responder_handle_event(FlKeyChannelResponder* self,
72  FlKeyEvent* event,
73  uint64_t specified_logical_key,
74  GCancellable* cancellable,
75  GAsyncReadyCallback callback,
76  gpointer user_data) {
77  g_return_if_fail(event != nullptr);
78  g_return_if_fail(callback != nullptr);
79 
83  int64_t scan_code = fl_key_event_get_keycode(event);
84  int64_t unicode_scalar_values =
85  gdk_keyval_to_unicode(fl_key_event_get_keyval(event));
86 
87  // For most modifier keys, GTK keeps track of the "pressed" state of the
88  // modifier keys. Flutter uses this information to keep modifier keys from
89  // being "stuck" when a key-up event is lost because it happens after the app
90  // loses focus.
91  //
92  // For Lock keys (ShiftLock, CapsLock, NumLock), however, GTK keeps track of
93  // the state of the locks themselves, not the "pressed" state of the key.
94  //
95  // Since Flutter expects the "pressed" state of the modifier keys, the lock
96  // state for these keys is discarded here, and it is substituted for the
97  // pressed state of the key.
98  //
99  // This code has the flaw that if a key event is missed due to the app losing
100  // focus, then this state will still think the key is pressed when it isn't,
101  // but that is no worse than for "regular" keys until we implement the
102  // sync/cancel events on app focus changes.
103  //
104  // This is necessary to do here instead of in the framework because Flutter
105  // does modifier key syncing in the framework, and will turn on/off these keys
106  // as being "pressed" whenever the lock is on, which breaks a lot of
107  // interactions (for example, if shift-lock is on, tab traversal is broken).
108 
109  // Remove lock states from state mask.
110  guint state =
111  fl_key_event_get_state(event) & ~(GDK_LOCK_MASK | GDK_MOD2_MASK);
112 
113  static bool shift_lock_pressed = FALSE;
114  static bool caps_lock_pressed = FALSE;
115  static bool num_lock_pressed = FALSE;
116  switch (fl_key_event_get_keyval(event)) {
117  case GDK_KEY_Num_Lock:
118  num_lock_pressed = fl_key_event_get_is_press(event);
119  break;
120  case GDK_KEY_Caps_Lock:
121  caps_lock_pressed = fl_key_event_get_is_press(event);
122  break;
123  case GDK_KEY_Shift_Lock:
124  shift_lock_pressed = fl_key_event_get_is_press(event);
125  break;
126  }
127 
128  // Add back in the state matching the actual pressed state of the lock keys,
129  // not the lock states.
130  state |= (shift_lock_pressed || caps_lock_pressed) ? GDK_LOCK_MASK : 0x0;
131  state |= num_lock_pressed ? GDK_MOD2_MASK : 0x0;
132 
134  self->channel, type, scan_code, fl_key_event_get_keyval(event), state,
135  unicode_scalar_values, specified_logical_key, nullptr, handle_response,
136  g_task_new(self, cancellable, callback, user_data));
137 }
138 
140  FlKeyChannelResponder* self,
141  GAsyncResult* result,
142  gboolean* handled,
143  GError** error) {
144  g_return_val_if_fail(g_task_is_valid(result, self), FALSE);
145 
146  g_autofree gboolean* return_value =
147  static_cast<gboolean*>(g_task_propagate_pointer(G_TASK(result), error));
148  if (return_value == nullptr) {
149  return FALSE;
150  }
151 
152  *handled = *return_value;
153  return TRUE;
154 }
FL_KEY_EVENT_TYPE_KEYUP
@ FL_KEY_EVENT_TYPE_KEYUP
Definition: fl_key_event_channel.h:26
type
uint8_t type
Definition: fl_standard_message_codec_test.cc:1115
fl_key_channel_responder_init
static void fl_key_channel_responder_init(FlKeyChannelResponder *self)
Definition: fl_key_channel_responder.cc:54
fl_key_channel_responder_new
FlKeyChannelResponder * fl_key_channel_responder_new(FlBinaryMessenger *messenger)
Definition: fl_key_channel_responder.cc:59
FlKeyEventType
FlKeyEventType
Definition: fl_key_event_channel.h:25
handle_response
static void handle_response(GObject *object, GAsyncResult *result, gpointer user_data)
Definition: fl_key_channel_responder.cc:22
fl_key_event_channel.h
fl_key_channel_responder_dispose
static void fl_key_channel_responder_dispose(GObject *object)
Definition: fl_key_channel_responder.cc:39
state
AtkStateType state
Definition: fl_accessible_node.cc:10
FL_KEY_EVENT_TYPE_KEYDOWN
@ FL_KEY_EVENT_TYPE_KEYDOWN
Definition: fl_key_event_channel.h:27
_FlKeyChannelResponder
Definition: fl_key_channel_responder.cc:12
user_data
G_BEGIN_DECLS G_MODULE_EXPORT FlValue gpointer user_data
Definition: fl_event_channel.h:90
fl_key_event_get_keyval
guint fl_key_event_get_keyval(FlKeyEvent *self)
Definition: fl_key_event.cc:94
fl_key_event_channel_new
FlKeyEventChannel * fl_key_event_channel_new(FlBinaryMessenger *messenger)
Definition: fl_key_event_channel.cc:50
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
TRUE
return TRUE
Definition: fl_pixel_buffer_texture_test.cc:53
fl_key_event_channel_send_finish
gboolean fl_key_event_channel_send_finish(GObject *object, GAsyncResult *result, gboolean *handled, GError **error)
Definition: fl_key_event_channel.cc:108
fl_key_channel_responder_class_init
static void fl_key_channel_responder_class_init(FlKeyChannelResponderClass *klass)
Definition: fl_key_channel_responder.cc:48
fl_key_channel_responder_handle_event
void fl_key_channel_responder_handle_event(FlKeyChannelResponder *self, FlKeyEvent *event, uint64_t specified_logical_key, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
Definition: fl_key_channel_responder.cc:71
fl_key_event_get_state
GdkModifierType fl_key_event_get_state(FlKeyEvent *self)
Definition: fl_key_event.cc:99
fl_key_event_get_keycode
guint16 fl_key_event_get_keycode(FlKeyEvent *self)
Definition: fl_key_event.cc:89
fl_key_channel_responder_handle_event_finish
gboolean fl_key_channel_responder_handle_event_finish(FlKeyChannelResponder *self, GAsyncResult *result, gboolean *handled, GError **error)
Definition: fl_key_channel_responder.cc:139
error
const uint8_t uint32_t uint32_t GError ** error
Definition: fl_pixel_buffer_texture_test.cc:40
fl_key_event_get_is_press
gboolean fl_key_event_get_is_press(FlKeyEvent *self)
Definition: fl_key_event.cc:84
fl_key_event_channel_send
void fl_key_event_channel_send(FlKeyEventChannel *self, FlKeyEventType type, int64_t scan_code, int64_t key_code, int64_t modifiers, int64_t unicode_scalar_values, int64_t specified_logical_key, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
Definition: fl_key_event_channel.cc:63
fl_key_channel_responder.h
_FlKeyChannelResponder::parent_instance
GObject parent_instance
Definition: fl_key_channel_responder.cc:13
_FlKeyChannelResponder::channel
FlKeyEventChannel * channel
Definition: fl_key_channel_responder.cc:15