1-- Copyright (C) 2011 Jared Krinke. 2-- 3-- This is free software; you can redistribute it and/or 4-- modify it under the terms of the GNU General Public License 5-- as published by the Free Software Foundation; either version 2 6-- of the License, or (at your option) any later version. 7-- 8-- This program is distributed in the hope that it will be useful, 9-- but WITHOUT ANY WARRANTY; without even the implied warranty of 10-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11-- GNU General Public License for more details. 12-- 13-- You should have received a copy of the GNU General Public License 14-- along with this program; if not, write to the Free Software 15-- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 17-- Raw events are string representations of unique raw events (e.g. "escape," "c") 18-- Logical events are application defined (e.g. "move up") 19require("Utility/List.lua") 20 21Input = { 22 joystickButtonNames = { }, 23 joystickAxisNames = { }, 24} 25 26local maxJoysticks = 4 27local maxJoystickButtons = 16 28local maxJoystickAxes = 4 29local joystickAxisThreshold = 0.4 30local j = 1 31 32while j <= maxJoysticks do 33 local buttons = { } 34 local b = 1 35 36 while b <= maxJoystickButtons do 37 local rawEvent = nil 38 39 if j == 1 then 40 rawEvent = "jb" .. b 41 else 42 rawEvent = "j" .. j .. "b" .. b 43 end 44 45 buttons[b] = rawEvent 46 b = b + 1 47 end 48 49 local axes = { } 50 local a = 0 51 52 while a <= maxJoystickAxes do 53 local axis = { } 54 55 if j == 1 then 56 axis[1] = "ja" .. a .. "+" 57 axis[-1] = "ja" .. a .. "-" 58 else 59 axis[1] = "j" .. j .. "a" .. a .. "+" 60 axis[-1] = "j" .. j .. "a" .. a .. "-" 61 end 62 63 axes[a] = axis 64 a = a + 1 65 end 66 67 Input.joystickButtonNames[j] = buttons 68 Input.joystickAxisNames[j] = axes 69 j = j + 1 70end 71 72local function unbind(self, rawEvent, logicalEvent) 73 local rawEvents = self.logicalToRaw[logicalEvent] 74 local acceptable = false 75 76 if not isNil(rawEvents) then 77 -- Make sure the binding can be removed (i.e. the existing binding is not the only binding to a necessary logical event) 78 local properties = self.logicalEvents[logicalEvent] 79 80 if isNil(properties) 81 or not isBoolean(properties.necessary) 82 or not properties.necessary 83 or rawEvents:getCount() > 1 84 then 85 rawEvents:remove(rawEvent) 86 acceptable = true 87 end 88 end 89 90 if acceptable then 91 self.rawToLogical[rawEvent] = nil 92 end 93 94 return acceptable 95end 96 97local function notify(self) 98 -- Notify all listeners that input bindings have been updated 99 self.listeners:forEach(function(handler) 100 handler() 101 end) 102end 103 104function Input.translateJoystickButtonToRawEvent(joystick, button) 105 local name = nil 106 107 if joystick <= maxJoysticks and button <= maxJoystickButtons then 108 name = Input.joystickButtonNames[joystick][button] 109 end 110 111 return name 112end 113 114function Input.translateJoystickAxisMoveToRawEvent(layer, joystick, axis, value) 115 -- Check for previous state tables 116 local joystickAxisPositions = layer.joystickAxisPositions 117 118 if not isTable(joystickAxisPositions) then 119 joystickAxisPositions = { } 120 layer.joystickAxisPositions = joystickAxisPositions 121 end 122 123 local joystickAxisPosition = joystickAxisPositions[joystick] 124 125 if not isTable(joystickAxisPosition) then 126 joystickAxisPosition = { } 127 layer.joystickAxisPositions[joystick] = joystickAxisPosition 128 end 129 130 -- Determine current position 131 local position = 0 132 133 if abs(value) >= joystickAxisThreshold then 134 if value > 0 then 135 position = 1 136 else 137 position = -1 138 end 139 end 140 141 -- Compare to previous position 142 local rawEventPressed = nil 143 local rawEventReleased = nil 144 local previousPosition = joystickAxisPosition[axis] 145 146 if isNil(previousPosition) then 147 previousPosition = 0 148 end 149 150 if position ~= previousPosition then 151 if previousPosition ~= 0 then 152 -- Previously set, but no longer set, so send a release event 153 rawEventReleased = Input.joystickAxisNames[joystick][axis][previousPosition] 154 end 155 156 if position ~= 0 then 157 -- Newly set; send a press event 158 rawEventPressed = Input.joystickAxisNames[joystick][axis][position] 159 end 160 end 161 162 joystickAxisPosition[axis] = position 163 164 return rawEventPressed, rawEventReleased 165end 166 167function Input.new(logicalEvents, defaultRawToLogical) 168 -- Mapping from a raw event to a logical event 169 local input = { } 170 171 function input.bind(self, rawEvent, logicalEvent) 172 -- Remove the old binding (if one exists) 173 local oldLogicalEvent = self.rawToLogical[rawEvent] 174 local acceptable = true 175 176 if not isNil(oldLogicalEvent) then 177 -- Check to make sure the existing binding can be removed 178 acceptable = unbind(self, rawEvent, oldLogicalEvent) 179 end 180 181 if acceptable then 182 -- Insert the new binding 183 self.rawToLogical[rawEvent] = logicalEvent 184 185 if not isNil(logicalEvent) then 186 -- Ensure a list of raw events is present 187 local rawEvents = self.logicalToRaw[logicalEvent] 188 189 if isNil(rawEvents) then 190 rawEvents = List.new() 191 self.logicalToRaw[logicalEvent] = rawEvents 192 end 193 194 rawEvents:add(rawEvent) 195 end 196 197 -- Notify all listeners that input bindings have been updated 198 notify(self) 199 end 200 201 return acceptable 202 end 203 204 function input.unbind(self, rawEvent, logicalEvent) 205 unbind(self, rawEvent, logicalEvent) 206 207 -- Notify all listeners that input bindings have been updated 208 notify(self) 209 end 210 211 function input.setupEventHandlers(self, layer) 212 -- Key presses 213 local defaultKeyPressed = layer.keyPressed 214 215 layer.keyPressed = function(l, key, pressed, character) 216 local logicalEvent = self.rawToLogical[key] 217 local handled = false 218 219 -- Call the logical event handler if a mapping exists 220 if isString(logicalEvent) then 221 handled = l:inputReceived(logicalEvent, pressed) 222 end 223 224 -- If no mapping exists or the logical event was not handled, send the raw event 225 if not handled and isFunction(defaultKeyPressed) then 226 handled = defaultKeyPressed(l, key, pressed, character) 227 end 228 229 return handled 230 end 231 232 -- Mouse buttons 233 local defaultMouseButtonPressed = layer.mouseButtonPressed 234 235 layer.mouseButtonPressed = function(l, button, pressed, x, y) 236 -- Convert mouse button to raw event 237 local rawEvent = button 238 local logicalEvent = self.rawToLogical[rawEvent] 239 local handled = false 240 241 if isString(logicalEvent) then 242 handled = l:inputReceived(logicalEvent, pressed) 243 end 244 245 if not handled and isFunction(defaultMouseButtonPressed) then 246 handled = defaultMouseButtonPressed(l, button, pressed, x, y) 247 end 248 249 return handled 250 end 251 252 -- Joystick buttons 253 local defaultJoystickButtonPressed = layer.joystickButtonPressed 254 255 layer.joystickButtonPressed = function(l, joystick, button, pressed) 256 local rawEvent = Input.translateJoystickButtonToRawEvent(joystick, button) 257 local handled = false 258 259 if isString(rawEvent) then 260 local logicalEvent = self.rawToLogical[rawEvent] 261 262 -- Call the logical event handler if a mapping exists 263 if isString(logicalEvent) then 264 handled = l:inputReceived(logicalEvent, pressed) 265 end 266 end 267 268 -- If no mapping exists or the logical event was not handled, send the raw event 269 if not handled and isFunction(defaultJoystickButtonPressed) then 270 handled = defaultJoystickButtonPressed(l, joystick, button, character) 271 end 272 273 return handled 274 end 275 276 -- Joystick axes 277 local defaultJoystickAxisMoved = layer.joystickAxisMoved 278 279 layer.joystickAxisMoved = function(l, joystick, axis, value) 280 local rawEventPressed 281 local rawEventReleased 282 local handledLogicalPress = false 283 local handledLogicalRelease = false 284 local handledRaw = false 285 286 -- Check both possible logical events for handlers 287 rawEventPressed, rawEventReleased = Input.translateJoystickAxisMoveToRawEvent(l, joystick, axis, value) 288 289 if isString(rawEventPressed) then 290 local logicalEvent = self.rawToLogical[rawEventPressed] 291 292 if isString(logicalEvent) then 293 handledLogicalPress = l:inputReceived(logicalEvent, true) 294 end 295 end 296 297 if isString(rawEventReleased) then 298 local logicalEvent = self.rawToLogical[rawEventReleased] 299 300 if isString(logicalEvent) then 301 handledLogicalRelease = l:inputReceived(logicalEvent, false) 302 end 303 end 304 305 -- For joystick axes (which are actually stateless), always call the raw callback 306 if isFunction(defaultJoystickAxisMoved) then 307 handledRaw = defaultJoystickAxisMoved(l, joystick, button, character) 308 end 309 310 return handledLogicalPress or handledLogicalRelease or handledRaw 311 end 312 end 313 314 function input.addListener(self, handler) 315 if isFunction(handler) then 316 self.listeners:add(handler) 317 end 318 end 319 320 function input.getRawEvents(self, logicalEvent) 321 return self.logicalToRaw[logicalEvent] 322 end 323 324 function input.getRawToLogical(self) 325 return input.rawToLogical 326 end 327 328 function input.getLogicalEventProperties(self, logicalEvent) 329 return input.logicalEvents[logicalEvent] 330 end 331 332 input.listeners = List.new() 333 334 if not isNil(defaultRawToLogical) then 335 input.rawToLogical = { } 336 input.logicalToRaw = { } 337 338 Table.forEach(defaultRawToLogical, function(key, value) 339 input:bind(key, value) 340 end) 341 else 342 input.rawToLogical = { } 343 input.logicalToRaw = { } 344 end 345 346 input.logicalEvents = logicalEvents 347 348 return input 349end 350 351