From f1d7848a6bd8f944d3ac56e656452f3cfd94fe6d Mon Sep 17 00:00:00 2001 From: TheFGFSEagle Date: Sun, 8 Jan 2023 15:34:17 +0100 Subject: [PATCH] Added keyboard Nasal module --- Nasal/keyboard.nas | 443 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 443 insertions(+) create mode 100644 Nasal/keyboard.nas diff --git a/Nasal/keyboard.nas b/Nasal/keyboard.nas new file mode 100644 index 000000000..de857b5d1 --- /dev/null +++ b/Nasal/keyboard.nas @@ -0,0 +1,443 @@ +PrintableKeys = { + 0: 0x30, + 1: 0x31, + 2: 0x32, + 3: 0x33, + 4: 0x34, + 5: 0x35, + 6: 0x36, + 7: 0x37, + 8: 0x38, + 9: 0x39, + A: 0x61, + a: 0x61, + B: 0x62, + b: 0x62, + C: 0x63, + c: 0x63, + D: 0x64, + d: 0x64, + E: 0x65, + e: 0x65, + F: 0x66, + f: 0x66, + G: 0x67, + g: 0x67, + H: 0x68, + h: 0x68, + I: 0x69, + i: 0x69, + J: 0x6a, + j: 0x6a, + K: 0x6b, + k: 0x6b, + L: 0x6c, + l: 0x6c, + M: 0x6d, + m: 0x6d, + N: 0x6e, + n: 0x6e, + O: 0x6f, + o: 0x6f, + P: 0x70, + p: 0x70, + Q: 0x71, + q: 0x71, + R: 0x72, + r: 0x72, + S: 0x73, + s: 0x73, + T: 0x74, + t: 0x74, + U: 0x75, + u: 0x75, + V: 0x76, + v: 0x76, + W: 0x77, + w: 0x77, + X: 0x78, + x: 0x78, + Y: 0x79, + y: 0x79, + Z: 0x7a, + z: 0x7a, + "!": 0x21, + Exclaim: 0x21, + '"': 0x22, + DoubleQuote: 0x22, + "#": 0x23, + Hash: 0x23, + "$": 0x24, + Dollar: 0x24, + "&": 0x26, + Ampersand: 0x26, + "'": 0x27, + SingleQuote: 0x27, + "(": 0x28, + OpeningParenthesis: 0x28, + ")": 0x29, + ClosingParenthesis: 0x29, + "*": 0x2a, + Asterisk: 0x2A, + "+": 0x2b, + Plus: 0x2B, + ",": 0x2c, + Comma: 0x2C, + "-": 0x2d, + Minus: 0x2D, + ".": 0x2e, + Period: 0x2E, + "/": 0x2f, + Slash: 0x2F, + ",": 0x3a, + Colon: 0x3A, + ";": 0x3b, + SemiColon: 0x3B, + "<": 0x3c, + Less: 0x3C, + "=": 0x3d, + Equals: 0x3D, + ">": 0x3e, + Greater: 0x3E, + "?": 0x3f, + Question: 0x3F, + "@": 0x40, + At: 0x40, + "[": 0x5b, + OpeningBracket: 0x5B, + "\\": 0x5c, + BackSlash: 0x5C, + "]": 0x5d, + ClosingBracket: 0x5D, + "^": 0x5e, + Caret: 0x5E, + "_": 0x5f, + Underscore: 0x5F, + "`": 0x60, + BackQuote: 0x60, +}; + +FunctionKeys = { + Space: 0x20, + Backspace: 0xFF08, + Tab: 0xFF09, + Linefeed: 0xFF0A, + Clear: 0xFF0B, + Return: 0xFF0D, + Pause: 0xFF13, + Sys_Req: 0xFF15, + "Esc": 0xff1b, + Escape: 0xFF1B, + "Del": 0xffff, + Delete: 0xFFFF, + Home: 0xFF50, + Left: 0xFF51, + Up: 0xFF52, + Right: 0xFF53, + Down: 0xFF54, + Prior: 0xFF55, + Page_Up: 0xFF55, + Next: 0xFF56, + Page_Down: 0xFF56, + End: 0xFF57, + Begin: 0xFF58, + Select: 0xFF60, + Print: 0xFF61, + Execute: 0xFF62, + Insert: 0xFF63, + Undo: 0xFF65, + Redo: 0xFF66, + Menu: 0xFF67, + Find: 0xFF68, + Cancel: 0xFF69, + Help: 0xFF6A, + Break: 0xFF6B, + + # Any key binding using these would be pretty confusing … + Mode_switch: 0xFF7E, + Script_switch: 0xFF7E, + Num_Lock: 0xFF7F, + Scroll_Lock: 0xFF14, + + # Keypad keys probably should not be used because their normal key equivalent will be passed by OSG AFAIK + KP_Space: 0xFF80, + KP_Tab: 0xFF89, + KP_Enter: 0xFF8D, + KP_F1: 0xFF91, + KP_F2: 0xFF92, + KP_F3: 0xFF93, + KP_F4: 0xFF94, + KP_Home: 0xFF95, + KP_Left: 0xFF96, + KP_Up: 0xFF97, + KP_Right: 0xFF98, + KP_Down: 0xFF99, + KP_Prior: 0xFF9A, + KP_Page_Up: 0xFF9A, + KP_Next: 0xFF9B, + KP_Page_Down: 0xFF9B, + KP_End: 0xFF9C, + KP_Begin: 0xFF9D, + KP_Insert: 0xFF9E, + KP_Delete: 0xFF9F, + KP_Equal: 0xFFBD, + KP_Multiply: 0xFFAA, + KP_Add: 0xFFAB, + KP_Separator: 0xFFAC, + KP_Subtract: 0xFFAD, + KP_Decimal: 0xFFAE, + KP_Divide: 0xFFAF, + KP_0: 0xFFB0, + KP_1: 0xFFB1, + KP_2: 0xFFB2, + KP_3: 0xFFB3, + KP_4: 0xFFB4, + KP_5: 0xFFB5, + KP_6: 0xFFB6, + KP_7: 0xFFB7, + KP_8: 0xFFB8, + KP_9: 0xFFB9, + F1: 0xFFBE, + F2: 0xFFBF, + F3: 0xFFC0, + F4: 0xFFC1, + F5: 0xFFC2, + F6: 0xFFC3, + F7: 0xFFC4, + F8: 0xFFC5, + F9: 0xFFC6, + F10: 0xFFC7, + F11: 0xFFC8, + + # most keyboards only have F1 - F11, so better not use any of the below FunctionKeys + F12: 0xFFC9, + F13: 0xFFCA, + F14: 0xFFCB, + F15: 0xFFCC, + F16: 0xFFCD, + F17: 0xFFCE, + F18: 0xFFCF, + F19: 0xFFD0, + F20: 0xFFD1, + F21: 0xFFD2, + F22: 0xFFD3, + F23: 0xFFD4, + F24: 0xFFD5, + F25: 0xFFD6, + F26: 0xFFD7, + F27: 0xFFD8, + F28: 0xFFD9, + F29: 0xFFDA, + F30: 0xFFDB, + F31: 0xFFDC, + F32: 0xFFDD, + F33: 0xFFDE, + F34: 0xFFDF, + F35: 0xFFE0, + + # Do not use the below keys ! + Shift_L: 0xFFE1, + Shift_R: 0xFFE2, + Control_L: 0xFFE3, + Control_R: 0xFFE4, + Caps_Lock: 0xFFE5, + Shift_Lock: 0xFFE6, + Meta_L: 0xFFE7, + Meta_R: 0xFFE8, + Alt_L: 0xFFE9, + Alt_R: 0xFFEA, + #Super_L: 0xFFEB, + #Super_R: 0xFFEC, + #Hyper_L: 0xFFED, + #Hyper_R: 0xFFEE, +}; + +ModifierKeys = { + Shift_L: 0x0001, + Shift_R: 0x0002, + Control_L: 0x0004, + Control_R: 0x0008, + Alt_L: 0x0010, + Alt_R: 0x0020, + Meta_L: 0x0040, + Meta_R: 0x0080, + + # These do not seem to be available in OSG events + #Super_L: 0x0100, + #Super_R: 0x0200, + #Hyper_L: 0x0400, + #Hyper_R: 0x0800, + #Num_Lock: 0x1000, + Caps_Lock: 0x2000, +}; + +# Only use the below keys ! +ModifierKeys.Ctrl = (ModifierKeys.Control_L | ModifierKeys.Control_R); +ModifierKeys.Shift = (ModifierKeys.Shift_L | ModifierKeys.Shift_R); +ModifierKeys.Alt = (ModifierKeys.Alt_L | ModifierKeys.Alt_R); +ModifierKeys.Meta = (ModifierKeys.Meta_L | ModifierKeys.Meta_R); + +# These do not seem to be available in OSG events +#ModifierKeys.Super = (ModifierKeys.Super_L | ModifierKeys.Super_R); +#ModifierKeys.Hyper = (ModifierKeys.Hyper_L | ModifierKeys.Hyper_R); + +var Shortcut = { + new: func(modifiers, keys...) { + var m = { + parents: [Shortcut], + modifiers: modifiers, + keys: keys, + }; + if (m.modifiers == nil) { + m.modifiers = []; + m.keys = []; + } elsif (isa(m.modifiers, Shortcut)) { + var shortcut = m.modifiers; + m.modifiers = shortcut.modifiers; + m.keys = shortcut.keys; + } elsif (typeof(m.modifiers) == "scalar") { + var res = m.parseString(m.modifiers); + if (typeof(res) == "scalar") { + logprint(LOG_ALERT, "keyboard.Shortcut.parseString failed parsing '" ~ m.modifiers ~ "' with the following reason:"); + logprint(LOG_ALERT, "\t" ~ res); + m.modifiers = []; + m.keys = []; + } else { + m.modifiers = res[0]; + m.keys = res[1]; + } + } + + return m; + }, + + parseString: func(s) { + if (size(s) == 0) { + return "shortcut string is empty"; + } + + var found = []; + var modifiers = []; + var input = split("+", s); + foreach (var key; input) { + if (string.match(key, "<*>")) { + append(modifiers, substr(key, 1, size(key) - 2)); + } else { + append(found, key); + } + } + + var newmodifiers = []; + foreach (var mod; modifiers) { + if (ModifierKeys[mod] == nil) { + return "Unknown modifier key '" ~ mod ~ "' !"; + } else { + append(newmodifiers, ModifierKeys[mod]); + } + } + + var newfound = []; + foreach (var key; found) { + if (PrintableKeys[key] == nil) { + if (FunctionKeys[key] == nil) { + return "Unknown key '" ~ key ~ "' !"; + } else { + append(newfound, FunctionKeys[key]); + } + } else { + append(newfound, PrintableKeys[key]); + } + } + + return [newmodifiers, newfound]; + }, + + match: func(keys, shift=0, ctrl=0, alt=0, meta=0) { + if (!me.modifiers and !me.keys) { + return 0; + } + var match = 1; + match &= veccontains(me.modifiers, ModifierKeys["Shift"]) == shift; + match &= veccontains(me.modifiers, ModifierKeys["Ctrl"]) == ctrl; + match &= veccontains(me.modifiers, ModifierKeys["Alt"]) == alt; + match &= veccontains(me.modifiers, ModifierKeys["Meta"]) == meta; + match &= size(keys) == size(me.keys); + if (!match) { + return 0; + } + for (var i = 0; i < size(keys); i += 1) { + match &= keys[i] == me.keys[i]; + } + return match; + }, + + repr: func { + if (!me.modifiers and !me.keys) { + return ""; + } + var names = []; + debug.dump(me.modifiers); + foreach (var mod; me.modifiers) { + append(names, findKeyName(mod)); + } + foreach (var key; me.keys) { + append(names, findKeyName(key)); + } + return string.join(" + ", names); + }, + + equals: func(other) { + return me.modifiers == other.modifiers and me.keys == other.keys; + }, +}; + +var findKeyName = func(key) { + foreach (var mod; keys(ModifierKeys)) { + if (ModifierKeys[mod] == key) { + return mod; + } + } + foreach (var printable; keys(PrintableKeys)) { + if (PrintableKeys[printable] == key) { + return printable; + } + } + foreach (var function; keys(FunctionKeys)) { + if (FunctionKeys[function] == key) { + return function; + } + } + return nil; +}; + +var namesToKeys = func(strings...) { + var res = []; + foreach (var s; strings) { + var key = ModifierKeys[s] or PrintableKeys[s] or FunctionKeys[s]; + if (!key) { + logprint(LOG_ALERT, "keyboard.namesToKeys: unknown key '" ~ key ~ "' - skipping !"); + continue; + } + append(res, key); + } + return res; +}; + +var Binding = { + new: func(shortcut, f) { + var m = { + parents: [Binding], + f: f, + shortcut: shortcut, + }; + return m; + }, + + fire: func(e) { + if (isfunc(me.f)) { + me.f(e); + } + } +}; + +