mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Refactor FlKeyboardHandler (flutter/engine#55601)
Refactor FlKeyboardHandler to be more GObject and less C++. Done as we will need to move the handler from FlView to FlEngine to support multi-view.
This commit is contained in:
parent
887fcf0563
commit
971dbd79fb
@ -44809,6 +44809,8 @@ ORIGIN: ../../../flutter/shell/platform/linux/fl_key_responder.h + ../../../flut
|
||||
ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_handler.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_handler.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_handler_test.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_pending_event.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_pending_event.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_view_delegate.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_view_delegate.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/linux/fl_message_codec.cc + ../../../flutter/LICENSE
|
||||
@ -47715,6 +47717,8 @@ FILE: ../../../flutter/shell/platform/linux/fl_key_responder.h
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_keyboard_handler.cc
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_keyboard_handler.h
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_keyboard_handler_test.cc
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_keyboard_pending_event.cc
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_keyboard_pending_event.h
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_keyboard_view_delegate.cc
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_keyboard_view_delegate.h
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_message_codec.cc
|
||||
|
||||
@ -81,6 +81,7 @@ source_set("flutter_linux_sources") {
|
||||
"fl_dart_project_private.h",
|
||||
"fl_engine_private.h",
|
||||
"fl_keyboard_handler.h",
|
||||
"fl_keyboard_pending_event.h",
|
||||
"fl_keyboard_view_delegate.h",
|
||||
"fl_key_event.h",
|
||||
"fl_key_responder.h",
|
||||
@ -116,6 +117,7 @@ source_set("flutter_linux_sources") {
|
||||
"fl_key_event.cc",
|
||||
"fl_key_responder.cc",
|
||||
"fl_keyboard_handler.cc",
|
||||
"fl_keyboard_pending_event.cc",
|
||||
"fl_keyboard_view_delegate.cc",
|
||||
"fl_message_codec.cc",
|
||||
"fl_method_call.cc",
|
||||
|
||||
@ -212,9 +212,11 @@ static void fl_key_channel_responder_handle_event(
|
||||
g_return_if_fail(event != nullptr);
|
||||
g_return_if_fail(callback != nullptr);
|
||||
|
||||
const gchar* type = event->is_press ? kTypeValueDown : kTypeValueUp;
|
||||
int64_t scan_code = event->keycode;
|
||||
int64_t unicode_scarlar_values = gdk_keyval_to_unicode(event->keyval);
|
||||
const gchar* type =
|
||||
fl_key_event_get_is_press(event) ? kTypeValueDown : kTypeValueUp;
|
||||
int64_t scan_code = fl_key_event_get_keycode(event);
|
||||
int64_t unicode_scarlar_values =
|
||||
gdk_keyval_to_unicode(fl_key_event_get_keyval(event));
|
||||
|
||||
// For most modifier keys, GTK keeps track of the "pressed" state of the
|
||||
// modifier keys. Flutter uses this information to keep modifier keys from
|
||||
@ -239,20 +241,21 @@ static void fl_key_channel_responder_handle_event(
|
||||
// interactions (for example, if shift-lock is on, tab traversal is broken).
|
||||
|
||||
// Remove lock states from state mask.
|
||||
guint state = event->state & ~(GDK_LOCK_MASK | GDK_MOD2_MASK);
|
||||
guint state =
|
||||
fl_key_event_get_state(event) & ~(GDK_LOCK_MASK | GDK_MOD2_MASK);
|
||||
|
||||
static bool shift_lock_pressed = FALSE;
|
||||
static bool caps_lock_pressed = FALSE;
|
||||
static bool num_lock_pressed = FALSE;
|
||||
switch (event->keyval) {
|
||||
switch (fl_key_event_get_keyval(event)) {
|
||||
case GDK_KEY_Num_Lock:
|
||||
num_lock_pressed = event->is_press;
|
||||
num_lock_pressed = fl_key_event_get_is_press(event);
|
||||
break;
|
||||
case GDK_KEY_Caps_Lock:
|
||||
caps_lock_pressed = event->is_press;
|
||||
caps_lock_pressed = fl_key_event_get_is_press(event);
|
||||
break;
|
||||
case GDK_KEY_Shift_Lock:
|
||||
shift_lock_pressed = event->is_press;
|
||||
shift_lock_pressed = fl_key_event_get_is_press(event);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -269,7 +272,7 @@ static void fl_key_channel_responder_handle_event(
|
||||
fl_value_set_string_take(message, kToolkitKey,
|
||||
fl_value_new_string(kGtkToolkit));
|
||||
fl_value_set_string_take(message, kKeyCodeKey,
|
||||
fl_value_new_int(event->keyval));
|
||||
fl_value_new_int(fl_key_event_get_keyval(event)));
|
||||
fl_value_set_string_take(message, kModifiersKey, fl_value_new_int(state));
|
||||
if (unicode_scarlar_values != 0) {
|
||||
fl_value_set_string_take(message, kUnicodeScalarValuesKey,
|
||||
|
||||
@ -29,33 +29,6 @@ static void responder_callback(bool handled, gpointer user_data) {
|
||||
g_main_loop_quit(static_cast<GMainLoop*>(user_data));
|
||||
}
|
||||
|
||||
namespace {
|
||||
// A global variable to store new event. It is a global variable so that it can
|
||||
// be returned by #fl_key_event_new_by_mock for easy use.
|
||||
FlKeyEvent _g_key_event;
|
||||
} // namespace
|
||||
|
||||
// Create a new #FlKeyEvent with the given information.
|
||||
//
|
||||
// This event is passed to #fl_key_responder_handle_event,
|
||||
// which assumes that the event is managed by callee.
|
||||
// Therefore #fl_key_event_new_by_mock doesn't need to
|
||||
// dynamically allocate, but reuses the same global object.
|
||||
static FlKeyEvent* fl_key_event_new_by_mock(guint32 time_in_milliseconds,
|
||||
bool is_press,
|
||||
guint keyval,
|
||||
guint16 keycode,
|
||||
GdkModifierType state,
|
||||
gboolean is_modifier) {
|
||||
_g_key_event.is_press = is_press;
|
||||
_g_key_event.time = time_in_milliseconds;
|
||||
_g_key_event.state = state;
|
||||
_g_key_event.keyval = keyval;
|
||||
_g_key_event.keycode = keycode;
|
||||
_g_key_event.origin = nullptr;
|
||||
return &_g_key_event;
|
||||
}
|
||||
|
||||
// Test sending a letter "A";
|
||||
TEST(FlKeyChannelResponderTest, SendKeyEvent) {
|
||||
g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
|
||||
@ -69,11 +42,9 @@ TEST(FlKeyChannelResponderTest, SendKeyEvent) {
|
||||
g_autoptr(FlKeyResponder) responder =
|
||||
FL_KEY_RESPONDER(fl_key_channel_responder_new(messenger, &mock));
|
||||
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(12345, true, GDK_KEY_A, 0x04,
|
||||
static_cast<GdkModifierType>(0), false),
|
||||
responder_callback, loop);
|
||||
g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
|
||||
12345, TRUE, 0x04, GDK_KEY_A, static_cast<GdkModifierType>(0), 0);
|
||||
fl_key_responder_handle_event(responder, event1, responder_callback, loop);
|
||||
expected_value =
|
||||
"{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, "
|
||||
"modifiers: 0, unicodeScalarValues: 65}";
|
||||
@ -82,11 +53,9 @@ TEST(FlKeyChannelResponderTest, SendKeyEvent) {
|
||||
// Blocks here until echo_response_cb is called.
|
||||
g_main_loop_run(loop);
|
||||
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(23456, false, GDK_KEY_A, 0x04,
|
||||
static_cast<GdkModifierType>(0), false),
|
||||
responder_callback, loop);
|
||||
g_autoptr(FlKeyEvent) event2 = fl_key_event_new(
|
||||
23456, FALSE, 0x04, GDK_KEY_A, static_cast<GdkModifierType>(0), 0);
|
||||
fl_key_responder_handle_event(responder, event2, responder_callback, loop);
|
||||
expected_value =
|
||||
"{type: keyup, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, "
|
||||
"modifiers: 0, unicodeScalarValues: 65}";
|
||||
@ -110,11 +79,9 @@ void test_lock_event(guint key_code,
|
||||
g_autoptr(FlKeyResponder) responder =
|
||||
FL_KEY_RESPONDER(fl_key_channel_responder_new(messenger, &mock));
|
||||
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(12345, true, key_code, 0x04,
|
||||
static_cast<GdkModifierType>(0), false),
|
||||
responder_callback, loop);
|
||||
g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
|
||||
12345, TRUE, 0x04, key_code, static_cast<GdkModifierType>(0), 0);
|
||||
fl_key_responder_handle_event(responder, event1, responder_callback, loop);
|
||||
expected_value = down_expected;
|
||||
expected_handled = FALSE;
|
||||
|
||||
@ -123,11 +90,9 @@ void test_lock_event(guint key_code,
|
||||
|
||||
expected_value = up_expected;
|
||||
expected_handled = FALSE;
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(12346, false, key_code, 0x04,
|
||||
static_cast<GdkModifierType>(0), false),
|
||||
responder_callback, loop);
|
||||
g_autoptr(FlKeyEvent) event2 = fl_key_event_new(
|
||||
12346, FALSE, 0x04, key_code, static_cast<GdkModifierType>(0), 0);
|
||||
fl_key_responder_handle_event(responder, event2, responder_callback, loop);
|
||||
|
||||
// Blocks here until echo_response_cb is called.
|
||||
g_main_loop_run(loop);
|
||||
@ -172,11 +137,9 @@ TEST(FlKeyChannelResponderTest, TestKeyEventHandledByFramework) {
|
||||
g_autoptr(FlKeyResponder) responder =
|
||||
FL_KEY_RESPONDER(fl_key_channel_responder_new(messenger, &mock));
|
||||
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(12345, true, GDK_KEY_A, 0x04,
|
||||
static_cast<GdkModifierType>(0), false),
|
||||
responder_callback, loop);
|
||||
g_autoptr(FlKeyEvent) event = fl_key_event_new(
|
||||
12345, TRUE, 0x04, GDK_KEY_A, static_cast<GdkModifierType>(0), 0);
|
||||
fl_key_responder_handle_event(responder, event, responder_callback, loop);
|
||||
expected_handled = TRUE;
|
||||
expected_value =
|
||||
"{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, "
|
||||
@ -198,11 +161,10 @@ TEST(FlKeyChannelResponderTest, UseSpecifiedLogicalKey) {
|
||||
g_autoptr(FlKeyResponder) responder =
|
||||
FL_KEY_RESPONDER(fl_key_channel_responder_new(messenger, &mock));
|
||||
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(12345, true, GDK_KEY_A, 0x04,
|
||||
static_cast<GdkModifierType>(0), false),
|
||||
responder_callback, loop, 888);
|
||||
g_autoptr(FlKeyEvent) event = fl_key_event_new(
|
||||
12345, TRUE, 0x04, GDK_KEY_A, static_cast<GdkModifierType>(0), 0);
|
||||
fl_key_responder_handle_event(responder, event, responder_callback, loop,
|
||||
888);
|
||||
expected_handled = TRUE;
|
||||
expected_value =
|
||||
"{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, "
|
||||
|
||||
@ -297,16 +297,16 @@ static uint64_t apply_id_plane(uint64_t logical_id, uint64_t plane) {
|
||||
return (logical_id & kValueMask) | plane;
|
||||
}
|
||||
|
||||
static uint64_t event_to_physical_key(const FlKeyEvent* event) {
|
||||
auto found = xkb_to_physical_key_map.find(event->keycode);
|
||||
static uint64_t event_to_physical_key(FlKeyEvent* event) {
|
||||
auto found = xkb_to_physical_key_map.find(fl_key_event_get_keycode(event));
|
||||
if (found != xkb_to_physical_key_map.end()) {
|
||||
return found->second;
|
||||
}
|
||||
return apply_id_plane(event->keycode, kGtkPlane);
|
||||
return apply_id_plane(fl_key_event_get_keycode(event), kGtkPlane);
|
||||
}
|
||||
|
||||
static uint64_t event_to_logical_key(const FlKeyEvent* event) {
|
||||
guint keyval = event->keyval;
|
||||
static uint64_t event_to_logical_key(FlKeyEvent* event) {
|
||||
guint keyval = fl_key_event_get_keyval(event);
|
||||
auto found = gtk_keyval_to_logical_key_map.find(keyval);
|
||||
if (found != gtk_keyval_to_logical_key_map.end()) {
|
||||
return found->second;
|
||||
@ -319,14 +319,15 @@ static uint64_t event_to_logical_key(const FlKeyEvent* event) {
|
||||
return apply_id_plane(keyval, kGtkPlane);
|
||||
}
|
||||
|
||||
static uint64_t event_to_timestamp(const FlKeyEvent* event) {
|
||||
return kMicrosecondsPerMillisecond * static_cast<double>(event->time);
|
||||
static uint64_t event_to_timestamp(FlKeyEvent* event) {
|
||||
return kMicrosecondsPerMillisecond *
|
||||
static_cast<double>(fl_key_event_get_time(event));
|
||||
}
|
||||
|
||||
// Returns a newly accocated UTF-8 string from event->keyval that must be
|
||||
// freed later with g_free().
|
||||
static char* event_to_character(const FlKeyEvent* event) {
|
||||
gunichar unicodeChar = gdk_keyval_to_unicode(event->keyval);
|
||||
// Returns a newly accocated UTF-8 string from fl_key_event_get_keyval(event)
|
||||
// that must be freed later with g_free().
|
||||
static char* event_to_character(FlKeyEvent* event) {
|
||||
gunichar unicodeChar = gdk_keyval_to_unicode(fl_key_event_get_keyval(event));
|
||||
glong items_written;
|
||||
gchar* result = g_ucs4_to_utf8(&unicodeChar, 1, NULL, &items_written, NULL);
|
||||
if (items_written == 0) {
|
||||
@ -790,11 +791,11 @@ static void fl_key_embedder_responder_handle_event_impl(
|
||||
const uint64_t physical_key = corrected_modifier_physical_key(
|
||||
self->modifier_bit_to_checked_keys, physical_key_from_event, logical_key);
|
||||
const double timestamp = event_to_timestamp(event);
|
||||
const bool is_down_event = event->is_press;
|
||||
const bool is_down_event = fl_key_event_get_is_press(event);
|
||||
|
||||
SyncStateLoopContext sync_state_context;
|
||||
sync_state_context.self = self;
|
||||
sync_state_context.state = event->state;
|
||||
sync_state_context.state = fl_key_event_get_state(event);
|
||||
sync_state_context.timestamp = timestamp;
|
||||
sync_state_context.is_down = is_down_event;
|
||||
sync_state_context.event_logical_key = logical_key;
|
||||
|
||||
@ -16,9 +16,6 @@ namespace {
|
||||
constexpr gboolean kRelease = FALSE;
|
||||
constexpr gboolean kPress = TRUE;
|
||||
|
||||
constexpr gboolean kIsModifier = TRUE;
|
||||
constexpr gboolean kIsNotModifier = FALSE;
|
||||
|
||||
constexpr guint16 kKeyCodeDigit1 = 0x0au;
|
||||
constexpr guint16 kKeyCodeKeyA = 0x26u;
|
||||
constexpr guint16 kKeyCodeShiftLeft = 0x32u;
|
||||
@ -100,33 +97,6 @@ static FlKeyEmbedderCallRecord* fl_key_embedder_call_record_new(
|
||||
return self;
|
||||
}
|
||||
|
||||
namespace {
|
||||
// A global variable to store new event. It is a global variable so that it can
|
||||
// be returned by #fl_key_event_new_by_mock for easy use.
|
||||
FlKeyEvent _g_key_event;
|
||||
} // namespace
|
||||
|
||||
// Create a new #FlKeyEvent with the given information.
|
||||
//
|
||||
// This event is passed to #fl_key_responder_handle_event,
|
||||
// which assumes that the event is managed by callee.
|
||||
// Therefore #fl_key_event_new_by_mock doesn't need to
|
||||
// dynamically allocate, but reuses the same global object.
|
||||
static FlKeyEvent* fl_key_event_new_by_mock(guint32 time_in_milliseconds,
|
||||
bool is_press,
|
||||
guint keyval,
|
||||
guint16 keycode,
|
||||
GdkModifierType state,
|
||||
gboolean is_modifier) {
|
||||
_g_key_event.is_press = is_press;
|
||||
_g_key_event.time = time_in_milliseconds;
|
||||
_g_key_event.state = state;
|
||||
_g_key_event.keyval = keyval;
|
||||
_g_key_event.keycode = keycode;
|
||||
_g_key_event.origin = nullptr;
|
||||
return &_g_key_event;
|
||||
}
|
||||
|
||||
static gboolean g_expected_handled;
|
||||
static gpointer g_expected_user_data;
|
||||
|
||||
@ -176,11 +146,11 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) {
|
||||
|
||||
// On a QWERTY keyboard, press key Q (physically key A), and release.
|
||||
// Key down
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(12345, kPress, GDK_KEY_a, kKeyCodeKeyA,
|
||||
static_cast<GdkModifierType>(0), kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event1 =
|
||||
fl_key_event_new(12345, kPress, kKeyCodeKeyA, GDK_KEY_a,
|
||||
static_cast<GdkModifierType>(0), 0);
|
||||
fl_key_responder_handle_event(responder, event1, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -196,11 +166,11 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) {
|
||||
g_ptr_array_clear(g_call_records);
|
||||
|
||||
// Key up
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(12346, kRelease, GDK_KEY_a, kKeyCodeKeyA,
|
||||
static_cast<GdkModifierType>(0), kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event2 =
|
||||
fl_key_event_new(12346, kRelease, kKeyCodeKeyA, GDK_KEY_a,
|
||||
static_cast<GdkModifierType>(0), 0);
|
||||
fl_key_responder_handle_event(responder, event2, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -217,11 +187,11 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) {
|
||||
|
||||
// On an AZERTY keyboard, press key Q (physically key A), and release.
|
||||
// Key down
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(12347, kPress, GDK_KEY_q, kKeyCodeKeyA,
|
||||
static_cast<GdkModifierType>(0), kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event3 =
|
||||
fl_key_event_new(12347, kPress, kKeyCodeKeyA, GDK_KEY_q,
|
||||
static_cast<GdkModifierType>(0), 0);
|
||||
fl_key_responder_handle_event(responder, event3, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -237,11 +207,11 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) {
|
||||
g_ptr_array_clear(g_call_records);
|
||||
|
||||
// Key up
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(12348, kRelease, GDK_KEY_q, kKeyCodeKeyA,
|
||||
static_cast<GdkModifierType>(0), kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event4 =
|
||||
fl_key_event_new(12348, kRelease, kKeyCodeKeyA, GDK_KEY_q,
|
||||
static_cast<GdkModifierType>(0), 0);
|
||||
fl_key_responder_handle_event(responder, event4, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -272,11 +242,11 @@ TEST(FlKeyEmbedderResponderTest, UsesSpecifiedLogicalKey) {
|
||||
|
||||
// On an AZERTY keyboard, press physical key 1, and release.
|
||||
// Key down
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(12345, kPress, GDK_KEY_ampersand, kKeyCodeDigit1,
|
||||
static_cast<GdkModifierType>(0), kIsNotModifier),
|
||||
verify_response_handled, &user_data, kLogicalDigit1);
|
||||
g_autoptr(FlKeyEvent) event =
|
||||
fl_key_event_new(12345, kPress, kKeyCodeDigit1, GDK_KEY_ampersand,
|
||||
static_cast<GdkModifierType>(0), 0);
|
||||
fl_key_responder_handle_event(responder, event, verify_response_handled,
|
||||
&user_data, kLogicalDigit1);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -306,11 +276,11 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) {
|
||||
FlKeyEmbedderCallRecord* record;
|
||||
|
||||
// Press shift right
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(101, kPress, GDK_KEY_Shift_R, kKeyCodeShiftRight,
|
||||
static_cast<GdkModifierType>(0), kIsModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event1 =
|
||||
fl_key_event_new(101, kPress, kKeyCodeShiftRight, GDK_KEY_Shift_R,
|
||||
static_cast<GdkModifierType>(0), 0);
|
||||
fl_key_responder_handle_event(responder, event1, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -324,11 +294,10 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) {
|
||||
g_ptr_array_clear(g_call_records);
|
||||
|
||||
// Press key A
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(102, kPress, GDK_KEY_A, kKeyCodeKeyA,
|
||||
GDK_SHIFT_MASK, kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event2 =
|
||||
fl_key_event_new(102, kPress, kKeyCodeKeyA, GDK_KEY_A, GDK_SHIFT_MASK, 0);
|
||||
fl_key_responder_handle_event(responder, event2, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -342,11 +311,10 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) {
|
||||
g_ptr_array_clear(g_call_records);
|
||||
|
||||
// Release shift right
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Shift_R,
|
||||
kKeyCodeShiftRight, GDK_SHIFT_MASK, kIsModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event3 = fl_key_event_new(
|
||||
103, kRelease, kKeyCodeShiftRight, GDK_KEY_Shift_R, GDK_SHIFT_MASK, 0);
|
||||
fl_key_responder_handle_event(responder, event3, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -360,11 +328,11 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) {
|
||||
g_ptr_array_clear(g_call_records);
|
||||
|
||||
// Release key A
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(104, kRelease, GDK_KEY_A, kKeyCodeKeyA,
|
||||
static_cast<GdkModifierType>(0), kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event4 =
|
||||
fl_key_event_new(104, kRelease, kKeyCodeKeyA, GDK_KEY_A,
|
||||
static_cast<GdkModifierType>(0), 0);
|
||||
fl_key_responder_handle_event(responder, event4, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -399,11 +367,11 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) {
|
||||
FlKeyEmbedderCallRecord* record;
|
||||
|
||||
// Press Numpad 1 (stage 0)
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(101, kPress, GDK_KEY_KP_End, kKeyCodeNumpad1,
|
||||
static_cast<GdkModifierType>(0), kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event1 =
|
||||
fl_key_event_new(101, kPress, kKeyCodeNumpad1, GDK_KEY_KP_End,
|
||||
static_cast<GdkModifierType>(0), 0);
|
||||
fl_key_responder_handle_event(responder, event1, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -417,11 +385,11 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) {
|
||||
g_ptr_array_clear(g_call_records);
|
||||
|
||||
// Press NumLock (stage 0 -> 1)
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock,
|
||||
static_cast<GdkModifierType>(0), kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event2 =
|
||||
fl_key_event_new(102, kPress, kKeyCodeNumLock, GDK_KEY_Num_Lock,
|
||||
static_cast<GdkModifierType>(0), 0);
|
||||
fl_key_responder_handle_event(responder, event2, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -435,11 +403,10 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) {
|
||||
g_ptr_array_clear(g_call_records);
|
||||
|
||||
// Release numpad 1 (stage 1)
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(104, kRelease, GDK_KEY_KP_1, kKeyCodeNumpad1,
|
||||
GDK_MOD2_MASK, kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event3 = fl_key_event_new(
|
||||
104, kRelease, kKeyCodeNumpad1, GDK_KEY_KP_1, GDK_MOD2_MASK, 0);
|
||||
fl_key_responder_handle_event(responder, event3, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -453,11 +420,10 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) {
|
||||
g_ptr_array_clear(g_call_records);
|
||||
|
||||
// Release NumLock (stage 1 -> 2)
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Num_Lock, kKeyCodeNumLock,
|
||||
GDK_MOD2_MASK, kIsModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event4 = fl_key_event_new(
|
||||
103, kRelease, kKeyCodeNumLock, GDK_KEY_Num_Lock, GDK_MOD2_MASK, 0);
|
||||
fl_key_responder_handle_event(responder, event4, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -471,11 +437,10 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) {
|
||||
g_ptr_array_clear(g_call_records);
|
||||
|
||||
// Press Numpad 1 (stage 2)
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(101, kPress, GDK_KEY_KP_End, kKeyCodeNumpad1,
|
||||
GDK_MOD2_MASK, kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event5 = fl_key_event_new(
|
||||
101, kPress, kKeyCodeNumpad1, GDK_KEY_KP_End, GDK_MOD2_MASK, 0);
|
||||
fl_key_responder_handle_event(responder, event5, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -489,11 +454,10 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) {
|
||||
g_ptr_array_clear(g_call_records);
|
||||
|
||||
// Press NumLock (stage 2 -> 3)
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock,
|
||||
GDK_MOD2_MASK, kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event6 = fl_key_event_new(
|
||||
102, kPress, kKeyCodeNumLock, GDK_KEY_Num_Lock, GDK_MOD2_MASK, 0);
|
||||
fl_key_responder_handle_event(responder, event6, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -507,11 +471,10 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) {
|
||||
g_ptr_array_clear(g_call_records);
|
||||
|
||||
// Release numpad 1 (stage 3)
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(104, kRelease, GDK_KEY_KP_1, kKeyCodeNumpad1,
|
||||
GDK_MOD2_MASK, kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event7 = fl_key_event_new(
|
||||
104, kRelease, kKeyCodeNumpad1, GDK_KEY_KP_1, GDK_MOD2_MASK, 0);
|
||||
fl_key_responder_handle_event(responder, event7, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -525,11 +488,10 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) {
|
||||
g_ptr_array_clear(g_call_records);
|
||||
|
||||
// Release NumLock (stage 3 -> 0)
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Num_Lock, kKeyCodeNumLock,
|
||||
GDK_MOD2_MASK, kIsModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event8 = fl_key_event_new(
|
||||
103, kRelease, kKeyCodeNumLock, GDK_KEY_Num_Lock, GDK_MOD2_MASK, 0);
|
||||
fl_key_responder_handle_event(responder, event8, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -562,11 +524,10 @@ TEST(FlKeyEmbedderResponderTest, ReleaseShiftKeyBetweenDigitKeyEvents) {
|
||||
GdkModifierType state = static_cast<GdkModifierType>(0);
|
||||
|
||||
// Press shift left
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(101, kPress, GDK_KEY_Shift_L, kKeyCodeShiftLeft,
|
||||
state, kIsModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
|
||||
101, kPress, kKeyCodeShiftLeft, GDK_KEY_Shift_L, state, 0);
|
||||
fl_key_responder_handle_event(responder, event1, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -582,11 +543,10 @@ TEST(FlKeyEmbedderResponderTest, ReleaseShiftKeyBetweenDigitKeyEvents) {
|
||||
state = GDK_SHIFT_MASK;
|
||||
|
||||
// Press digit 1, which is '!' on a US keyboard
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(102, kPress, GDK_KEY_exclam, kKeyCodeDigit1,
|
||||
state, kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event2 =
|
||||
fl_key_event_new(102, kPress, kKeyCodeDigit1, GDK_KEY_exclam, state, 0);
|
||||
fl_key_responder_handle_event(responder, event2, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -600,11 +560,10 @@ TEST(FlKeyEmbedderResponderTest, ReleaseShiftKeyBetweenDigitKeyEvents) {
|
||||
g_ptr_array_clear(g_call_records);
|
||||
|
||||
// Release shift
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Shift_L,
|
||||
kKeyCodeShiftLeft, state, kIsModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event3 = fl_key_event_new(
|
||||
103, kRelease, kKeyCodeShiftLeft, GDK_KEY_Shift_L, state, 0);
|
||||
fl_key_responder_handle_event(responder, event3, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -620,11 +579,10 @@ TEST(FlKeyEmbedderResponderTest, ReleaseShiftKeyBetweenDigitKeyEvents) {
|
||||
state = static_cast<GdkModifierType>(0);
|
||||
|
||||
// Release digit 1, which is "1" because shift has been released.
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(104, kRelease, GDK_KEY_1, kKeyCodeDigit1, state,
|
||||
kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event4 =
|
||||
fl_key_event_new(104, kRelease, kKeyCodeDigit1, GDK_KEY_1, state, 0);
|
||||
fl_key_responder_handle_event(responder, event4, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -655,11 +613,11 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) {
|
||||
FlKeyEmbedderCallRecord* record;
|
||||
|
||||
// Press CapsLock (stage 0 -> 1)
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(101, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock,
|
||||
static_cast<GdkModifierType>(0), kIsModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event1 =
|
||||
fl_key_event_new(101, kPress, kKeyCodeCapsLock, GDK_KEY_Caps_Lock,
|
||||
static_cast<GdkModifierType>(0), 0);
|
||||
fl_key_responder_handle_event(responder, event1, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -673,11 +631,10 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) {
|
||||
g_ptr_array_clear(g_call_records);
|
||||
|
||||
// Press key A (stage 1)
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(102, kPress, GDK_KEY_A, kKeyCodeKeyA,
|
||||
GDK_LOCK_MASK, kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event2 =
|
||||
fl_key_event_new(102, kPress, kKeyCodeKeyA, GDK_KEY_A, GDK_LOCK_MASK, 0);
|
||||
fl_key_responder_handle_event(responder, event2, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -691,11 +648,10 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) {
|
||||
g_ptr_array_clear(g_call_records);
|
||||
|
||||
// Release CapsLock (stage 1 -> 2)
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Caps_Lock,
|
||||
kKeyCodeCapsLock, GDK_LOCK_MASK, kIsModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event3 = fl_key_event_new(
|
||||
103, kRelease, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, GDK_LOCK_MASK, 0);
|
||||
fl_key_responder_handle_event(responder, event3, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -709,11 +665,10 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) {
|
||||
g_ptr_array_clear(g_call_records);
|
||||
|
||||
// Release key A (stage 2)
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(104, kRelease, GDK_KEY_A, kKeyCodeKeyA,
|
||||
GDK_LOCK_MASK, kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event4 = fl_key_event_new(104, kRelease, kKeyCodeKeyA,
|
||||
GDK_KEY_A, GDK_LOCK_MASK, 0);
|
||||
fl_key_responder_handle_event(responder, event4, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -727,11 +682,10 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) {
|
||||
g_ptr_array_clear(g_call_records);
|
||||
|
||||
// Press CapsLock (stage 2 -> 3)
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(105, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock,
|
||||
GDK_LOCK_MASK, kIsModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event5 = fl_key_event_new(
|
||||
105, kPress, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, GDK_LOCK_MASK, 0);
|
||||
fl_key_responder_handle_event(responder, event5, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -745,11 +699,10 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) {
|
||||
g_ptr_array_clear(g_call_records);
|
||||
|
||||
// Press key A (stage 3)
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(106, kPress, GDK_KEY_A, kKeyCodeKeyA,
|
||||
GDK_LOCK_MASK, kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event6 =
|
||||
fl_key_event_new(106, kPress, kKeyCodeKeyA, GDK_KEY_A, GDK_LOCK_MASK, 0);
|
||||
fl_key_responder_handle_event(responder, event6, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -763,11 +716,10 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) {
|
||||
g_ptr_array_clear(g_call_records);
|
||||
|
||||
// Release CapsLock (stage 3 -> 0)
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(107, kRelease, GDK_KEY_Caps_Lock,
|
||||
kKeyCodeCapsLock, GDK_LOCK_MASK, kIsModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event7 = fl_key_event_new(
|
||||
107, kRelease, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, GDK_LOCK_MASK, 0);
|
||||
fl_key_responder_handle_event(responder, event7, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -781,11 +733,11 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) {
|
||||
g_ptr_array_clear(g_call_records);
|
||||
|
||||
// Release key A (stage 0)
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(108, kRelease, GDK_KEY_a, kKeyCodeKeyA,
|
||||
static_cast<GdkModifierType>(0), kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event8 =
|
||||
fl_key_event_new(108, kRelease, kKeyCodeKeyA, GDK_KEY_a,
|
||||
static_cast<GdkModifierType>(0), 0);
|
||||
fl_key_responder_handle_event(responder, event8, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -816,11 +768,10 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) {
|
||||
FlKeyEmbedderCallRecord* record;
|
||||
|
||||
// Press key A (stage 0)
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(101, kPress, GDK_KEY_a, kKeyCodeKeyA,
|
||||
static_cast<GdkModifierType>(0), kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
|
||||
101, kPress, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
|
||||
fl_key_responder_handle_event(responder, event1, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -834,11 +785,10 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) {
|
||||
g_ptr_array_clear(g_call_records);
|
||||
|
||||
// Press CapsLock (stage 0 -> 1)
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(102, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock,
|
||||
GDK_LOCK_MASK, kIsModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event2 = fl_key_event_new(
|
||||
102, kPress, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, GDK_LOCK_MASK, 0);
|
||||
fl_key_responder_handle_event(responder, event2, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -852,11 +802,10 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) {
|
||||
g_ptr_array_clear(g_call_records);
|
||||
|
||||
// Release CapsLock (stage 1 -> 2)
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Caps_Lock,
|
||||
kKeyCodeCapsLock, GDK_LOCK_MASK, kIsModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event3 = fl_key_event_new(
|
||||
103, kRelease, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, GDK_LOCK_MASK, 0);
|
||||
fl_key_responder_handle_event(responder, event3, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -870,11 +819,10 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) {
|
||||
g_ptr_array_clear(g_call_records);
|
||||
|
||||
// Release key A (stage 2)
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(104, kRelease, GDK_KEY_A, kKeyCodeKeyA,
|
||||
GDK_LOCK_MASK, kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event4 = fl_key_event_new(104, kRelease, kKeyCodeKeyA,
|
||||
GDK_KEY_A, GDK_LOCK_MASK, 0);
|
||||
fl_key_responder_handle_event(responder, event4, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -888,11 +836,10 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) {
|
||||
g_ptr_array_clear(g_call_records);
|
||||
|
||||
// Press key A (stage 2)
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(105, kPress, GDK_KEY_A, kKeyCodeKeyA,
|
||||
GDK_LOCK_MASK, kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event5 =
|
||||
fl_key_event_new(105, kPress, kKeyCodeKeyA, GDK_KEY_A, GDK_LOCK_MASK, 0);
|
||||
fl_key_responder_handle_event(responder, event5, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -906,11 +853,11 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) {
|
||||
g_ptr_array_clear(g_call_records);
|
||||
|
||||
// Press CapsLock (stage 2 -> 3)
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(106, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock,
|
||||
static_cast<GdkModifierType>(0), kIsModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event6 =
|
||||
fl_key_event_new(106, kPress, kKeyCodeCapsLock, GDK_KEY_Caps_Lock,
|
||||
static_cast<GdkModifierType>(0), 0);
|
||||
fl_key_responder_handle_event(responder, event6, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -924,11 +871,10 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) {
|
||||
g_ptr_array_clear(g_call_records);
|
||||
|
||||
// Release CapsLock (stage 3 -> 0)
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(107, kRelease, GDK_KEY_Caps_Lock,
|
||||
kKeyCodeCapsLock, GDK_LOCK_MASK, kIsModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event7 = fl_key_event_new(
|
||||
107, kRelease, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, GDK_LOCK_MASK, 0);
|
||||
fl_key_responder_handle_event(responder, event7, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -942,11 +888,11 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) {
|
||||
g_ptr_array_clear(g_call_records);
|
||||
|
||||
// Release key A (stage 0)
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(108, kRelease, GDK_KEY_a, kKeyCodeKeyA,
|
||||
static_cast<GdkModifierType>(0), kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event8 =
|
||||
fl_key_event_new(108, kRelease, kKeyCodeKeyA, GDK_KEY_a,
|
||||
static_cast<GdkModifierType>(0), 0);
|
||||
fl_key_responder_handle_event(responder, event8, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -973,11 +919,10 @@ TEST(FlKeyEmbedderResponderTest, TurnDuplicateDownEventsToRepeats) {
|
||||
FlKeyEmbedderCallRecord* record;
|
||||
|
||||
// Press KeyA
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(101, kPress, GDK_KEY_a, kKeyCodeKeyA,
|
||||
static_cast<GdkModifierType>(0), kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
|
||||
101, kPress, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
|
||||
fl_key_responder_handle_event(responder, event1, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
|
||||
@ -987,11 +932,10 @@ TEST(FlKeyEmbedderResponderTest, TurnDuplicateDownEventsToRepeats) {
|
||||
|
||||
// Another KeyA down events, which usually means a repeated event.
|
||||
g_expected_handled = false;
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(102, kPress, GDK_KEY_a, kKeyCodeKeyA,
|
||||
static_cast<GdkModifierType>(0), kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event2 = fl_key_event_new(
|
||||
102, kPress, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
|
||||
fl_key_responder_handle_event(responder, event2, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
|
||||
@ -1007,11 +951,11 @@ TEST(FlKeyEmbedderResponderTest, TurnDuplicateDownEventsToRepeats) {
|
||||
g_ptr_array_clear(g_call_records);
|
||||
|
||||
// Release KeyA
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(103, kRelease, GDK_KEY_q, kKeyCodeKeyA,
|
||||
static_cast<GdkModifierType>(0), kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event3 =
|
||||
fl_key_event_new(103, kRelease, kKeyCodeKeyA, GDK_KEY_q,
|
||||
static_cast<GdkModifierType>(0), 0);
|
||||
fl_key_responder_handle_event(responder, event3, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -1033,11 +977,11 @@ TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) {
|
||||
|
||||
// Release KeyA before it was even pressed.
|
||||
g_expected_handled = true; // The empty event is always handled.
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(103, kRelease, GDK_KEY_q, kKeyCodeKeyA,
|
||||
static_cast<GdkModifierType>(0), kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event =
|
||||
fl_key_event_new(103, kRelease, kKeyCodeKeyA, GDK_KEY_q,
|
||||
static_cast<GdkModifierType>(0), 0);
|
||||
fl_key_responder_handle_event(responder, event, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
|
||||
@ -1069,11 +1013,10 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) {
|
||||
GdkModifierType state = GDK_CONTROL_MASK;
|
||||
|
||||
// Send a ControlLeft up
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(101, kRelease, GDK_KEY_Control_L,
|
||||
kKeyCodeControlLeft, state, kIsModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
|
||||
101, kRelease, kKeyCodeControlLeft, GDK_KEY_Control_L, state, 0);
|
||||
fl_key_responder_handle_event(responder, event1, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 2u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -1099,11 +1042,10 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) {
|
||||
|
||||
// Send a ControlLeft down.
|
||||
state = static_cast<GdkModifierType>(0);
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(102, kPress, GDK_KEY_Control_L,
|
||||
kKeyCodeControlLeft, state, kIsModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event2 = fl_key_event_new(
|
||||
102, kPress, kKeyCodeControlLeft, GDK_KEY_Control_L, state, 0);
|
||||
fl_key_responder_handle_event(responder, event2, verify_response_handled,
|
||||
&user_data);
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
invoke_record_callback_and_verify(record, TRUE, &user_data);
|
||||
@ -1113,11 +1055,10 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) {
|
||||
state = static_cast<GdkModifierType>(0);
|
||||
|
||||
// Send another ControlLeft down
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(103, kPress, GDK_KEY_Control_L,
|
||||
kKeyCodeControlLeft, state, kIsModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event3 = fl_key_event_new(
|
||||
103, kPress, kKeyCodeControlLeft, GDK_KEY_Control_L, state, 0);
|
||||
fl_key_responder_handle_event(responder, event3, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 2u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -1141,11 +1082,10 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) {
|
||||
|
||||
// Send a ControlLeft up to clear up state.
|
||||
state = GDK_CONTROL_MASK;
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(104, kRelease, GDK_KEY_Control_L,
|
||||
kKeyCodeControlLeft, state, kIsModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event4 = fl_key_event_new(
|
||||
104, kRelease, kKeyCodeControlLeft, GDK_KEY_Control_L, state, 0);
|
||||
fl_key_responder_handle_event(responder, event4, verify_response_handled,
|
||||
&user_data);
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
invoke_record_callback_and_verify(record, TRUE, &user_data);
|
||||
@ -1157,11 +1097,10 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) {
|
||||
state = GDK_CONTROL_MASK;
|
||||
|
||||
// Send a ControlRight up.
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(105, kRelease, GDK_KEY_Control_R,
|
||||
kKeyCodeControlRight, state, kIsModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event5 = fl_key_event_new(
|
||||
105, kRelease, kKeyCodeControlRight, GDK_KEY_Control_R, state, 0);
|
||||
fl_key_responder_handle_event(responder, event5, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
// A ControlLeft down is synthesized, with an empty event.
|
||||
// Reason: The ControlLeft down is synthesized to synchronize the state
|
||||
@ -1198,11 +1137,10 @@ TEST(FlKeyEmbedderResponderTest,
|
||||
GdkModifierType state = GDK_CONTROL_MASK;
|
||||
|
||||
// Send a normal event (KeyA down)
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(101, kPress, GDK_KEY_a, kKeyCodeKeyA, state,
|
||||
kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event1 =
|
||||
fl_key_event_new(101, kPress, kKeyCodeKeyA, GDK_KEY_a, state, 0);
|
||||
fl_key_responder_handle_event(responder, event1, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 2u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -1228,11 +1166,10 @@ TEST(FlKeyEmbedderResponderTest,
|
||||
state = static_cast<GdkModifierType>(0);
|
||||
|
||||
// Send a normal event (KeyA up)
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(102, kRelease, GDK_KEY_A, kKeyCodeKeyA, state,
|
||||
kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event2 =
|
||||
fl_key_event_new(102, kRelease, kKeyCodeKeyA, GDK_KEY_A, state, 0);
|
||||
fl_key_responder_handle_event(responder, event2, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 2u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -1259,11 +1196,10 @@ TEST(FlKeyEmbedderResponderTest,
|
||||
// Press a key with physical CapsLock and logical ControlLeft.
|
||||
state = static_cast<GdkModifierType>(0);
|
||||
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(101, kPress, GDK_KEY_Control_L, kKeyCodeCapsLock,
|
||||
state, kIsModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event3 = fl_key_event_new(101, kPress, kKeyCodeCapsLock,
|
||||
GDK_KEY_Control_L, state, 0);
|
||||
fl_key_responder_handle_event(responder, event3, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -1281,11 +1217,10 @@ TEST(FlKeyEmbedderResponderTest,
|
||||
state = static_cast<GdkModifierType>(0);
|
||||
|
||||
// Send a normal event (KeyA down).
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(102, kPress, GDK_KEY_A, kKeyCodeKeyA, state,
|
||||
kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event4 =
|
||||
fl_key_event_new(102, kPress, kKeyCodeKeyA, GDK_KEY_A, state, 0);
|
||||
fl_key_responder_handle_event(responder, event4, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
// The synthesized event should have physical CapsLock and logical
|
||||
// ControlLeft.
|
||||
@ -1328,11 +1263,10 @@ TEST(FlKeyEmbedderResponderTest,
|
||||
// Press a key with physical CapsLock and logical ControlLeft.
|
||||
GdkModifierType state = static_cast<GdkModifierType>(0);
|
||||
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(101, kPress, GDK_KEY_Control_L, kKeyCodeCapsLock,
|
||||
state, kIsModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event1 = fl_key_event_new(101, kPress, kKeyCodeCapsLock,
|
||||
GDK_KEY_Control_L, state, 0);
|
||||
fl_key_responder_handle_event(responder, event1, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -1350,11 +1284,10 @@ TEST(FlKeyEmbedderResponderTest,
|
||||
state = static_cast<GdkModifierType>(0);
|
||||
|
||||
// Send a normal event (KeyA down).
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(102, kPress, GDK_KEY_A, kKeyCodeKeyA, state,
|
||||
kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event2 =
|
||||
fl_key_event_new(102, kPress, kKeyCodeKeyA, GDK_KEY_A, state, 0);
|
||||
fl_key_responder_handle_event(responder, event2, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
// The synthesized event should have physical CapsLock and logical
|
||||
// ControlLeft.
|
||||
@ -1397,11 +1330,10 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) {
|
||||
GdkModifierType state = GDK_MOD2_MASK;
|
||||
|
||||
// Send a normal event
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(101, kPress, GDK_KEY_a, kKeyCodeKeyA, state,
|
||||
kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event1 =
|
||||
fl_key_event_new(101, kPress, kKeyCodeKeyA, GDK_KEY_a, state, 0);
|
||||
fl_key_responder_handle_event(responder, event1, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 2u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -1427,11 +1359,10 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) {
|
||||
state = static_cast<GdkModifierType>(0);
|
||||
|
||||
// Release key A
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(102, kRelease, GDK_KEY_A, kKeyCodeKeyA, state,
|
||||
kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event2 =
|
||||
fl_key_event_new(102, kRelease, kKeyCodeKeyA, GDK_KEY_A, state, 0);
|
||||
fl_key_responder_handle_event(responder, event2, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 4u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -1472,11 +1403,10 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) {
|
||||
// Release NumLock. Since the previous event should have synthesized NumLock
|
||||
// to be released, this should result in only an empty event.
|
||||
g_expected_handled = true;
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Num_Lock, kKeyCodeNumLock,
|
||||
state, kIsModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event3 = fl_key_event_new(
|
||||
103, kRelease, kKeyCodeNumLock, GDK_KEY_Num_Lock, state, 0);
|
||||
fl_key_responder_handle_event(responder, event3, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 1u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -1505,11 +1435,10 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) {
|
||||
GdkModifierType state = GDK_MOD2_MASK;
|
||||
|
||||
// NumLock down
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(101, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock,
|
||||
state, kIsModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event1 = fl_key_event_new(101, kPress, kKeyCodeNumLock,
|
||||
GDK_KEY_Num_Lock, state, 0);
|
||||
fl_key_responder_handle_event(responder, event1, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 3u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -1543,11 +1472,10 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) {
|
||||
state = GDK_MOD2_MASK;
|
||||
|
||||
// NumLock up
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock,
|
||||
state, kIsModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event2 = fl_key_event_new(102, kPress, kKeyCodeNumLock,
|
||||
GDK_KEY_Num_Lock, state, 0);
|
||||
fl_key_responder_handle_event(responder, event2, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 4u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -1606,11 +1534,10 @@ TEST(FlKeyEmbedderResponderTest, SynthesizationOccursOnIgnoredEvents) {
|
||||
|
||||
// Send a KeyA up event, which will be ignored.
|
||||
g_expected_handled = true; // The ignored event is always handled.
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(101, kRelease, GDK_KEY_a, kKeyCodeKeyA, state,
|
||||
kIsNotModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event =
|
||||
fl_key_event_new(101, kRelease, kKeyCodeKeyA, GDK_KEY_a, state, 0);
|
||||
fl_key_responder_handle_event(responder, event, verify_response_handled,
|
||||
&user_data);
|
||||
|
||||
EXPECT_EQ(g_call_records->len, 2u);
|
||||
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
|
||||
@ -1659,11 +1586,10 @@ TEST(FlKeyEmbedderResponderTest, HandlesShiftAltVersusGroupNext) {
|
||||
GdkModifierType state) {
|
||||
now_time += 1;
|
||||
int user_data = 123; // Arbitrary user data
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(now_time, is_press, keyval, keycode, state,
|
||||
kIsModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event =
|
||||
fl_key_event_new(now_time, is_press, keycode, keyval, state, 0);
|
||||
fl_key_responder_handle_event(responder, event, verify_response_handled,
|
||||
&user_data);
|
||||
};
|
||||
|
||||
FlKeyEmbedderCallRecord* record;
|
||||
@ -1768,11 +1694,10 @@ TEST(FlKeyEmbedderResponderTest, HandlesShiftAltLeftIsMetaLeft) {
|
||||
GdkModifierType state) {
|
||||
now_time += 1;
|
||||
int user_data = 123; // Arbitrary user data
|
||||
fl_key_responder_handle_event(
|
||||
responder,
|
||||
fl_key_event_new_by_mock(now_time, is_press, keyval, keycode, state,
|
||||
kIsModifier),
|
||||
verify_response_handled, &user_data);
|
||||
g_autoptr(FlKeyEvent) event =
|
||||
fl_key_event_new(now_time, is_press, keycode, keyval, state, 0);
|
||||
fl_key_responder_handle_event(responder, event, verify_response_handled,
|
||||
&user_data);
|
||||
};
|
||||
|
||||
FlKeyEmbedderCallRecord* record;
|
||||
|
||||
@ -4,12 +4,59 @@
|
||||
|
||||
#include "flutter/shell/platform/linux/fl_key_event.h"
|
||||
|
||||
struct _FlKeyEvent {
|
||||
GObject parent_instance;
|
||||
|
||||
// Time in milliseconds.
|
||||
guint32 time;
|
||||
|
||||
// True if is a press event, otherwise a release event.
|
||||
gboolean is_press;
|
||||
|
||||
// Hardware keycode.
|
||||
guint16 keycode;
|
||||
|
||||
// Keyval.
|
||||
guint keyval;
|
||||
|
||||
// Modifier state.
|
||||
GdkModifierType state;
|
||||
|
||||
// Keyboard group.
|
||||
guint8 group;
|
||||
|
||||
// The original event.
|
||||
GdkEvent* origin;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(FlKeyEvent, fl_key_event, G_TYPE_OBJECT)
|
||||
|
||||
FlKeyEvent* fl_key_event_new(guint32 time,
|
||||
gboolean is_press,
|
||||
guint16 keycode,
|
||||
guint keyval,
|
||||
GdkModifierType state,
|
||||
guint8 group) {
|
||||
FlKeyEvent* self =
|
||||
FL_KEY_EVENT(g_object_new(fl_key_event_get_type(), nullptr));
|
||||
|
||||
self->time = time;
|
||||
self->is_press = is_press;
|
||||
self->keycode = keycode;
|
||||
self->keyval = keyval;
|
||||
self->state = state;
|
||||
self->group = group;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
FlKeyEvent* fl_key_event_new_from_gdk_event(GdkEvent* event) {
|
||||
g_return_val_if_fail(event != nullptr, nullptr);
|
||||
FlKeyEvent* self =
|
||||
FL_KEY_EVENT(g_object_new(fl_key_event_get_type(), nullptr));
|
||||
|
||||
GdkEventType type = gdk_event_get_event_type(event);
|
||||
g_return_val_if_fail(type == GDK_KEY_PRESS || type == GDK_KEY_RELEASE,
|
||||
nullptr);
|
||||
FlKeyEvent* result = g_new(FlKeyEvent, 1);
|
||||
|
||||
guint16 keycode = 0;
|
||||
gdk_event_get_keycode(event, &keycode);
|
||||
@ -18,26 +65,76 @@ FlKeyEvent* fl_key_event_new_from_gdk_event(GdkEvent* event) {
|
||||
GdkModifierType state = static_cast<GdkModifierType>(0);
|
||||
gdk_event_get_state(event, &state);
|
||||
|
||||
result->time = gdk_event_get_time(event);
|
||||
result->is_press = type == GDK_KEY_PRESS;
|
||||
result->keycode = keycode;
|
||||
result->keyval = keyval;
|
||||
result->state = state;
|
||||
result->group = event->key.group;
|
||||
result->origin = event;
|
||||
self->time = gdk_event_get_time(event);
|
||||
self->is_press = type == GDK_KEY_PRESS;
|
||||
self->keycode = keycode;
|
||||
self->keyval = keyval;
|
||||
self->state = state;
|
||||
self->group = event->key.group;
|
||||
self->origin = event;
|
||||
|
||||
return result;
|
||||
return self;
|
||||
}
|
||||
|
||||
void fl_key_event_dispose(FlKeyEvent* event) {
|
||||
if (event->origin != nullptr) {
|
||||
gdk_event_free(event->origin);
|
||||
}
|
||||
g_free(event);
|
||||
guint32 fl_key_event_get_time(FlKeyEvent* self) {
|
||||
g_return_val_if_fail(FL_IS_KEY_EVENT(self), 0);
|
||||
return self->time;
|
||||
}
|
||||
|
||||
FlKeyEvent* fl_key_event_clone(const FlKeyEvent* event) {
|
||||
FlKeyEvent* new_event = g_new(FlKeyEvent, 1);
|
||||
*new_event = *event;
|
||||
return new_event;
|
||||
gboolean fl_key_event_get_is_press(FlKeyEvent* self) {
|
||||
g_return_val_if_fail(FL_IS_KEY_EVENT(self), FALSE);
|
||||
return self->is_press;
|
||||
}
|
||||
|
||||
guint16 fl_key_event_get_keycode(FlKeyEvent* self) {
|
||||
g_return_val_if_fail(FL_IS_KEY_EVENT(self), 0);
|
||||
return self->keycode;
|
||||
}
|
||||
|
||||
guint fl_key_event_get_keyval(FlKeyEvent* self) {
|
||||
g_return_val_if_fail(FL_IS_KEY_EVENT(self), 0);
|
||||
return self->keyval;
|
||||
}
|
||||
|
||||
GdkModifierType fl_key_event_get_state(FlKeyEvent* self) {
|
||||
g_return_val_if_fail(FL_IS_KEY_EVENT(self), static_cast<GdkModifierType>(0));
|
||||
return self->state;
|
||||
}
|
||||
|
||||
guint8 fl_key_event_get_group(FlKeyEvent* self) {
|
||||
g_return_val_if_fail(FL_IS_KEY_EVENT(self), 0);
|
||||
return self->group;
|
||||
}
|
||||
|
||||
GdkEvent* fl_key_event_get_origin(FlKeyEvent* self) {
|
||||
g_return_val_if_fail(FL_IS_KEY_EVENT(self), nullptr);
|
||||
return self->origin;
|
||||
}
|
||||
|
||||
uint64_t fl_key_event_hash(FlKeyEvent* self) {
|
||||
g_return_val_if_fail(FL_IS_KEY_EVENT(self), 0);
|
||||
|
||||
// Combine the event timestamp, the type of event, and the hardware keycode
|
||||
// (scan code) of the event to come up with a unique id for this event that
|
||||
// can be derived solely from the event data itself, so that we can identify
|
||||
// whether or not we have seen this event already.
|
||||
guint64 type =
|
||||
static_cast<uint64_t>(self->is_press ? GDK_KEY_PRESS : GDK_KEY_RELEASE);
|
||||
guint64 keycode = static_cast<uint64_t>(self->keycode);
|
||||
return (self->time & 0xffffffff) | ((type & 0xffff) << 32) |
|
||||
((keycode & 0xffff) << 48);
|
||||
}
|
||||
|
||||
static void fl_key_event_dispose(GObject* object) {
|
||||
FlKeyEvent* self = FL_KEY_EVENT(object);
|
||||
|
||||
g_clear_pointer(&self->origin, gdk_event_free);
|
||||
|
||||
G_OBJECT_CLASS(fl_key_event_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void fl_key_event_class_init(FlKeyEventClass* klass) {
|
||||
G_OBJECT_CLASS(klass)->dispose = fl_key_event_dispose;
|
||||
}
|
||||
|
||||
static void fl_key_event_init(FlKeyEvent* self) {}
|
||||
|
||||
@ -5,8 +5,12 @@
|
||||
#ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_EVENT_H_
|
||||
#define FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_EVENT_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
|
||||
G_DECLARE_FINAL_TYPE(FlKeyEvent, fl_key_event, FL, KEY_EVENT, GObject);
|
||||
|
||||
/**
|
||||
* FlKeyEvent:
|
||||
* A struct that stores information from GdkEvent.
|
||||
@ -19,42 +23,47 @@
|
||||
* object, so that Flutter can create an event object in unit tests even after
|
||||
* migrating to GDK 4.0 which stops supporting creating GdkEvent.
|
||||
*/
|
||||
typedef struct _FlKeyEvent {
|
||||
// Time in milliseconds.
|
||||
guint32 time;
|
||||
// True if is a press event, otherwise a release event.
|
||||
bool is_press;
|
||||
// Hardware keycode.
|
||||
guint16 keycode;
|
||||
// Keyval.
|
||||
guint keyval;
|
||||
// Modifier state.
|
||||
GdkModifierType state;
|
||||
// Keyboard group.
|
||||
guint8 group;
|
||||
// The original event.
|
||||
GdkEvent* origin;
|
||||
} FlKeyEvent;
|
||||
|
||||
FlKeyEvent* fl_key_event_new(guint32 time,
|
||||
gboolean is_press,
|
||||
guint16 keycode,
|
||||
guint keyval,
|
||||
GdkModifierType state,
|
||||
guint8 group);
|
||||
|
||||
/**
|
||||
* fl_key_event_new_from_gdk_event:
|
||||
* @event: the #GdkEvent this #FlKeyEvent is based on. The #event must be a
|
||||
* #GdkEventKey, and will be destroyed by #fl_key_event_dispose.
|
||||
* @event: the #GdkEvent this #FlKeyEvent is based on.
|
||||
*
|
||||
* Create a new #FlKeyEvent based on a #GdkEvent.
|
||||
*
|
||||
* Returns: a new #FlKeyEvent. Must be freed with #fl_key_event_dispose.
|
||||
* Returns: a new #FlKeyEvent.
|
||||
*/
|
||||
FlKeyEvent* fl_key_event_new_from_gdk_event(GdkEvent* event);
|
||||
|
||||
/**
|
||||
* fl_key_event_dispose:
|
||||
* @event: the event to dispose.
|
||||
*
|
||||
* Properly disposes the content of #event and then the pointer.
|
||||
*/
|
||||
void fl_key_event_dispose(FlKeyEvent* event);
|
||||
guint32 fl_key_event_get_time(FlKeyEvent* event);
|
||||
|
||||
FlKeyEvent* fl_key_event_clone(const FlKeyEvent* source);
|
||||
gboolean fl_key_event_get_is_press(FlKeyEvent* event);
|
||||
|
||||
guint16 fl_key_event_get_keycode(FlKeyEvent* event);
|
||||
|
||||
guint fl_key_event_get_keyval(FlKeyEvent* event);
|
||||
|
||||
GdkModifierType fl_key_event_get_state(FlKeyEvent* event);
|
||||
|
||||
guint8 fl_key_event_get_group(FlKeyEvent* event);
|
||||
|
||||
GdkEvent* fl_key_event_get_origin(FlKeyEvent* event);
|
||||
|
||||
/**
|
||||
* fl_key_event_hash:
|
||||
* @event: an #FlKeyEvent.
|
||||
*
|
||||
* Calculates a unique ID for a given FlKeyEvent object to use for
|
||||
* identification of responses from the framework.
|
||||
*
|
||||
* Returns: a hash code.
|
||||
*/
|
||||
uint64_t fl_key_event_hash(FlKeyEvent* event);
|
||||
|
||||
#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_EVENT_H_
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
|
||||
#include "flutter/shell/platform/linux/fl_key_channel_responder.h"
|
||||
#include "flutter/shell/platform/linux/fl_key_embedder_responder.h"
|
||||
#include "flutter/shell/platform/linux/fl_keyboard_pending_event.h"
|
||||
#include "flutter/shell/platform/linux/key_mapping.h"
|
||||
#include "flutter/shell/platform/linux/public/flutter_linux/fl_method_channel.h"
|
||||
#include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h"
|
||||
@ -24,12 +25,6 @@ static constexpr char kGetKeyboardStateMethod[] = "getKeyboardState";
|
||||
|
||||
/* Declarations of private classes */
|
||||
|
||||
G_DECLARE_FINAL_TYPE(FlKeyboardPendingEvent,
|
||||
fl_keyboard_pending_event,
|
||||
FL,
|
||||
KEYBOARD_PENDING_EVENT,
|
||||
GObject);
|
||||
|
||||
#define FL_TYPE_KEYBOARD_HANDLER_USER_DATA \
|
||||
fl_keyboard_handler_user_data_get_type()
|
||||
G_DECLARE_FINAL_TYPE(FlKeyboardHandlerUserData,
|
||||
@ -94,10 +89,10 @@ void debug_format_layout_data(std::string& debug_layout_data,
|
||||
|
||||
} // namespace
|
||||
|
||||
static uint64_t get_logical_key_from_layout(const FlKeyEvent* event,
|
||||
static uint64_t get_logical_key_from_layout(FlKeyEvent* event,
|
||||
const DerivedLayout& layout) {
|
||||
guint8 group = event->group;
|
||||
guint16 keycode = event->keycode;
|
||||
guint8 group = fl_key_event_get_group(event);
|
||||
guint16 keycode = fl_key_event_get_keycode(event);
|
||||
if (keycode >= kLayoutSize) {
|
||||
return 0;
|
||||
}
|
||||
@ -109,93 +104,6 @@ static uint64_t get_logical_key_from_layout(const FlKeyEvent* event,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Define FlKeyboardPendingEvent */
|
||||
|
||||
/**
|
||||
* FlKeyboardPendingEvent:
|
||||
* A record for events that have been received by the handler, but
|
||||
* dispatched to other objects, whose results have yet to return.
|
||||
*
|
||||
* This object is used by both the "pending_responds" list and the
|
||||
* "pending_redispatches" list.
|
||||
*/
|
||||
|
||||
struct _FlKeyboardPendingEvent {
|
||||
GObject parent_instance;
|
||||
|
||||
// The target event.
|
||||
//
|
||||
// This is freed by #FlKeyboardPendingEvent if not null.
|
||||
std::unique_ptr<FlKeyEvent> event;
|
||||
|
||||
// Self-incrementing ID attached to an event sent to the framework.
|
||||
//
|
||||
// Used to identify pending responds.
|
||||
uint64_t sequence_id;
|
||||
// The number of responders that haven't replied.
|
||||
size_t unreplied;
|
||||
// Whether any replied responders reported true (handled).
|
||||
bool any_handled;
|
||||
|
||||
// A value calculated out of critical event information that can be used
|
||||
// to identify redispatched events.
|
||||
uint64_t hash;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(FlKeyboardPendingEvent, fl_keyboard_pending_event, G_TYPE_OBJECT)
|
||||
|
||||
static void fl_keyboard_pending_event_dispose(GObject* object) {
|
||||
// Redundant, but added so that we don't get a warning about unused function
|
||||
// for FL_IS_KEYBOARD_PENDING_EVENT.
|
||||
g_return_if_fail(FL_IS_KEYBOARD_PENDING_EVENT(object));
|
||||
|
||||
FlKeyboardPendingEvent* self = FL_KEYBOARD_PENDING_EVENT(object);
|
||||
if (self->event != nullptr) {
|
||||
fl_key_event_dispose(self->event.release());
|
||||
}
|
||||
G_OBJECT_CLASS(fl_keyboard_pending_event_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void fl_keyboard_pending_event_class_init(
|
||||
FlKeyboardPendingEventClass* klass) {
|
||||
G_OBJECT_CLASS(klass)->dispose = fl_keyboard_pending_event_dispose;
|
||||
}
|
||||
|
||||
static void fl_keyboard_pending_event_init(FlKeyboardPendingEvent* self) {}
|
||||
|
||||
// Calculates a unique ID for a given FlKeyEvent object to use for
|
||||
// identification of responses from the framework.
|
||||
static uint64_t fl_keyboard_handler_get_event_hash(FlKeyEvent* event) {
|
||||
// Combine the event timestamp, the type of event, and the hardware keycode
|
||||
// (scan code) of the event to come up with a unique id for this event that
|
||||
// can be derived solely from the event data itself, so that we can identify
|
||||
// whether or not we have seen this event already.
|
||||
guint64 type =
|
||||
static_cast<uint64_t>(event->is_press ? GDK_KEY_PRESS : GDK_KEY_RELEASE);
|
||||
guint64 keycode = static_cast<uint64_t>(event->keycode);
|
||||
return (event->time & 0xffffffff) | ((type & 0xffff) << 32) |
|
||||
((keycode & 0xffff) << 48);
|
||||
}
|
||||
|
||||
// Create a new FlKeyboardPendingEvent by providing the target event,
|
||||
// the sequence ID, and the number of responders that will reply.
|
||||
//
|
||||
// This will acquire the ownership of the event.
|
||||
static FlKeyboardPendingEvent* fl_keyboard_pending_event_new(
|
||||
std::unique_ptr<FlKeyEvent> event,
|
||||
uint64_t sequence_id,
|
||||
size_t to_reply) {
|
||||
FlKeyboardPendingEvent* self = FL_KEYBOARD_PENDING_EVENT(
|
||||
g_object_new(fl_keyboard_pending_event_get_type(), nullptr));
|
||||
|
||||
self->event = std::move(event);
|
||||
self->sequence_id = sequence_id;
|
||||
self->unreplied = to_reply;
|
||||
self->any_handled = false;
|
||||
self->hash = fl_keyboard_handler_get_event_hash(self->event.get());
|
||||
return self;
|
||||
}
|
||||
|
||||
/* Define FlKeyboardHandlerUserData */
|
||||
|
||||
/**
|
||||
@ -299,60 +207,6 @@ struct _FlKeyboardHandler {
|
||||
|
||||
G_DEFINE_TYPE(FlKeyboardHandler, fl_keyboard_handler, G_TYPE_OBJECT);
|
||||
|
||||
static void fl_keyboard_handler_dispose(GObject* object);
|
||||
|
||||
static void fl_keyboard_handler_class_init(FlKeyboardHandlerClass* klass) {
|
||||
G_OBJECT_CLASS(klass)->dispose = fl_keyboard_handler_dispose;
|
||||
}
|
||||
|
||||
static void fl_keyboard_handler_init(FlKeyboardHandler* self) {
|
||||
self->derived_layout = std::make_unique<DerivedLayout>();
|
||||
|
||||
self->keycode_to_goals =
|
||||
std::make_unique<std::map<uint16_t, const LayoutGoal*>>();
|
||||
self->logical_to_mandatory_goals =
|
||||
std::make_unique<std::map<uint64_t, const LayoutGoal*>>();
|
||||
for (const LayoutGoal& goal : layout_goals) {
|
||||
(*self->keycode_to_goals)[goal.keycode] = &goal;
|
||||
if (goal.mandatory) {
|
||||
(*self->logical_to_mandatory_goals)[goal.logical_key] = &goal;
|
||||
}
|
||||
}
|
||||
|
||||
self->responder_list = g_ptr_array_new_with_free_func(g_object_unref);
|
||||
|
||||
self->pending_responds = g_ptr_array_new();
|
||||
self->pending_redispatches = g_ptr_array_new_with_free_func(g_object_unref);
|
||||
|
||||
self->last_sequence_id = 1;
|
||||
}
|
||||
|
||||
static void fl_keyboard_handler_dispose(GObject* object) {
|
||||
FlKeyboardHandler* self = FL_KEYBOARD_HANDLER(object);
|
||||
|
||||
if (self->view_delegate != nullptr) {
|
||||
fl_keyboard_view_delegate_subscribe_to_layout_change(self->view_delegate,
|
||||
nullptr);
|
||||
g_object_remove_weak_pointer(
|
||||
G_OBJECT(self->view_delegate),
|
||||
reinterpret_cast<gpointer*>(&(self->view_delegate)));
|
||||
self->view_delegate = nullptr;
|
||||
}
|
||||
|
||||
self->derived_layout.reset();
|
||||
self->keycode_to_goals.reset();
|
||||
self->logical_to_mandatory_goals.reset();
|
||||
|
||||
g_ptr_array_free(self->responder_list, TRUE);
|
||||
g_ptr_array_set_free_func(self->pending_responds, g_object_unref);
|
||||
g_ptr_array_free(self->pending_responds, TRUE);
|
||||
g_ptr_array_free(self->pending_redispatches, TRUE);
|
||||
|
||||
G_OBJECT_CLASS(fl_keyboard_handler_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
/* Implement FlKeyboardHandler */
|
||||
|
||||
// This is an exact copy of g_ptr_array_find_with_equal_func. Somehow CI
|
||||
// reports that can not find symbol g_ptr_array_find_with_equal_func, despite
|
||||
// the fact that it runs well locally.
|
||||
@ -377,22 +231,21 @@ static gboolean g_ptr_array_find_with_equal_func1(GPtrArray* haystack,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Compare a #FlKeyboardPendingEvent with the given sequence_id. The needle
|
||||
// should be a pointer to uint64_t sequence_id.
|
||||
static gboolean compare_pending_by_sequence_id(
|
||||
gconstpointer pending,
|
||||
gconstpointer needle_sequence_id) {
|
||||
uint64_t sequence_id = *reinterpret_cast<const uint64_t*>(needle_sequence_id);
|
||||
return static_cast<const FlKeyboardPendingEvent*>(pending)->sequence_id ==
|
||||
sequence_id;
|
||||
// Compare a #FlKeyboardPendingEvent with the given sequence_id.
|
||||
static gboolean compare_pending_by_sequence_id(gconstpointer a,
|
||||
gconstpointer b) {
|
||||
FlKeyboardPendingEvent* pending =
|
||||
FL_KEYBOARD_PENDING_EVENT(const_cast<gpointer>(a));
|
||||
uint64_t sequence_id = *reinterpret_cast<const uint64_t*>(b);
|
||||
return fl_keyboard_pending_event_get_sequence_id(pending) == sequence_id;
|
||||
}
|
||||
|
||||
// Compare a #FlKeyboardPendingEvent with the given hash. The #needle should be
|
||||
// a pointer to uint64_t hash.
|
||||
static gboolean compare_pending_by_hash(gconstpointer pending,
|
||||
gconstpointer needle_hash) {
|
||||
uint64_t hash = *reinterpret_cast<const uint64_t*>(needle_hash);
|
||||
return static_cast<const FlKeyboardPendingEvent*>(pending)->hash == hash;
|
||||
// Compare a #FlKeyboardPendingEvent with the given hash.
|
||||
static gboolean compare_pending_by_hash(gconstpointer a, gconstpointer b) {
|
||||
FlKeyboardPendingEvent* pending =
|
||||
FL_KEYBOARD_PENDING_EVENT(const_cast<gpointer>(a));
|
||||
uint64_t hash = *reinterpret_cast<const uint64_t*>(b);
|
||||
return fl_keyboard_pending_event_get_hash(pending) == hash;
|
||||
}
|
||||
|
||||
// Try to remove a pending event from `pending_redispatches` with the target
|
||||
@ -431,22 +284,22 @@ static void responder_handle_event_callback(bool handled,
|
||||
FlKeyboardPendingEvent* pending = FL_KEYBOARD_PENDING_EVENT(
|
||||
g_ptr_array_index(self->pending_responds, result_index));
|
||||
g_return_if_fail(pending != nullptr);
|
||||
g_return_if_fail(pending->unreplied > 0);
|
||||
pending->unreplied -= 1;
|
||||
pending->any_handled = pending->any_handled || handled;
|
||||
fl_keyboard_pending_event_mark_replied(pending, handled);
|
||||
// All responders have replied.
|
||||
if (pending->unreplied == 0) {
|
||||
if (fl_keyboard_pending_event_is_complete(pending)) {
|
||||
g_object_unref(user_data_ptr);
|
||||
gpointer removed =
|
||||
g_ptr_array_remove_index_fast(self->pending_responds, result_index);
|
||||
g_return_if_fail(removed == pending);
|
||||
bool should_redispatch = !pending->any_handled &&
|
||||
!fl_keyboard_view_delegate_text_filter_key_press(
|
||||
self->view_delegate, pending->event.get());
|
||||
bool should_redispatch =
|
||||
!fl_keyboard_pending_event_get_any_handled(pending) &&
|
||||
!fl_keyboard_view_delegate_text_filter_key_press(
|
||||
self->view_delegate, fl_keyboard_pending_event_get_event(pending));
|
||||
if (should_redispatch) {
|
||||
g_ptr_array_add(self->pending_redispatches, pending);
|
||||
fl_keyboard_view_delegate_redispatch_event(self->view_delegate,
|
||||
std::move(pending->event));
|
||||
fl_keyboard_view_delegate_redispatch_event(
|
||||
self->view_delegate,
|
||||
FL_KEY_EVENT(fl_keyboard_pending_event_get_event(pending)));
|
||||
} else {
|
||||
g_object_unref(pending);
|
||||
}
|
||||
@ -466,11 +319,11 @@ static uint16_t convert_key_to_char(FlKeyboardViewDelegate* view_delegate,
|
||||
// Make sure that Flutter has derived the layout for the group of the event,
|
||||
// if the event contains a goal keycode.
|
||||
static void guarantee_layout(FlKeyboardHandler* self, FlKeyEvent* event) {
|
||||
guint8 group = event->group;
|
||||
guint8 group = fl_key_event_get_group(event);
|
||||
if (self->derived_layout->find(group) != self->derived_layout->end()) {
|
||||
return;
|
||||
}
|
||||
if (self->keycode_to_goals->find(event->keycode) ==
|
||||
if (self->keycode_to_goals->find(fl_key_event_get_keycode(event)) ==
|
||||
self->keycode_to_goals->end()) {
|
||||
return;
|
||||
}
|
||||
@ -541,7 +394,7 @@ static void guarantee_layout(FlKeyboardHandler* self, FlKeyEvent* event) {
|
||||
}
|
||||
|
||||
// Returns the keyboard pressed state.
|
||||
FlMethodResponse* get_keyboard_state(FlKeyboardHandler* self) {
|
||||
static FlMethodResponse* get_keyboard_state(FlKeyboardHandler* self) {
|
||||
g_autoptr(FlValue) result = fl_value_new_map();
|
||||
|
||||
GHashTable* pressing_records =
|
||||
@ -582,6 +435,67 @@ static void method_call_handler(FlMethodChannel* channel,
|
||||
}
|
||||
}
|
||||
|
||||
// The loop body to dispatch an event to a responder.
|
||||
static void dispatch_to_responder(gpointer responder_data,
|
||||
gpointer foreach_data_ptr) {
|
||||
DispatchToResponderLoopContext* context =
|
||||
reinterpret_cast<DispatchToResponderLoopContext*>(foreach_data_ptr);
|
||||
FlKeyResponder* responder = FL_KEY_RESPONDER(responder_data);
|
||||
fl_key_responder_handle_event(
|
||||
responder, context->event, responder_handle_event_callback,
|
||||
context->user_data, context->specified_logical_key);
|
||||
}
|
||||
|
||||
static void fl_keyboard_handler_dispose(GObject* object) {
|
||||
FlKeyboardHandler* self = FL_KEYBOARD_HANDLER(object);
|
||||
|
||||
if (self->view_delegate != nullptr) {
|
||||
fl_keyboard_view_delegate_subscribe_to_layout_change(self->view_delegate,
|
||||
nullptr);
|
||||
g_object_remove_weak_pointer(
|
||||
G_OBJECT(self->view_delegate),
|
||||
reinterpret_cast<gpointer*>(&(self->view_delegate)));
|
||||
self->view_delegate = nullptr;
|
||||
}
|
||||
|
||||
self->derived_layout.reset();
|
||||
self->keycode_to_goals.reset();
|
||||
self->logical_to_mandatory_goals.reset();
|
||||
|
||||
g_ptr_array_free(self->responder_list, TRUE);
|
||||
g_ptr_array_set_free_func(self->pending_responds, g_object_unref);
|
||||
g_ptr_array_free(self->pending_responds, TRUE);
|
||||
g_ptr_array_free(self->pending_redispatches, TRUE);
|
||||
|
||||
G_OBJECT_CLASS(fl_keyboard_handler_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void fl_keyboard_handler_class_init(FlKeyboardHandlerClass* klass) {
|
||||
G_OBJECT_CLASS(klass)->dispose = fl_keyboard_handler_dispose;
|
||||
}
|
||||
|
||||
static void fl_keyboard_handler_init(FlKeyboardHandler* self) {
|
||||
self->derived_layout = std::make_unique<DerivedLayout>();
|
||||
|
||||
self->keycode_to_goals =
|
||||
std::make_unique<std::map<uint16_t, const LayoutGoal*>>();
|
||||
self->logical_to_mandatory_goals =
|
||||
std::make_unique<std::map<uint64_t, const LayoutGoal*>>();
|
||||
for (const LayoutGoal& goal : layout_goals) {
|
||||
(*self->keycode_to_goals)[goal.keycode] = &goal;
|
||||
if (goal.mandatory) {
|
||||
(*self->logical_to_mandatory_goals)[goal.logical_key] = &goal;
|
||||
}
|
||||
}
|
||||
|
||||
self->responder_list = g_ptr_array_new_with_free_func(g_object_unref);
|
||||
|
||||
self->pending_responds = g_ptr_array_new();
|
||||
self->pending_redispatches = g_ptr_array_new_with_free_func(g_object_unref);
|
||||
|
||||
self->last_sequence_id = 1;
|
||||
}
|
||||
|
||||
FlKeyboardHandler* fl_keyboard_handler_new(
|
||||
FlBinaryMessenger* messenger,
|
||||
FlKeyboardViewDelegate* view_delegate) {
|
||||
@ -624,17 +538,6 @@ FlKeyboardHandler* fl_keyboard_handler_new(
|
||||
return self;
|
||||
}
|
||||
|
||||
// The loop body to dispatch an event to a responder.
|
||||
static void dispatch_to_responder(gpointer responder_data,
|
||||
gpointer foreach_data_ptr) {
|
||||
DispatchToResponderLoopContext* context =
|
||||
reinterpret_cast<DispatchToResponderLoopContext*>(foreach_data_ptr);
|
||||
FlKeyResponder* responder = FL_KEY_RESPONDER(responder_data);
|
||||
fl_key_responder_handle_event(
|
||||
responder, context->event, responder_handle_event_callback,
|
||||
context->user_data, context->specified_logical_key);
|
||||
}
|
||||
|
||||
gboolean fl_keyboard_handler_handle_event(FlKeyboardHandler* self,
|
||||
FlKeyEvent* event) {
|
||||
g_return_val_if_fail(FL_IS_KEYBOARD_HANDLER(self), FALSE);
|
||||
@ -643,18 +546,17 @@ gboolean fl_keyboard_handler_handle_event(FlKeyboardHandler* self,
|
||||
|
||||
guarantee_layout(self, event);
|
||||
|
||||
uint64_t incoming_hash = fl_keyboard_handler_get_event_hash(event);
|
||||
uint64_t incoming_hash = fl_key_event_hash(event);
|
||||
if (fl_keyboard_handler_remove_redispatched(self, incoming_hash)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
FlKeyboardPendingEvent* pending = fl_keyboard_pending_event_new(
|
||||
std::unique_ptr<FlKeyEvent>(event), ++self->last_sequence_id,
|
||||
self->responder_list->len);
|
||||
event, ++self->last_sequence_id, self->responder_list->len);
|
||||
|
||||
g_ptr_array_add(self->pending_responds, pending);
|
||||
FlKeyboardHandlerUserData* user_data =
|
||||
fl_keyboard_handler_user_data_new(self, pending->sequence_id);
|
||||
FlKeyboardHandlerUserData* user_data = fl_keyboard_handler_user_data_new(
|
||||
self, fl_keyboard_pending_event_get_sequence_id(pending));
|
||||
DispatchToResponderLoopContext data{
|
||||
.event = event,
|
||||
.specified_logical_key =
|
||||
|
||||
@ -71,7 +71,7 @@ typedef std::function<void(AsyncKeyCallback callback)> ChannelCallHandler;
|
||||
typedef std::function<void(const FlutterKeyEvent* event,
|
||||
AsyncKeyCallback callback)>
|
||||
EmbedderCallHandler;
|
||||
typedef std::function<void(std::unique_ptr<FlKeyEvent>)> RedispatchHandler;
|
||||
typedef std::function<void(FlKeyEvent*)> RedispatchHandler;
|
||||
|
||||
// A type that can record all kinds of effects that the keyboard handler
|
||||
// triggers.
|
||||
@ -377,11 +377,11 @@ static FlBinaryMessenger* fl_mock_view_keyboard_get_messenger(
|
||||
|
||||
static void fl_mock_view_keyboard_redispatch_event(
|
||||
FlKeyboardViewDelegate* view_delegate,
|
||||
std::unique_ptr<FlKeyEvent> event) {
|
||||
FlKeyEvent* event) {
|
||||
FlMockViewDelegatePrivate* priv =
|
||||
FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(view_delegate);
|
||||
if (priv->redispatch_handler) {
|
||||
priv->redispatch_handler(std::move(event));
|
||||
priv->redispatch_handler(event);
|
||||
}
|
||||
}
|
||||
|
||||
@ -467,23 +467,6 @@ static void fl_mock_view_set_layout(FlMockViewDelegate* self,
|
||||
|
||||
/***** End FlMockViewDelegate *****/
|
||||
|
||||
// Create a new #FlKeyEvent with the given information.
|
||||
static FlKeyEvent* fl_key_event_new_by_mock(bool is_press,
|
||||
guint keyval,
|
||||
guint16 keycode,
|
||||
GdkModifierType state,
|
||||
gboolean is_modifier,
|
||||
guint8 group = 0) {
|
||||
FlKeyEvent* event = g_new0(FlKeyEvent, 1);
|
||||
event->is_press = is_press;
|
||||
event->time = 0;
|
||||
event->state = state;
|
||||
event->keyval = keyval;
|
||||
event->group = group;
|
||||
event->keycode = keycode;
|
||||
return event;
|
||||
}
|
||||
|
||||
class KeyboardTester {
|
||||
public:
|
||||
KeyboardTester() {
|
||||
@ -502,6 +485,7 @@ class KeyboardTester {
|
||||
~KeyboardTester() {
|
||||
g_clear_object(&view_);
|
||||
g_clear_object(&handler_);
|
||||
g_clear_pointer(&redispatched_events_, g_ptr_array_unref);
|
||||
}
|
||||
|
||||
FlKeyboardHandler* handler() { return handler_; }
|
||||
@ -520,21 +504,20 @@ class KeyboardTester {
|
||||
// Returns the number of events redispatched. If any result is unexpected
|
||||
// (handled), return a minus number `-x` instead, where `x` is the index of
|
||||
// the first unexpected redispatch.
|
||||
int redispatchEventsAndClear(
|
||||
std::vector<std::unique_ptr<FlKeyEvent>>& events) {
|
||||
size_t event_count = events.size();
|
||||
int redispatchEventsAndClear(GPtrArray* events) {
|
||||
guint event_count = events->len;
|
||||
int first_error = -1;
|
||||
during_redispatch_ = true;
|
||||
for (size_t event_id = 0; event_id < event_count; event_id += 1) {
|
||||
bool handled = fl_keyboard_handler_handle_event(
|
||||
handler_, events[event_id].release());
|
||||
for (guint event_id = 0; event_id < event_count; event_id += 1) {
|
||||
FlKeyEvent* event = FL_KEY_EVENT(g_ptr_array_index(events, event_id));
|
||||
bool handled = fl_keyboard_handler_handle_event(handler_, event);
|
||||
EXPECT_FALSE(handled);
|
||||
if (handled) {
|
||||
first_error = first_error == -1 ? event_id : first_error;
|
||||
}
|
||||
}
|
||||
during_redispatch_ = false;
|
||||
events.clear();
|
||||
g_ptr_array_set_size(events, 0);
|
||||
return first_error < 0 ? event_count : -first_error;
|
||||
}
|
||||
|
||||
@ -610,12 +593,11 @@ class KeyboardTester {
|
||||
fl_mock_view_set_text_filter_result(view_, response);
|
||||
}
|
||||
|
||||
void recordRedispatchedEventsTo(
|
||||
std::vector<std::unique_ptr<FlKeyEvent>>& storage) {
|
||||
fl_mock_view_set_redispatch_handler(
|
||||
view_, [&storage](std::unique_ptr<FlKeyEvent> key) {
|
||||
storage.push_back(std::move(key));
|
||||
});
|
||||
void recordRedispatchedEventsTo(GPtrArray* storage) {
|
||||
redispatched_events_ = g_ptr_array_ref(storage);
|
||||
fl_mock_view_set_redispatch_handler(view_, [this](FlKeyEvent* key) {
|
||||
g_ptr_array_add(redispatched_events_, g_object_ref(key));
|
||||
});
|
||||
}
|
||||
|
||||
void setLayout(const MockLayoutData& layout) {
|
||||
@ -625,6 +607,7 @@ class KeyboardTester {
|
||||
private:
|
||||
FlMockViewDelegate* view_;
|
||||
FlKeyboardHandler* handler_;
|
||||
GPtrArray* redispatched_events_ = nullptr;
|
||||
bool during_redispatch_ = false;
|
||||
|
||||
static gboolean _flushChannelMessagesCb(gpointer data) {
|
||||
@ -642,16 +625,14 @@ TEST(FlKeyboardHandlerTest, DisposeWithUnresolvedPends) {
|
||||
|
||||
// Record calls so that they aren't responded.
|
||||
tester.recordEmbedderCallsTo(call_records);
|
||||
fl_keyboard_handler_handle_event(
|
||||
tester.handler(),
|
||||
fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA,
|
||||
static_cast<GdkModifierType>(0), false));
|
||||
g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
|
||||
0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
|
||||
fl_keyboard_handler_handle_event(tester.handler(), event1);
|
||||
|
||||
tester.respondToEmbedderCallsWith(true);
|
||||
fl_keyboard_handler_handle_event(
|
||||
tester.handler(),
|
||||
fl_key_event_new_by_mock(false, GDK_KEY_a, kKeyCodeKeyA,
|
||||
static_cast<GdkModifierType>(0), false));
|
||||
g_autoptr(FlKeyEvent) event2 = fl_key_event_new(
|
||||
0, FALSE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
|
||||
fl_keyboard_handler_handle_event(tester.handler(), event2);
|
||||
|
||||
tester.flushChannelMessages();
|
||||
|
||||
@ -661,7 +642,8 @@ TEST(FlKeyboardHandlerTest, DisposeWithUnresolvedPends) {
|
||||
TEST(FlKeyboardHandlerTest, SingleDelegateWithAsyncResponds) {
|
||||
KeyboardTester tester;
|
||||
std::vector<CallRecord> call_records;
|
||||
std::vector<std::unique_ptr<FlKeyEvent>> redispatched;
|
||||
g_autoptr(GPtrArray) redispatched =
|
||||
g_ptr_array_new_with_free_func(g_object_unref);
|
||||
|
||||
gboolean handler_handled = false;
|
||||
|
||||
@ -670,55 +652,56 @@ TEST(FlKeyboardHandlerTest, SingleDelegateWithAsyncResponds) {
|
||||
tester.recordRedispatchedEventsTo(redispatched);
|
||||
|
||||
// Dispatch a key event
|
||||
handler_handled = fl_keyboard_handler_handle_event(
|
||||
tester.handler(),
|
||||
fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA,
|
||||
static_cast<GdkModifierType>(0), false));
|
||||
g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
|
||||
0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
|
||||
handler_handled = fl_keyboard_handler_handle_event(tester.handler(), event1);
|
||||
tester.flushChannelMessages();
|
||||
EXPECT_EQ(handler_handled, true);
|
||||
EXPECT_EQ(redispatched.size(), 0u);
|
||||
EXPECT_EQ(redispatched->len, 0u);
|
||||
EXPECT_EQ(call_records.size(), 1u);
|
||||
EXPECT_KEY_EVENT(call_records[0], kFlutterKeyEventTypeDown, kPhysicalKeyA,
|
||||
kLogicalKeyA, "a", false);
|
||||
|
||||
call_records[0].callback(true);
|
||||
tester.flushChannelMessages();
|
||||
EXPECT_EQ(redispatched.size(), 0u);
|
||||
EXPECT_EQ(redispatched->len, 0u);
|
||||
EXPECT_TRUE(fl_keyboard_handler_is_state_clear(tester.handler()));
|
||||
call_records.clear();
|
||||
|
||||
/// Test 2: Two events that are unhandled by the framework
|
||||
handler_handled = fl_keyboard_handler_handle_event(
|
||||
tester.handler(),
|
||||
fl_key_event_new_by_mock(false, GDK_KEY_a, kKeyCodeKeyA,
|
||||
static_cast<GdkModifierType>(0), false));
|
||||
g_autoptr(FlKeyEvent) event2 = fl_key_event_new(
|
||||
0, FALSE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
|
||||
handler_handled = fl_keyboard_handler_handle_event(tester.handler(), event2);
|
||||
tester.flushChannelMessages();
|
||||
EXPECT_EQ(handler_handled, true);
|
||||
EXPECT_EQ(redispatched.size(), 0u);
|
||||
EXPECT_EQ(redispatched->len, 0u);
|
||||
EXPECT_EQ(call_records.size(), 1u);
|
||||
EXPECT_KEY_EVENT(call_records[0], kFlutterKeyEventTypeUp, kPhysicalKeyA,
|
||||
kLogicalKeyA, nullptr, false);
|
||||
|
||||
// Dispatch another key event
|
||||
handler_handled = fl_keyboard_handler_handle_event(
|
||||
tester.handler(),
|
||||
fl_key_event_new_by_mock(true, GDK_KEY_b, kKeyCodeKeyB,
|
||||
static_cast<GdkModifierType>(0), false));
|
||||
g_autoptr(FlKeyEvent) event3 = fl_key_event_new(
|
||||
0, TRUE, kKeyCodeKeyB, GDK_KEY_b, static_cast<GdkModifierType>(0), 0);
|
||||
handler_handled = fl_keyboard_handler_handle_event(tester.handler(), event3);
|
||||
tester.flushChannelMessages();
|
||||
EXPECT_EQ(handler_handled, true);
|
||||
EXPECT_EQ(redispatched.size(), 0u);
|
||||
EXPECT_EQ(redispatched->len, 0u);
|
||||
EXPECT_EQ(call_records.size(), 2u);
|
||||
EXPECT_KEY_EVENT(call_records[1], kFlutterKeyEventTypeDown, kPhysicalKeyB,
|
||||
kLogicalKeyB, "b", false);
|
||||
|
||||
// Resolve the second event first to test out-of-order response
|
||||
call_records[1].callback(false);
|
||||
EXPECT_EQ(redispatched.size(), 1u);
|
||||
EXPECT_EQ(redispatched[0]->keyval, 0x62u);
|
||||
EXPECT_EQ(redispatched->len, 1u);
|
||||
EXPECT_EQ(
|
||||
fl_key_event_get_keyval(FL_KEY_EVENT(g_ptr_array_index(redispatched, 0))),
|
||||
0x62u);
|
||||
call_records[0].callback(false);
|
||||
tester.flushChannelMessages();
|
||||
EXPECT_EQ(redispatched.size(), 2u);
|
||||
EXPECT_EQ(redispatched[1]->keyval, 0x61u);
|
||||
EXPECT_EQ(redispatched->len, 2u);
|
||||
EXPECT_EQ(
|
||||
fl_key_event_get_keyval(FL_KEY_EVENT(g_ptr_array_index(redispatched, 1))),
|
||||
0x61u);
|
||||
|
||||
EXPECT_FALSE(fl_keyboard_handler_is_state_clear(tester.handler()));
|
||||
call_records.clear();
|
||||
@ -731,13 +714,12 @@ TEST(FlKeyboardHandlerTest, SingleDelegateWithAsyncResponds) {
|
||||
|
||||
/// Test 3: Dispatch the same event again to ensure that prevention from
|
||||
/// redispatching only works once.
|
||||
handler_handled = fl_keyboard_handler_handle_event(
|
||||
tester.handler(),
|
||||
fl_key_event_new_by_mock(false, GDK_KEY_a, kKeyCodeKeyA,
|
||||
static_cast<GdkModifierType>(0), false));
|
||||
g_autoptr(FlKeyEvent) event4 = fl_key_event_new(
|
||||
0, FALSE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
|
||||
handler_handled = fl_keyboard_handler_handle_event(tester.handler(), event4);
|
||||
tester.flushChannelMessages();
|
||||
EXPECT_EQ(handler_handled, true);
|
||||
EXPECT_EQ(redispatched.size(), 0u);
|
||||
EXPECT_EQ(redispatched->len, 0u);
|
||||
EXPECT_EQ(call_records.size(), 1u);
|
||||
|
||||
call_records[0].callback(true);
|
||||
@ -748,40 +730,39 @@ TEST(FlKeyboardHandlerTest, SingleDelegateWithSyncResponds) {
|
||||
KeyboardTester tester;
|
||||
gboolean handler_handled = false;
|
||||
std::vector<CallRecord> call_records;
|
||||
std::vector<std::unique_ptr<FlKeyEvent>> redispatched;
|
||||
g_autoptr(GPtrArray) redispatched =
|
||||
g_ptr_array_new_with_free_func(g_object_unref);
|
||||
|
||||
/// Test 1: One event that is handled by the framework
|
||||
tester.respondToEmbedderCallsWithAndRecordsTo(true, call_records);
|
||||
tester.recordRedispatchedEventsTo(redispatched);
|
||||
|
||||
// Dispatch a key event
|
||||
handler_handled = fl_keyboard_handler_handle_event(
|
||||
tester.handler(),
|
||||
fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA,
|
||||
static_cast<GdkModifierType>(0), false));
|
||||
g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
|
||||
0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
|
||||
handler_handled = fl_keyboard_handler_handle_event(tester.handler(), event1);
|
||||
tester.flushChannelMessages();
|
||||
EXPECT_EQ(handler_handled, true);
|
||||
EXPECT_EQ(call_records.size(), 1u);
|
||||
EXPECT_KEY_EVENT(call_records[0], kFlutterKeyEventTypeDown, kPhysicalKeyA,
|
||||
kLogicalKeyA, "a", false);
|
||||
EXPECT_EQ(redispatched.size(), 0u);
|
||||
EXPECT_EQ(redispatched->len, 0u);
|
||||
call_records.clear();
|
||||
|
||||
EXPECT_TRUE(fl_keyboard_handler_is_state_clear(tester.handler()));
|
||||
redispatched.clear();
|
||||
g_ptr_array_set_size(redispatched, 0);
|
||||
|
||||
/// Test 2: An event unhandled by the framework
|
||||
tester.respondToEmbedderCallsWithAndRecordsTo(false, call_records);
|
||||
handler_handled = fl_keyboard_handler_handle_event(
|
||||
tester.handler(),
|
||||
fl_key_event_new_by_mock(false, GDK_KEY_a, kKeyCodeKeyA,
|
||||
static_cast<GdkModifierType>(0), false));
|
||||
g_autoptr(FlKeyEvent) event2 = fl_key_event_new(
|
||||
0, FALSE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
|
||||
handler_handled = fl_keyboard_handler_handle_event(tester.handler(), event2);
|
||||
tester.flushChannelMessages();
|
||||
EXPECT_EQ(handler_handled, true);
|
||||
EXPECT_EQ(call_records.size(), 1u);
|
||||
EXPECT_KEY_EVENT(call_records[0], kFlutterKeyEventTypeUp, kPhysicalKeyA,
|
||||
kLogicalKeyA, nullptr, false);
|
||||
EXPECT_EQ(redispatched.size(), 1u);
|
||||
EXPECT_EQ(redispatched->len, 1u);
|
||||
call_records.clear();
|
||||
|
||||
EXPECT_FALSE(fl_keyboard_handler_is_state_clear(tester.handler()));
|
||||
@ -795,7 +776,8 @@ TEST(FlKeyboardHandlerTest, SingleDelegateWithSyncResponds) {
|
||||
TEST(FlKeyboardHandlerTest, WithTwoAsyncDelegates) {
|
||||
KeyboardTester tester;
|
||||
std::vector<CallRecord> call_records;
|
||||
std::vector<std::unique_ptr<FlKeyEvent>> redispatched;
|
||||
g_autoptr(GPtrArray) redispatched =
|
||||
g_ptr_array_new_with_free_func(g_object_unref);
|
||||
|
||||
gboolean handler_handled = false;
|
||||
|
||||
@ -805,13 +787,12 @@ TEST(FlKeyboardHandlerTest, WithTwoAsyncDelegates) {
|
||||
|
||||
/// Test 1: One delegate responds true, the other false
|
||||
|
||||
handler_handled = fl_keyboard_handler_handle_event(
|
||||
tester.handler(),
|
||||
fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA,
|
||||
static_cast<GdkModifierType>(0), false));
|
||||
g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
|
||||
0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
|
||||
handler_handled = fl_keyboard_handler_handle_event(tester.handler(), event1);
|
||||
|
||||
EXPECT_EQ(handler_handled, true);
|
||||
EXPECT_EQ(redispatched.size(), 0u);
|
||||
EXPECT_EQ(redispatched->len, 0u);
|
||||
EXPECT_EQ(call_records.size(), 2u);
|
||||
|
||||
EXPECT_EQ(call_records[0].type, CallRecord::kKeyCallEmbedder);
|
||||
@ -820,19 +801,18 @@ TEST(FlKeyboardHandlerTest, WithTwoAsyncDelegates) {
|
||||
call_records[0].callback(true);
|
||||
call_records[1].callback(false);
|
||||
tester.flushChannelMessages();
|
||||
EXPECT_EQ(redispatched.size(), 0u);
|
||||
EXPECT_EQ(redispatched->len, 0u);
|
||||
|
||||
EXPECT_TRUE(fl_keyboard_handler_is_state_clear(tester.handler()));
|
||||
call_records.clear();
|
||||
|
||||
/// Test 2: All delegates respond false
|
||||
handler_handled = fl_keyboard_handler_handle_event(
|
||||
tester.handler(),
|
||||
fl_key_event_new_by_mock(false, GDK_KEY_a, kKeyCodeKeyA,
|
||||
static_cast<GdkModifierType>(0), false));
|
||||
g_autoptr(FlKeyEvent) event2 = fl_key_event_new(
|
||||
0, FALSE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
|
||||
handler_handled = fl_keyboard_handler_handle_event(tester.handler(), event2);
|
||||
|
||||
EXPECT_EQ(handler_handled, true);
|
||||
EXPECT_EQ(redispatched.size(), 0u);
|
||||
EXPECT_EQ(redispatched->len, 0u);
|
||||
EXPECT_EQ(call_records.size(), 2u);
|
||||
|
||||
EXPECT_EQ(call_records[0].type, CallRecord::kKeyCallEmbedder);
|
||||
@ -845,7 +825,7 @@ TEST(FlKeyboardHandlerTest, WithTwoAsyncDelegates) {
|
||||
|
||||
// Resolve redispatch
|
||||
tester.flushChannelMessages();
|
||||
EXPECT_EQ(redispatched.size(), 1u);
|
||||
EXPECT_EQ(redispatched->len, 1u);
|
||||
EXPECT_EQ(tester.redispatchEventsAndClear(redispatched), 1);
|
||||
EXPECT_EQ(call_records.size(), 0u);
|
||||
|
||||
@ -854,20 +834,20 @@ TEST(FlKeyboardHandlerTest, WithTwoAsyncDelegates) {
|
||||
|
||||
TEST(FlKeyboardHandlerTest, TextInputHandlerReturnsFalse) {
|
||||
KeyboardTester tester;
|
||||
std::vector<std::unique_ptr<FlKeyEvent>> redispatched;
|
||||
g_autoptr(GPtrArray) redispatched =
|
||||
g_ptr_array_new_with_free_func(g_object_unref);
|
||||
gboolean handler_handled = false;
|
||||
tester.recordRedispatchedEventsTo(redispatched);
|
||||
tester.respondToTextInputWith(false);
|
||||
|
||||
// Dispatch a key event.
|
||||
handler_handled = fl_keyboard_handler_handle_event(
|
||||
tester.handler(),
|
||||
fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA,
|
||||
static_cast<GdkModifierType>(0), false));
|
||||
g_autoptr(FlKeyEvent) event = fl_key_event_new(
|
||||
0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
|
||||
handler_handled = fl_keyboard_handler_handle_event(tester.handler(), event);
|
||||
tester.flushChannelMessages();
|
||||
EXPECT_EQ(handler_handled, true);
|
||||
// The event was redispatched because no one handles it.
|
||||
EXPECT_EQ(redispatched.size(), 1u);
|
||||
EXPECT_EQ(redispatched->len, 1u);
|
||||
|
||||
// Resolve redispatched event.
|
||||
EXPECT_EQ(tester.redispatchEventsAndClear(redispatched), 1);
|
||||
@ -877,20 +857,20 @@ TEST(FlKeyboardHandlerTest, TextInputHandlerReturnsFalse) {
|
||||
|
||||
TEST(FlKeyboardHandlerTest, TextInputHandlerReturnsTrue) {
|
||||
KeyboardTester tester;
|
||||
std::vector<std::unique_ptr<FlKeyEvent>> redispatched;
|
||||
g_autoptr(GPtrArray) redispatched =
|
||||
g_ptr_array_new_with_free_func(g_object_unref);
|
||||
gboolean handler_handled = false;
|
||||
tester.recordRedispatchedEventsTo(redispatched);
|
||||
tester.respondToTextInputWith(true);
|
||||
|
||||
// Dispatch a key event.
|
||||
handler_handled = fl_keyboard_handler_handle_event(
|
||||
tester.handler(),
|
||||
fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA,
|
||||
static_cast<GdkModifierType>(0), false));
|
||||
g_autoptr(FlKeyEvent) event = fl_key_event_new(
|
||||
0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
|
||||
handler_handled = fl_keyboard_handler_handle_event(tester.handler(), event);
|
||||
tester.flushChannelMessages();
|
||||
EXPECT_EQ(handler_handled, true);
|
||||
// The event was not redispatched because handler handles it.
|
||||
EXPECT_EQ(redispatched.size(), 0u);
|
||||
EXPECT_EQ(redispatched->len, 0u);
|
||||
|
||||
EXPECT_TRUE(fl_keyboard_handler_is_state_clear(tester.handler()));
|
||||
}
|
||||
@ -902,14 +882,12 @@ TEST(FlKeyboardHandlerTest, CorrectLogicalKeyForLayouts) {
|
||||
tester.recordEmbedderCallsTo(call_records);
|
||||
|
||||
auto sendTap = [&](guint8 keycode, guint keyval, guint8 group) {
|
||||
fl_keyboard_handler_handle_event(
|
||||
tester.handler(), fl_key_event_new_by_mock(
|
||||
true, keyval, keycode,
|
||||
static_cast<GdkModifierType>(0), false, group));
|
||||
fl_keyboard_handler_handle_event(
|
||||
tester.handler(), fl_key_event_new_by_mock(
|
||||
false, keyval, keycode,
|
||||
static_cast<GdkModifierType>(0), false, group));
|
||||
g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
|
||||
0, TRUE, keycode, keyval, static_cast<GdkModifierType>(0), group);
|
||||
fl_keyboard_handler_handle_event(tester.handler(), event1);
|
||||
g_autoptr(FlKeyEvent) event2 = fl_key_event_new(
|
||||
0, FALSE, keycode, keyval, static_cast<GdkModifierType>(0), group);
|
||||
fl_keyboard_handler_handle_event(tester.handler(), event2);
|
||||
};
|
||||
|
||||
/* US keyboard layout */
|
||||
@ -1033,10 +1011,9 @@ TEST(FlKeyboardHandlerTest, GetPressedState) {
|
||||
tester.respondToTextInputWith(true);
|
||||
|
||||
// Dispatch a key event.
|
||||
fl_keyboard_handler_handle_event(
|
||||
tester.handler(),
|
||||
fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA,
|
||||
static_cast<GdkModifierType>(0), false));
|
||||
g_autoptr(FlKeyEvent) event = fl_key_event_new(
|
||||
0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
|
||||
fl_keyboard_handler_handle_event(tester.handler(), event);
|
||||
|
||||
GHashTable* pressedState =
|
||||
fl_keyboard_handler_get_pressed_state(tester.handler());
|
||||
|
||||
@ -0,0 +1,105 @@
|
||||
// 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_keyboard_pending_event.h"
|
||||
|
||||
/**
|
||||
* FlKeyboardPendingEvent:
|
||||
* A record for events that have been received by the handler, but
|
||||
* dispatched to other objects, whose results have yet to return.
|
||||
*
|
||||
* This object is used by both the "pending_responds" list and the
|
||||
* "pending_redispatches" list.
|
||||
*/
|
||||
|
||||
struct _FlKeyboardPendingEvent {
|
||||
GObject parent_instance;
|
||||
|
||||
// The target event.
|
||||
FlKeyEvent* event;
|
||||
|
||||
// Unique ID to identify pending responds.
|
||||
uint64_t sequence_id;
|
||||
|
||||
// The number of responders that haven't replied.
|
||||
size_t unreplied;
|
||||
|
||||
// Whether any replied responders reported true (handled).
|
||||
bool any_handled;
|
||||
|
||||
// A value calculated out of critical event information that can be used
|
||||
// to identify redispatched events.
|
||||
uint64_t hash;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(FlKeyboardPendingEvent, fl_keyboard_pending_event, G_TYPE_OBJECT)
|
||||
|
||||
static void fl_keyboard_pending_event_dispose(GObject* object) {
|
||||
FlKeyboardPendingEvent* self = FL_KEYBOARD_PENDING_EVENT(object);
|
||||
|
||||
g_clear_object(&self->event);
|
||||
|
||||
G_OBJECT_CLASS(fl_keyboard_pending_event_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void fl_keyboard_pending_event_class_init(
|
||||
FlKeyboardPendingEventClass* klass) {
|
||||
G_OBJECT_CLASS(klass)->dispose = fl_keyboard_pending_event_dispose;
|
||||
}
|
||||
|
||||
static void fl_keyboard_pending_event_init(FlKeyboardPendingEvent* self) {}
|
||||
|
||||
// Creates a new FlKeyboardPendingEvent by providing the target event,
|
||||
// the sequence ID, and the number of responders that will reply.
|
||||
FlKeyboardPendingEvent* fl_keyboard_pending_event_new(FlKeyEvent* event,
|
||||
uint64_t sequence_id,
|
||||
size_t to_reply) {
|
||||
FlKeyboardPendingEvent* self = FL_KEYBOARD_PENDING_EVENT(
|
||||
g_object_new(fl_keyboard_pending_event_get_type(), nullptr));
|
||||
|
||||
self->event = FL_KEY_EVENT(g_object_ref(event));
|
||||
self->sequence_id = sequence_id;
|
||||
self->unreplied = to_reply;
|
||||
self->any_handled = false;
|
||||
self->hash = fl_key_event_hash(self->event);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
FlKeyEvent* fl_keyboard_pending_event_get_event(FlKeyboardPendingEvent* self) {
|
||||
g_return_val_if_fail(FL_IS_KEYBOARD_PENDING_EVENT(self), nullptr);
|
||||
return self->event;
|
||||
}
|
||||
|
||||
uint64_t fl_keyboard_pending_event_get_sequence_id(
|
||||
FlKeyboardPendingEvent* self) {
|
||||
g_return_val_if_fail(FL_IS_KEYBOARD_PENDING_EVENT(self), 0);
|
||||
return self->sequence_id;
|
||||
}
|
||||
|
||||
uint64_t fl_keyboard_pending_event_get_hash(FlKeyboardPendingEvent* self) {
|
||||
g_return_val_if_fail(FL_IS_KEYBOARD_PENDING_EVENT(self), 0);
|
||||
return self->hash;
|
||||
}
|
||||
|
||||
void fl_keyboard_pending_event_mark_replied(FlKeyboardPendingEvent* self,
|
||||
gboolean handled) {
|
||||
g_return_if_fail(FL_IS_KEYBOARD_PENDING_EVENT(self));
|
||||
g_return_if_fail(self->unreplied > 0);
|
||||
self->unreplied -= 1;
|
||||
if (handled) {
|
||||
self->any_handled = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean fl_keyboard_pending_event_get_any_handled(
|
||||
FlKeyboardPendingEvent* self) {
|
||||
g_return_val_if_fail(FL_IS_KEYBOARD_PENDING_EVENT(self), FALSE);
|
||||
return self->any_handled;
|
||||
}
|
||||
|
||||
gboolean fl_keyboard_pending_event_is_complete(FlKeyboardPendingEvent* self) {
|
||||
g_return_val_if_fail(FL_IS_KEYBOARD_PENDING_EVENT(self), FALSE);
|
||||
return self->unreplied == 0;
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
// 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_KEYBOARD_PENDING_EVENT_H_
|
||||
#define FLUTTER_SHELL_PLATFORM_LINUX_FL_KEYBOARD_PENDING_EVENT_H_
|
||||
|
||||
#include "fl_key_event.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
G_DECLARE_FINAL_TYPE(FlKeyboardPendingEvent,
|
||||
fl_keyboard_pending_event,
|
||||
FL,
|
||||
KEYBOARD_PENDING_EVENT,
|
||||
GObject);
|
||||
|
||||
FlKeyboardPendingEvent* fl_keyboard_pending_event_new(FlKeyEvent* event,
|
||||
uint64_t sequence_id,
|
||||
size_t to_reply);
|
||||
|
||||
FlKeyEvent* fl_keyboard_pending_event_get_event(FlKeyboardPendingEvent* event);
|
||||
|
||||
uint64_t fl_keyboard_pending_event_get_sequence_id(
|
||||
FlKeyboardPendingEvent* event);
|
||||
|
||||
uint64_t fl_keyboard_pending_event_get_hash(FlKeyboardPendingEvent* event);
|
||||
|
||||
void fl_keyboard_pending_event_mark_replied(FlKeyboardPendingEvent* event,
|
||||
gboolean handled);
|
||||
|
||||
gboolean fl_keyboard_pending_event_get_any_handled(
|
||||
FlKeyboardPendingEvent* event);
|
||||
|
||||
gboolean fl_keyboard_pending_event_is_complete(FlKeyboardPendingEvent* event);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_KEYBOARD_PENDING_EVENT_H_
|
||||
@ -39,14 +39,13 @@ FlBinaryMessenger* fl_keyboard_view_delegate_get_messenger(
|
||||
return FL_KEYBOARD_VIEW_DELEGATE_GET_IFACE(self)->get_messenger(self);
|
||||
}
|
||||
|
||||
void fl_keyboard_view_delegate_redispatch_event(
|
||||
FlKeyboardViewDelegate* self,
|
||||
std::unique_ptr<FlKeyEvent> event) {
|
||||
void fl_keyboard_view_delegate_redispatch_event(FlKeyboardViewDelegate* self,
|
||||
FlKeyEvent* event) {
|
||||
g_return_if_fail(FL_IS_KEYBOARD_VIEW_DELEGATE(self));
|
||||
g_return_if_fail(event != nullptr);
|
||||
|
||||
return FL_KEYBOARD_VIEW_DELEGATE_GET_IFACE(self)->redispatch_event(
|
||||
self, std::move(event));
|
||||
return FL_KEYBOARD_VIEW_DELEGATE_GET_IFACE(self)->redispatch_event(self,
|
||||
event);
|
||||
}
|
||||
|
||||
void fl_keyboard_view_delegate_subscribe_to_layout_change(
|
||||
|
||||
@ -46,8 +46,7 @@ struct _FlKeyboardViewDelegateInterface {
|
||||
|
||||
FlBinaryMessenger* (*get_messenger)(FlKeyboardViewDelegate* delegate);
|
||||
|
||||
void (*redispatch_event)(FlKeyboardViewDelegate* delegate,
|
||||
std::unique_ptr<FlKeyEvent> event);
|
||||
void (*redispatch_event)(FlKeyboardViewDelegate* delegate, FlKeyEvent* event);
|
||||
|
||||
void (*subscribe_to_layout_change)(FlKeyboardViewDelegate* delegate,
|
||||
KeyboardLayoutNotifier notifier);
|
||||
@ -103,13 +102,10 @@ FlBinaryMessenger* fl_keyboard_view_delegate_get_messenger(
|
||||
*
|
||||
* Handles `FlKeyboardHandler`'s request to insert a GDK event to the system for
|
||||
* redispatching.
|
||||
*
|
||||
* The ownership of event will be transferred to the view delegate. The view
|
||||
* delegate is responsible to call fl_key_event_dispose.
|
||||
*/
|
||||
void fl_keyboard_view_delegate_redispatch_event(
|
||||
FlKeyboardViewDelegate* delegate,
|
||||
std::unique_ptr<FlKeyEvent> event);
|
||||
FlKeyEvent* event);
|
||||
|
||||
void fl_keyboard_view_delegate_subscribe_to_layout_change(
|
||||
FlKeyboardViewDelegate* delegate,
|
||||
|
||||
@ -627,7 +627,8 @@ static gboolean fl_text_input_handler_filter_keypress_default(
|
||||
}
|
||||
|
||||
if (gtk_im_context_filter_keypress(
|
||||
priv->im_context, reinterpret_cast<GdkEventKey*>(event->origin))) {
|
||||
priv->im_context,
|
||||
reinterpret_cast<GdkEventKey*>(fl_key_event_get_origin(event)))) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -639,11 +640,11 @@ static gboolean fl_text_input_handler_filter_keypress_default(
|
||||
gboolean do_action = FALSE;
|
||||
// Handle navigation keys.
|
||||
gboolean changed = FALSE;
|
||||
if (event->is_press) {
|
||||
switch (event->keyval) {
|
||||
if (fl_key_event_get_is_press(event)) {
|
||||
switch (fl_key_event_get_keyval(event)) {
|
||||
case GDK_KEY_End:
|
||||
case GDK_KEY_KP_End:
|
||||
if (event->state & GDK_SHIFT_MASK) {
|
||||
if (fl_key_event_get_state(event) & GDK_SHIFT_MASK) {
|
||||
changed = priv->text_model->SelectToEnd();
|
||||
} else {
|
||||
changed = priv->text_model->MoveCursorToEnd();
|
||||
@ -662,7 +663,7 @@ static gboolean fl_text_input_handler_filter_keypress_default(
|
||||
break;
|
||||
case GDK_KEY_Home:
|
||||
case GDK_KEY_KP_Home:
|
||||
if (event->state & GDK_SHIFT_MASK) {
|
||||
if (fl_key_event_get_state(event) & GDK_SHIFT_MASK) {
|
||||
changed = priv->text_model->SelectToBeginning();
|
||||
} else {
|
||||
changed = priv->text_model->MoveCursorToBeginning();
|
||||
|
||||
@ -184,9 +184,8 @@ static void send_key_event(FlTextInputHandler* handler,
|
||||
GdkEvent* gdk_event = gdk_event_new(GDK_KEY_PRESS);
|
||||
gdk_event->key.keyval = keyval;
|
||||
gdk_event->key.state = state;
|
||||
FlKeyEvent* key_event = fl_key_event_new_from_gdk_event(gdk_event);
|
||||
g_autoptr(FlKeyEvent) key_event = fl_key_event_new_from_gdk_event(gdk_event);
|
||||
fl_text_input_handler_filter_keypress(handler, key_event);
|
||||
fl_key_event_dispose(key_event);
|
||||
}
|
||||
|
||||
TEST(FlTextInputHandlerTest, MessageHandler) {
|
||||
|
||||
@ -357,13 +357,12 @@ static void fl_view_keyboard_delegate_iface_init(
|
||||
};
|
||||
|
||||
iface->redispatch_event = [](FlKeyboardViewDelegate* view_delegate,
|
||||
std::unique_ptr<FlKeyEvent> in_event) {
|
||||
FlKeyEvent* event = in_event.release();
|
||||
GdkEventType event_type = gdk_event_get_event_type(event->origin);
|
||||
FlKeyEvent* event) {
|
||||
GdkEventType event_type =
|
||||
gdk_event_get_event_type(fl_key_event_get_origin(event));
|
||||
g_return_if_fail(event_type == GDK_KEY_PRESS ||
|
||||
event_type == GDK_KEY_RELEASE);
|
||||
gdk_event_put(event->origin);
|
||||
fl_key_event_dispose(event);
|
||||
gdk_event_put(fl_key_event_get_origin(event));
|
||||
};
|
||||
|
||||
iface->subscribe_to_layout_change = [](FlKeyboardViewDelegate* view_delegate,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user