#ifndef NALL_INPUT_HPP #define NALL_INPUT_HPP #include #include #include #include #include namespace nall { struct Keyboard; Keyboard& keyboard(unsigned = 0); static const char KeyboardScancodeName[][64] = { "Escape", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "PrintScreen", "ScrollLock", "Pause", "Tilde", "Num1", "Num2", "Num3", "Num4", "Num5", "Num6", "Num7", "Num8", "Num9", "Num0", "Dash", "Equal", "Backspace", "Insert", "Delete", "Home", "End", "PageUp", "PageDown", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "LeftBracket", "RightBracket", "Backslash", "Semicolon", "Apostrophe", "Comma", "Period", "Slash", "Keypad1", "Keypad2", "Keypad3", "Keypad4", "Keypad5", "Keypad6", "Keypad7", "Keypad8", "Keypad9", "Keypad0", "Point", "Enter", "Add", "Subtract", "Multiply", "Divide", "NumLock", "CapsLock", "Up", "Down", "Left", "Right", "Tab", "Return", "Spacebar", "Menu", "Shift", "Control", "Alt", "Super", }; struct Keyboard { const unsigned ID; enum { Base = 1 }; enum { Count = 8, Size = 128 }; enum Scancode { Escape, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PrintScreen, ScrollLock, Pause, Tilde, Num1, Num2, Num3, Num4, Num5, Num6, Num7, Num8, Num9, Num0, Dash, Equal, Backspace, Insert, Delete, Home, End, PageUp, PageDown, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, LeftBracket, RightBracket, Backslash, Semicolon, Apostrophe, Comma, Period, Slash, Keypad1, Keypad2, Keypad3, Keypad4, Keypad5, Keypad6, Keypad7, Keypad8, Keypad9, Keypad0, Point, Enter, Add, Subtract, Multiply, Divide, NumLock, CapsLock, Up, Down, Left, Right, Tab, Return, Spacebar, Menu, Shift, Control, Alt, Super, Limit, }; static signed numberDecode(uint16_t scancode) { for(unsigned i = 0; i < Count; i++) { if(keyboard(i).belongsTo(scancode)) return i; } return -1; } static signed keyDecode(uint16_t scancode) { for(unsigned i = 0; i < Count; i++) { if(keyboard(i).isKey(scancode)) return scancode - keyboard(i).key(Escape); } return -1; } static signed modifierDecode(uint16_t scancode) { for(unsigned i = 0; i < Count; i++) { if(keyboard(i).isModifier(scancode)) return scancode - keyboard(i).key(Shift); } return -1; } static bool isAnyKey(uint16_t scancode) { for(unsigned i = 0; i < Count; i++) { if(keyboard(i).isKey(scancode)) return true; } return false; } static bool isAnyModifier(uint16_t scancode) { for(unsigned i = 0; i < Count; i++) { if(keyboard(i).isModifier(scancode)) return true; } return false; } static uint16_t decode(const char *name) { string s(name); if(!strbegin(name, "KB")) return 0; s.ltrim("KB"); unsigned id = strunsigned(s); auto pos = strpos(s, "::"); if(!pos) return 0; s = substr(s, pos() + 2); for(unsigned i = 0; i < Limit; i++) { if(s == KeyboardScancodeName[i]) return Base + Size * id + i; } return 0; } string encode(uint16_t code) const { unsigned index = 0; for(unsigned i = 0; i < Count; i++) { if(code >= Base + Size * i && code < Base + Size * (i + 1)) { index = code - (Base + Size * i); break; } } return string() << "KB" << ID << "::" << KeyboardScancodeName[index]; } uint16_t operator[](Scancode code) const { return Base + ID * Size + code; } uint16_t key(unsigned id) const { return Base + Size * ID + id; } bool isKey(unsigned id) const { return id >= key(Escape) && id <= key(Menu); } bool isModifier(unsigned id) const { return id >= key(Shift) && id <= key(Super); } bool belongsTo(uint16_t scancode) const { return isKey(scancode) || isModifier(scancode); } Keyboard(unsigned ID_) : ID(ID_) {} }; inline Keyboard& keyboard(unsigned id) { static Keyboard kb0(0), kb1(1), kb2(2), kb3(3), kb4(4), kb5(5), kb6(6), kb7(7); switch(id) { default: case 0: return kb0; case 1: return kb1; case 2: return kb2; case 3: return kb3; case 4: return kb4; case 5: return kb5; case 6: return kb6; case 7: return kb7; } } static const char MouseScancodeName[][64] = { "Xaxis", "Yaxis", "Zaxis", "Button0", "Button1", "Button2", "Button3", "Button4", "Button5", "Button6", "Button7", }; struct Mouse; Mouse& mouse(unsigned = 0); struct Mouse { const unsigned ID; enum { Base = Keyboard::Base + Keyboard::Size * Keyboard::Count }; enum { Count = 8, Size = 16 }; enum { Axes = 3, Buttons = 8 }; enum Scancode { Xaxis, Yaxis, Zaxis, Button0, Button1, Button2, Button3, Button4, Button5, Button6, Button7, Limit, }; static signed numberDecode(uint16_t scancode) { for(unsigned i = 0; i < Count; i++) { if(mouse(i).belongsTo(scancode)) return i; } return -1; } static signed axisDecode(uint16_t scancode) { for(unsigned i = 0; i < Count; i++) { if(mouse(i).isAxis(scancode)) return scancode - mouse(i).axis(0); } return -1; } static signed buttonDecode(uint16_t scancode) { for(unsigned i = 0; i < Count; i++) { if(mouse(i).isButton(scancode)) return scancode - mouse(i).button(0); } return -1; } static bool isAnyAxis(uint16_t scancode) { for(unsigned i = 0; i < Count; i++) { if(mouse(i).isAxis(scancode)) return true; } return false; } static bool isAnyButton(uint16_t scancode) { for(unsigned i = 0; i < Count; i++) { if(mouse(i).isButton(scancode)) return true; } return false; } static uint16_t decode(const char *name) { string s(name); if(!strbegin(name, "MS")) return 0; s.ltrim("MS"); unsigned id = strunsigned(s); auto pos = strpos(s, "::"); if(!pos) return 0; s = substr(s, pos() + 2); for(unsigned i = 0; i < Limit; i++) { if(s == MouseScancodeName[i]) return Base + Size * id + i; } return 0; } string encode(uint16_t code) const { unsigned index = 0; for(unsigned i = 0; i < Count; i++) { if(code >= Base + Size * i && code < Base + Size * (i + 1)) { index = code - (Base + Size * i); break; } } return string() << "MS" << ID << "::" << MouseScancodeName[index]; } uint16_t operator[](Scancode code) const { return Base + ID * Size + code; } uint16_t axis(unsigned id) const { return Base + Size * ID + Xaxis + id; } uint16_t button(unsigned id) const { return Base + Size * ID + Button0 + id; } bool isAxis(unsigned id) const { return id >= axis(0) && id <= axis(2); } bool isButton(unsigned id) const { return id >= button(0) && id <= button(7); } bool belongsTo(uint16_t scancode) const { return isAxis(scancode) || isButton(scancode); } Mouse(unsigned ID_) : ID(ID_) {} }; inline Mouse& mouse(unsigned id) { static Mouse ms0(0), ms1(1), ms2(2), ms3(3), ms4(4), ms5(5), ms6(6), ms7(7); switch(id) { default: case 0: return ms0; case 1: return ms1; case 2: return ms2; case 3: return ms3; case 4: return ms4; case 5: return ms5; case 6: return ms6; case 7: return ms7; } } static const char JoypadScancodeName[][64] = { "Hat0", "Hat1", "Hat2", "Hat3", "Hat4", "Hat5", "Hat6", "Hat7", "Axis0", "Axis1", "Axis2", "Axis3", "Axis4", "Axis5", "Axis6", "Axis7", "Axis8", "Axis9", "Axis10", "Axis11", "Axis12", "Axis13", "Axis14", "Axis15", "Button0", "Button1", "Button2", "Button3", "Button4", "Button5", "Button6", "Button7", "Button8", "Button9", "Button10", "Button11", "Button12", "Button13", "Button14", "Button15", "Button16", "Button17", "Button18", "Button19", "Button20", "Button21", "Button22", "Button23", "Button24", "Button25", "Button26", "Button27", "Button28", "Button29", "Button30", "Button31", }; struct Joypad; Joypad& joypad(unsigned = 0); struct Joypad { const unsigned ID; enum { Base = Mouse::Base + Mouse::Size * Mouse::Count }; enum { Count = 8, Size = 64 }; enum { Hats = 8, Axes = 16, Buttons = 32 }; enum Scancode { Hat0, Hat1, Hat2, Hat3, Hat4, Hat5, Hat6, Hat7, Axis0, Axis1, Axis2, Axis3, Axis4, Axis5, Axis6, Axis7, Axis8, Axis9, Axis10, Axis11, Axis12, Axis13, Axis14, Axis15, Button0, Button1, Button2, Button3, Button4, Button5, Button6, Button7, Button8, Button9, Button10, Button11, Button12, Button13, Button14, Button15, Button16, Button17, Button18, Button19, Button20, Button21, Button22, Button23, Button24, Button25, Button26, Button27, Button28, Button29, Button30, Button31, Limit, }; enum Hat { HatCenter = 0, HatUp = 1, HatRight = 2, HatDown = 4, HatLeft = 8 }; static signed numberDecode(uint16_t scancode) { for(unsigned i = 0; i < Count; i++) { if(joypad(i).belongsTo(scancode)) return i; } return -1; } static signed hatDecode(uint16_t scancode) { for(unsigned i = 0; i < Count; i++) { if(joypad(i).isHat(scancode)) return scancode - joypad(i).hat(0); } return -1; } static signed axisDecode(uint16_t scancode) { for(unsigned i = 0; i < Count; i++) { if(joypad(i).isAxis(scancode)) return scancode - joypad(i).axis(0); } return -1; } static signed buttonDecode(uint16_t scancode) { for(unsigned i = 0; i < Count; i++) { if(joypad(i).isButton(scancode)) return scancode - joypad(i).button(0); } return -1; } static bool isAnyHat(uint16_t scancode) { for(unsigned i = 0; i < Count; i++) { if(joypad(i).isHat(scancode)) return true; } return false; } static bool isAnyAxis(uint16_t scancode) { for(unsigned i = 0; i < Count; i++) { if(joypad(i).isAxis(scancode)) return true; } return false; } static bool isAnyButton(uint16_t scancode) { for(unsigned i = 0; i < Count; i++) { if(joypad(i).isButton(scancode)) return true; } return false; } static uint16_t decode(const char *name) { string s(name); if(!strbegin(name, "JP")) return 0; s.ltrim("JP"); unsigned id = strunsigned(s); auto pos = strpos(s, "::"); if(!pos) return 0; s = substr(s, pos() + 2); for(unsigned i = 0; i < Limit; i++) { if(s == JoypadScancodeName[i]) return Base + Size * id + i; } return 0; } string encode(uint16_t code) const { unsigned index = 0; for(unsigned i = 0; i < Count; i++) { if(code >= Base + Size * i && code < Base + Size * (i + 1)) { index = code - (Base + Size * i); } } return string() << "JP" << ID << "::" << JoypadScancodeName[index]; } uint16_t operator[](Scancode code) const { return Base + ID * Size + code; } uint16_t hat(unsigned id) const { return Base + Size * ID + Hat0 + id; } uint16_t axis(unsigned id) const { return Base + Size * ID + Axis0 + id; } uint16_t button(unsigned id) const { return Base + Size * ID + Button0 + id; } bool isHat(unsigned id) const { return id >= hat(0) && id <= hat(7); } bool isAxis(unsigned id) const { return id >= axis(0) && id <= axis(15); } bool isButton(unsigned id) const { return id >= button(0) && id <= button(31); } bool belongsTo(uint16_t scancode) const { return isHat(scancode) || isAxis(scancode) || isButton(scancode); } Joypad(unsigned ID_) : ID(ID_) {} }; inline Joypad& joypad(unsigned id) { static Joypad jp0(0), jp1(1), jp2(2), jp3(3), jp4(4), jp5(5), jp6(6), jp7(7); switch(id) { default: case 0: return jp0; case 1: return jp1; case 2: return jp2; case 3: return jp3; case 4: return jp4; case 5: return jp5; case 6: return jp6; case 7: return jp7; } } struct Scancode { enum { None = 0, Limit = Joypad::Base + Joypad::Size * Joypad::Count }; static uint16_t decode(const char *name) { uint16_t code; code = Keyboard::decode(name); if(code) return code; code = Mouse::decode(name); if(code) return code; code = Joypad::decode(name); if(code) return code; return None; } static string encode(uint16_t code) { for(unsigned i = 0; i < Keyboard::Count; i++) { if(keyboard(i).belongsTo(code)) return keyboard(i).encode(code); } for(unsigned i = 0; i < Mouse::Count; i++) { if(mouse(i).belongsTo(code)) return mouse(i).encode(code); } for(unsigned i = 0; i < Joypad::Count; i++) { if(joypad(i).belongsTo(code)) return joypad(i).encode(code); } return "None"; } }; } #endif