@@ -6,6 +6,187 @@ const wasm = import("@/../wasm/pkg").then(panicProxy);
6
6
7
7
let viewportMouseInteractionOngoing = false ;
8
8
9
+ // Keyboard and mouse events
10
+ type MouseKeys = "Lmb" | "Rmb" | "Mmb" | "Bmb" | "Fmb" ;
11
+ const keyboardKeys = {
12
+ A : "KeyA" ,
13
+ B : "KeyB" ,
14
+ C : "KeyC" ,
15
+ D : "KeyD" ,
16
+ E : "KeyE" ,
17
+ F : "KeyF" ,
18
+ G : "KeyG" ,
19
+ H : "KeyH" ,
20
+ I : "KeyI" ,
21
+ J : "KeyJ" ,
22
+ K : "KeyK" ,
23
+ L : "KeyL" ,
24
+ M : "KeyM" ,
25
+ N : "KeyN" ,
26
+ O : "KeyO" ,
27
+ P : "KeyP" ,
28
+ Q : "KeyQ" ,
29
+ R : "KeyR" ,
30
+ S : "KeyS" ,
31
+ T : "KeyT" ,
32
+ U : "KeyU" ,
33
+ V : "KeyV" ,
34
+ W : "KeyW" ,
35
+ X : "KeyX" ,
36
+ Y : "KeyY" ,
37
+ Z : "KeyZ" ,
38
+ "0" : "Key0" ,
39
+ "1" : "Key1" ,
40
+ "2" : "Key2" ,
41
+ "3" : "Key3" ,
42
+ "4" : "Key4" ,
43
+ "5" : "Key5" ,
44
+ "6" : "Key6" ,
45
+ "7" : "Key7" ,
46
+ "8" : "Key8" ,
47
+ "9" : "Key9" ,
48
+ Enter : "KeyEnter" ,
49
+ "=" : "KeyEquals" ,
50
+ "-" : "KeyMinus" ,
51
+ "+" : "KeyPlus" ,
52
+ Shift : "KeyShift" ,
53
+ Space : "KeySpace" ,
54
+ Control : "KeyControl" ,
55
+ Delete : "KeyDelete" ,
56
+ Backspace : "KeyBackspace" ,
57
+ Alt : "KeyAlt" ,
58
+ Escape : "KeyEscape" ,
59
+ Tab : "KeyTab" ,
60
+ ArrowUp : "KeyArrowUp" ,
61
+ ArrowDown : "KeyArrowDown" ,
62
+ ArrowLeft : "KeyArrowLeft" ,
63
+ ArrowRight : "KeyArrowRight" ,
64
+ LeftBracket : "KeyLeftBracket" ,
65
+ RightBracket : "KeyRightBracket" ,
66
+ LeftCurlyBracket : "KeyLeftCurlyBracket" ,
67
+ RightCurlyBracket : "KeyRightCurlyBracket" ,
68
+ PageUp : "KeyPageUp" ,
69
+ PageDown : "KeyPageDown" ,
70
+ Comma : "KeyComma" ,
71
+ Period : "KeyPeriod" ,
72
+ } ;
73
+ type KeyboardKeys = typeof keyboardKeys [ keyof typeof keyboardKeys ] ;
74
+ type ModifierKeys = "ctrl" | "cmd" | "shift" | "alt" ;
75
+ type EventBehavior = "stop" | "prevent" | "self" ;
76
+ type HandlerChoice = { functionName : string ; includeKeys : ( MouseKeys | KeyboardKeys ) [ ] ; includeModifiers : ModifierKeys [ ] ; excludeModifiers : ModifierKeys [ ] ; eventBehavior : EventBehavior [ ] } ;
77
+ type Handlers = HandlerChoice [ ] ;
78
+
79
+ const standardKeymap : Record < string , Handlers > = {
80
+ layerTreeLayerClick : [
81
+ { functionName : "handleControlClick" , includeKeys : [ ] , includeModifiers : [ "ctrl" ] , excludeModifiers : [ "shift" , "alt" ] , eventBehavior : [ "stop" ] } ,
82
+ { functionName : "handleShiftClick" , includeKeys : [ ] , includeModifiers : [ "shift" ] , excludeModifiers : [ "ctrl" , "alt" ] , eventBehavior : [ "stop" ] } ,
83
+ { functionName : "handleControlClick" , includeKeys : [ ] , includeModifiers : [ "alt" ] , excludeModifiers : [ "ctrl" , "shift" ] , eventBehavior : [ "stop" ] } ,
84
+ { functionName : "handleClick" , includeKeys : [ ] , includeModifiers : [ ] , excludeModifiers : [ "ctrl" , "shift" , "alt" ] , eventBehavior : [ "stop" ] } ,
85
+ ] ,
86
+ numberInputAbort : [ { functionName : "numberInputAbort" , includeKeys : [ "KeyEscape" ] , includeModifiers : [ ] , excludeModifiers : [ ] , eventBehavior : [ ] } ] ,
87
+ } ;
88
+ const keymapApple : Record < string , Handlers > = {
89
+ layerTreeLayerClick : [
90
+ { functionName : "handleControlClick" , includeKeys : [ ] , includeModifiers : [ "cmd" ] , excludeModifiers : [ "ctrl" , "shift" , "alt" ] , eventBehavior : [ "stop" ] } ,
91
+ { functionName : "handleShiftClick" , includeKeys : [ ] , includeModifiers : [ "shift" ] , excludeModifiers : [ "ctrl" , "cmd" , "alt" ] , eventBehavior : [ "stop" ] } ,
92
+ { functionName : "handleControlClick" , includeKeys : [ ] , includeModifiers : [ "alt" ] , excludeModifiers : [ "ctrl" , "cmd" , "shift" ] , eventBehavior : [ "stop" ] } ,
93
+ { functionName : "handleClick" , includeKeys : [ ] , includeModifiers : [ ] , excludeModifiers : [ "ctrl" , "cmd" , "shift" , "alt" ] , eventBehavior : [ "stop" ] } ,
94
+ ] ,
95
+ numberInputAbort : [ { functionName : "numberInputAbort" , includeKeys : [ "KeyEscape" ] , includeModifiers : [ ] , excludeModifiers : [ ] , eventBehavior : [ ] } ] ,
96
+ } ;
97
+
98
+ export function handleInputEvent ( event : KeyboardEvent | MouseEvent | TouchEvent , keymapEntryId : keyof typeof standardKeymap , functions : Record < string , ( ) => void > ) {
99
+ const isApple = / ^ M a c | ^ i P h o n e | ^ i P a d / i. test ( navigator . platform ) ;
100
+ const keymap = isApple ? keymapApple : standardKeymap ;
101
+ const handlers = keymap [ keymapEntryId ] ;
102
+
103
+ // Same physical key on all keyboard layouts but used differently between platform keymaps
104
+ const ctrlModifier = event . ctrlKey ;
105
+ // Used only by the Apple keymap (Graphite should never use the meta/Windows key on the non-Apple platform keymap)
106
+ const cmdModifier = isApple && event . metaKey ;
107
+ // Consistent across all keyboard layouts
108
+ const shiftModifier = event . shiftKey ;
109
+ // Consistent across all keyboard layouts but this physical key is labeled "Option" on Apple layouts
110
+ const altModifier = event . altKey ;
111
+
112
+ const matchedHandlers = handlers . filter ( ( handler ) => {
113
+ // Reject any excluded modifier keys
114
+ if ( ctrlModifier && handler . excludeModifiers . includes ( "ctrl" ) ) return false ;
115
+ if ( cmdModifier && handler . excludeModifiers . includes ( "cmd" ) ) return false ;
116
+ if ( shiftModifier && handler . excludeModifiers . includes ( "shift" ) ) return false ;
117
+ if ( altModifier && handler . excludeModifiers . includes ( "alt" ) ) return false ;
118
+
119
+ // Reject if missing any included modifier keys
120
+ if ( ! ctrlModifier && handler . includeModifiers . includes ( "ctrl" ) ) return false ;
121
+ if ( ! cmdModifier && handler . includeModifiers . includes ( "cmd" ) ) return false ;
122
+ if ( ! shiftModifier && handler . includeModifiers . includes ( "shift" ) ) return false ;
123
+ if ( ! altModifier && handler . includeModifiers . includes ( "alt" ) ) return false ;
124
+
125
+ if ( event instanceof MouseEvent ) {
126
+ // handler.includeKeys.includes(mouseKeys[event.buttons])
127
+ // const key = mouseKeys?[event.button + ""];
128
+ let lmb = false ; // Left
129
+ let rmb = false ; // Right
130
+ let mmb = false ; // Middle
131
+ let bmb = false ; // Back
132
+ let fmb = false ; // Forward
133
+
134
+ let buttonsValue = event . buttons ;
135
+ if ( buttonsValue >= 16 ) {
136
+ fmb = true ;
137
+ buttonsValue -= 16 ;
138
+ }
139
+ if ( buttonsValue >= 8 ) {
140
+ bmb = true ;
141
+ buttonsValue -= 8 ;
142
+ }
143
+ if ( buttonsValue >= 4 ) {
144
+ mmb = true ;
145
+ buttonsValue -= 4 ;
146
+ }
147
+ if ( buttonsValue >= 2 ) {
148
+ rmb = true ;
149
+ buttonsValue -= 2 ;
150
+ }
151
+ if ( buttonsValue >= 1 ) {
152
+ lmb = true ;
153
+ buttonsValue -= 1 ;
154
+ }
155
+
156
+ if ( ! lmb && handler . includeKeys . includes ( "Lmb" ) ) return false ;
157
+ if ( ! rmb && handler . includeKeys . includes ( "Rmb" ) ) return false ;
158
+ if ( ! mmb && handler . includeKeys . includes ( "Mmb" ) ) return false ;
159
+ if ( ! bmb && handler . includeKeys . includes ( "Bmb" ) ) return false ;
160
+ if ( ! fmb && handler . includeKeys . includes ( "Fmb" ) ) return false ;
161
+ }
162
+
163
+ if ( event instanceof KeyboardEvent ) {
164
+ event . key ;
165
+ }
166
+
167
+ // Reject unmatched keybind
168
+ return false ;
169
+ } ) ;
170
+
171
+ if ( matchedHandlers . length === 0 ) return ;
172
+ if ( matchedHandlers . length > 1 ) {
173
+ console . log ( `Ambiguous set of matched input event handlers.
174
+ Keymap entry ID: ${ keymapEntryId }
175
+ Modifiers: [Ctrl: ${ ctrlModifier } ] [Cmd: ${ cmdModifier } ] [Shift: ${ shiftModifier } ] [Alt: ${ altModifier } ]
176
+ Matched handlers: ${ matchedHandlers }
177
+ ` ) ;
178
+ }
179
+ const handler = matchedHandlers [ 0 ] ;
180
+
181
+ // Apply any additional event behavior
182
+ if ( handler . eventBehavior . includes ( "stop" ) ) event . stopPropagation ( ) ;
183
+ if ( handler . eventBehavior . includes ( "prevent" ) ) event . preventDefault ( ) ;
184
+ if ( handler . eventBehavior . includes ( "self" ) && event . target !== event . currentTarget ) return ;
185
+
186
+ // Execute the callback function
187
+ functions [ handler . functionName ] ( ) ;
188
+ }
189
+
9
190
// Keyboard events
10
191
11
192
function shouldRedirectKeyboardEventToBackend ( e : KeyboardEvent ) : boolean {
0 commit comments