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

Commit 9ab52b6

Browse files
committed
Check all modifiers for PointerEvent, MouseEvent and TouchEvent
1 parent 6521515 commit 9ab52b6

File tree

3 files changed

+143
-34
lines changed

3 files changed

+143
-34
lines changed

lib/web_ui/lib/src/engine/dom.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1142,6 +1142,10 @@ extension DomWheelEventExtension on DomWheelEvent {
11421142
class DomTouchEvent extends DomUIEvent {}
11431143

11441144
extension DomTouchEventExtension on DomTouchEvent {
1145+
external bool get altKey;
1146+
external bool get ctrlKey;
1147+
external bool get metaKey;
1148+
external bool get shiftKey;
11451149
List<DomTouch>? get changedTouches => js_util
11461150
.getProperty<List<Object?>?>(this, 'changedTouches')
11471151
?.cast<DomTouch>();

lib/web_ui/lib/src/engine/keyboard_binding.dart

Lines changed: 99 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,16 @@ final int _kLogicalShiftLeft = kWebLogicalLocationMap['Shift']![_kLocationLeft]!
3030
final int _kLogicalShiftRight = kWebLogicalLocationMap['Shift']![_kLocationRight]!;
3131
final int _kLogicalMetaLeft = kWebLogicalLocationMap['Meta']![_kLocationLeft]!;
3232
final int _kLogicalMetaRight = kWebLogicalLocationMap['Meta']![_kLocationRight]!;
33+
34+
final int _kPhysicalAltLeft = kWebToPhysicalKey['AltLeft']!;
35+
final int _kPhysicalAltRight = kWebToPhysicalKey['AltRight']!;
36+
final int _kPhysicalControlLeft = kWebToPhysicalKey['ControlLeft']!;
37+
final int _kPhysicalControlRight = kWebToPhysicalKey['ControlRight']!;
38+
final int _kPhysicalShiftLeft = kWebToPhysicalKey['ShiftLeft']!;
39+
final int _kPhysicalShiftRight = kWebToPhysicalKey['ShiftRight']!;
40+
final int _kPhysicalMetaLeft = kWebToPhysicalKey['MetaLeft']!;
41+
final int _kPhysicalMetaRight = kWebToPhysicalKey['MetaRight']!;
42+
3343
// Map logical keys for modifier keys to the functions that can get their
3444
// modifier flag out of an event.
3545
final Map<int, _ModifierGetter> _kLogicalKeyToModifierGetter = <int, _ModifierGetter>{
@@ -152,34 +162,102 @@ class KeyboardBinding {
152162
_converter = KeyboardConverter(_onKeyData, onMacOs: operatingSystem == OperatingSystem.macOs);
153163
}
154164

155-
// Synthesize shift key up or down event only when the known pressing state is different.
156-
void synthesizeShiftKeyIfNeeded(ui.KeyEventType type, num eventTimestamp) {
157-
// TODO(bleroux): should we take care of shift left AND shift right?
158-
final int physicalShift = kWebToPhysicalKey['ShiftLeft']!;
159-
final bool alreadyPressed = _converter._pressingRecords.containsKey(physicalShift);
165+
// Synthesize modifier keys up or down events only when the known pressing states are different.
166+
void synthesizeModifiersIfNeeded(
167+
bool altPressed,
168+
bool controlPressed,
169+
bool metaPressed,
170+
bool shiftPressed,
171+
num eventTimestamp,
172+
) {
173+
_synthesizeModifierIfNeeded(
174+
_kPhysicalAltLeft,
175+
_kPhysicalAltRight,
176+
_kLogicalAltLeft,
177+
_kLogicalAltRight,
178+
altPressed ? ui.KeyEventType.down : ui.KeyEventType.up,
179+
eventTimestamp,
180+
);
181+
_synthesizeModifierIfNeeded(
182+
_kPhysicalControlLeft,
183+
_kPhysicalControlRight,
184+
_kLogicalControlLeft,
185+
_kLogicalControlRight,
186+
controlPressed ? ui.KeyEventType.down : ui.KeyEventType.up,
187+
eventTimestamp,
188+
);
189+
_synthesizeModifierIfNeeded(
190+
_kPhysicalMetaLeft,
191+
_kPhysicalMetaRight,
192+
_kLogicalMetaLeft,
193+
_kLogicalMetaRight,
194+
metaPressed ? ui.KeyEventType.down : ui.KeyEventType.up,
195+
eventTimestamp,
196+
);
197+
_synthesizeModifierIfNeeded(
198+
_kPhysicalShiftLeft,
199+
_kPhysicalShiftRight,
200+
_kLogicalShiftLeft,
201+
_kLogicalShiftRight,
202+
shiftPressed ? ui.KeyEventType.down : ui.KeyEventType.up,
203+
eventTimestamp,
204+
);
205+
}
206+
207+
void _synthesizeModifierIfNeeded(
208+
int physicalLeft,
209+
int physicalRight,
210+
int logicalLeft,
211+
int logicalRight,
212+
ui.KeyEventType type,
213+
num domTimestamp,
214+
) {
215+
final bool leftPressed = _converter._pressingRecords.containsKey(physicalLeft);
216+
final bool rightPressed = _converter._pressingRecords.containsKey(physicalRight);
217+
final bool alreadyPressed = leftPressed || rightPressed;
160218
final bool synthesizeDown = type == ui.KeyEventType.down && !alreadyPressed;
161219
final bool synthesizeUp = type == ui.KeyEventType.up && alreadyPressed;
162-
if (synthesizeDown || synthesizeUp) {
163-
final Duration timestamp = _eventTimeStampToDuration(eventTimestamp);
164-
_converter.performDispatchKeyData(_shiftLeftKeyData(type, timestamp));
165-
// Update pressing state
166-
if (synthesizeDown) {
167-
_converter._pressingRecords[physicalShift] = _kLogicalShiftLeft;
168-
} else {
169-
_converter._pressingRecords.remove(physicalShift);
170-
}
220+
221+
// Synthesize a down event only for the left key if right and left are not pressed
222+
if (synthesizeDown) {
223+
_synthesizeKeyDownEvent(domTimestamp, physicalLeft, logicalLeft);
224+
}
225+
226+
// Synthesize an up event for left key if pressed
227+
if (synthesizeUp && leftPressed) {
228+
_synthesizeKeyUpEvent(domTimestamp, physicalLeft, logicalLeft);
229+
}
230+
231+
// Synthesize an up event for right key if pressed
232+
if (synthesizeUp && rightPressed) {
233+
_synthesizeKeyUpEvent(domTimestamp, physicalRight, logicalRight);
171234
}
172235
}
173236

174-
ui.KeyData _shiftLeftKeyData(ui.KeyEventType type, Duration timestamp) {
175-
return ui.KeyData(
176-
timeStamp: timestamp,
177-
type: type,
178-
physical: kWebToPhysicalKey['ShiftLeft']!,
179-
logical: _kLogicalShiftLeft,
237+
void _synthesizeKeyDownEvent(num domTimestamp, int physical, int logical) {
238+
_converter.performDispatchKeyData(ui.KeyData(
239+
timeStamp: _eventTimeStampToDuration(domTimestamp),
240+
type: ui.KeyEventType.down,
241+
physical: physical,
242+
logical: logical,
180243
character: null,
181244
synthesized: true,
182-
);
245+
));
246+
// Update pressing state
247+
_converter._pressingRecords[physical] = logical;
248+
}
249+
250+
void _synthesizeKeyUpEvent(num domTimestamp, int physical, int logical) {
251+
_converter.performDispatchKeyData(ui.KeyData(
252+
timeStamp: _eventTimeStampToDuration(domTimestamp),
253+
type: ui.KeyEventType.up,
254+
physical: physical,
255+
logical: logical,
256+
character: null,
257+
synthesized: true,
258+
));
259+
// Update pressing states
260+
_converter._pressingRecords.remove(physical);
183261
}
184262

185263
void _reset() {

lib/web_ui/lib/src/engine/pointer_binding.dart

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -603,28 +603,30 @@ class _PointerAdapter extends _BaseAdapter with _WheelEventListenerMixin {
603603
String eventName,
604604
_PointerEventListener handler, {
605605
bool useCapture = true,
606+
bool checkModifiers = true,
606607
}) {
607608
addEventListener(target, eventName, (DomEvent event) {
608609
final DomPointerEvent pointerEvent = event as DomPointerEvent;
610+
if (checkModifiers) {
611+
_checkModifiersState(event);
612+
}
609613
handler(pointerEvent);
610614
}, useCapture: useCapture);
611615
}
612616

613-
void _checkModifiersState(DomEvent event) {
614-
// TODO(bleroux): add support for 'Meta', 'Ctrl' and 'Alt'
615-
final DomPointerEvent pointerEvent = event as DomPointerEvent;
616-
617-
final bool shiftPressed = pointerEvent.getModifierState('Shift');
618-
KeyboardBinding.instance!.synthesizeShiftKeyIfNeeded(
619-
shiftPressed ? ui.KeyEventType.down : ui.KeyEventType.up,
617+
void _checkModifiersState(DomPointerEvent event) {
618+
KeyboardBinding.instance!.synthesizeModifiersIfNeeded(
619+
event.getModifierState('Alt'),
620+
event.getModifierState('Control'),
621+
event.getModifierState('Meta'),
622+
event.getModifierState('Shift'),
620623
event.timeStamp!,
621624
);
622625
}
623626

624627
@override
625628
void setup() {
626629
_addPointerEventListener(glassPaneElement, 'pointerdown', (DomPointerEvent event) {
627-
_checkModifiersState(event);
628630
final int device = _getPointerId(event);
629631
final List<ui.PointerData> pointerData = <ui.PointerData>[];
630632
final _ButtonSanitizer sanitizer = _ensureSanitizer(device);
@@ -643,7 +645,6 @@ class _PointerAdapter extends _BaseAdapter with _WheelEventListenerMixin {
643645
});
644646

645647
_addPointerEventListener(domWindow, 'pointermove', (DomPointerEvent event) {
646-
_checkModifiersState(event);
647648
final int device = _getPointerId(event);
648649
final _ButtonSanitizer sanitizer = _ensureSanitizer(device);
649650
final List<ui.PointerData> pointerData = <ui.PointerData>[];
@@ -668,10 +669,9 @@ class _PointerAdapter extends _BaseAdapter with _WheelEventListenerMixin {
668669
_convertEventsToPointerData(data: pointerData, event: event, details: details);
669670
_callback(pointerData);
670671
}
671-
}, useCapture: false);
672+
}, useCapture: false, checkModifiers: false);
672673

673674
_addPointerEventListener(domWindow, 'pointerup', (DomPointerEvent event) {
674-
_checkModifiersState(event);
675675
final int device = _getPointerId(event);
676676
if (_hasSanitizer(device)) {
677677
final List<ui.PointerData> pointerData = <ui.PointerData>[];
@@ -695,7 +695,7 @@ class _PointerAdapter extends _BaseAdapter with _WheelEventListenerMixin {
695695
_convertEventsToPointerData(data: pointerData, event: event, details: details);
696696
_callback(pointerData);
697697
}
698-
});
698+
}, checkModifiers: false);
699699

700700
_addWheelEventListener((DomEvent event) {
701701
_handleWheelEvent(event);
@@ -790,13 +790,26 @@ class _TouchAdapter extends _BaseAdapter {
790790
void _pressTouch(int identifier) { _pressedTouches.add(identifier); }
791791
void _unpressTouch(int identifier) { _pressedTouches.remove(identifier); }
792792

793-
void _addTouchEventListener(DomEventTarget target, String eventName, _TouchEventListener handler) {
793+
void _addTouchEventListener(DomEventTarget target, String eventName, _TouchEventListener handler, {bool checkModifiers = true,}) {
794794
addEventListener(target, eventName, (DomEvent event) {
795795
final DomTouchEvent touchEvent = event as DomTouchEvent;
796+
if (checkModifiers) {
797+
_checkModifiersState(event);
798+
}
796799
handler(touchEvent);
797800
});
798801
}
799802

803+
void _checkModifiersState(DomTouchEvent event) {
804+
KeyboardBinding.instance!.synthesizeModifiersIfNeeded(
805+
event.altKey,
806+
event.ctrlKey,
807+
event.metaKey,
808+
event.shiftKey,
809+
event.timeStamp!,
810+
);
811+
}
812+
800813
@override
801814
void setup() {
802815
_addTouchEventListener(glassPaneElement, 'touchstart', (DomTouchEvent event) {
@@ -935,13 +948,27 @@ class _MouseAdapter extends _BaseAdapter with _WheelEventListenerMixin {
935948
String eventName,
936949
_MouseEventListener handler, {
937950
bool useCapture = true,
951+
bool checkModifiers = true,
938952
}) {
939953
addEventListener(target, eventName, (DomEvent event) {
940954
final DomMouseEvent mouseEvent = event as DomMouseEvent;
955+
if (checkModifiers) {
956+
_checkModifiersState(event);
957+
}
941958
handler(mouseEvent);
942959
}, useCapture: useCapture);
943960
}
944961

962+
void _checkModifiersState(DomMouseEvent event) {
963+
KeyboardBinding.instance!.synthesizeModifiersIfNeeded(
964+
event.getModifierState('Alt'),
965+
event.getModifierState('Control'),
966+
event.getModifierState('Meta'),
967+
event.getModifierState('Shift'),
968+
event.timeStamp!,
969+
);
970+
}
971+
945972
@override
946973
void setup() {
947974
_addMouseEventListener(glassPaneElement, 'mousedown', (DomMouseEvent event) {

0 commit comments

Comments
 (0)