From 1560bae757889597011f3652da6600dfc9eb04c6 Mon Sep 17 00:00:00 2001 From: Vodkannelle Date: Sat, 8 May 2021 10:40:24 +0200 Subject: [PATCH] added an input lib to deps --- deps/boipushy.lua | 292 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 292 insertions(+) create mode 100644 deps/boipushy.lua diff --git a/deps/boipushy.lua b/deps/boipushy.lua new file mode 100644 index 0000000..f792681 --- /dev/null +++ b/deps/boipushy.lua @@ -0,0 +1,292 @@ +--[[ +Copyright (c) 2018 SSYGEN + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +]]-- + +local input_path = (...):match('(.-)[^%.]+$') .. '.' +local Input = {} +Input.__index = Input + +Input.all_keys = { + " ", "return", "escape", "backspace", "tab", "space", "!", "\"", "#", "$", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", + "5", "6", "7", "8", "9", ":", ";", "<", "=", ">", "?", "@", "[", "\\", "]", "^", "", "`", "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", "capslock", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "printscreen", + "scrolllock", "pause", "insert", "home", "pageup", "delete", "end", "pagedown", "right", "left", "down", "up", "numlock", "kp/", "kp*", "kp-", "kp+", "kpenter", + "kp0", "kp1", "kp2", "kp3", "kp4", "kp5", "kp6", "kp7", "kp8", "kp9", "kp.", "kp,", "kp=", "application", "power", "f13", "f14", "f15", "f16", "f17", "f18", "f19", + "f20", "f21", "f22", "f23", "f24", "execute", "help", "menu", "select", "stop", "again", "undo", "cut", "copy", "paste", "find", "mute", "volumeup", "volumedown", + "alterase", "sysreq", "cancel", "clear", "prior", "return2", "separator", "out", "oper", "clearagain", "thsousandsseparator", "decimalseparator", "currencyunit", + "currencysubunit", "lctrl", "lshift", "lalt", "lgui", "rctrl", "rshift", "ralt", "rgui", "mode", "audionext", "audioprev", "audiostop", "audioplay", "audiomute", + "mediaselect", "brightnessdown", "brightnessup", "displayswitch", "kbdillumtoggle", "kbdillumdown", "kbdillumup", "eject", "sleep", "mouse1", "mouse2", "mouse3", + "mouse4", "mouse5", "wheelup", "wheeldown", "fdown", "fup", "fleft", "fright", "back", "guide", "start", "leftstick", "rightstick", "l1", "r1", "l2", "r2", "dpup", + "dpdown", "dpleft", "dpright", "leftx", "lefty", "rightx", "righty", +} + +function Input.new() + local self = {} + + self.prev_state = {} + self.state = {} + self.binds = {} + self.functions = {} + self.repeat_state = {} + self.sequences = {} + + -- Gamepads... currently only supports 1 gamepad, adding support for more is not that hard, just lazy. + self.joysticks = love.joystick.getJoysticks() + + -- Register callbacks automagically + local callbacks = {'keypressed', 'keyreleased', 'mousepressed', 'mousereleased', 'gamepadpressed', 'gamepadreleased', 'gamepadaxis', 'wheelmoved', 'update'} + local old_functions = {} + local empty_function = function() end + for _, f in ipairs(callbacks) do + old_functions[f] = love[f] or empty_function + love[f] = function(...) + old_functions[f](...) + self[f](self, ...) + end + end + + return setmetatable(self, Input) +end + +function Input:bind(key, action) + if type(action) == 'function' then self.functions[key] = action; return end + if not self.binds[action] then self.binds[action] = {} end + table.insert(self.binds[action], key) +end + +function Input:pressed(action) + if action then + for _, key in ipairs(self.binds[action]) do + if self.state[key] and not self.prev_state[key] then + return true + end + end + + else + for _, key in ipairs(Input.all_keys) do + if self.state[key] and not self.prev_state[key] then + if self.functions[key] then + self.functions[key]() + end + end + end + end +end + +function Input:released(action) + for _, key in ipairs(self.binds[action]) do + if self.prev_state[key] and not self.state[key] then + return true + end + end +end + +function Input:sequence(...) + local sequence = {...} + if #sequence <= 1 then error("Use :pressed instead if you only need to check 1 action") end + if type(sequence[#sequence]) ~= 'string' then error("The last argument must be an action") end + if #sequence % 2 == 0 then error("The number of arguments passed in must be odd") end + + local sequence_key = '' + for _, seq in ipairs(sequence) do sequence_key = sequence_key .. tostring(seq) end + + if not self.sequences[sequence_key] then + self.sequences[sequence_key] = {sequence = sequence, current_index = 1} + + else + if self.sequences[sequence_key].current_index == 1 then + local action = self.sequences[sequence_key].sequence[self.sequences[sequence_key].current_index] + for _, key in ipairs(self.binds[action]) do + if self.state[key] and not self.prev_state[key] then + self.sequences[sequence_key].last_pressed = love.timer.getTime() + self.sequences[sequence_key].current_index = self.sequences[sequence_key].current_index + 1 + end + end + + else + local delay = self.sequences[sequence_key].sequence[self.sequences[sequence_key].current_index] + local action = self.sequences[sequence_key].sequence[self.sequences[sequence_key].current_index + 1] + + if (love.timer.getTime() - self.sequences[sequence_key].last_pressed) > delay then self.sequences[sequence_key] = nil end + for _, key in ipairs(self.binds[action]) do + if self.state[key] and not self.prev_state[key] then + if (love.timer.getTime() - self.sequences[sequence_key].last_pressed) <= delay then + if self.sequences[sequence_key].current_index + 1 == #self.sequences[sequence_key].sequence then + self.sequences[sequence_key] = nil + return true + else + self.sequences[sequence_key].last_pressed = love.timer.getTime() + self.sequences[sequence_key].current_index = self.sequences[sequence_key].current_index + 2 + end + else + self.sequences[sequence_key] = nil + end + end + end + end + end +end + +local key_to_button = {mouse1 = '1', mouse2 = '2', mouse3 = '3', mouse4 = '4', mouse5 = '5'} +local gamepad_to_button = {fdown = 'a', fup = 'y', fleft = 'x', fright = 'b', back = 'back', guide = 'guide', start = 'start', + leftstick = 'leftstick', rightstick = 'rightstick', l1 = 'leftshoulder', r1 = 'rightshoulder', + dpup = 'dpup', dpdown = 'dpdown', dpleft = 'dpleft', dpright = 'dpright'} +local axis_to_button = {leftx = 'leftx', lefty = 'lefty', rightx = 'rightx', righty = 'righty', l2 = 'triggerleft', r2 = 'triggerright'} + +function Input:down(action, interval, delay) + if action and delay and interval then + for _, key in ipairs(self.binds[action]) do + if self.state[key] and not self.prev_state[key] then + self.repeat_state[key] = {pressed_time = love.timer.getTime(), delay = delay, interval = interval, delay_stage = true} + return true + elseif self.repeat_state[key] and self.repeat_state[key].pressed then + return true + end + end + + elseif action and interval and not delay then + for _, key in ipairs(self.binds[action]) do + if self.state[key] and not self.prev_state[key] then + self.repeat_state[key] = {pressed_time = love.timer.getTime(), delay = 0, interval = interval, delay_stage = false} + return true + elseif self.repeat_state[key] and self.repeat_state[key].pressed then + return true + end + end + + elseif action and not interval and not delay then + for _, key in ipairs(self.binds[action]) do + if (love.keyboard.isDown(key) or love.mouse.isDown(key_to_button[key] or 0)) then + return true + end + + -- Supports only 1 gamepad, add more later... + if self.joysticks[1] then + if axis_to_button[key] then + return self.state[key] + elseif gamepad_to_button[key] then + if self.joysticks[1]:isGamepadDown(gamepad_to_button[key]) then + return true + end + end + end + end + end +end + +function Input:unbind(key) + for action, keys in pairs(self.binds) do + for i = #keys, 1, -1 do + if key == self.binds[action][i] then + table.remove(self.binds[action], i) + end + end + end + if self.functions[key] then + self.functions[key] = nil + end +end + +function Input:unbindAll() + self.binds = {} + self.functions = {} +end + +local copy = function(t1) + local out = {} + for k, v in pairs(t1) do out[k] = v end + return out +end + +function Input:update() + self:pressed() + self.prev_state = copy(self.state) + self.state['wheelup'] = false + self.state['wheeldown'] = false + + for k, v in pairs(self.repeat_state) do + if v then + v.pressed = false + local t = love.timer.getTime() - v.pressed_time + if v.delay_stage then + if t > v.delay then + v.pressed = true + v.pressed_time = love.timer.getTime() + v.delay_stage = false + end + else + if t > v.interval then + v.pressed = true + v.pressed_time = love.timer.getTime() + end + end + end + end +end + +function Input:keypressed(key) + self.state[key] = true +end + +function Input:keyreleased(key) + self.state[key] = false + self.repeat_state[key] = false +end + +local button_to_key = { + [1] = 'mouse1', [2] = 'mouse2', [3] = 'mouse3', [4] = 'mouse4', [5] = 'mouse5', + ['l'] = 'mouse1', ['r'] = 'mouse2', ['m'] = 'mouse3', ['x1'] = 'mouse4', ['x2'] = 'mouse5' +} + +function Input:mousepressed(x, y, button) + self.state[button_to_key[button]] = true +end + +function Input:mousereleased(x, y, button) + self.state[button_to_key[button]] = false + self.repeat_state[button_to_key[button]] = false +end + +function Input:wheelmoved(x, y) + if y > 0 then self.state['wheelup'] = true + elseif y < 0 then self.state['wheeldown'] = true end +end + +local button_to_gamepad = {a = 'fdown', y = 'fup', x = 'fleft', b = 'fright', back = 'back', guide = 'guide', start = 'start', + leftstick = 'leftstick', rightstick = 'rightstick', leftshoulder = 'l1', rightshoulder = 'r1', + dpup = 'dpup', dpdown = 'dpdown', dpleft = 'dpleft', dpright = 'dpright'} + +function Input:gamepadpressed(joystick, button) + self.state[button_to_gamepad[button]] = true +end + +function Input:gamepadreleased(joystick, button) + self.state[button_to_gamepad[button]] = false + self.repeat_state[button_to_gamepad[button]] = false +end + +local button_to_axis = {leftx = 'leftx', lefty = 'lefty', rightx = 'rightx', righty = 'righty', triggerleft = 'l2', triggerright = 'r2'} + +function Input:gamepadaxis(joystick, axis, newvalue) + self.state[button_to_axis[axis]] = newvalue +end + +return setmetatable({}, {__call = function(_, ...) return Input.new(...) end})