mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Add FlKeyEventPlugin (flutter/engine#18313)
This commit is contained in:
parent
6baffb9091
commit
5161b7eece
@ -1202,6 +1202,8 @@ FILE: ../../../flutter/shell/platform/linux/fl_json_message_codec.cc
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_json_message_codec_test.cc
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_json_method_codec.cc
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_json_method_codec_test.cc
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_key_event_plugin.cc
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_key_event_plugin.h
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_message_codec.cc
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_message_codec_test.cc
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_method_call.cc
|
||||
|
||||
@ -79,6 +79,7 @@ source_set("flutter_linux") {
|
||||
"fl_engine.cc",
|
||||
"fl_json_message_codec.cc",
|
||||
"fl_json_method_codec.cc",
|
||||
"fl_key_event_plugin.cc",
|
||||
"fl_message_codec.cc",
|
||||
"fl_method_call.cc",
|
||||
"fl_method_channel.cc",
|
||||
|
||||
255
engine/src/flutter/shell/platform/linux/fl_key_event_plugin.cc
Normal file
255
engine/src/flutter/shell/platform/linux/fl_key_event_plugin.cc
Normal file
@ -0,0 +1,255 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "flutter/shell/platform/linux/fl_key_event_plugin.h"
|
||||
#include "flutter/shell/platform/linux/public/flutter_linux/fl_basic_message_channel.h"
|
||||
#include "flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h"
|
||||
|
||||
static constexpr char kChannelName[] = "flutter/keyevent";
|
||||
static constexpr char kTypeKey[] = "type";
|
||||
static constexpr char kTypeValueUp[] = "keyup";
|
||||
static constexpr char kTypeValueDown[] = "keydown";
|
||||
static constexpr char kKeymapKey[] = "keymap";
|
||||
static constexpr char kKeyCodeKey[] = "keyCode";
|
||||
static constexpr char kScanCodeKey[] = "scanCode";
|
||||
static constexpr char kModifiersKey[] = "modifiers";
|
||||
static constexpr char kToolkitKey[] = "toolkit";
|
||||
static constexpr char kUnicodeScalarValuesKey[] = "unicodeScalarValues";
|
||||
|
||||
static constexpr char kGLFWToolkit[] = "glfw";
|
||||
static constexpr char kLinuxKeymap[] = "linux";
|
||||
|
||||
struct _FlKeyEventPlugin {
|
||||
GObject parent_instance;
|
||||
|
||||
FlBasicMessageChannel* channel;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(FlKeyEventPlugin, fl_key_event_plugin, G_TYPE_OBJECT)
|
||||
|
||||
// Converts a Gdk key code to its GLFW equivalent.
|
||||
// TODO(robert-ancell) Create a "gtk" toolkit in Flutter so we don't have to
|
||||
// convert values. https://github.com/flutter/flutter/issues/57603
|
||||
static int gdk_keyval_to_glfw_key_code(guint keyval) {
|
||||
switch (keyval) {
|
||||
case GDK_KEY_space:
|
||||
return 32;
|
||||
case GDK_KEY_apostrophe:
|
||||
return 39;
|
||||
case GDK_KEY_comma:
|
||||
return 44;
|
||||
case GDK_KEY_minus:
|
||||
return 45;
|
||||
case GDK_KEY_period:
|
||||
return 46;
|
||||
case GDK_KEY_slash:
|
||||
return 47;
|
||||
case GDK_KEY_0:
|
||||
return 48;
|
||||
case GDK_KEY_1:
|
||||
return 49;
|
||||
case GDK_KEY_2:
|
||||
return 50;
|
||||
case GDK_KEY_3:
|
||||
return 51;
|
||||
case GDK_KEY_4:
|
||||
return 52;
|
||||
case GDK_KEY_5:
|
||||
return 53;
|
||||
case GDK_KEY_6:
|
||||
return 54;
|
||||
case GDK_KEY_7:
|
||||
return 55;
|
||||
case GDK_KEY_8:
|
||||
return 56;
|
||||
case GDK_KEY_9:
|
||||
return 57;
|
||||
case GDK_KEY_semicolon:
|
||||
return 59;
|
||||
case GDK_KEY_equal:
|
||||
return 61;
|
||||
case GDK_KEY_a:
|
||||
return 65;
|
||||
case GDK_KEY_b:
|
||||
return 66;
|
||||
case GDK_KEY_c:
|
||||
return 67;
|
||||
case GDK_KEY_d:
|
||||
return 68;
|
||||
case GDK_KEY_e:
|
||||
return 69;
|
||||
case GDK_KEY_f:
|
||||
return 70;
|
||||
case GDK_KEY_g:
|
||||
return 71;
|
||||
case GDK_KEY_h:
|
||||
return 72;
|
||||
case GDK_KEY_i:
|
||||
return 73;
|
||||
case GDK_KEY_j:
|
||||
return 74;
|
||||
case GDK_KEY_k:
|
||||
return 75;
|
||||
case GDK_KEY_l:
|
||||
return 76;
|
||||
case GDK_KEY_m:
|
||||
return 77;
|
||||
case GDK_KEY_n:
|
||||
return 78;
|
||||
case GDK_KEY_o:
|
||||
return 79;
|
||||
case GDK_KEY_p:
|
||||
return 80;
|
||||
case GDK_KEY_q:
|
||||
return 81;
|
||||
case GDK_KEY_r:
|
||||
return 82;
|
||||
case GDK_KEY_s:
|
||||
return 83;
|
||||
case GDK_KEY_t:
|
||||
return 84;
|
||||
case GDK_KEY_u:
|
||||
return 85;
|
||||
case GDK_KEY_v:
|
||||
return 86;
|
||||
case GDK_KEY_w:
|
||||
return 87;
|
||||
case GDK_KEY_x:
|
||||
return 88;
|
||||
case GDK_KEY_y:
|
||||
return 89;
|
||||
case GDK_KEY_z:
|
||||
return 90;
|
||||
case GDK_KEY_bracketleft:
|
||||
return 91;
|
||||
case GDK_KEY_bracketright:
|
||||
return 92;
|
||||
case GDK_KEY_grave:
|
||||
return 96;
|
||||
case GDK_KEY_Escape:
|
||||
return 256;
|
||||
case GDK_KEY_Return:
|
||||
return 257;
|
||||
case GDK_KEY_Tab:
|
||||
return 258;
|
||||
case GDK_KEY_BackSpace:
|
||||
return 259;
|
||||
case GDK_KEY_Insert:
|
||||
return 260;
|
||||
case GDK_KEY_Delete:
|
||||
return 261;
|
||||
case GDK_KEY_Right:
|
||||
return 262;
|
||||
case GDK_KEY_Left:
|
||||
return 263;
|
||||
case GDK_KEY_Down:
|
||||
return 264;
|
||||
case GDK_KEY_Up:
|
||||
return 265;
|
||||
case GDK_KEY_Page_Up:
|
||||
return 266;
|
||||
case GDK_KEY_Page_Down:
|
||||
return 267;
|
||||
case GDK_KEY_Home:
|
||||
return 268;
|
||||
case GDK_KEY_End:
|
||||
return 269;
|
||||
case GDK_KEY_Shift_L:
|
||||
return 340;
|
||||
case GDK_KEY_Control_L:
|
||||
return 341;
|
||||
case GDK_KEY_Alt_L:
|
||||
return 342;
|
||||
case GDK_KEY_Super_L:
|
||||
return 343;
|
||||
case GDK_KEY_Shift_R:
|
||||
return 344;
|
||||
case GDK_KEY_Control_R:
|
||||
return 345;
|
||||
case GDK_KEY_Alt_R:
|
||||
return 346;
|
||||
case GDK_KEY_Super_R:
|
||||
return 347;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Converts a Gdk key state to its GLFW equivalent.
|
||||
int64_t gdk_state_to_glfw_modifiers(guint8 state) {
|
||||
int64_t modifiers = 0;
|
||||
|
||||
if ((state & GDK_SHIFT_MASK) != 0)
|
||||
modifiers |= 0x0001;
|
||||
if ((state & GDK_CONTROL_MASK) != 0)
|
||||
modifiers |= 0x0002;
|
||||
if ((state & GDK_MOD1_MASK) != 0)
|
||||
modifiers |= 0x0004;
|
||||
if ((state & GDK_SUPER_MASK) != 0)
|
||||
modifiers |= 0x0008;
|
||||
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
static void fl_key_event_plugin_dispose(GObject* object) {
|
||||
FlKeyEventPlugin* self = FL_KEY_EVENT_PLUGIN(object);
|
||||
|
||||
g_clear_object(&self->channel);
|
||||
|
||||
G_OBJECT_CLASS(fl_key_event_plugin_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void fl_key_event_plugin_class_init(FlKeyEventPluginClass* klass) {
|
||||
G_OBJECT_CLASS(klass)->dispose = fl_key_event_plugin_dispose;
|
||||
}
|
||||
|
||||
static void fl_key_event_plugin_init(FlKeyEventPlugin* self) {}
|
||||
|
||||
FlKeyEventPlugin* fl_key_event_plugin_new(FlBinaryMessenger* messenger) {
|
||||
g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr);
|
||||
|
||||
FlKeyEventPlugin* self = FL_KEY_EVENT_PLUGIN(
|
||||
g_object_new(fl_key_event_plugin_get_type(), nullptr));
|
||||
|
||||
g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new();
|
||||
self->channel = fl_basic_message_channel_new(messenger, kChannelName,
|
||||
FL_MESSAGE_CODEC(codec));
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void fl_key_event_plugin_send_key_event(FlKeyEventPlugin* self,
|
||||
GdkEventKey* event) {
|
||||
g_return_if_fail(FL_IS_KEY_EVENT_PLUGIN(self));
|
||||
g_return_if_fail(event != nullptr);
|
||||
|
||||
const gchar* type;
|
||||
if (event->type == GDK_KEY_PRESS)
|
||||
type = kTypeValueDown;
|
||||
else if (event->type == GDK_KEY_RELEASE)
|
||||
type = kTypeValueUp;
|
||||
else
|
||||
return;
|
||||
|
||||
int64_t scan_code = event->hardware_keycode;
|
||||
int64_t key_code = gdk_keyval_to_glfw_key_code(event->keyval);
|
||||
int64_t modifiers = gdk_state_to_glfw_modifiers(event->state);
|
||||
int64_t unicodeScalarValues = gdk_keyval_to_unicode(event->keyval);
|
||||
|
||||
g_autoptr(FlValue) message = fl_value_new_map();
|
||||
fl_value_set_string_take(message, kTypeKey, fl_value_new_string(type));
|
||||
fl_value_set_string_take(message, kKeymapKey,
|
||||
fl_value_new_string(kLinuxKeymap));
|
||||
fl_value_set_string_take(message, kScanCodeKey, fl_value_new_int(scan_code));
|
||||
fl_value_set_string_take(message, kToolkitKey,
|
||||
fl_value_new_string(kGLFWToolkit));
|
||||
fl_value_set_string_take(message, kKeyCodeKey, fl_value_new_int(key_code));
|
||||
fl_value_set_string_take(message, kModifiersKey, fl_value_new_int(modifiers));
|
||||
if (unicodeScalarValues != 0)
|
||||
fl_value_set_string_take(message, kUnicodeScalarValuesKey,
|
||||
fl_value_new_int(unicodeScalarValues));
|
||||
|
||||
fl_basic_message_channel_send(self->channel, message, nullptr, nullptr,
|
||||
nullptr);
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_EVENT_PLUGIN_H_
|
||||
#define FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_EVENT_PLUGIN_H_
|
||||
|
||||
#include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h"
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
G_DECLARE_FINAL_TYPE(FlKeyEventPlugin,
|
||||
fl_key_event_plugin,
|
||||
FL,
|
||||
KEY_EVENT_PLUGIN,
|
||||
GObject);
|
||||
|
||||
/**
|
||||
* FlKeyEventPlugin:
|
||||
*
|
||||
* #FlKeyEventPlugin is a plugin that implements the shell side
|
||||
* of SystemChannels.keyEvent from the Flutter services library.
|
||||
*/
|
||||
|
||||
/**
|
||||
* fl_key_event_plugin_new:
|
||||
* @messenger: an #FlBinaryMessenger.
|
||||
*
|
||||
* Creates a #FlKeyEventPlugin.
|
||||
*
|
||||
* Returns: a new #FlKeyEventPlugin.
|
||||
*/
|
||||
FlKeyEventPlugin* fl_key_event_plugin_new(FlBinaryMessenger* messenger);
|
||||
|
||||
/**
|
||||
* fl_key_event_plugin_send_key_event:
|
||||
* @plugin: an #FlKeyEventPlugin.
|
||||
* @event: a #GdkEventKey.
|
||||
*
|
||||
* Sends a key event to Flutter.
|
||||
*/
|
||||
void fl_key_event_plugin_send_key_event(FlKeyEventPlugin* plugin,
|
||||
GdkEventKey* event);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_EVENT_PLUGIN_H_
|
||||
@ -5,6 +5,7 @@
|
||||
#include "flutter/shell/platform/linux/public/flutter_linux/fl_view.h"
|
||||
|
||||
#include "flutter/shell/platform/linux/fl_engine_private.h"
|
||||
#include "flutter/shell/platform/linux/fl_key_event_plugin.h"
|
||||
#include "flutter/shell/platform/linux/fl_renderer_x11.h"
|
||||
#include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h"
|
||||
|
||||
@ -26,13 +27,16 @@ struct _FlView {
|
||||
|
||||
// Pointer button state recorded for sending status updates
|
||||
int64_t button_state;
|
||||
|
||||
// Flutter system channel handlers.
|
||||
FlKeyEventPlugin* key_event_plugin;
|
||||
};
|
||||
|
||||
enum { PROP_FLUTTER_PROJECT = 1, PROP_LAST };
|
||||
|
||||
G_DEFINE_TYPE(FlView, fl_view, GTK_TYPE_WIDGET)
|
||||
|
||||
// Convert a GDK button event into a Flutter event and send to the engine
|
||||
// Converts a GDK button event into a Flutter event and sends it to the engine.
|
||||
static gboolean fl_view_send_pointer_button_event(FlView* self,
|
||||
GdkEventButton* event) {
|
||||
int64_t button;
|
||||
@ -81,6 +85,10 @@ static void fl_view_constructed(GObject* object) {
|
||||
|
||||
self->renderer = fl_renderer_x11_new();
|
||||
self->engine = fl_engine_new(self->project, FL_RENDERER(self->renderer));
|
||||
|
||||
// Create system channel handlers
|
||||
FlBinaryMessenger* messenger = fl_engine_get_binary_messenger(self->engine);
|
||||
self->key_event_plugin = fl_key_event_plugin_new(messenger);
|
||||
}
|
||||
|
||||
static void fl_view_set_property(GObject* object,
|
||||
@ -122,6 +130,7 @@ static void fl_view_dispose(GObject* object) {
|
||||
g_clear_object(&self->project);
|
||||
g_clear_object(&self->renderer);
|
||||
g_clear_object(&self->engine);
|
||||
g_clear_object(&self->key_event_plugin);
|
||||
|
||||
G_OBJECT_CLASS(fl_view_parent_class)->dispose(object);
|
||||
}
|
||||
@ -145,7 +154,8 @@ static void fl_view_realize(GtkWidget* widget) {
|
||||
window_attributes.visual = gtk_widget_get_visual(widget);
|
||||
window_attributes.event_mask =
|
||||
gtk_widget_get_events(widget) | GDK_EXPOSURE_MASK |
|
||||
GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK;
|
||||
GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK |
|
||||
GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK;
|
||||
|
||||
gint window_attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
|
||||
|
||||
@ -217,6 +227,25 @@ static gboolean fl_view_motion_notify_event(GtkWidget* widget,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Implements GtkWidget::key_press_event
|
||||
static gboolean fl_view_key_press_event(GtkWidget* widget, GdkEventKey* event) {
|
||||
FlView* self = FL_VIEW(widget);
|
||||
|
||||
fl_key_event_plugin_send_key_event(self->key_event_plugin, event);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Implements GtkWidget::key_release_event
|
||||
static gboolean fl_view_key_release_event(GtkWidget* widget,
|
||||
GdkEventKey* event) {
|
||||
FlView* self = FL_VIEW(widget);
|
||||
|
||||
fl_key_event_plugin_send_key_event(self->key_event_plugin, event);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void fl_view_class_init(FlViewClass* klass) {
|
||||
G_OBJECT_CLASS(klass)->constructed = fl_view_constructed;
|
||||
G_OBJECT_CLASS(klass)->set_property = fl_view_set_property;
|
||||
@ -227,6 +256,8 @@ static void fl_view_class_init(FlViewClass* klass) {
|
||||
GTK_WIDGET_CLASS(klass)->button_press_event = fl_view_button_press_event;
|
||||
GTK_WIDGET_CLASS(klass)->button_release_event = fl_view_button_release_event;
|
||||
GTK_WIDGET_CLASS(klass)->motion_notify_event = fl_view_motion_notify_event;
|
||||
GTK_WIDGET_CLASS(klass)->key_press_event = fl_view_key_press_event;
|
||||
GTK_WIDGET_CLASS(klass)->key_release_event = fl_view_key_release_event;
|
||||
|
||||
g_object_class_install_property(
|
||||
G_OBJECT_CLASS(klass), PROP_FLUTTER_PROJECT,
|
||||
@ -237,7 +268,9 @@ static void fl_view_class_init(FlViewClass* klass) {
|
||||
G_PARAM_STATIC_STRINGS)));
|
||||
}
|
||||
|
||||
static void fl_view_init(FlView* self) {}
|
||||
static void fl_view_init(FlView* self) {
|
||||
gtk_widget_set_can_focus(GTK_WIDGET(self), TRUE);
|
||||
}
|
||||
|
||||
G_MODULE_EXPORT FlView* fl_view_new(FlDartProject* project) {
|
||||
return static_cast<FlView*>(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user