key.go

  1package uv
  2
  3import (
  4	"strings"
  5	"unicode"
  6	"unicode/utf8"
  7
  8	"github.com/charmbracelet/x/ansi"
  9)
 10
 11// KeyMod represents modifier keys.
 12type KeyMod int
 13
 14// Modifier keys.
 15const (
 16	ModShift KeyMod = 1 << iota
 17	ModAlt
 18	ModCtrl
 19	ModMeta
 20
 21	// These modifiers are used with the Kitty protocol.
 22	// XXX: Meta and Super are swapped in the Kitty protocol,
 23	// this is to preserve compatibility with XTerm modifiers.
 24
 25	ModHyper
 26	ModSuper // Windows/Command keys
 27
 28	// These are key lock states.
 29
 30	ModCapsLock
 31	ModNumLock
 32	ModScrollLock // Defined in Windows API only
 33)
 34
 35// Contains reports whether m contains the given modifiers.
 36//
 37// Example:
 38//
 39//	m := ModAlt | ModCtrl
 40//	m.Contains(ModCtrl) // true
 41//	m.Contains(ModAlt | ModCtrl) // true
 42//	m.Contains(ModAlt | ModCtrl | ModShift) // false
 43func (m KeyMod) Contains(mods KeyMod) bool {
 44	return m&mods == mods
 45}
 46
 47const (
 48	// KeyExtended is a special key code used to signify that a key event
 49	// contains multiple runes.
 50	KeyExtended = unicode.MaxRune + 1
 51)
 52
 53// Special key symbols.
 54const (
 55
 56	// Special keys.
 57
 58	KeyUp rune = KeyExtended + iota + 1
 59	KeyDown
 60	KeyRight
 61	KeyLeft
 62	KeyBegin
 63	KeyFind
 64	KeyInsert
 65	KeyDelete
 66	KeySelect
 67	KeyPgUp
 68	KeyPgDown
 69	KeyHome
 70	KeyEnd
 71
 72	// Keypad keys.
 73
 74	KeyKpEnter
 75	KeyKpEqual
 76	KeyKpMultiply
 77	KeyKpPlus
 78	KeyKpComma
 79	KeyKpMinus
 80	KeyKpDecimal
 81	KeyKpDivide
 82	KeyKp0
 83	KeyKp1
 84	KeyKp2
 85	KeyKp3
 86	KeyKp4
 87	KeyKp5
 88	KeyKp6
 89	KeyKp7
 90	KeyKp8
 91	KeyKp9
 92
 93	//nolint:godox
 94	// The following are keys defined in the Kitty keyboard protocol.
 95	// TODO: Investigate the names of these keys.
 96
 97	KeyKpSep
 98	KeyKpUp
 99	KeyKpDown
100	KeyKpLeft
101	KeyKpRight
102	KeyKpPgUp
103	KeyKpPgDown
104	KeyKpHome
105	KeyKpEnd
106	KeyKpInsert
107	KeyKpDelete
108	KeyKpBegin
109
110	// Function keys.
111
112	KeyF1
113	KeyF2
114	KeyF3
115	KeyF4
116	KeyF5
117	KeyF6
118	KeyF7
119	KeyF8
120	KeyF9
121	KeyF10
122	KeyF11
123	KeyF12
124	KeyF13
125	KeyF14
126	KeyF15
127	KeyF16
128	KeyF17
129	KeyF18
130	KeyF19
131	KeyF20
132	KeyF21
133	KeyF22
134	KeyF23
135	KeyF24
136	KeyF25
137	KeyF26
138	KeyF27
139	KeyF28
140	KeyF29
141	KeyF30
142	KeyF31
143	KeyF32
144	KeyF33
145	KeyF34
146	KeyF35
147	KeyF36
148	KeyF37
149	KeyF38
150	KeyF39
151	KeyF40
152	KeyF41
153	KeyF42
154	KeyF43
155	KeyF44
156	KeyF45
157	KeyF46
158	KeyF47
159	KeyF48
160	KeyF49
161	KeyF50
162	KeyF51
163	KeyF52
164	KeyF53
165	KeyF54
166	KeyF55
167	KeyF56
168	KeyF57
169	KeyF58
170	KeyF59
171	KeyF60
172	KeyF61
173	KeyF62
174	KeyF63
175
176	//nolint:godox
177	// The following are keys defined in the Kitty keyboard protocol.
178	// TODO: Investigate the names of these keys.
179
180	KeyCapsLock
181	KeyScrollLock
182	KeyNumLock
183	KeyPrintScreen
184	KeyPause
185	KeyMenu
186
187	KeyMediaPlay
188	KeyMediaPause
189	KeyMediaPlayPause
190	KeyMediaReverse
191	KeyMediaStop
192	KeyMediaFastForward
193	KeyMediaRewind
194	KeyMediaNext
195	KeyMediaPrev
196	KeyMediaRecord
197
198	KeyLowerVol
199	KeyRaiseVol
200	KeyMute
201
202	KeyLeftShift
203	KeyLeftAlt
204	KeyLeftCtrl
205	KeyLeftSuper
206	KeyLeftHyper
207	KeyLeftMeta
208	KeyRightShift
209	KeyRightAlt
210	KeyRightCtrl
211	KeyRightSuper
212	KeyRightHyper
213	KeyRightMeta
214	KeyIsoLevel3Shift
215	KeyIsoLevel5Shift
216
217	// Special names in C0.
218
219	KeyBackspace = rune(ansi.DEL)
220	KeyTab       = rune(ansi.HT)
221	KeyEnter     = rune(ansi.CR)
222	KeyReturn    = KeyEnter
223	KeyEscape    = rune(ansi.ESC)
224	KeyEsc       = KeyEscape
225
226	// Special names in G0.
227
228	KeySpace = rune(ansi.SP)
229)
230
231// Key represents a Key press or release event. It contains information about
232// the Key pressed, like the runes, the type of Key, and the modifiers pressed.
233// There are a couple general patterns you could use to check for key presses
234// or releases:
235//
236//	// Switch on the string representation of the key (shorter)
237//	switch ev := ev.(type) {
238//	case KeyPressEvent:
239//	    switch ev.String() {
240//	    case "enter":
241//	        fmt.Println("you pressed enter!")
242//	    case "a":
243//	        fmt.Println("you pressed a!")
244//	    }
245//	}
246//
247//	// Switch on the key type (more foolproof)
248//	switch ev := ev.(type) {
249//	case KeyEvent:
250//	    // catch both KeyPressEvent and KeyReleaseEvent
251//	    switch key := ev.Key(); key.Code {
252//	    case KeyEnter:
253//	        fmt.Println("you pressed enter!")
254//	    default:
255//	        switch key.Text {
256//	        case "a":
257//	            fmt.Println("you pressed a!")
258//	        }
259//	    }
260//	}
261//
262// Note that [Key.Text] will be empty for special keys like [KeyEnter],
263// [KeyTab], and for keys that don't represent printable characters like key
264// combos with modifier keys. In other words, [Key.Text] is populated only for
265// keys that represent printable characters shifted or unshifted (like 'a',
266// 'A', '1', '!', etc.).
267type Key struct {
268	// Text contains the actual characters received. This usually the same as
269	// [Key.Code]. When [Key.Text] is non-empty, it indicates that the key
270	// pressed represents printable character(s).
271	Text string
272
273	// Mod represents modifier keys, like [ModCtrl], [ModAlt], and so on.
274	Mod KeyMod
275
276	// Code represents the key pressed. This is usually a special key like
277	// [KeyTab], [KeyEnter], [KeyF1], or a printable character like 'a'.
278	Code rune
279
280	// ShiftedCode is the actual, shifted key pressed by the user. For example,
281	// if the user presses shift+a, or caps lock is on, [Key.ShiftedCode] will
282	// be 'A' and [Key.Code] will be 'a'.
283	//
284	// In the case of non-latin keyboards, like Arabic, [Key.ShiftedCode] is the
285	// unshifted key on the keyboard.
286	//
287	// This is only available with the Kitty Keyboard Protocol or the Windows
288	// Console API.
289	ShiftedCode rune
290
291	// BaseCode is the key pressed according to the standard PC-101 key layout.
292	// On international keyboards, this is the key that would be pressed if the
293	// keyboard was set to US PC-101 layout.
294	//
295	// For example, if the user presses 'q' on a French AZERTY keyboard,
296	// [Key.BaseCode] will be 'q'.
297	//
298	// This is only available with the Kitty Keyboard Protocol or the Windows
299	// Console API.
300	BaseCode rune
301
302	// IsRepeat indicates whether the key is being held down and sending events
303	// repeatedly.
304	//
305	// This is only available with the Kitty Keyboard Protocol or the Windows
306	// Console API.
307	IsRepeat bool
308}
309
310// MatchString returns true if the [Key] matches the given string. The string
311// can be a key name like "enter", "tab", "a", or a printable character like
312// "1" or " ". It can also have combinations of modifiers like "ctrl+a",
313// "shift+enter", "alt+tab", "ctrl+shift+enter", etc.
314func (k Key) MatchString(s string) bool {
315	var (
316		mod  KeyMod
317		code rune
318		text string
319	)
320	parts := strings.Split(s, "+")
321	for _, part := range parts {
322		switch part {
323		case "ctrl":
324			mod |= ModCtrl
325		case "alt":
326			mod |= ModAlt
327		case "shift":
328			mod |= ModShift
329		case "meta":
330			mod |= ModMeta
331		case "hyper":
332			mod |= ModHyper
333		case "super":
334			mod |= ModSuper
335		case "capslock":
336			mod |= ModCapsLock
337		case "scrolllock":
338			mod |= ModScrollLock
339		case "numlock":
340			mod |= ModNumLock
341		default:
342			// Check if the part is a key name.
343			if k, ok := stringKeyType[part]; ok {
344				code = k
345			} else {
346				// Check if the part is a printable character.
347				if utf8.RuneCountInString(part) == 1 {
348					code, _ = utf8.DecodeRuneInString(part)
349				} else {
350					// Multi-rune key.
351					code = KeyExtended
352					text = part
353				}
354			}
355		}
356	}
357
358	// Check if we have a printable character.
359	smod := mod &^ (ModShift | ModCapsLock)
360	if smod == 0 && text == "" && unicode.IsPrint(code) {
361		if mod&ModShift != 0 || mod&ModCapsLock != 0 {
362			// Shifted code we need to use uppercase.
363			text = string(unicode.ToUpper(code))
364		} else {
365			// Otherwise, use the code as is.
366			text = string(code)
367		}
368	}
369
370	// Check if we have a match.
371	return (k.Mod == mod && k.Code == code) ||
372		(k.Text != "" && k.Text == text)
373}
374
375// MatchStrings returns true if the [Key] matches any of the given strings. The
376// strings can be key names like "enter", "tab", "a", or a printable character
377// like "1" or " ". It can also have combinations of modifiers like "ctrl+a",
378// "shift+enter", "alt+tab", "ctrl+shift+enter", etc.
379// See [Key.MatchString] for more details.
380func (k Key) MatchStrings(ss ...string) bool {
381	for _, s := range ss {
382		if k.MatchString(s) {
383			return true
384		}
385	}
386	return false
387}
388
389// String implements [fmt.Stringer] and is quite useful for matching key
390// events. It will return the textual representation of the [Key] if there is
391// one, otherwise, it will fallback to [Key.Keystroke].
392//
393// For example, you'll always get "?" and instead of "shift+/" on a US ANSI
394// keyboard.
395func (k Key) String() string {
396	if len(k.Text) > 0 && k.Text != " " {
397		return k.Text
398	}
399	return k.Keystroke()
400}
401
402// Keystroke returns the keystroke representation of the [Key]. While less type
403// safe than looking at the individual fields, it will usually be more
404// convenient and readable to use this method when matching against keys.
405//
406// Note that modifier keys are always printed in the following order:
407//   - ctrl
408//   - alt
409//   - shift
410//   - meta
411//   - hyper
412//   - super
413//
414// For example, you'll always see "ctrl+shift+alt+a" and never
415// "shift+ctrl+alt+a".
416func (k Key) Keystroke() string {
417	var sb strings.Builder
418	if k.Mod.Contains(ModCtrl) && k.Code != KeyLeftCtrl && k.Code != KeyRightCtrl {
419		sb.WriteString("ctrl+")
420	}
421	if k.Mod.Contains(ModAlt) && k.Code != KeyLeftAlt && k.Code != KeyRightAlt {
422		sb.WriteString("alt+")
423	}
424	if k.Mod.Contains(ModShift) && k.Code != KeyLeftShift && k.Code != KeyRightShift {
425		sb.WriteString("shift+")
426	}
427	if k.Mod.Contains(ModMeta) && k.Code != KeyLeftMeta && k.Code != KeyRightMeta {
428		sb.WriteString("meta+")
429	}
430	if k.Mod.Contains(ModHyper) && k.Code != KeyLeftHyper && k.Code != KeyRightHyper {
431		sb.WriteString("hyper+")
432	}
433	if k.Mod.Contains(ModSuper) && k.Code != KeyLeftSuper && k.Code != KeyRightSuper {
434		sb.WriteString("super+")
435	}
436
437	if kt, ok := keyTypeString[k.Code]; ok {
438		sb.WriteString(kt)
439	} else {
440		code := k.Code
441		if k.BaseCode != 0 {
442			// If a [Key.BaseCode] is present, use it to represent a key using the standard
443			// PC-101 key layout.
444			code = k.BaseCode
445		}
446
447		switch code {
448		case KeySpace:
449			// Space is the only invisible printable character.
450			sb.WriteString("space")
451		case KeyExtended:
452			// Write the actual text of the key when the key contains multiple
453			// runes.
454			sb.WriteString(k.Text)
455		default:
456			sb.WriteRune(code)
457		}
458	}
459
460	return sb.String()
461}
462
463var keyTypeString = map[rune]string{
464	KeyEnter:      "enter",
465	KeyTab:        "tab",
466	KeyBackspace:  "backspace",
467	KeyEscape:     "esc",
468	KeySpace:      "space",
469	KeyUp:         "up",
470	KeyDown:       "down",
471	KeyLeft:       "left",
472	KeyRight:      "right",
473	KeyBegin:      "begin",
474	KeyFind:       "find",
475	KeyInsert:     "insert",
476	KeyDelete:     "delete",
477	KeySelect:     "select",
478	KeyPgUp:       "pgup",
479	KeyPgDown:     "pgdown",
480	KeyHome:       "home",
481	KeyEnd:        "end",
482	KeyKpEnter:    "kpenter",
483	KeyKpEqual:    "kpequal",
484	KeyKpMultiply: "kpmul",
485	KeyKpPlus:     "kpplus",
486	KeyKpComma:    "kpcomma",
487	KeyKpMinus:    "kpminus",
488	KeyKpDecimal:  "kpperiod",
489	KeyKpDivide:   "kpdiv",
490	KeyKp0:        "kp0",
491	KeyKp1:        "kp1",
492	KeyKp2:        "kp2",
493	KeyKp3:        "kp3",
494	KeyKp4:        "kp4",
495	KeyKp5:        "kp5",
496	KeyKp6:        "kp6",
497	KeyKp7:        "kp7",
498	KeyKp8:        "kp8",
499	KeyKp9:        "kp9",
500
501	// Kitty keyboard extension
502	KeyKpSep:    "kpsep",
503	KeyKpUp:     "kpup",
504	KeyKpDown:   "kpdown",
505	KeyKpLeft:   "kpleft",
506	KeyKpRight:  "kpright",
507	KeyKpPgUp:   "kppgup",
508	KeyKpPgDown: "kppgdown",
509	KeyKpHome:   "kphome",
510	KeyKpEnd:    "kpend",
511	KeyKpInsert: "kpinsert",
512	KeyKpDelete: "kpdelete",
513	KeyKpBegin:  "kpbegin",
514
515	KeyF1:  "f1",
516	KeyF2:  "f2",
517	KeyF3:  "f3",
518	KeyF4:  "f4",
519	KeyF5:  "f5",
520	KeyF6:  "f6",
521	KeyF7:  "f7",
522	KeyF8:  "f8",
523	KeyF9:  "f9",
524	KeyF10: "f10",
525	KeyF11: "f11",
526	KeyF12: "f12",
527	KeyF13: "f13",
528	KeyF14: "f14",
529	KeyF15: "f15",
530	KeyF16: "f16",
531	KeyF17: "f17",
532	KeyF18: "f18",
533	KeyF19: "f19",
534	KeyF20: "f20",
535	KeyF21: "f21",
536	KeyF22: "f22",
537	KeyF23: "f23",
538	KeyF24: "f24",
539	KeyF25: "f25",
540	KeyF26: "f26",
541	KeyF27: "f27",
542	KeyF28: "f28",
543	KeyF29: "f29",
544	KeyF30: "f30",
545	KeyF31: "f31",
546	KeyF32: "f32",
547	KeyF33: "f33",
548	KeyF34: "f34",
549	KeyF35: "f35",
550	KeyF36: "f36",
551	KeyF37: "f37",
552	KeyF38: "f38",
553	KeyF39: "f39",
554	KeyF40: "f40",
555	KeyF41: "f41",
556	KeyF42: "f42",
557	KeyF43: "f43",
558	KeyF44: "f44",
559	KeyF45: "f45",
560	KeyF46: "f46",
561	KeyF47: "f47",
562	KeyF48: "f48",
563	KeyF49: "f49",
564	KeyF50: "f50",
565	KeyF51: "f51",
566	KeyF52: "f52",
567	KeyF53: "f53",
568	KeyF54: "f54",
569	KeyF55: "f55",
570	KeyF56: "f56",
571	KeyF57: "f57",
572	KeyF58: "f58",
573	KeyF59: "f59",
574	KeyF60: "f60",
575	KeyF61: "f61",
576	KeyF62: "f62",
577	KeyF63: "f63",
578
579	// Kitty keyboard extension
580	KeyCapsLock:         "capslock",
581	KeyScrollLock:       "scrolllock",
582	KeyNumLock:          "numlock",
583	KeyPrintScreen:      "printscreen",
584	KeyPause:            "pause",
585	KeyMenu:             "menu",
586	KeyMediaPlay:        "mediaplay",
587	KeyMediaPause:       "mediapause",
588	KeyMediaPlayPause:   "mediaplaypause",
589	KeyMediaReverse:     "mediareverse",
590	KeyMediaStop:        "mediastop",
591	KeyMediaFastForward: "mediafastforward",
592	KeyMediaRewind:      "mediarewind",
593	KeyMediaNext:        "medianext",
594	KeyMediaPrev:        "mediaprev",
595	KeyMediaRecord:      "mediarecord",
596	KeyLowerVol:         "lowervol",
597	KeyRaiseVol:         "raisevol",
598	KeyMute:             "mute",
599	KeyLeftShift:        "leftshift",
600	KeyLeftAlt:          "leftalt",
601	KeyLeftCtrl:         "leftctrl",
602	KeyLeftSuper:        "leftsuper",
603	KeyLeftHyper:        "lefthyper",
604	KeyLeftMeta:         "leftmeta",
605	KeyRightShift:       "rightshift",
606	KeyRightAlt:         "rightalt",
607	KeyRightCtrl:        "rightctrl",
608	KeyRightSuper:       "rightsuper",
609	KeyRightHyper:       "righthyper",
610	KeyRightMeta:        "rightmeta",
611	KeyIsoLevel3Shift:   "isolevel3shift",
612	KeyIsoLevel5Shift:   "isolevel5shift",
613}
614
615var stringKeyType = map[string]rune{
616	"enter":     KeyEnter,
617	"tab":       KeyTab,
618	"backspace": KeyBackspace,
619	"escape":    KeyEscape,
620	"esc":       KeyEscape,
621	"space":     KeySpace,
622	"up":        KeyUp,
623	"down":      KeyDown,
624	"left":      KeyLeft,
625	"right":     KeyRight,
626	"begin":     KeyBegin,
627	"find":      KeyFind,
628	"insert":    KeyInsert,
629	"delete":    KeyDelete,
630	"select":    KeySelect,
631	"pgup":      KeyPgUp,
632	"pgdown":    KeyPgDown,
633	"home":      KeyHome,
634	"end":       KeyEnd,
635	"kpenter":   KeyKpEnter,
636	"kpequal":   KeyKpEqual,
637	"kpmul":     KeyKpMultiply,
638	"kpplus":    KeyKpPlus,
639	"kpcomma":   KeyKpComma,
640	"kpminus":   KeyKpMinus,
641	"kpperiod":  KeyKpDecimal,
642	"kpdiv":     KeyKpDivide,
643	"kp0":       KeyKp0,
644	"kp1":       KeyKp1,
645	"kp2":       KeyKp2,
646	"kp3":       KeyKp3,
647	"kp4":       KeyKp4,
648	"kp5":       KeyKp5,
649	"kp6":       KeyKp6,
650	"kp7":       KeyKp7,
651	"kp8":       KeyKp8,
652	"kp9":       KeyKp9,
653
654	// Kitty keyboard extension
655	"kpsep":    KeyKpSep,
656	"kpup":     KeyKpUp,
657	"kpdown":   KeyKpDown,
658	"kpleft":   KeyKpLeft,
659	"kpright":  KeyKpRight,
660	"kppgup":   KeyKpPgUp,
661	"kppgdown": KeyKpPgDown,
662	"kphome":   KeyKpHome,
663	"kpend":    KeyKpEnd,
664	"kpinsert": KeyKpInsert,
665	"kpdelete": KeyKpDelete,
666	"kpbegin":  KeyKpBegin,
667
668	"f1":  KeyF1,
669	"f2":  KeyF2,
670	"f3":  KeyF3,
671	"f4":  KeyF4,
672	"f5":  KeyF5,
673	"f6":  KeyF6,
674	"f7":  KeyF7,
675	"f8":  KeyF8,
676	"f9":  KeyF9,
677	"f10": KeyF10,
678	"f11": KeyF11,
679	"f12": KeyF12,
680	"f13": KeyF13,
681	"f14": KeyF14,
682	"f15": KeyF15,
683	"f16": KeyF16,
684	"f17": KeyF17,
685	"f18": KeyF18,
686	"f19": KeyF19,
687	"f20": KeyF20,
688	"f21": KeyF21,
689	"f22": KeyF22,
690	"f23": KeyF23,
691	"f24": KeyF24,
692	"f25": KeyF25,
693	"f26": KeyF26,
694	"f27": KeyF27,
695	"f28": KeyF28,
696	"f29": KeyF29,
697	"f30": KeyF30,
698	"f31": KeyF31,
699	"f32": KeyF32,
700	"f33": KeyF33,
701	"f34": KeyF34,
702	"f35": KeyF35,
703	"f36": KeyF36,
704	"f37": KeyF37,
705	"f38": KeyF38,
706	"f39": KeyF39,
707	"f40": KeyF40,
708	"f41": KeyF41,
709	"f42": KeyF42,
710	"f43": KeyF43,
711	"f44": KeyF44,
712	"f45": KeyF45,
713	"f46": KeyF46,
714	"f47": KeyF47,
715	"f48": KeyF48,
716	"f49": KeyF49,
717	"f50": KeyF50,
718	"f51": KeyF51,
719	"f52": KeyF52,
720	"f53": KeyF53,
721	"f54": KeyF54,
722	"f55": KeyF55,
723	"f56": KeyF56,
724	"f57": KeyF57,
725	"f58": KeyF58,
726	"f59": KeyF59,
727	"f60": KeyF60,
728	"f61": KeyF61,
729	"f62": KeyF62,
730	"f63": KeyF63,
731
732	// Kitty keyboard extension
733	"capslock":         KeyCapsLock,
734	"scrolllock":       KeyScrollLock,
735	"numlock":          KeyNumLock,
736	"printscreen":      KeyPrintScreen,
737	"pause":            KeyPause,
738	"menu":             KeyMenu,
739	"mediaplay":        KeyMediaPlay,
740	"mediapause":       KeyMediaPause,
741	"mediaplaypause":   KeyMediaPlayPause,
742	"mediareverse":     KeyMediaReverse,
743	"mediastop":        KeyMediaStop,
744	"mediafastforward": KeyMediaFastForward,
745	"mediarewind":      KeyMediaRewind,
746	"medianext":        KeyMediaNext,
747	"mediaprev":        KeyMediaPrev,
748	"mediarecord":      KeyMediaRecord,
749	"lowervol":         KeyLowerVol,
750	"raisevol":         KeyRaiseVol,
751	"mute":             KeyMute,
752	"leftshift":        KeyLeftShift,
753	"leftalt":          KeyLeftAlt,
754	"leftctrl":         KeyLeftCtrl,
755	"leftsuper":        KeyLeftSuper,
756	"lefthyper":        KeyLeftHyper,
757	"leftmeta":         KeyLeftMeta,
758	"rightshift":       KeyRightShift,
759	"rightalt":         KeyRightAlt,
760	"rightctrl":        KeyRightCtrl,
761	"rightsuper":       KeyRightSuper,
762	"righthyper":       KeyRightHyper,
763	"rightmeta":        KeyRightMeta,
764	"isolevel3shift":   KeyIsoLevel3Shift,
765	"isolevel5shift":   KeyIsoLevel5Shift,
766}