diff --git a/singe/Framework.singe b/singe/Framework.singe index 810e52b10..deb1e0f4e 100644 --- a/singe/Framework.singe +++ b/singe/Framework.singe @@ -23,287 +23,332 @@ -- Singe 2.xx Features + +function deepcopy(orig) + local orig_type = type(orig) + local copy + if orig_type == 'table' then + copy = {} + for orig_key, orig_value in next, orig, nil do + copy[deepcopy(orig_key)] = deepcopy(orig_value) + end + setmetatable(copy, deepcopy(getmetatable(orig))) + else -- number, string, boolean, etc + copy = orig + end + return copy +end + + SCANCODE = { - A = 4, - B = 5, - C = 6, - D = 7, - E = 8, - F = 9, - G = 10, - H = 11, - I = 12, - J = 13, - K = 14, - L = 15, - M = 16, - N = 17, - O = 18, - P = 19, - Q = 20, - R = 21, - S = 22, - T = 23, - U = 24, - V = 25, - W = 26, - X = 27, - Y = 28, - Z = 29, - MAIN_1 = 30, - MAIN_2 = 31, - MAIN_3 = 32, - MAIN_4 = 33, - MAIN_5 = 34, - MAIN_6 = 35, - MAIN_7 = 36, - MAIN_8 = 37, - MAIN_9 = 38, - MAIN_0 = 39, - RETURN = 40, - ESCAPE = 41, - BACKSPACE = 42, - TAB = 43, - SPACE = 44, - MINUS = 45, - EQUALS = 46, - LEFTBRACKET = 47, - RIGHTBRACKET = 48, - BACKSLASH = 49, - NONUSHASH = 50, - SEMICOLON = 51, - APOSTROPHE = 52, - GRAVE = 53, - COMMA = 54, - PERIOD = 55, - SLASH = 56, - CAPSLOCK = 57, - F1 = 58, - F2 = 59, - F3 = 60, - F4 = 61, - F5 = 62, - F6 = 63, - F7 = 64, - F8 = 65, - F9 = 66, - F10 = 67, - F11 = 68, - F12 = 69, - PRINTSCREEN = 70, - SCROLLLOCK = 71, - PAUSE = 72, - INSERT = 73, - HOME = 74, - PAGEUP = 75, - DELETE = 76, - END = 77, - PAGEDOWN = 78, - RIGHT = 79, - LEFT = 80, - DOWN = 81, - UP = 82, - NUMLOCKCLEAR = 83, - KP_DIVIDE = 84, - KP_MULTIPLY = 85, - KP_MINUS = 86, - KP_PLUS = 87, - KP_ENTER = 88, - KP_1 = 89, - KP_2 = 90, - KP_3 = 91, - KP_4 = 92, - KP_5 = 93, - KP_6 = 94, - KP_7 = 95, - KP_8 = 96, - KP_9 = 97, - KP_0 = 98, - KP_PERIOD = 99, - NONUSBACKSLASH = 100, - APPLICATION = 101, - POWER = 102, - KP_EQUALS = 103, - F13 = 104, - F14 = 105, - F15 = 106, - F16 = 107, - F17 = 108, - F18 = 109, - F19 = 110, - F20 = 111, - F21 = 112, - F22 = 113, - F23 = 114, - F24 = 115, - EXECUTE = 116, - HELP = 117, - MENU = 118, - SELECT = 119, - STOP = 120, - AGAIN = 121, - UNDO = 122, - CUT = 123, - COPY = 124, - PASTE = 125, - FIND = 126, - MUTE = 127, - VOLUMEUP = 128, - VOLUMEDOWN = 129, - KP_COMMA = 133, - KP_EQUALSAS400 = 134, - INTERNATIONAL1 = 135, - INTERNATIONAL2 = 136, - INTERNATIONAL3 = 137, - INTERNATIONAL4 = 138, - INTERNATIONAL5 = 139, - INTERNATIONAL6 = 140, - INTERNATIONAL7 = 141, - INTERNATIONAL8 = 142, - INTERNATIONAL9 = 143, - LANG1 = 144, - LANG2 = 145, - LANG3 = 146, - LANG4 = 147, - LANG5 = 148, - LANG6 = 149, - LANG7 = 150, - LANG8 = 151, - LANG9 = 152, - ALTERASE = 153, - SYSREQ = 154, - CANCEL = 155, - CLEAR = 156, - PRIOR = 157, - RETURN2 = 158, - SEPARATOR = 159, - OUT = 160, - OPER = 161, - CLEARAGAIN = 162, - CRSEL = 163, - EXSEL = 164, - KP_00 = 176, - KP_000 = 177, - THOUSANDSSEPARATOR = 178, - DECIMALSEPARATOR = 179, - CURRENCYUNIT = 180, - CURRENCYSUBUNIT = 181, - KP_LEFTPAREN = 182, - KP_RIGHTPAREN = 183, - KP_LEFTBRACE = 184, - KP_RIGHTBRACE = 185, - KP_TAB = 186, - KP_BACKSPACE = 187, - KP_A = 188, - KP_B = 189, - KP_C = 190, - KP_D = 191, - KP_E = 192, - KP_F = 193, - KP_XOR = 194, - KP_POWER = 195, - KP_PERCENT = 196, - KP_LESS = 197, - KP_GREATER = 198, - KP_AMPERSAND = 199, - KP_DBLAMPERSAND = 200, - KP_VERTICALBAR = 201, - KP_DBLVERTICALBAR = 202, - KP_COLON = 203, - KP_HASH = 204, - KP_SPACE = 205, - KP_AT = 206, - KP_EXCLAM = 207, - KP_MEMSTORE = 208, - KP_MEMRECALL = 209, - KP_MEMCLEAR = 210, - KP_MEMADD = 211, - KP_MEMSUBTRACT = 212, - KP_MEMMULTIPLY = 213, - KP_MEMDIVIDE = 214, - KP_PLUSMINUS = 215, - KP_CLEAR = 216, - KP_CLEARENTRY = 217, - KP_BINARY = 218, - KP_OCTAL = 219, - KP_DECIMAL = 220, - KP_HEXADECIMAL = 221, - LCTRL = 224, - LSHIFT = 225, - LALT = 226, - LGUI = 227, - RCTRL = 228, - RSHIFT = 229, - RALT = 230, - RGUI = 231, - MODE = 257, - AUDIONEXT = 258, - AUDIOPREV = 259, - AUDIOSTOP = 260, - AUDIOPLAY = 261, - AUDIOMUTE = 262, - MEDIASELECT = 263, - WWW = 264, - MAIL = 265, - CALCULATOR = 266, - COMPUTER = 267, - AC_SEARCH = 268, - AC_HOME = 269, - AC_BACK = 270, - AC_FORWARD = 271, - AC_STOP = 272, - AC_REFRESH = 273, - AC_BOOKMARKS = 274, - BRIGHTNESSDOWN = 275, - BRIGHTNESSUP = 276, - DISPLAYSWITCH = 277, - KBDILLUMTOGGLE = 278, - KBDILLUMDOWN = 279, - KBDILLUMUP = 280, - EJECT = 281, - SLEEP = 282, - APP1 = 283, - APP2 = 284, - AUDIOREWIND = 285, - AUDIOFASTFORWARD = 286 + A = { name = "A", value = 4 }, + B = { name = "B", value = 5 }, + C = { name = "C", value = 6 }, + D = { name = "D", value = 7 }, + E = { name = "E", value = 8 }, + F = { name = "F", value = 9 }, + G = { name = "G", value = 10 }, + H = { name = "H", value = 11 }, + I = { name = "I", value = 12 }, + J = { name = "J", value = 13 }, + K = { name = "K", value = 14 }, + L = { name = "L", value = 15 }, + M = { name = "M", value = 16 }, + N = { name = "N", value = 17 }, + O = { name = "O", value = 18 }, + P = { name = "P", value = 19 }, + Q = { name = "Q", value = 20 }, + R = { name = "R", value = 21 }, + S = { name = "S", value = 22 }, + T = { name = "T", value = 23 }, + U = { name = "U", value = 24 }, + V = { name = "V", value = 25 }, + W = { name = "W", value = 26 }, + X = { name = "X", value = 27 }, + Y = { name = "Y", value = 28 }, + Z = { name = "Z", value = 29 }, + MAIN_1 = { name = "MAIN_1", value = 30 }, + MAIN_2 = { name = "MAIN_2", value = 31 }, + MAIN_3 = { name = "MAIN_3", value = 32 }, + MAIN_4 = { name = "MAIN_4", value = 33 }, + MAIN_5 = { name = "MAIN_5", value = 34 }, + MAIN_6 = { name = "MAIN_6", value = 35 }, + MAIN_7 = { name = "MAIN_7", value = 36 }, + MAIN_8 = { name = "MAIN_8", value = 37 }, + MAIN_9 = { name = "MAIN_9", value = 38 }, + MAIN_0 = { name = "MAIN_0", value = 39 }, + RETURN = { name = "RETURN", value = 40 }, + ESCAPE = { name = "ESCAPE", value = 41 }, + BACKSPACE = { name = "BACKSPACE", value = 42 }, + TAB = { name = "TAB", value = 43 }, + SPACE = { name = "SPACE", value = 44 }, + MINUS = { name = "MINUS", value = 45 }, + EQUALS = { name = "EQUALS", value = 46 }, + LEFTBRACKET = { name = "LEFTBRACKET", value = 47 }, + RIGHTBRACKET = { name = "RIGHTBRACKET", value = 48 }, + BACKSLASH = { name = "BACKSLASH", value = 49 }, + NONUSHASH = { name = "NONUSHASH", value = 50 }, + SEMICOLON = { name = "SEMICOLON", value = 51 }, + APOSTROPHE = { name = "APOSTROPHE", value = 52 }, + GRAVE = { name = "GRAVE", value = 53 }, + COMMA = { name = "COMMA", value = 54 }, + PERIOD = { name = "PERIOD", value = 55 }, + SLASH = { name = "SLASH", value = 56 }, + CAPSLOCK = { name = "CAPSLOCK", value = 57 }, + F1 = { name = "F1", value = 58 }, + F2 = { name = "F2", value = 59 }, + F3 = { name = "F3", value = 60 }, + F4 = { name = "F4", value = 61 }, + F5 = { name = "F5", value = 62 }, + F6 = { name = "F6", value = 63 }, + F7 = { name = "F7", value = 64 }, + F8 = { name = "F8", value = 65 }, + F9 = { name = "F9", value = 66 }, + F10 = { name = "F10", value = 67 }, + F11 = { name = "F11", value = 68 }, + F12 = { name = "F12", value = 69 }, + PRINTSCREEN = { name = "PRINTSCREEN", value = 70 }, + SCROLLLOCK = { name = "SCROLLLOCK", value = 71 }, + PAUSE = { name = "PAUSE", value = 72 }, + INSERT = { name = "INSERT", value = 73 }, + HOME = { name = "HOME", value = 74 }, + PAGEUP = { name = "PAGEUP", value = 75 }, + DELETE = { name = "DELETE", value = 76 }, + END = { name = "END", value = 77 }, + PAGEDOWN = { name = "PAGEDOWN", value = 78 }, + RIGHT = { name = "RIGHT", value = 79 }, + LEFT = { name = "LEFT", value = 80 }, + DOWN = { name = "DOWN", value = 81 }, + UP = { name = "UP", value = 82 }, + NUMLOCKCLEAR = { name = "NUMLOCKCLEAR", value = 83 }, + KP_DIVIDE = { name = "KP_DIVIDE", value = 84 }, + KP_MULTIPLY = { name = "KP_MULTIPLY", value = 85 }, + KP_MINUS = { name = "KP_MINUS", value = 86 }, + KP_PLUS = { name = "KP_PLUS", value = 87 }, + KP_ENTER = { name = "KP_ENTER", value = 88 }, + KP_1 = { name = "KP_1", value = 89 }, + KP_2 = { name = "KP_2", value = 90 }, + KP_3 = { name = "KP_3", value = 91 }, + KP_4 = { name = "KP_4", value = 92 }, + KP_5 = { name = "KP_5", value = 93 }, + KP_6 = { name = "KP_6", value = 94 }, + KP_7 = { name = "KP_7", value = 95 }, + KP_8 = { name = "KP_8", value = 96 }, + KP_9 = { name = "KP_9", value = 97 }, + KP_0 = { name = "KP_0", value = 98 }, + KP_PERIOD = { name = "KP_PERIOD", value = 99 }, + NONUSBACKSLASH = { name = "NONUSBACKSLASH", value = 100 }, + APPLICATION = { name = "APPLICATION", value = 101 }, + POWER = { name = "POWER", value = 102 }, + KP_EQUALS = { name = "KP_EQUALS", value = 103 }, + F13 = { name = "F13", value = 104 }, + F14 = { name = "F14", value = 105 }, + F15 = { name = "F15", value = 106 }, + F16 = { name = "F16", value = 107 }, + F17 = { name = "F17", value = 108 }, + F18 = { name = "F18", value = 109 }, + F19 = { name = "F19", value = 110 }, + F20 = { name = "F20", value = 111 }, + F21 = { name = "F21", value = 112 }, + F22 = { name = "F22", value = 113 }, + F23 = { name = "F23", value = 114 }, + F24 = { name = "F24", value = 115 }, + EXECUTE = { name = "EXECUTE", value = 116 }, + HELP = { name = "HELP", value = 117 }, + MENU = { name = "MENU", value = 118 }, + SELECT = { name = "SELECT", value = 119 }, + STOP = { name = "STOP", value = 120 }, + AGAIN = { name = "AGAIN", value = 121 }, + UNDO = { name = "UNDO", value = 122 }, + CUT = { name = "CUT", value = 123 }, + COPY = { name = "COPY", value = 124 }, + PASTE = { name = "PASTE", value = 125 }, + FIND = { name = "FIND", value = 126 }, + MUTE = { name = "MUTE", value = 127 }, + VOLUMEUP = { name = "VOLUMEUP", value = 128 }, + VOLUMEDOWN = { name = "VOLUMEDOWN", value = 129 }, + KP_COMMA = { name = "KP_COMMA", value = 133 }, + KP_EQUALSAS400 = { name = "KP_EQUALSAS400", value = 134 }, + INTERNATIONAL1 = { name = "INTERNATIONAL1", value = 135 }, + INTERNATIONAL2 = { name = "INTERNATIONAL2", value = 136 }, + INTERNATIONAL3 = { name = "INTERNATIONAL3", value = 137 }, + INTERNATIONAL4 = { name = "INTERNATIONAL4", value = 138 }, + INTERNATIONAL5 = { name = "INTERNATIONAL5", value = 139 }, + INTERNATIONAL6 = { name = "INTERNATIONAL6", value = 140 }, + INTERNATIONAL7 = { name = "INTERNATIONAL7", value = 141 }, + INTERNATIONAL8 = { name = "INTERNATIONAL8", value = 142 }, + INTERNATIONAL9 = { name = "INTERNATIONAL9", value = 143 }, + LANG1 = { name = "LANG1", value = 144 }, + LANG2 = { name = "LANG2", value = 145 }, + LANG3 = { name = "LANG3", value = 146 }, + LANG4 = { name = "LANG4", value = 147 }, + LANG5 = { name = "LANG5", value = 148 }, + LANG6 = { name = "LANG6", value = 149 }, + LANG7 = { name = "LANG7", value = 150 }, + LANG8 = { name = "LANG8", value = 151 }, + LANG9 = { name = "LANG9", value = 152 }, + ALTERASE = { name = "ALTERASE", value = 153 }, + SYSREQ = { name = "SYSREQ", value = 154 }, + CANCEL = { name = "CANCEL", value = 155 }, + CLEAR = { name = "CLEAR", value = 156 }, + PRIOR = { name = "PRIOR", value = 157 }, + RETURN2 = { name = "RETURN2", value = 158 }, + SEPARATOR = { name = "SEPARATOR", value = 159 }, + OUT = { name = "OUT", value = 160 }, + OPER = { name = "OPER", value = 161 }, + CLEARAGAIN = { name = "CLEARAGAIN", value = 162 }, + CRSEL = { name = "CRSEL", value = 163 }, + EXSEL = { name = "EXSEL", value = 164 }, + KP_00 = { name = "KP_00", value = 176 }, + KP_000 = { name = "KP_000", value = 177 }, + THOUSANDSSEPARATOR = { name = "THOUSANDSSEPARATOR", value = 178 }, + DECIMALSEPARATOR = { name = "DECIMALSEPARATOR", value = 179 }, + CURRENCYUNIT = { name = "CURRENCYUNIT", value = 180 }, + CURRENCYSUBUNIT = { name = "CURRENCYSUBUNIT", value = 181 }, + KP_LEFTPAREN = { name = "KP_LEFTPAREN", value = 182 }, + KP_RIGHTPAREN = { name = "KP_RIGHTPAREN", value = 183 }, + KP_LEFTBRACE = { name = "KP_LEFTBRACE", value = 184 }, + KP_RIGHTBRACE = { name = "KP_RIGHTBRACE", value = 185 }, + KP_TAB = { name = "KP_TAB", value = 186 }, + KP_BACKSPACE = { name = "KP_BACKSPACE", value = 187 }, + KP_A = { name = "KP_A", value = 188 }, + KP_B = { name = "KP_B", value = 189 }, + KP_C = { name = "KP_C", value = 190 }, + KP_D = { name = "KP_D", value = 191 }, + KP_E = { name = "KP_E", value = 192 }, + KP_F = { name = "KP_F", value = 193 }, + KP_XOR = { name = "KP_XOR", value = 194 }, + KP_POWER = { name = "KP_POWER", value = 195 }, + KP_PERCENT = { name = "KP_PERCENT", value = 196 }, + KP_LESS = { name = "KP_LESS", value = 197 }, + KP_GREATER = { name = "KP_GREATER", value = 198 }, + KP_AMPERSAND = { name = "KP_AMPERSAND", value = 199 }, + KP_DBLAMPERSAND = { name = "KP_DBLAMPERSAND", value = 200 }, + KP_VERTICALBAR = { name = "KP_VERTICALBAR", value = 201 }, + KP_DBLVERTICALBAR = { name = "KP_DBLVERTICALBAR", value = 202 }, + KP_COLON = { name = "KP_COLON", value = 203 }, + KP_HASH = { name = "KP_HASH", value = 204 }, + KP_SPACE = { name = "KP_SPACE", value = 205 }, + KP_AT = { name = "KP_AT", value = 206 }, + KP_EXCLAM = { name = "KP_EXCLAM", value = 207 }, + KP_MEMSTORE = { name = "KP_MEMSTORE", value = 208 }, + KP_MEMRECALL = { name = "KP_MEMRECALL", value = 209 }, + KP_MEMCLEAR = { name = "KP_MEMCLEAR", value = 210 }, + KP_MEMADD = { name = "KP_MEMADD", value = 211 }, + KP_MEMSUBTRACT = { name = "KP_MEMSUBTRACT", value = 212 }, + KP_MEMMULTIPLY = { name = "KP_MEMMULTIPLY", value = 213 }, + KP_MEMDIVIDE = { name = "KP_MEMDIVIDE", value = 214 }, + KP_PLUSMINUS = { name = "KP_PLUSMINUS", value = 215 }, + KP_CLEAR = { name = "KP_CLEAR", value = 216 }, + KP_CLEARENTRY = { name = "KP_CLEARENTRY", value = 217 }, + KP_BINARY = { name = "KP_BINARY", value = 218 }, + KP_OCTAL = { name = "KP_OCTAL", value = 219 }, + KP_DECIMAL = { name = "KP_DECIMAL", value = 220 }, + KP_HEXADECIMAL = { name = "KP_HEXADECIMAL", value = 221 }, + LCTRL = { name = "LCTRL", value = 224 }, + LSHIFT = { name = "LSHIFT", value = 225 }, + LALT = { name = "LALT", value = 226 }, + LGUI = { name = "LGUI", value = 227 }, + RCTRL = { name = "RCTRL", value = 228 }, + RSHIFT = { name = "RSHIFT", value = 229 }, + RALT = { name = "RALT", value = 230 }, + RGUI = { name = "RGUI", value = 231 }, + MODE = { name = "MODE", value = 257 }, + AUDIONEXT = { name = "AUDIONEXT", value = 258 }, + AUDIOPREV = { name = "AUDIOPREV", value = 259 }, + AUDIOSTOP = { name = "AUDIOSTOP", value = 260 }, + AUDIOPLAY = { name = "AUDIOPLAY", value = 261 }, + AUDIOMUTE = { name = "AUDIOMUTE", value = 262 }, + MEDIASELECT = { name = "MEDIASELECT", value = 263 }, + WWW = { name = "WWW", value = 264 }, + MAIL = { name = "MAIL", value = 265 }, + CALCULATOR = { name = "CALCULATOR", value = 266 }, + COMPUTER = { name = "COMPUTER", value = 267 }, + AC_SEARCH = { name = "AC_SEARCH", value = 268 }, + AC_HOME = { name = "AC_HOME", value = 269 }, + AC_BACK = { name = "AC_BACK", value = 270 }, + AC_FORWARD = { name = "AC_FORWARD", value = 271 }, + AC_STOP = { name = "AC_STOP", value = 272 }, + AC_REFRESH = { name = "AC_REFRESH", value = 273 }, + AC_BOOKMARKS = { name = "AC_BOOKMARKS", value = 274 }, + BRIGHTNESSDOWN = { name = "BRIGHTNESSDOWN", value = 275 }, + BRIGHTNESSUP = { name = "BRIGHTNESSUP", value = 276 }, + DISPLAYSWITCH = { name = "DISPLAYSWITCH", value = 277 }, + KBDILLUMTOGGLE = { name = "KBDILLUMTOGGLE", value = 278 }, + KBDILLUMDOWN = { name = "KBDILLUMDOWN", value = 279 }, + KBDILLUMUP = { name = "KBDILLUMUP", value = 280 }, + EJECT = { name = "EJECT", value = 281 }, + SLEEP = { name = "SLEEP", value = 282 }, + APP1 = { name = "APP1", value = 283 }, + APP2 = { name = "APP2", value = 284 }, + AUDIOREWIND = { name = "AUDIOREWIND", value = 285 }, + AUDIOFASTFORWARD = { name = "AUDIOFASTFORWARD", value = 286 } } +SCANCODE_MIN = 4 -- Lowest value +SCANCODE_MAX = 286 -- Highest value, not the number of items in the table. + GAMEPAD_1 = { - AXIS_LEFT_X = -1, - AXIS_LEFT_Y = -2, - AXIS_RIGHT_X = -3, - AXIS_RIGHT_Y = -4, - AXIS_LEFT_TRIGGER = -5, - AXIS_RIGHT_TRIGGER = -6, - BUTTON_A = -7, - BUTTON_B = -8, - BUTTON_X = -9, - BUTTON_Y = -10, - BUTTON_BACK = -11, - BUTTON_GUIDE = -12, - BUTTON_START = -13, - BUTTON_LEFT_STICK = -14, - BUTTON_RIGHT_STICK = -15, - BUTTON_LEFT_BUMPER = -16, - BUTTON_RIGHT_BUMPER = -17, - DPAD_UP = -18, - DPAD_DOWN = -19, - DPAD_LEFT = -20, - DPAD_RIGHT = -21 + AXIS_LEFT_X = { name = "AXIS_LEFT_X", value = 500 }, + AXIS_LEFT_X_L = { name = "AXIS_LEFT_X_L", value = 501 }, + AXIS_LEFT_X_R = { name = "AXIS_LEFT_X_R", value = 502 }, + AXIS_LEFT_Y = { name = "AXIS_LEFT_Y", value = 503 }, + AXIS_LEFT_Y_U = { name = "AXIS_LEFT_Y_U", value = 504 }, + AXIS_LEFT_Y_D = { name = "AXIS_LEFT_Y_D", value = 505 }, + AXIS_RIGHT_X = { name = "AXIS_RIGHT_X", value = 506 }, + AXIS_RIGHT_X_L = { name = "AXIS_RIGHT_X_L", value = 507 }, + AXIS_RIGHT_X_R = { name = "AXIS_RIGHT_X_R", value = 508 }, + AXIS_RIGHT_Y = { name = "AXIS_RIGHT_Y", value = 509 }, + AXIS_RIGHT_Y_U = { name = "AXIS_RIGHT_Y_U", value = 510 }, + AXIS_RIGHT_Y_D = { name = "AXIS_RIGHT_Y_D", value = 511 }, + AXIS_LEFT_TRIGGER = { name = "AXIS_LEFT_TRIGGER", value = 512 }, + AXIS_LEFT_TRIGGER_N = { name = "AXIS_LEFT_TRIGGER_N", value = 513 }, + AXIS_LEFT_TRIGGER_P = { name = "AXIS_LEFT_TRIGGER_P", value = 514 }, + AXIS_RIGHT_TRIGGER = { name = "AXIS_RIGHT_TRIGGER", value = 515 }, + AXIS_RIGHT_TRIGGER_N = { name = "AXIS_RIGHT_TRIGGER_N", value = 516 }, + AXIS_RIGHT_TRIGGER_P = { name = "AXIS_RIGHT_TRIGGER_P", value = 517 }, + BUTTON_A = { name = "BUTTON_A", value = 518 }, + BUTTON_B = { name = "BUTTON_B", value = 519 }, + BUTTON_X = { name = "BUTTON_X", value = 520 }, + BUTTON_Y = { name = "BUTTON_Y", value = 521 }, + BUTTON_BACK = { name = "BUTTON_BACK", value = 522 }, + BUTTON_GUIDE = { name = "BUTTON_GUIDE", value = 523 }, + BUTTON_START = { name = "BUTTON_START", value = 524 }, + BUTTON_LEFT_STICK = { name = "BUTTON_LEFT_STICK", value = 525 }, + BUTTON_RIGHT_STICK = { name = "BUTTON_RIGHT_STICK", value = 526 }, + BUTTON_LEFT_BUMPER = { name = "BUTTON_LEFT_BUMPER", value = 527 }, + BUTTON_RIGHT_BUMPER = { name = "BUTTON_RIGHT_BUMPER", value = 528 }, + DPAD_UP = { name = "DPAD_UP", value = 529 }, + DPAD_DOWN = { name = "DPAD_DOWN", value = 530 }, + DPAD_LEFT = { name = "DPAD_LEFT", value = 531 }, + DPAD_RIGHT = { name = "DPAD_RIGHT", value = 532 } } -GAMEPAD_2 = {} -GAMEPAD_3 = {} -GAMEPAD_4 = {} +GAMEPAD_1_MIN = 500 -- Lowest value +GAMEPAD_1_MAX = 532 -- Highest value, not the number of items in the table. + +GAMEPAD_2 = deepcopy(GAMEPAD_1) +GAMEPAD_3 = deepcopy(GAMEPAD_1) +GAMEPAD_4 = deepcopy(GAMEPAD_1) + for key, value in pairs(GAMEPAD_1) do - GAMEPAD_2[key] = value + -21 - GAMEPAD_3[key] = value + -21 * 2 - GAMEPAD_4[key] = value + -21 * 3 + GAMEPAD_2[key].value = GAMEPAD_2[key].value + 100 + GAMEPAD_3[key].value = GAMEPAD_3[key].value + 200 + GAMEPAD_4[key].value = GAMEPAD_4[key].value + 300 end +GAMEPAD_2_MIN = GAMEPAD_1_MAX + 100 +GAMEPAD_2_MAX = GAMEPAD_1_MAX + 100 + +GAMEPAD_3_MIN = GAMEPAD_1_MAX + 200 +GAMEPAD_3_MAX = GAMEPAD_1_MAX + 200 + +GAMEPAD_4_MIN = GAMEPAD_1_MAX + 300 +GAMEPAD_4_MAX = GAMEPAD_1_MAX + 300 + SWITCH_BUTTON4 = 21 SWITCH_TILT = 22 -RESET_CPU = 23 +SWITCH_GRAB = 23 -- Singe 1.xx Features diff --git a/singe/controls.cfg b/singe/controls.cfg index 04501c83e..392f2f095 100644 --- a/singe/controls.cfg +++ b/singe/controls.cfg @@ -1,11 +1,11 @@ -- Default Mappings -DEAD_ZONE = 10 +DEAD_ZONE = 8000 -INPUT_UP = { SCANCODE.UP, SCANCODE.KP_8, GAMEPAD_1.AXIS_LEFT_Y, GAMEPAD_1.AXIS_RIGHT_Y, GAMEPAD_1.DPAD_UP } -INPUT_LEFT = { SCANCODE.LEFT, SCANCODE.KP_4, GAMEPAD_1.AXIS_LEFT_X, GAMEPAD_1.AXIS_RIGHT_X, GAMEPAD_1.DPAD_LEFT } -INPUT_DOWN = { SCANCODE.DOWN, SCANCODE.KP_2, GAMEPAD_1.AXIS_LEFT_Y, GAMEPAD_1.AXIS_RIGHT_Y, GAMEPAD_1.DPAD_DOWN } -INPUT_RIGHT = { SCANCODE.RIGHT, SCANCODE.KP_6, GAMEPAD_1.AXIS_LEFT_X, GAMEPAD_1.AXIS_RIGHT_X, GAMEPAD_1.DPAD_RIGHT } +INPUT_UP = { SCANCODE.UP, SCANCODE.KP_8, GAMEPAD_1.AXIS_LEFT_Y_U, GAMEPAD_1.AXIS_RIGHT_Y_U, GAMEPAD_1.DPAD_UP } +INPUT_LEFT = { SCANCODE.LEFT, SCANCODE.KP_4, GAMEPAD_1.AXIS_LEFT_X_L, GAMEPAD_1.AXIS_RIGHT_X_L, GAMEPAD_1.DPAD_LEFT } +INPUT_DOWN = { SCANCODE.DOWN, SCANCODE.KP_2, GAMEPAD_1.AXIS_LEFT_Y_D, GAMEPAD_1.AXIS_RIGHT_Y_D, GAMEPAD_1.DPAD_DOWN } +INPUT_RIGHT = { SCANCODE.RIGHT, SCANCODE.KP_6, GAMEPAD_1.AXIS_LEFT_X_R, GAMEPAD_1.AXIS_RIGHT_X_R, GAMEPAD_1.DPAD_RIGHT } INPUT_1P_COIN = { SCANCODE.MAIN_5, SCANCODE.C, GAMEPAD_1.BUTTON_LEFT_BUMPER } INPUT_2P_COIN = { SCANCODE.MAIN_6 } INPUT_1P_START = { SCANCODE.MAIN_1, GAMEPAD_1.BUTTON_RIGHT_BUMPER } @@ -25,3 +25,4 @@ INPUT_QUIT = { SCANCODE.ESCAPE, SCANCODE.Q } INPUT_PAUSE = { SCANCODE.P, GAMEPAD_1.BUTTON_START } INPUT_CONSOLE = { SCANCODE.GRAVE } INPUT_TILT = { SCANCODE.T } +INPUT_GRAB = { SCANCODE.G } diff --git a/singe/main.c b/singe/main.c index b1e2dbd08..9f5faa0bd 100644 --- a/singe/main.c +++ b/singe/main.c @@ -23,7 +23,7 @@ // -c -x 720 -y 480 -d data/maddog_dvd -v maddog_dvd/frame_maddog_dvd.txt maddog_dvd/maddog_dvd.singe // -c -x 640 -y 480 -v ActionMax/frame_SonicFury.txt ActionMax/SonicFury.singe // -x 640 -y 480 -d data/ActionMax ActionMax/BlueThunder.singe -// -v ActionMax/BlueThunder.mp4 test.singe +// -d data/ActionMax -v ActionMax/BlueThunder.mp4 test.singe #include @@ -79,7 +79,8 @@ void extractFile(char *filename, unsigned char *data, int32_t length) { __attribute__((noreturn)) void showUsage(char *name, char *message) { - int32_t result = 0; + char *temp = NULL; + int32_t result = 0; // 00000000011111111112222222222333333333344444444445555555555666666666677777777778 // 12345678901234567890123456789012345678901234567890123456789012345678901234567890 @@ -115,6 +116,14 @@ void showUsage(char *name, char *message) { utilSay(""); result = 1; } + + // Extract any missing support files. We do this here so they're not generated if launched from a front end. + if (!utilPathExists("Singe")) utilMkDirP("Singe", 0777); + temp = utilCreateString("Singe%cFramework.singe", utilGetPathSeparator()); + extractFile(temp, Framework_singe, Framework_singe_len); + free(temp); + temp = NULL; + #ifdef _WIN32 getchar(); #endif @@ -614,10 +623,6 @@ int main(int argc, char *argv[]) { // Finish our setup SDL_DisableScreenSaver(); - // Extract any missing support files. - if (!utilPathExists("Singe")) utilMkDirP("Singe", 0777); - extractFile("Singe/Framework.singe", Framework_singe, Framework_singe_len); - // Run Singe! singe(window, renderer); diff --git a/singe/singe.c b/singe/singe.c index 362c05a19..b73549fe6 100644 --- a/singe/singe.c +++ b/singe/singe.c @@ -127,6 +127,7 @@ enum { SWITCH_PAUSE, SWITCH_CONSOLE, SWITCH_TILT, + SWITCH_GRAB, SWITCH_MOUSE_SCROLL_UP, SWITCH_MOUSE_SCROLL_DOWN, SWITCH_MOUSE_DISCONNECT, @@ -175,41 +176,44 @@ int32_t _confSindenArgv[SINDEN_OPTION_COUNT]; // Other globals -static MouseT _mice[MAX_MICE]; -static lua_State *_luaContext = NULL; -static SDL_Color _colorForeground = { 255, 255, 255, 255 }; -static SDL_Color _colorBackground = { 0, 0, 0, 0 }; -static SDL_Surface *_overlay = NULL; -static SDL_Window *_window = NULL; -static SDL_Renderer *_renderer = NULL; -static SDL_Texture *_videoTexture = NULL; -static SDL_Surface *_consoleFontSurface = NULL; -static int32_t _controllerDeadZone = 0; -static int32_t _consoleFontWidth = 0; -static int32_t _consoleFontHeight = 0; -static int32_t _nextSpriteId = 0; -static int32_t _nextSoundId = 0; -static int32_t _nextFontId = 0; -static int32_t _effectsVolume = AUDIO_MAX_VOLUME; -static int32_t _keyboardMode = KEYBD_NORMAL; -static int32_t _frameFileHandle = -1; -static int32_t _videoHandle = -1; -static int32_t _fontQuality = 1; -static int32_t _mouseMode = MOUSE_SINGLE; -static int32_t _mouseCount = 0; -static double _overlayScaleX = 1; // Difference between overlay and video -static double _overlayScaleY = 1; // Difference between overlay and video -static bool _pauseState = false; // by RDG2010 -static bool _pauseEnabled = true; // by RDG2010 -static bool _refreshDisplay = false; -static bool _running = true; -static bool _discStopped = true; -static bool _mouseEnabled = true; -static bool _requestScreenShot = false; -static SpriteT *_spriteList = NULL; -static SoundT *_soundList = NULL; -static FontT *_fontList = NULL; -static FontT *_fontCurrent = NULL; +static MouseT _mice[MAX_MICE]; +static lua_State *_luaContext = NULL; +static SDL_Color _colorForeground = { 255, 255, 255, 255 }; +static SDL_Color _colorBackground = { 0, 0, 0, 0 }; +static SDL_Surface *_overlay = NULL; +static SDL_Window *_window = NULL; +static SDL_Renderer *_renderer = NULL; +static SDL_Texture *_videoTexture = NULL; +static SDL_Surface *_consoleFontSurface = NULL; +static SDL_GameController **_controllers = NULL; +static int32_t _controllerCount = 0; +static int32_t _controllerDeadZone = 0; +static int32_t _consoleFontWidth = 0; +static int32_t _consoleFontHeight = 0; +static int32_t _nextSpriteId = 0; +static int32_t _nextSoundId = 0; +static int32_t _nextFontId = 0; +static int32_t _effectsVolume = AUDIO_MAX_VOLUME; +static int32_t _keyboardMode = KEYBD_NORMAL; +static int32_t _frameFileHandle = -1; +static int32_t _videoHandle = -1; +static int32_t _fontQuality = 1; +static int32_t _mouseMode = MOUSE_SINGLE; +static int32_t _mouseCount = 0; +static double _overlayScaleX = 1; // Difference between overlay and video +static double _overlayScaleY = 1; // Difference between overlay and video +static bool _pauseState = false; // by RDG2010 +static bool _pauseEnabled = true; // by RDG2010 +static bool _refreshDisplay = false; +static bool _running = true; +static bool _discStopped = true; +static bool _mouseEnabled = true; +static bool _mouseGrabbed = false; +static bool _requestScreenShot = false; +static SpriteT *_spriteList = NULL; +static SoundT *_soundList = NULL; +static FontT *_fontList = NULL; +static FontT *_fontCurrent = NULL; // Index into _controlMappings array @@ -237,7 +241,8 @@ static FontT *_fontCurrent = NULL; // Added in Singe 2.x #define INPUT_ACTION_4 21 #define INPUT_TILT 22 -#define INPUT_COUNT 23 +#define INPUT_GRAB 23 +#define INPUT_COUNT 24 static MappingT _controlMappings[] = { @@ -263,7 +268,8 @@ static MappingT _controlMappings[] = { { "INPUT_PAUSE", 19, 0, NULL }, { "INPUT_CONSOLE", 20, 0, NULL }, { "INPUT_ACTION_4", 21, 0, NULL }, - { "INPUT_TILT", 22, 0, NULL } + { "INPUT_TILT", 22, 0, NULL }, + { "INPUT_GRAB", 23, 0, NULL } }; @@ -338,6 +344,8 @@ void luaDie(lua_State *L, char *method, char *fmt, ...); int32_t luaError(lua_State *L); void luaTrace(lua_State *L, char *method, char *fmt, ...); void processKey(bool down, int keysym, int32_t scancode); +void startControllers(void); +void stopControllers(void); void takeScreenshot(void); #ifdef DEBUG_TOOLS @@ -2130,24 +2138,40 @@ void processKey(bool down, int32_t keysym, int32_t scancode) { int32_t move; int32_t index; + utilSay("U:%d SY:%d SC:%d", down, keysym, scancode); + if (_keyboardMode == KEYBD_NORMAL) { // Mappable keys for (move=0; move 0) { for (index=0; index<_controlMappings[move].inputCount; index++) { + utilSay("Checking %s %d = %d", _controlMappings[move].name, _controlMappings[move].input[index], scancode); if (_controlMappings[move].input[index] == scancode) { if (!down) { - if ((move == SWITCH_PAUSE) && (_pauseEnabled)) { + if ((move == INPUT_PAUSE) && (_pauseEnabled)) { //***TODO*** g_game->toggle_game_pause(); } - if (move == SWITCH_QUIT) { + if (move == INPUT_GRAB) { + if (_mouseGrabbed) { + // Ungrab mouse + _mouseGrabbed = false; + SDL_SetWindowGrab(_window, SDL_FALSE); + SDL_ShowCursor(SDL_ENABLE); + } else { + // Grab mouse + _mouseGrabbed = true; + SDL_SetWindowGrab(_window, SDL_TRUE); + SDL_ShowCursor(SDL_DISABLE); + } + } + if (move == INPUT_QUIT) { _running = false; } - if (move == SWITCH_SCREENSHOT) { + if (move == INPUT_SCREENSHOT) { _requestScreenShot = true; } } - if (move != SWITCH_PAUSE) { + if (move != INPUT_PAUSE) { callLua(down ? "onInputPressed" : "onInputReleased", "ii", move, NOMOUSE); } } @@ -2225,7 +2249,7 @@ void singe(SDL_Window *window, SDL_Renderer *renderer) { if (utilFileExists(temp) && luaL_dofile(_luaContext, temp)) utilDie("%s", lua_tostring(_luaContext, -1)); free(temp); // Parse results - lua_getglobal(_luaContext, "DEAD_ZONEX"); + lua_getglobal(_luaContext, "DEAD_ZONE"); if (lua_isnumber(_luaContext, -1)) { _controllerDeadZone = (int32_t)lua_tonumber(_luaContext, -1); } @@ -2253,10 +2277,20 @@ void singe(SDL_Window *window, SDL_Renderer *renderer) { // Then load them for real. lua_getglobal(_luaContext, _controlMappings[x].name); if (lua_istable(_luaContext, -1)) { - lua_pushnil(_luaContext); y = 0; + lua_pushnil(_luaContext); while (lua_next(_luaContext, -2)) { - _controlMappings[x].input[y++] = (int32_t)lua_tonumber(_luaContext, -1); + if (lua_istable(_luaContext, -1)) { + lua_pushnil(_luaContext); + while (lua_next(_luaContext, -2)) { + if (lua_type(_luaContext, -2) == LUA_TSTRING) { + if (utilStricmp((char *)lua_tostring(_luaContext, -2), "value") == 0) { + _controlMappings[x].input[y++] = (int32_t)lua_tonumber(_luaContext, -1); + } + } + lua_pop(_luaContext, 1); + } + } lua_pop(_luaContext, 1); } } @@ -2475,9 +2509,14 @@ void singe(SDL_Window *window, SDL_Renderer *renderer) { _mice[x].y = (int32_t)(videoGetHeight(_videoHandle) * _overlayScaleY); //utilSay("***DEBUG*** Mouse %d: %s", x, _mice[x].name); } + + // Grab mouse + _mouseGrabbed = true; SDL_SetWindowGrab(_window, SDL_TRUE); SDL_ShowCursor(SDL_DISABLE); + // Controllers are started by the event loop + // Set volume _effectsVolume = (int32_t)((float)AUDIO_MAX_VOLUME * (float)_confVolumeNonVldp * (float)0.01); Mix_Volume(-1, _effectsVolume * 2); @@ -2505,9 +2544,53 @@ void singe(SDL_Window *window, SDL_Renderer *renderer) { // SDL Event Loop while (SDL_PollEvent(&event)) { switch (event.type) { + case SDL_CONTROLLERAXISMOTION: + // Is this in a range we care about? + if (abs(event.caxis.value) > _controllerDeadZone) { + // Determine which "scancode" to process - see Framework.singe + // Controller codes begin at 500 and increment in 100 + x = event.caxis.which * 100 + 500; + // The axis value lines up with the enumeration used by SDL * 3 + x += event.caxis.axis * 3; + // Fire the down/up event for the entire axis + processKey(true, 0, x); + processKey(false, 0, x); + // Finally we add the particular direction we're interested in + x += (event.caxis.value < 0) ? 1 : 2; + // Fire the down/up event for the axis direction + processKey(true, 0, x); + processKey(false, 0, x); + } + break; + + case SDL_CONTROLLERBUTTONUP: + // Determine which "scancode" to process - see Framework.singe + // Controller codes begin at 500 and increment in 100 + x = event.cbutton.which * 100 + 500; + // The button values line up with the enumeration used by SDL + 18 + x += event.cbutton.button + 18; + // Fire down event + processKey(false, 0, x); + break; + + case SDL_CONTROLLERBUTTONDOWN: + // Determine which "scancode" to process - see Framework.singe + // Controller codes begin at 500 and increment in 100 + x = event.cbutton.which * 100 + 500; + // The button values line up with the enumeration used by SDL + 18 + x += event.cbutton.button + 18; + // Fire down event + processKey(true, 0, x); + break; + + case SDL_CONTROLLERDEVICEADDED: + case SDL_CONTROLLERDEVICEREMOVED: + stopControllers(); + startControllers(); + break; + case SDL_KEYDOWN: processKey(true, event.key.keysym.sym, event.key.keysym.scancode); - //***TODO*** RDG used "g" to re-grab/re-scan for mice break; case SDL_KEYUP: @@ -2754,12 +2837,63 @@ void singe(SDL_Window *window, SDL_Renderer *renderer) { videoUnload(_videoHandle); } + // Stop controllers + stopControllers(); + // Stop mice SDL_ShowCursor(SDL_ENABLE); ManyMouse_Quit(); } +void startControllers(void) { + int32_t x; + + stopControllers(); + + // Clamp to the first four controllers found for now + _controllerCount = SDL_NumJoysticks(); + if (_controllerCount > 4) _controllerCount = 4; + + _controllers = (SDL_GameController **)malloc(sizeof(SDL_GameController *) * (size_t)_controllerCount); + for (x=0; x<_controllerCount; x++) { + _controllers[x] = NULL; + if (SDL_IsGameController(x)) { + _controllers[x] = SDL_GameControllerOpen(x); + /* + if (_controllers[x]) { + utilSay("Found #%d - %s\n", x, SDL_GameControllerName(_controllers[x])); + } else { + utilSay("Controller #%d not opened!\n", x); + } + */ + } else { + //utilSay("Joystick #%d is not a controller!\n", x); + } + } + + SDL_GameControllerEventState(SDL_ENABLE); +} + + +void stopControllers(void) { + int32_t x; + + if (_controllerCount > 0) { + for (x=0; x<_controllerCount; x++) { + if (_controllers[x] != NULL) { + SDL_GameControllerClose(_controllers[x]); + _controllers[x] = NULL; + } + } + free(_controllers); + _controllers = NULL; + _controllerCount = 0; + } + +} + + void takeScreenshot(void) { int32_t x = 0; char filename[1024]; diff --git a/singe/util.c b/singe/util.c index 125130a6e..c082e5317 100644 --- a/singe/util.c +++ b/singe/util.c @@ -37,6 +37,7 @@ static const int CONSOLE_LINES = 1000; #include #include #include +#include #include "util.h" @@ -377,6 +378,16 @@ void utilSay(char *fmt, ...) { +int utilStricmp(char *a, char *b) { + for (;; a++, b++) { + int d = tolower((unsigned char)*a) - tolower((unsigned char)*b); + if (d != 0 || !*a) { + return d; + } + } +} + + // Windows does not have strndup() so we implement our own. char *utilStrndup( const char *s1, size_t n) { char *copy = (char *)malloc(n + 1); diff --git a/singe/util.h b/singe/util.h index 4da5210db..b6e8f5cec 100644 --- a/singe/util.h +++ b/singe/util.h @@ -52,6 +52,7 @@ char *utilReadFile(char *filename, size_t *bytes); char *utilReadLine(char *haystack, size_t length, char **offset); void utilRedirectConsole(void); void utilSay(char *fmt, ...); +int utilStricmp(char *a, char *b); char *utilStrndup( const char *s1, size_t n); void utilTrace(char *fmt, ...); void utilTraceEnd(void);