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

Commit c78e68c

Browse files
committed
Implement handling of framework-handled key combinations
1 parent 859494f commit c78e68c

File tree

2 files changed

+58
-16
lines changed

2 files changed

+58
-16
lines changed

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

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,6 @@ class Keyboard {
8080
}
8181

8282
final html.KeyboardEvent keyboardEvent = event;
83-
84-
if (_shouldPreventDefault(event)) {
85-
event.preventDefault();
86-
}
87-
8883
final String timerKey = keyboardEvent.code!;
8984

9085
// Don't handle synthesizing a keyup event for modifier keys
@@ -132,16 +127,18 @@ class Keyboard {
132127
};
133128

134129
EnginePlatformDispatcher.instance.invokeOnPlatformMessage('flutter/keyevent',
135-
_messageCodec.encodeMessage(eventData), _noopCallback);
136-
}
137-
138-
bool _shouldPreventDefault(html.KeyboardEvent event) {
139-
switch (event.key) {
140-
case 'Tab':
141-
return true;
142-
default:
143-
return false;
144-
}
130+
_messageCodec.encodeMessage(eventData), (ByteData? data) {
131+
if (data == null) {
132+
return;
133+
}
134+
final String response = utf8.decode(data.buffer.asUint8List());
135+
final Map<String, dynamic> jsonResponse = json.decode(response);
136+
if (jsonResponse['handled'] as bool) {
137+
// If the framework handled it, then don't propagate it any further.
138+
event.preventDefault();
139+
}
140+
},
141+
);
145142
}
146143

147144
void _synthesizeKeyup(html.KeyboardEvent event) {

lib/web_ui/test/keyboard_test.dart

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import 'dart:html' as html;
77
import 'dart:js_util' as js_util;
88
import 'dart:typed_data';
9+
import 'dart:convert' hide Codec;
910

1011
import 'package:quiver/testing/async.dart';
1112
import 'package:test/bootstrap/browser.dart';
@@ -17,6 +18,14 @@ void main() {
1718
internalBootstrapBrowserTest(() => testMain);
1819
}
1920

21+
ByteData _toByteData(List<int> bytes) {
22+
final ByteData byteData = ByteData(bytes.length);
23+
for (int i = 0; i < bytes.length; i++) {
24+
byteData.setUint8(i, bytes[i]);
25+
}
26+
return byteData;
27+
}
28+
2029
void testMain() {
2130
group('Keyboard', () {
2231
/// Used to save and restore [ui.window.onPlatformMessage] after each test.
@@ -226,13 +235,23 @@ void testMain() {
226235
expect(count, 2);
227236
});
228237

229-
test('prevents default when "Tab" is pressed', () {
238+
test('prevents default when key is handled by the framework', () {
239+
ByteData _toByteData(List<int> bytes) {
240+
final ByteData byteData = ByteData(bytes.length);
241+
for (int i = 0; i < bytes.length; i++) {
242+
byteData.setUint8(i, bytes[i]);
243+
}
244+
return byteData;
245+
}
246+
230247
Keyboard.initialize();
231248

232249
int count = 0;
233250
ui.window.onPlatformMessage = (String channel, ByteData data,
234251
ui.PlatformMessageResponseCallback callback) {
235252
count += 1;
253+
ByteData response = _toByteData(utf8.encode(json.encode(<String, dynamic>{'handled': true})));
254+
callback(response);
236255
};
237256

238257
final html.KeyboardEvent event = dispatchKeyboardEvent(
@@ -247,6 +266,30 @@ void testMain() {
247266
Keyboard.instance.dispose();
248267
});
249268

269+
test("Doesn't prevent default when key is not handled by the framework", () {
270+
Keyboard.initialize();
271+
272+
int count = 0;
273+
ui.window.onPlatformMessage = (String channel, ByteData data,
274+
ui.PlatformMessageResponseCallback callback) {
275+
count += 1;
276+
ByteData response = _toByteData(utf8.encode(json.encode(<String, dynamic>{'handled': false})));
277+
callback(response);
278+
};
279+
280+
final html.KeyboardEvent event = dispatchKeyboardEvent(
281+
'keydown',
282+
key: 'Tab',
283+
code: 'Tab',
284+
);
285+
286+
expect(event.defaultPrevented, isFalse);
287+
expect(count, 1);
288+
289+
Keyboard.instance.dispose();
290+
});
291+
292+
250293
test('keyboard events should be triggered on text fields', () {
251294
Keyboard.initialize();
252295

@@ -278,6 +321,8 @@ void testMain() {
278321
ui.window.onPlatformMessage = (String channel, ByteData data,
279322
ui.PlatformMessageResponseCallback callback) {
280323
count += 1;
324+
ByteData response = _toByteData(utf8.encode(json.encode(<String, dynamic>{'handled': true})));
325+
callback(response);
281326
};
282327

283328
useTextEditingElement((html.Element element) {

0 commit comments

Comments
 (0)