Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 284ef22

Browse files
authored
[web] Fix CapsLock keyevent (#21584)
* Fix metaState for Key events for lock modifiers
1 parent 3351524 commit 284ef22

File tree

2 files changed

+76
-3
lines changed

2 files changed

+76
-3
lines changed

e2etests/web/regular_integration_tests/test_driver/text_editing_integration.dart

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,57 @@ void main() {
143143
expect(input2.value, 'Text2');
144144
});
145145

146+
testWidgets('Jump between TextFormFields with tab key after CapsLock is'
147+
'activated',
148+
(WidgetTester tester) async {
149+
app.main();
150+
await tester.pumpAndSettle();
151+
152+
// TODO(nurhan): https://github.com/flutter/flutter/issues/51885
153+
SystemChannels.textInput.setMockMethodCallHandler(null);
154+
155+
// Focus on a TextFormField.
156+
final Finder finder = find.byKey(const Key('input'));
157+
expect(finder, findsOneWidget);
158+
await tester.tap(find.byKey(const Key('input')));
159+
160+
// A native input element will be appended to the DOM.
161+
final List<Node> nodeList = document.getElementsByTagName('input');
162+
expect(nodeList.length, equals(1));
163+
final InputElement input =
164+
document.getElementsByTagName('input')[0] as InputElement;
165+
166+
// Press and release CapsLock.
167+
dispatchKeyboardEvent(input, 'keydown', <String, dynamic>{
168+
'key': 'CapsLock',
169+
'code': 'CapsLock',
170+
'bubbles': true,
171+
'cancelable': true,
172+
});
173+
dispatchKeyboardEvent(input, 'keyup', <String, dynamic>{
174+
'key': 'CapsLock',
175+
'code': 'CapsLock',
176+
'bubbles': true,
177+
'cancelable': true,
178+
});
179+
180+
// Press Tab. The focus should move to the next TextFormField.
181+
dispatchKeyboardEvent(input, 'keydown', <String, dynamic>{
182+
'key': 'Tab',
183+
'code': 'Tab',
184+
'bubbles': true,
185+
'cancelable': true,
186+
});
187+
188+
await tester.pumpAndSettle();
189+
190+
// A native input element for the next TextField should be attached to the
191+
// DOM.
192+
final InputElement input2 =
193+
document.getElementsByTagName('input')[0] as InputElement;
194+
expect(input2.value, 'Text2');
195+
});
196+
146197
testWidgets('Read-only fields work', (WidgetTester tester) async {
147198
const String text = 'Lorem ipsum dolor sit amet';
148199
app.main();

lib/web_ui/lib/src/engine/keyboard.dart

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,17 @@ class Keyboard {
116116
}
117117

118118
_lastMetaState = _getMetaState(event);
119+
if (event.type == 'keydown') {
120+
// For lock modifiers _getMetaState won't report a metaState at keydown.
121+
// See https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/getModifierState.
122+
if (event.key == 'CapsLock') {
123+
_lastMetaState |= modifierCapsLock;
124+
} else if (event.code == 'NumLock') {
125+
_lastMetaState |= modifierNumLock;
126+
} else if (event.key == 'ScrollLock') {
127+
_lastMetaState |= modifierScrollLock;
128+
}
129+
}
119130
final Map<String, dynamic> eventData = <String, dynamic>{
120131
'type': event.type,
121132
'keymap': 'web',
@@ -132,7 +143,6 @@ class Keyboard {
132143
switch (event.key) {
133144
case 'Tab':
134145
return true;
135-
136146
default:
137147
return false;
138148
}
@@ -157,6 +167,9 @@ const int _modifierShift = 0x01;
157167
const int _modifierAlt = 0x02;
158168
const int _modifierControl = 0x04;
159169
const int _modifierMeta = 0x08;
170+
const int modifierNumLock = 0x10;
171+
const int modifierCapsLock = 0x20;
172+
const int modifierScrollLock = 0x40;
160173

161174
/// Creates a bitmask representing the meta state of the [event].
162175
int _getMetaState(html.KeyboardEvent event) {
@@ -173,8 +186,17 @@ int _getMetaState(html.KeyboardEvent event) {
173186
if (event.getModifierState('Meta')) {
174187
metaState |= _modifierMeta;
175188
}
176-
// TODO: Re-enable lock key modifiers once there is support on Flutter
177-
// Framework. https://github.com/flutter/flutter/issues/46718
189+
// See https://github.com/flutter/flutter/issues/66601 for why we don't
190+
// set the ones below based on persistent state.
191+
// if (event.getModifierState("CapsLock")) {
192+
// metaState |= modifierCapsLock;
193+
// }
194+
// if (event.getModifierState("NumLock")) {
195+
// metaState |= modifierNumLock;
196+
// }
197+
// if (event.getModifierState("ScrollLock")) {
198+
// metaState |= modifierScrollLock;
199+
// }
178200
return metaState;
179201
}
180202

0 commit comments

Comments
 (0)