|
| 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_event_plugin.h" |
| 6 | +#include "flutter/shell/platform/linux/public/flutter_linux/fl_basic_message_channel.h" |
| 7 | +#include "flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h" |
| 8 | + |
| 9 | +static constexpr char kChannelName[] = "flutter/keyevent"; |
| 10 | +static constexpr char kTypeKey[] = "type"; |
| 11 | +static constexpr char kTypeValueUp[] = "keyup"; |
| 12 | +static constexpr char kTypeValueDown[] = "keydown"; |
| 13 | +static constexpr char kKeymapKey[] = "keymap"; |
| 14 | +static constexpr char kKeyCodeKey[] = "keyCode"; |
| 15 | +static constexpr char kScanCodeKey[] = "scanCode"; |
| 16 | +static constexpr char kModifiersKey[] = "modifiers"; |
| 17 | +static constexpr char kToolkitKey[] = "toolkit"; |
| 18 | +static constexpr char kUnicodeScalarValuesKey[] = "unicodeScalarValues"; |
| 19 | + |
| 20 | +static constexpr char kGLFWToolkit[] = "glfw"; |
| 21 | +static constexpr char kLinuxKeymap[] = "linux"; |
| 22 | + |
| 23 | +struct _FlKeyEventPlugin { |
| 24 | + GObject parent_instance; |
| 25 | + |
| 26 | + FlBasicMessageChannel* channel; |
| 27 | +}; |
| 28 | + |
| 29 | +G_DEFINE_TYPE(FlKeyEventPlugin, fl_key_event_plugin, G_TYPE_OBJECT) |
| 30 | + |
| 31 | +// Converts a Gdk key code to its GLFW equivalent. |
| 32 | +// TODO(robert-ancell) Create a "gtk" toolkit in Flutter so we don't have to |
| 33 | +// convert values. https://github.com/flutter/flutter/issues/57603 |
| 34 | +static int gdk_keyval_to_glfw_key_code(guint keyval) { |
| 35 | + switch (keyval) { |
| 36 | + case GDK_KEY_space: |
| 37 | + return 32; |
| 38 | + case GDK_KEY_apostrophe: |
| 39 | + return 39; |
| 40 | + case GDK_KEY_comma: |
| 41 | + return 44; |
| 42 | + case GDK_KEY_minus: |
| 43 | + return 45; |
| 44 | + case GDK_KEY_period: |
| 45 | + return 46; |
| 46 | + case GDK_KEY_slash: |
| 47 | + return 47; |
| 48 | + case GDK_KEY_0: |
| 49 | + return 48; |
| 50 | + case GDK_KEY_1: |
| 51 | + return 49; |
| 52 | + case GDK_KEY_2: |
| 53 | + return 50; |
| 54 | + case GDK_KEY_3: |
| 55 | + return 51; |
| 56 | + case GDK_KEY_4: |
| 57 | + return 52; |
| 58 | + case GDK_KEY_5: |
| 59 | + return 53; |
| 60 | + case GDK_KEY_6: |
| 61 | + return 54; |
| 62 | + case GDK_KEY_7: |
| 63 | + return 55; |
| 64 | + case GDK_KEY_8: |
| 65 | + return 56; |
| 66 | + case GDK_KEY_9: |
| 67 | + return 57; |
| 68 | + case GDK_KEY_semicolon: |
| 69 | + return 59; |
| 70 | + case GDK_KEY_equal: |
| 71 | + return 61; |
| 72 | + case GDK_KEY_a: |
| 73 | + return 65; |
| 74 | + case GDK_KEY_b: |
| 75 | + return 66; |
| 76 | + case GDK_KEY_c: |
| 77 | + return 67; |
| 78 | + case GDK_KEY_d: |
| 79 | + return 68; |
| 80 | + case GDK_KEY_e: |
| 81 | + return 69; |
| 82 | + case GDK_KEY_f: |
| 83 | + return 70; |
| 84 | + case GDK_KEY_g: |
| 85 | + return 71; |
| 86 | + case GDK_KEY_h: |
| 87 | + return 72; |
| 88 | + case GDK_KEY_i: |
| 89 | + return 73; |
| 90 | + case GDK_KEY_j: |
| 91 | + return 74; |
| 92 | + case GDK_KEY_k: |
| 93 | + return 75; |
| 94 | + case GDK_KEY_l: |
| 95 | + return 76; |
| 96 | + case GDK_KEY_m: |
| 97 | + return 77; |
| 98 | + case GDK_KEY_n: |
| 99 | + return 78; |
| 100 | + case GDK_KEY_o: |
| 101 | + return 79; |
| 102 | + case GDK_KEY_p: |
| 103 | + return 80; |
| 104 | + case GDK_KEY_q: |
| 105 | + return 81; |
| 106 | + case GDK_KEY_r: |
| 107 | + return 82; |
| 108 | + case GDK_KEY_s: |
| 109 | + return 83; |
| 110 | + case GDK_KEY_t: |
| 111 | + return 84; |
| 112 | + case GDK_KEY_u: |
| 113 | + return 85; |
| 114 | + case GDK_KEY_v: |
| 115 | + return 86; |
| 116 | + case GDK_KEY_w: |
| 117 | + return 87; |
| 118 | + case GDK_KEY_x: |
| 119 | + return 88; |
| 120 | + case GDK_KEY_y: |
| 121 | + return 89; |
| 122 | + case GDK_KEY_z: |
| 123 | + return 90; |
| 124 | + case GDK_KEY_bracketleft: |
| 125 | + return 91; |
| 126 | + case GDK_KEY_bracketright: |
| 127 | + return 92; |
| 128 | + case GDK_KEY_grave: |
| 129 | + return 96; |
| 130 | + case GDK_KEY_Escape: |
| 131 | + return 256; |
| 132 | + case GDK_KEY_Return: |
| 133 | + return 257; |
| 134 | + case GDK_KEY_Tab: |
| 135 | + return 258; |
| 136 | + case GDK_KEY_BackSpace: |
| 137 | + return 259; |
| 138 | + case GDK_KEY_Insert: |
| 139 | + return 260; |
| 140 | + case GDK_KEY_Delete: |
| 141 | + return 261; |
| 142 | + case GDK_KEY_Right: |
| 143 | + return 262; |
| 144 | + case GDK_KEY_Left: |
| 145 | + return 263; |
| 146 | + case GDK_KEY_Down: |
| 147 | + return 264; |
| 148 | + case GDK_KEY_Up: |
| 149 | + return 265; |
| 150 | + case GDK_KEY_Page_Up: |
| 151 | + return 266; |
| 152 | + case GDK_KEY_Page_Down: |
| 153 | + return 267; |
| 154 | + case GDK_KEY_Home: |
| 155 | + return 268; |
| 156 | + case GDK_KEY_End: |
| 157 | + return 269; |
| 158 | + case GDK_KEY_Shift_L: |
| 159 | + return 340; |
| 160 | + case GDK_KEY_Control_L: |
| 161 | + return 341; |
| 162 | + case GDK_KEY_Alt_L: |
| 163 | + return 342; |
| 164 | + case GDK_KEY_Super_L: |
| 165 | + return 343; |
| 166 | + case GDK_KEY_Shift_R: |
| 167 | + return 344; |
| 168 | + case GDK_KEY_Control_R: |
| 169 | + return 345; |
| 170 | + case GDK_KEY_Alt_R: |
| 171 | + return 346; |
| 172 | + case GDK_KEY_Super_R: |
| 173 | + return 347; |
| 174 | + default: |
| 175 | + return 0; |
| 176 | + } |
| 177 | +} |
| 178 | + |
| 179 | +// Converts a Gdk key state to its GLFW equivalent. |
| 180 | +int64_t gdk_state_to_glfw_modifiers(guint8 state) { |
| 181 | + int64_t modifiers = 0; |
| 182 | + |
| 183 | + if ((state & GDK_SHIFT_MASK) != 0) |
| 184 | + modifiers |= 0x0001; |
| 185 | + if ((state & GDK_CONTROL_MASK) != 0) |
| 186 | + modifiers |= 0x0002; |
| 187 | + if ((state & GDK_MOD1_MASK) != 0) |
| 188 | + modifiers |= 0x0004; |
| 189 | + if ((state & GDK_SUPER_MASK) != 0) |
| 190 | + modifiers |= 0x0008; |
| 191 | + |
| 192 | + return modifiers; |
| 193 | +} |
| 194 | + |
| 195 | +static void fl_key_event_plugin_dispose(GObject* object) { |
| 196 | + FlKeyEventPlugin* self = FL_KEY_EVENT_PLUGIN(object); |
| 197 | + |
| 198 | + g_clear_object(&self->channel); |
| 199 | + |
| 200 | + G_OBJECT_CLASS(fl_key_event_plugin_parent_class)->dispose(object); |
| 201 | +} |
| 202 | + |
| 203 | +static void fl_key_event_plugin_class_init(FlKeyEventPluginClass* klass) { |
| 204 | + G_OBJECT_CLASS(klass)->dispose = fl_key_event_plugin_dispose; |
| 205 | +} |
| 206 | + |
| 207 | +static void fl_key_event_plugin_init(FlKeyEventPlugin* self) {} |
| 208 | + |
| 209 | +FlKeyEventPlugin* fl_key_event_plugin_new(FlBinaryMessenger* messenger) { |
| 210 | + g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr); |
| 211 | + |
| 212 | + FlKeyEventPlugin* self = FL_KEY_EVENT_PLUGIN( |
| 213 | + g_object_new(fl_key_event_plugin_get_type(), nullptr)); |
| 214 | + |
| 215 | + g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new(); |
| 216 | + self->channel = fl_basic_message_channel_new(messenger, kChannelName, |
| 217 | + FL_MESSAGE_CODEC(codec)); |
| 218 | + |
| 219 | + return self; |
| 220 | +} |
| 221 | + |
| 222 | +void fl_key_event_plugin_send_key_event(FlKeyEventPlugin* self, |
| 223 | + GdkEventKey* event) { |
| 224 | + g_return_if_fail(FL_IS_KEY_EVENT_PLUGIN(self)); |
| 225 | + g_return_if_fail(event != nullptr); |
| 226 | + |
| 227 | + const gchar* type; |
| 228 | + if (event->type == GDK_KEY_PRESS) |
| 229 | + type = kTypeValueDown; |
| 230 | + else if (event->type == GDK_KEY_RELEASE) |
| 231 | + type = kTypeValueUp; |
| 232 | + else |
| 233 | + return; |
| 234 | + |
| 235 | + int64_t scan_code = event->hardware_keycode; |
| 236 | + int64_t key_code = gdk_keyval_to_glfw_key_code(event->keyval); |
| 237 | + int64_t modifiers = gdk_state_to_glfw_modifiers(event->state); |
| 238 | + int64_t unicodeScalarValues = gdk_keyval_to_unicode(event->keyval); |
| 239 | + |
| 240 | + g_autoptr(FlValue) message = fl_value_new_map(); |
| 241 | + fl_value_set_string_take(message, kTypeKey, fl_value_new_string(type)); |
| 242 | + fl_value_set_string_take(message, kKeymapKey, |
| 243 | + fl_value_new_string(kLinuxKeymap)); |
| 244 | + fl_value_set_string_take(message, kScanCodeKey, fl_value_new_int(scan_code)); |
| 245 | + fl_value_set_string_take(message, kToolkitKey, |
| 246 | + fl_value_new_string(kGLFWToolkit)); |
| 247 | + fl_value_set_string_take(message, kKeyCodeKey, fl_value_new_int(key_code)); |
| 248 | + fl_value_set_string_take(message, kModifiersKey, fl_value_new_int(modifiers)); |
| 249 | + if (unicodeScalarValues != 0) |
| 250 | + fl_value_set_string_take(message, kUnicodeScalarValuesKey, |
| 251 | + fl_value_new_int(unicodeScalarValues)); |
| 252 | + |
| 253 | + fl_basic_message_channel_send(self->channel, message, nullptr, nullptr, |
| 254 | + nullptr); |
| 255 | +} |
0 commit comments