@@ -12,33 +12,98 @@ export type ShortcutBinding<Action extends ShortcutActionBase> = {
1212 repeat ?: boolean ;
1313} ;
1414
15+ const normalizeShortcutKey = ( key : string ) : string => ( key . length === 1 ? key . toLowerCase ( ) : key ) ;
16+
17+ type ParsedShortcutKey = {
18+ key : string ;
19+ altKey : boolean ;
20+ ctrlKey : boolean ;
21+ metaKey : boolean ;
22+ shiftKey : boolean ;
23+ } ;
24+
25+ const parseShortcutKey = ( shortcutKey : string ) : ParsedShortcutKey => {
26+ const parsed : ParsedShortcutKey = {
27+ key : "" ,
28+ altKey : false ,
29+ ctrlKey : false ,
30+ metaKey : false ,
31+ shiftKey : false ,
32+ } ;
33+
34+ for ( const part of shortcutKey . split ( "+" ) )
35+ switch ( part ) {
36+ case "Alt" :
37+ parsed . altKey = true ;
38+ break ;
39+ case "Ctrl" :
40+ parsed . ctrlKey = true ;
41+ break ;
42+ case "Meta" :
43+ parsed . metaKey = true ;
44+ break ;
45+ case "Shift" :
46+ parsed . shiftKey = true ;
47+ break ;
48+ default :
49+ parsed . key = normalizeShortcutKey ( part ) ;
50+ }
51+
52+ return parsed ;
53+ } ;
54+
55+ const eventMatchesShortcutKey = ( event : KeyboardEvent , shortcutKey : string ) : boolean => {
56+ const parsed = parseShortcutKey ( shortcutKey ) ;
57+ if ( parsed . key === "" ) return false ;
58+
59+ return (
60+ normalizeShortcutKey ( event . key ) === parsed . key &&
61+ event . altKey === parsed . altKey &&
62+ event . ctrlKey === parsed . ctrlKey &&
63+ event . metaKey === parsed . metaKey &&
64+ event . shiftKey === parsed . shiftKey
65+ ) ;
66+ } ;
67+
1568export const getAction = < Action extends ShortcutActionBase > (
1669 bindings : Array < ShortcutBinding < Action > > ,
1770 event : KeyboardEvent ,
1871) : Action | null => {
1972 for ( const binding of bindings ) {
20- if ( ! binding . keys . includes ( event . key ) ) continue ;
73+ if ( ! binding . keys . some ( ( shortcutKey ) => eventMatchesShortcutKey ( event , shortcutKey ) ) ) continue ;
2174 if ( binding . repeat === false && event . repeat ) continue ;
2275 return binding . action ;
2376 }
2477
2578 return null ;
2679} ;
2780
81+ const formatShortcutKey = ( key : string ) : string => {
82+ const parsed = parseShortcutKey ( key ) ;
83+ if ( parsed . key === "" ) return key ;
84+
85+ const modifiers = [
86+ parsed . ctrlKey ? "ctrl" : null ,
87+ parsed . altKey ? "alt" : null ,
88+ parsed . shiftKey ? "shift" : null ,
89+ parsed . metaKey ? "meta" : null ,
90+ ] . filter ( ( modifier ) => modifier !== null ) ;
91+
92+ const formattedKey = Match . value ( parsed . key ) . pipe (
93+ Match . when ( "ArrowUp" , ( ) => "↑" ) ,
94+ Match . when ( "ArrowDown" , ( ) => "↓" ) ,
95+ Match . when ( "ArrowLeft" , ( ) => "←" ) ,
96+ Match . when ( "ArrowRight" , ( ) => "→" ) ,
97+ Match . when ( "Escape" , ( ) => "esc" ) ,
98+ Match . when ( "Enter" , ( ) => "enter" ) ,
99+ Match . orElse ( ( ) => parsed . key ) ,
100+ ) ;
101+
102+ return [ ...modifiers , formattedKey ] . join ( "+" ) ;
103+ } ;
104+
28105export const formatShortcutKeys = ( keys : Array < string > ) : string =>
29- keys
30- . map ( ( key ) =>
31- Match . value ( key ) . pipe (
32- Match . when ( "ArrowUp" , ( ) => "↑" ) ,
33- Match . when ( "ArrowDown" , ( ) => "↓" ) ,
34- Match . when ( "ArrowLeft" , ( ) => "←" ) ,
35- Match . when ( "ArrowRight" , ( ) => "→" ) ,
36- Match . when ( "Escape" , ( ) => "esc" ) ,
37- Match . when ( "Enter" , ( ) => "enter" ) ,
38- Match . orElse ( ( ) => key ) ,
39- ) ,
40- )
41- . join ( "/" ) ;
106+ keys . map ( ( key ) => formatShortcutKey ( key ) ) . join ( "/" ) ;
42107
43108export const bindingButtonLabel = ( binding : ShortcutBinding < ShortcutActionBase > ) : string =>
44109 `${ binding . description } (${ formatShortcutKeys ( binding . keys ) } )` ;
0 commit comments