Skip to content

Commit

Permalink
[GTK] Handle global modifiers state in the UI process only
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=258965

Reviewed by Michael Catanzaro.

The web process updates the global modifiers state on every key event
received and when the view gets focused.

* Source/WebCore/platform/PlatformKeyboardEvent.h:
* Source/WebCore/platform/gtk/GtkUtilities.cpp:
(WebCore::eventModifiersContainCapsLock):
* Source/WebCore/platform/gtk/GtkUtilities.h:
* Source/WebCore/platform/gtk/GtkVersioning.h:
(gtk_event_controller_get_current_event):
(gdk_event_get_display):
* Source/WebCore/platform/gtk/PlatformKeyboardEventGtk.cpp:
(WebCore::PlatformKeyboardEvent::currentStateOfModifierKeys):
(WebCore::PlatformKeyboardEvent::modifiersContainCapsLock): Deleted.
* Source/WebKit/Shared/gtk/WebEventFactory.cpp:
(WebKit::modifiersForEvent):
* Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp:
(modifiersForSynthesizedEvent):
(webkitWebViewBaseTouchRelease):
(webkitWebViewBaseTouchDragUpdate):
(webkitWebViewBaseTouchDragEnd):
(toWebKitModifiers):
* Source/WebKit/UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::updateCurrentModifierState):
* Source/WebKit/UIProcess/WebPageProxy.h:
* Source/WebKit/UIProcess/gtk/WebPageProxyGtk.cpp:
(WebKit::WebPageProxy::currentStateOfModifierKeys):

Canonical link: https://commits.webkit.org/266095@main
  • Loading branch information
carlosgcampos committed Jul 17, 2023
1 parent 7707bd0 commit 02196eb
Show file tree
Hide file tree
Showing 10 changed files with 85 additions and 58 deletions.
1 change: 0 additions & 1 deletion Source/WebCore/platform/PlatformKeyboardEvent.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,6 @@ namespace WebCore {
static String keyIdentifierForGdkKeyCode(unsigned);
static int windowsKeyCodeForGdkKeyCode(unsigned);
static String singleCharacterString(unsigned);
static bool modifiersContainCapsLock(unsigned);
#endif

#if USE(LIBWPE)
Expand Down
12 changes: 12 additions & 0 deletions Source/WebCore/platform/gtk/GtkUtilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,4 +221,16 @@ bool shouldUseOverlayScrollbars()
return !!overlayScrolling;
}

bool eventModifiersContainCapsLock(GdkEvent* event)
{
#if USE(GTK4)
auto* device = gdk_event_get_source_device(event);
if (!device || gdk_device_get_source(device) != GDK_SOURCE_KEYBOARD)
device = gdk_seat_get_keyboard(gdk_display_get_default_seat(gdk_event_get_display(event)));
return gdk_device_get_caps_lock_state(device);
#else
return gdk_keymap_get_caps_lock_state(gdk_keymap_get_for_display(gdk_event_get_display(event)));
#endif
}

} // namespace WebCore
2 changes: 2 additions & 0 deletions Source/WebCore/platform/gtk/GtkUtilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,6 @@ void monitorWorkArea(GdkMonitor*, GdkRectangle*);

bool shouldUseOverlayScrollbars();

WEBCORE_EXPORT bool eventModifiersContainCapsLock(GdkEvent*);

} // namespace WebCore
12 changes: 12 additions & 0 deletions Source/WebCore/platform/gtk/GtkVersioning.h
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,12 @@ gtk_scrolled_window_new()
return gtk_scrolled_window_new(nullptr, nullptr);
}

static inline GdkEvent*
gtk_event_controller_get_current_event(GtkEventController*)
{
return gtk_get_current_event();
}

static inline GdkModifierType
gtk_event_controller_get_current_event_state(GtkEventController*)
{
Expand All @@ -295,4 +301,10 @@ static inline GtkIconTheme* gtk_icon_theme_get_for_display(GdkDisplay* display)
return gtk_icon_theme_get_for_screen(gdk_display_get_default_screen(display));
}

