Quellcode durchsuchen

LibWeb: Only fire keypress events if the key press produced a character

For example, pressing just the shift key should not producde a keypress
event.
Timothy Flynn vor 9 Monaten
Ursprung
Commit
448754d95d

+ 5 - 0
Tests/LibWeb/Text/expected/UIEvents/KeyEvent-keypress.txt

@@ -0,0 +1,5 @@
+keydown A
+keypress A
+keydown Shift
+keydown B
+keypress B

+ 18 - 0
Tests/LibWeb/Text/input/UIEvents/KeyEvent-keypress.html

@@ -0,0 +1,18 @@
+<input id="input" />
+<script src="../include.js"></script>
+<script>
+    test(() => {
+        let input = document.getElementById("input");
+
+        input.addEventListener("keydown", e => {
+            println(`keydown ${e.key}`);
+        });
+        input.addEventListener("keypress", e => {
+            println(`keypress ${e.key}`);
+        });
+
+        internals.sendText(input, "A");
+        internals.sendKey(input, "LeftShift");
+        internals.sendText(input, "B");
+    });
+</script>

+ 15 - 0
Userland/Libraries/LibUnicode/CharacterTypes.cpp

@@ -113,6 +113,16 @@ bool code_point_has_control_general_category(u32 code_point)
     return code_point_has_general_category(code_point, U_CONTROL_CHAR);
 }
 
+bool code_point_has_letter_general_category(u32 code_point)
+{
+    return code_point_has_general_category(code_point, GENERAL_CATEGORY_LETTER);
+}
+
+bool code_point_has_number_general_category(u32 code_point)
+{
+    return code_point_has_general_category(code_point, GENERAL_CATEGORY_NUMBER);
+}
+
 bool code_point_has_punctuation_general_category(u32 code_point)
 {
     return code_point_has_general_category(code_point, GENERAL_CATEGORY_PUNCTUATION);
@@ -128,6 +138,11 @@ bool code_point_has_space_separator_general_category(u32 code_point)
     return code_point_has_general_category(code_point, U_SPACE_SEPARATOR);
 }
 
+bool code_point_has_symbol_general_category(u32 code_point)
+{
+    return code_point_has_general_category(code_point, GENERAL_CATEGORY_SYMBOL);
+}
+
 static constexpr Property PROPERTY_ANY = UCHAR_BINARY_LIMIT + 1;
 static constexpr Property PROPERTY_ASCII = UCHAR_BINARY_LIMIT + 2;
 static constexpr Property PROPERTY_ASSIGNED = UCHAR_BINARY_LIMIT + 3;

+ 3 - 0
Userland/Libraries/LibUnicode/CharacterTypes.h

@@ -18,9 +18,12 @@ Optional<GeneralCategory> general_category_from_string(StringView);
 bool code_point_has_general_category(u32 code_point, GeneralCategory general_category);
 
 bool code_point_has_control_general_category(u32 code_point);
+bool code_point_has_letter_general_category(u32 code_point);
+bool code_point_has_number_general_category(u32 code_point);
 bool code_point_has_punctuation_general_category(u32 code_point);
 bool code_point_has_separator_general_category(u32 code_point);
 bool code_point_has_space_separator_general_category(u32 code_point);
+bool code_point_has_symbol_general_category(u32 code_point);
 
 Optional<Property> property_from_string(StringView);
 bool code_point_has_property(u32 code_point, Property property);

+ 21 - 4
Userland/Libraries/LibWeb/Page/EventHandler.cpp

@@ -5,6 +5,7 @@
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
+#include <LibUnicode/CharacterTypes.h>
 #include <LibUnicode/Segmenter.h>
 #include <LibWeb/DOM/Range.h>
 #include <LibWeb/DOM/Text.h>
@@ -836,6 +837,18 @@ EventResult EventHandler::fire_keyboard_event(FlyString const& event_name, HTML:
     return target->dispatch_event(event) ? EventResult::Accepted : EventResult::Cancelled;
 }
 
+// https://w3c.github.io/uievents/#unicode-character-categories
+static bool produces_character_value(u32 code_point)
+{
+    // A subset of the General Category values that are defined for each Unicode code point. This subset contains all
+    // the Letter (Ll, Lm, Lo, Lt, Lu), Number (Nd, Nl, No), Punctuation (Pc, Pd, Pe, Pf, Pi, Po, Ps) and Symbol (Sc,
+    // Sk, Sm, So) category values.
+    return Unicode::code_point_has_letter_general_category(code_point)
+        || Unicode::code_point_has_number_general_category(code_point)
+        || Unicode::code_point_has_punctuation_general_category(code_point)
+        || Unicode::code_point_has_symbol_general_category(code_point);
+}
+
 EventResult EventHandler::handle_keydown(UIEvents::KeyCode key, u32 modifiers, u32 code_point)
 {
     if (!m_navigable->active_document())
@@ -847,10 +860,14 @@ EventResult EventHandler::handle_keydown(UIEvents::KeyCode key, u32 modifiers, u
     if (dispatch_result != EventResult::Accepted)
         return dispatch_result;
 
-    // FIXME: Work out and implement the difference between this and keydown.
-    dispatch_result = fire_keyboard_event(UIEvents::EventNames::keypress, m_navigable, key, modifiers, code_point);
-    if (dispatch_result != EventResult::Accepted)
-        return dispatch_result;
+    // https://w3c.github.io/uievents/#event-type-keypress
+    // If supported by a user agent, this event MUST be dispatched when a key is pressed down, if and only if that key
+    // normally produces a character value.
+    if (produces_character_value(code_point)) {
+        dispatch_result = fire_keyboard_event(UIEvents::EventNames::keypress, m_navigable, key, modifiers, code_point);
+        if (dispatch_result != EventResult::Accepted)
+            return dispatch_result;
+    }
 
     JS::NonnullGCPtr<DOM::Document> document = *m_navigable->active_document();