Skip to content

Commit fae34b6

Browse files
committed
Bug 1784438 - Implement key repeat on wayland. r=masayuki
When running Firefox on wayland, we don't set key repeat flag. We should set this flag during repeating key. Differential Revision: https://phabricator.services.mozilla.com/D236097
1 parent 9f1011b commit fae34b6

File tree

4 files changed

+165
-11
lines changed

4 files changed

+165
-11
lines changed

widget/gtk/mozwayland/mozwayland.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,10 @@ MOZ_EXPORT struct xkb_keymap* xkb_keymap_new_from_string(
251251
return NULL;
252252
}
253253

254+
MOZ_EXPORT struct xkb_keymap* xkb_keymap_ref(struct xkb_keymap* keymap) {
255+
return NULL;
256+
}
257+
254258
MOZ_EXPORT void xkb_keymap_unref(struct xkb_keymap* keymap) {}
255259

256260
MOZ_EXPORT const char* xkb_keymap_layout_get_name(struct xkb_keymap* keymap,
@@ -262,3 +266,8 @@ MOZ_EXPORT xkb_mod_index_t xkb_keymap_mod_get_index(struct xkb_keymap* keymap,
262266
const char* name) {
263267
return XKB_MOD_INVALID;
264268
}
269+
270+
MOZ_EXPORT int xkb_keymap_key_repeats(struct xkb_keymap* keymap,
271+
xkb_keycode_t kc) {
272+
return 0;
273+
}

widget/gtk/nsGtkKeyUtils.cpp

Lines changed: 130 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ Time KeymapWrapper::sLastRepeatableKeyTime = 0;
6565
KeymapWrapper::RepeatState KeymapWrapper::sRepeatState =
6666
KeymapWrapper::NOT_PRESSED;
6767

68+
#ifdef MOZ_WAYLAND
69+
uint32_t KeymapWrapper::sLastRepeatableSerial = 0;
70+
#endif
71+
6872
static const char* GetBoolName(bool aBool) { return aBool ? "TRUE" : "FALSE"; }
6973

7074
static const char* GetStatusName(nsEventStatus aStatus) {
@@ -665,6 +669,8 @@ void KeymapWrapper::SetModifierMasks(xkb_keymap* aKeymap) {
665669
keymapWrapper->SetModifierMask(aKeymap, INDEX_LEVEL3, "Level3");
666670
keymapWrapper->SetModifierMask(aKeymap, INDEX_LEVEL5, "Level5");
667671

672+
keymapWrapper->SetKeymap(aKeymap);
673+
668674
MOZ_LOG(gKeyLog, LogLevel::Info,
669675
("%p KeymapWrapper::SetModifierMasks, CapsLock=0x%X, NumLock=0x%X, "
670676
"ScrollLock=0x%X, Level3=0x%X, Level5=0x%X, "
@@ -707,6 +713,13 @@ void KeymapWrapper::HandleKeymap(uint32_t format, int fd, uint32_t size) {
707713
}
708714

709715
struct xkb_context* xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
716+
if (!xkb_context) {
717+
MOZ_LOG(gKeyLog, LogLevel::Info,
718+
("KeymapWrapper::HandleKeymap(): failed to get xkb_context!"));
719+
close(fd);
720+
return;
721+
}
722+
710723
struct xkb_keymap* keymap = xkb_keymap_new_from_string(
711724
xkb_context, mapString, XKB_KEYMAP_FORMAT_TEXT_V1,
712725
XKB_KEYMAP_COMPILE_NO_FLAGS);
@@ -717,6 +730,7 @@ void KeymapWrapper::HandleKeymap(uint32_t format, int fd, uint32_t size) {
717730
if (!keymap) {
718731
MOZ_LOG(gKeyLog, LogLevel::Info,
719732
("KeymapWrapper::HandleKeymap(): Failed to compile keymap!"));
733+
xkb_context_unref(xkb_context);
720734
return;
721735
}
722736

@@ -731,6 +745,11 @@ void KeymapWrapper::HandleKeymap(uint32_t format, int fd, uint32_t size) {
731745
KeymapWrapper::~KeymapWrapper() {
732746
#ifdef MOZ_X11
733747
gdk_window_remove_filter(nullptr, FilterEvents, this);
748+
#endif
749+
#ifdef MOZ_WAYLAND
750+
if (mXkbKeymap) {
751+
xkb_keymap_unref(mXkbKeymap);
752+
}
734753
#endif
735754
if (mOnKeysChangedSignalHandle) {
736755
g_signal_handler_disconnect(mGdkKeymap, mOnKeysChangedSignalHandle);
@@ -858,6 +877,87 @@ GdkFilterReturn KeymapWrapper::FilterEvents(GdkXEvent* aXEvent,
858877
}
859878
#endif
860879

880+
#ifdef MOZ_WAYLAND
881+
// static
882+
void KeymapWrapper::KeyboardHandlerForWayland(uint32_t aSerial,
883+
uint32_t aHardwareKeycode,
884+
uint32_t aState) {
885+
KeymapWrapper* keymapWrapper = GetInstance();
886+
if (!keymapWrapper->IsAutoRepeatableKey(aHardwareKeycode)) {
887+
MOZ_LOG(gKeyLog, LogLevel::Info,
888+
("KeyboardHandlerForWayland(aSerial=%u, aHardwareKeycode=0x%08X, "
889+
"aState=%s), no repeat key",
890+
aSerial, aHardwareKeycode,
891+
aState == WL_KEYBOARD_KEY_STATE_PRESSED
892+
? "WL_KEYBOARD_KEY_STATE_PRESSED"
893+
: "WL_KEYBOARD_KEY_STATE_RELEASED"));
894+
return;
895+
}
896+
897+
if (aState == WL_KEYBOARD_KEY_STATE_PRESSED) {
898+
MOZ_LOG(gKeyLog, LogLevel::Info,
899+
("KeyboardHandlerForWayland(aSerial=%u, aHardwareKeycode=0x%08X, "
900+
"aState=WL_KEYBOARD_KEY_STATE_PRESSED), first key pressed",
901+
aSerial, aHardwareKeycode));
902+
903+
sLastRepeatableSerial = aSerial;
904+
sLastRepeatableHardwareKeyCode = aHardwareKeycode;
905+
sRepeatState = FIRST_PRESS;
906+
907+
// This runnable will be run after GDK's key event.
908+
//
909+
// Next key press of GDK will be after repeat's delay ms.
910+
// But event time in next key press wonn't updated.
911+
//
912+
// The delay's default is 400ms in GTK/wayland. Even if we can get this
913+
// information from repeat_info, if we wait for this time, it is too late.
914+
// We guess that 10ms will be enough durration to set repeat state.
915+
916+
NS_DelayedDispatchToCurrentThread(
917+
NS_NewRunnableFunction(
918+
__func__,
919+
[aSerial] {
920+
if (sLastRepeatableSerial != aSerial) {
921+
// We already receive newer key event. Don't set repeat state.
922+
return;
923+
}
924+
925+
MOZ_LOG(gKeyLog, LogLevel::Info,
926+
("KeyboardHandlerForWayland(aSerial=%u, "
927+
"aState=WL_KEYBOARD_KEY_STATE_PRESSED), repeating",
928+
aSerial));
929+
sRepeatState = REPEATING;
930+
}),
931+
10);
932+
return;
933+
}
934+
935+
if (sLastRepeatableHardwareKeyCode != aHardwareKeycode) {
936+
MOZ_LOG(gKeyLog, LogLevel::Info,
937+
("KeyboardHandlerForWayland(aSerial=%u, aHardwareKeycode=0x%08X "
938+
"aState=WL_KEYBOARD_KEY_STATE_RELEASED), released key isn't "
939+
"matched",
940+
aSerial, aHardwareKeycode));
941+
return;
942+
}
943+
944+
MOZ_LOG(gKeyLog, LogLevel::Info,
945+
("KeyboardHandlerForWayland(aSerial=%u, aHardwareKeycode=0x%08X"
946+
"aState=WL_KEYBOARD_KEY_STATE_RELEASED), not pressed",
947+
aSerial, aHardwareKeycode));
948+
949+
sLastRepeatableSerial = aSerial;
950+
sRepeatState = NOT_PRESSED;
951+
}
952+
953+
void KeymapWrapper::SetKeymap(xkb_keymap* aKeymap) {
954+
if (mXkbKeymap) {
955+
xkb_keymap_unref(mXkbKeymap);
956+
}
957+
mXkbKeymap = xkb_keymap_ref(aKeymap);
958+
}
959+
#endif
960+
861961
static void ResetBidiKeyboard() {
862962
// Reset the bidi keyboard settings for the new GdkKeymap
863963
nsCOMPtr<nsIBidiKeyboard> bidiKeyboard = nsContentUtils::GetBidiKeyboard();
@@ -2033,15 +2133,28 @@ bool KeymapWrapper::IsLatinGroup(guint8 aGroup) {
20332133
}
20342134

20352135
bool KeymapWrapper::IsAutoRepeatableKey(guint aHardwareKeyCode) {
2136+
GdkDisplay* gdkDisplay = gdk_display_get_default();
20362137
#ifdef MOZ_X11
2037-
uint8_t indexOfArray = aHardwareKeyCode / 8;
2038-
MOZ_ASSERT(indexOfArray < std::size(mKeyboardState.auto_repeats),
2039-
"invalid index");
2040-
char bitMask = 1 << (aHardwareKeyCode % 8);
2041-
return (mKeyboardState.auto_repeats[indexOfArray] & bitMask) != 0;
2042-
#else
2043-
return false;
2138+
if (GdkIsX11Display(gdkDisplay)) {
2139+
uint8_t indexOfArray = aHardwareKeyCode / 8;
2140+
MOZ_ASSERT(indexOfArray < std::size(mKeyboardState.auto_repeats),
2141+
"invalid index");
2142+
char bitMask = 1 << (aHardwareKeyCode % 8);
2143+
return (mKeyboardState.auto_repeats[indexOfArray] & bitMask) != 0;
2144+
}
2145+
#endif
2146+
#ifdef MOZ_WAYLAND
2147+
if (GdkIsWaylandDisplay(gdkDisplay)) {
2148+
if (MOZ_UNLIKELY(!mXkbKeymap)) {
2149+
static bool sWarned = false;
2150+
NS_WARNING_ASSERTION(sWarned, "no keymap!");
2151+
sWarned = true;
2152+
return false;
2153+
}
2154+
return !!xkb_keymap_key_repeats(mXkbKeymap, aHardwareKeyCode);
2155+
}
20442156
#endif
2157+
return false;
20452158
}
20462159

20472160
/* static */
@@ -2646,6 +2759,8 @@ void KeymapWrapper::SetFocusOut(wl_surface* aFocusSurface) {
26462759

26472760
keymapWrapper->mFocusSurface = nullptr;
26482761
keymapWrapper->mFocusSerial = 0;
2762+
2763+
sRepeatState = NOT_PRESSED;
26492764
}
26502765

26512766
void KeymapWrapper::GetFocusInfo(wl_surface** aFocusSurface,
@@ -2654,6 +2769,14 @@ void KeymapWrapper::GetFocusInfo(wl_surface** aFocusSurface,
26542769
*aFocusSurface = keymapWrapper->mFocusSurface;
26552770
*aFocusSerial = keymapWrapper->mFocusSerial;
26562771
}
2772+
2773+
void KeymapWrapper::ClearKeymap() {
2774+
KeymapWrapper* keymapWrapper = KeymapWrapper::GetInstance();
2775+
if (keymapWrapper->mXkbKeymap) {
2776+
xkb_keymap_unref(keymapWrapper->mXkbKeymap);
2777+
keymapWrapper->mXkbKeymap = nullptr;
2778+
}
2779+
}
26572780
#endif
26582781

26592782
} // namespace widget

widget/gtk/nsGtkKeyUtils.h

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -207,9 +207,13 @@ class KeymapWrapper {
207207
static void SetFocusOut(wl_surface* aFocusSurface);
208208
static void GetFocusInfo(wl_surface** aFocusSurface, uint32_t* aFocusSerial);
209209

210-
static void SetKeyboard(wl_keyboard* aKeyboard);
211-
static wl_keyboard* GetKeyboard();
212-
static void ClearKeyboard();
210+
/**
211+
* Key repeat helpers for Wayland
212+
*/
213+
static void KeyboardHandlerForWayland(uint32_t aSerial,
214+
uint32_t aHardwareKeycode,
215+
uint32_t aState);
216+
static void ClearKeymap();
213217

214218
/**
215219
* EnsureInstance() is provided on Wayland to register Wayland callbacks
@@ -350,12 +354,24 @@ class KeymapWrapper {
350354
enum RepeatState { NOT_PRESSED, FIRST_PRESS, REPEATING };
351355
static RepeatState sRepeatState;
352356

357+
#ifdef MOZ_WAYLAND
358+
xkb_keymap* mXkbKeymap = nullptr;
359+
static uint32_t sLastRepeatableSerial;
360+
#endif
361+
353362
/**
354363
* IsAutoRepeatableKey() returns true if the key supports auto repeat.
355364
* Otherwise, false.
356365
*/
357366
bool IsAutoRepeatableKey(guint aHardwareKeyCode);
358367

368+
#ifdef MOZ_WAYLAND
369+
/**
370+
* Set current xkb_keymap to detect auto repeat key on Wayland.
371+
*/
372+
void SetKeymap(xkb_keymap* aKeymap);
373+
#endif
374+
359375
/**
360376
* Signal handlers.
361377
*/

widget/gtk/nsWaylandDisplay.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,12 @@ static void keyboard_handle_leave(void* data, struct wl_keyboard* keyboard,
342342

343343
static void keyboard_handle_key(void* data, struct wl_keyboard* keyboard,
344344
uint32_t serial, uint32_t time, uint32_t key,
345-
uint32_t state) {}
345+
uint32_t state) {
346+
// hardware key code is +8.
347+
// https://gitlab.gnome.org/GNOME/gtk/-/blob/3.24.41/gdk/wayland/gdkdevice-wayland.c#L2341
348+
KeymapWrapper::KeyboardHandlerForWayland(serial, key + 8, state);
349+
}
350+
346351
static void keyboard_handle_modifiers(void* data, struct wl_keyboard* keyboard,
347352
uint32_t serial, uint32_t mods_depressed,
348353
uint32_t mods_latched,
@@ -367,6 +372,7 @@ void nsWaylandDisplay::ClearKeyboard() {
367372
if (mKeyboard) {
368373
wl_keyboard_destroy(mKeyboard);
369374
mKeyboard = nullptr;
375+
KeymapWrapper::ClearKeymap();
370376
}
371377
}
372378

0 commit comments

Comments
 (0)