static inline GdkDisplay*
gdk_event_get_display(GdkEvent* event)
{
return event->any.window ? gdk_window_get_display(event->any.window) : gdk_display_get_default();
}

#endif // USE(GTK4)
55 changes: 3 additions & 52 deletions Source/WebCore/platform/gtk/PlatformKeyboardEventGtk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
#include <gdk/gdkkeysyms.h>
#include <pal/text/TextEncoding.h>
#include <wtf/HexNumber.h>
#include <wtf/glib/GUniquePtr.h>

namespace WebCore {

Expand Down Expand Up @@ -1350,58 +1349,10 @@ void PlatformKeyboardEvent::disambiguateKeyDownEvent(Type type, bool backwardCom

OptionSet<PlatformEvent::Modifier> PlatformKeyboardEvent::currentStateOfModifierKeys()
{
GdkModifierType state;
#if USE(GTK4)
state = static_cast<GdkModifierType>(0); // FIXME: Implement.
#else
gtk_get_current_event_state(&state);
#endif
if (s_currentModifiers)
return *s_currentModifiers;

OptionSet<PlatformEvent::Modifier> modifiers;

if (state & GDK_SHIFT_MASK)
modifiers.add(PlatformEvent::Modifier::ShiftKey);
if (state & GDK_CONTROL_MASK)
modifiers.add(PlatformEvent::Modifier::ControlKey);
if (state & GDK_MOD1_MASK)
modifiers.add(PlatformEvent::Modifier::AltKey);
if (state & GDK_META_MASK)
modifiers.add(PlatformEvent::Modifier::MetaKey);

#if USE(GTK4)
bool capsLockActive = gdk_device_get_caps_lock_state(gdk_seat_get_keyboard(gdk_display_get_default_seat(gdk_display_get_default())));
#else
bool capsLockActive = gdk_keymap_get_caps_lock_state(gdk_keymap_get_for_display(gdk_display_get_default()));
#endif
if (capsLockActive)
modifiers.add(PlatformEvent::Modifier::CapsLockKey);

return modifiers;
}

bool PlatformKeyboardEvent::modifiersContainCapsLock(unsigned modifier)
{
if (!(modifier & GDK_LOCK_MASK))
return false;

// In X11 GDK_LOCK_MASK could be CapsLock or ShiftLock, depending on the modifier mapping of the X server.
// What GTK+ does in the X11 backend is checking if there is a key bound to GDK_KEY_Caps_Lock, so we do
// the same here. This will also return true in Wayland if there's a caps lock key, so it's not worth it
// checking the actual display here.
static bool lockMaskIsCapsLock = false;
#if !USE(GTK4)
static bool initialized = false;
if (!initialized) {
GUniqueOutPtr<GdkKeymapKey> keys;
int entriesCount;
#if USE(GTK4)
lockMaskIsCapsLock = gdk_display_map_keyval(gdk_display_get_default(), GDK_KEY_Caps_Lock, &keys.outPtr(), &entriesCount) && entriesCount;
#else
lockMaskIsCapsLock = gdk_keymap_get_entries_for_keyval(gdk_keymap_get_for_display(gdk_display_get_default()), GDK_KEY_Caps_Lock, &keys.outPtr(), &entriesCount) && entriesCount;
#endif
}
#endif
return lockMaskIsCapsLock;
return { };
}

}
2 changes: 1 addition & 1 deletion Source/WebKit/Shared/gtk/WebEventFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ static inline OptionSet<WebEventModifier> modifiersForEvent(const GdkEvent* even
modifiers.add(WebEventModifier::AltKey);
if (state & GDK_META_MASK)
modifiers.add(WebEventModifier::MetaKey);
if (PlatformKeyboardEvent::modifiersContainCapsLock(state))
if (state & GDK_LOCK_MASK && eventModifiersContainCapsLock(const_cast<GdkEvent*>(event)))
modifiers.add(WebEventModifier::CapsLockKey);

GdkEventType type = gdk_event_get_event_type(const_cast<GdkEvent*>(event));
Expand Down
26 changes: 22 additions & 4 deletions Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2139,6 +2139,24 @@ static void webkitWebViewBaseTouchPress(WebKitWebViewBase* webViewBase, int nPre
webViewBase->priv->isLongPressed = false;
}

static unsigned modifiersForSynthesizedEvent(GdkEvent* event)
{
if (!event)
return 0;

GdkModifierType state;
if (!gdk_event_get_state(event, &state))
return 0;

unsigned modifiers = state;
// For synthesized events we assume GDK_LOCK_MASK is always CapsLock
// so we remove the flag if present and caps lock state is disabled.
if (modifiers & GDK_LOCK_MASK && !eventModifiersContainCapsLock(event))
modifiers &= ~GDK_LOCK_MASK;

return modifiers;
}

static void webkitWebViewBaseTouchRelease(WebKitWebViewBase* webViewBase, int nPress, double x, double y, GtkGesture* gesture)
{
WebKitWebViewBasePrivate* priv = webViewBase->priv;
Expand All @@ -2157,7 +2175,7 @@ static void webkitWebViewBaseTouchRelease(WebKitWebViewBase* webViewBase, int nP
buttons = GDK_BUTTON1_MASK;
}

unsigned modifiers = gtk_event_controller_get_current_event_state(GTK_EVENT_CONTROLLER(gesture));
unsigned modifiers = modifiersForSynthesizedEvent(gtk_event_controller_get_current_event(GTK_EVENT_CONTROLLER(gesture)));
webkitWebViewBaseSynthesizeMouseEvent(webViewBase, MouseEventType::Motion, 0, 0, x, y, modifiers, nPress, mousePointerEventType(), PlatformMouseEvent::IsTouch::Yes);
webkitWebViewBaseSynthesizeMouseEvent(webViewBase, MouseEventType::Press, button, 0, x, y, modifiers, nPress, mousePointerEventType(), PlatformMouseEvent::IsTouch::Yes);
webkitWebViewBaseSynthesizeMouseEvent(webViewBase, MouseEventType::Release, button, buttons, x, y, modifiers, nPress, mousePointerEventType(), PlatformMouseEvent::IsTouch::Yes);
Expand Down Expand Up @@ -2187,7 +2205,7 @@ static void webkitWebViewBaseTouchDragUpdate(WebKitWebViewBase* webViewBase, dou
auto* sequence = gtk_gesture_single_get_current_sequence(GTK_GESTURE_SINGLE(gesture));
auto* event = gtk_gesture_get_last_event(gesture, sequence);

unsigned modifiers = gtk_event_controller_get_current_event_state(GTK_EVENT_CONTROLLER(gesture));
unsigned modifiers = modifiersForSynthesizedEvent(gtk_event_controller_get_current_event(GTK_EVENT_CONTROLLER(gesture)));
if (!priv->isBeingDragged) {
if (!gtk_drag_check_threshold(GTK_WIDGET(webViewBase), 0, 0, static_cast<int>(offsetX), static_cast<int>(offsetY)))
return;
Expand Down Expand Up @@ -2231,7 +2249,7 @@ static void webkitWebViewBaseTouchDragEnd(WebKitWebViewBase* webViewBase, gdoubl
if (priv->isLongPressed) {
double x, y;
gtk_gesture_drag_get_start_point(GTK_GESTURE_DRAG(gesture), &x, &y);
unsigned modifiers = gtk_event_controller_get_current_event_state(GTK_EVENT_CONTROLLER(gesture));
unsigned modifiers = modifiersForSynthesizedEvent(gtk_event_controller_get_current_event(GTK_EVENT_CONTROLLER(gesture)));
webkitWebViewBaseSynthesizeMouseEvent(webViewBase, MouseEventType::Release, GDK_BUTTON_PRIMARY, GDK_BUTTON1_MASK, x + offsetX, y + offsetY, modifiers, 0, mousePointerEventType(), PlatformMouseEvent::IsTouch::Yes);
}
}
Expand Down Expand Up @@ -3049,7 +3067,7 @@ static inline OptionSet<WebEventModifier> toWebKitModifiers(unsigned modifiers)
webEventModifiers.add(WebEventModifier::AltKey);
if (modifiers & GDK_META_MASK)
webEventModifiers.add(WebEventModifier::MetaKey);
if (PlatformKeyboardEvent::modifiersContainCapsLock(modifiers))
if (modifiers & GDK_LOCK_MASK)
webEventModifiers.add(WebEventModifier::CapsLockKey);
return webEventModifiers;
}
Expand Down
4 changes: 4 additions & 0 deletions Source/WebKit/UIProcess/WebPageProxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11756,8 +11756,12 @@ void WebPageProxy::getIsViewVisible(bool& result)

void WebPageProxy::updateCurrentModifierState()
{
#if PLATFORM(COCOA) || PLATFORM(GTK)
#if PLATFORM(COCOA)
auto modifiers = PlatformKeyboardEvent::currentStateOfModifierKeys();
#elif PLATFORM(GTK)
auto modifiers = currentStateOfModifierKeys();
#endif
send(Messages::WebPage::UpdateCurrentModifierState(modifiers));
#endif
}
Expand Down
2 changes: 2 additions & 0 deletions Source/WebKit/UIProcess/WebPageProxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ enum class ModalContainerDecision : uint8_t;
enum class MouseEventPolicy : uint8_t;
enum class PermissionName : uint8_t;
enum class PermissionState : uint8_t;
enum class PlatformEventModifier : uint8_t;
enum class PolicyAction : uint8_t;
enum class ReasonForDismissingAlternativeText : uint8_t;
enum class ReloadOption : uint8_t;
Expand Down Expand Up @@ -2523,6 +2524,7 @@ class WebPageProxy final : public API::ObjectImpl<API::Object::Type::Page>, publ

#if PLATFORM(GTK)
void showEmojiPicker(const WebCore::IntRect&, CompletionHandler<void(String)>&&);
OptionSet<WebCore::PlatformEventModifier> currentStateOfModifierKeys();
#endif

// Popup Menu.
Expand Down
27 changes: 27 additions & 0 deletions Source/WebKit/UIProcess/gtk/WebPageProxyGtk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "WebPasteboardProxy.h"
#include "WebProcessProxy.h"
#include <WebCore/PlatformDisplay.h>
#include <WebCore/PlatformEvent.h>
#include <wtf/NeverDestroyed.h>

namespace WebKit {
Expand Down Expand Up @@ -117,4 +118,30 @@ void WebPageProxy::accentColorDidChange()
send(Messages::WebPage::SetAccentColor(accentColor));
}

OptionSet<WebCore::PlatformEvent::Modifier> WebPageProxy::currentStateOfModifierKeys()
{
#if USE(GTK4)
auto* device = gdk_seat_get_keyboard(gdk_display_get_default_seat(gtk_widget_get_display(viewWidget())));
auto gdkModifiers = gdk_device_get_modifier_state(device);
bool capsLockActive = gdk_device_get_caps_lock_state(device);
#else
auto* keymap = gdk_keymap_get_for_display(gtk_widget_get_display(viewWidget()));
auto gdkModifiers = gdk_keymap_get_modifier_state(keymap);
bool capsLockActive = gdk_keymap_get_caps_lock_state(keymap);
#endif

OptionSet<WebCore::PlatformEvent::Modifier> modifiers;
if (gdkModifiers & GDK_SHIFT_MASK)
modifiers.add(WebCore::PlatformEvent::Modifier::ShiftKey);
if (gdkModifiers & GDK_CONTROL_MASK)
modifiers.add(WebCore::PlatformEvent::Modifier::ControlKey);
if (gdkModifiers & GDK_MOD1_MASK)
modifiers.add(WebCore::PlatformEvent::Modifier::AltKey);
if (gdkModifiers & GDK_META_MASK)
modifiers.add(WebCore::PlatformEvent::Modifier::MetaKey);
if (capsLockActive)
modifiers.add(WebCore::PlatformEvent::Modifier::CapsLockKey);
return modifiers;
}

} // namespace WebKit

0 comments on commit 02196eb

Please sign in to comment.