260 lines
10 KiB
Python
260 lines
10 KiB
Python
from time import time as get_secs
|
|
|
|
from pygame import joystick as joy
|
|
from pygame.key import get_pressed, get_mods
|
|
from pygame.locals import *
|
|
|
|
from .GameChild import *
|
|
|
|
class Input(GameChild):
|
|
|
|
def __init__(self, game):
|
|
GameChild.__init__(self, game)
|
|
self.last_mouse_down_left = None
|
|
self.axes_cancelled = {"up": True, "right": True, "down": True, "left": True}
|
|
self.last_command_post_time = get_secs()
|
|
self.joystick = Joystick()
|
|
self.delegate = self.get_delegate()
|
|
self.load_configuration()
|
|
self.set_any_press_ignore_list()
|
|
self.unsuppress()
|
|
self.unsuppress_any_on_mods()
|
|
self.subscribe_to_events()
|
|
self.build_key_map()
|
|
self.build_joy_button_map()
|
|
|
|
def load_configuration(self):
|
|
self.release_suffix = self.get_configuration("input", "release-suffix")
|
|
self.key_commands = self.get_configuration().items("keys")
|
|
self.double_click_time_limit = self.get_configuration(
|
|
"mouse", "double-click-time-limit")
|
|
|
|
def set_any_press_ignore_list(self):
|
|
self.any_press_ignored = set(["capture-screen", "toggle-fullscreen",
|
|
"reset-game", "record-video", "quit",
|
|
"toggle-interpolator", "toggle-audio-panel",
|
|
"volume-down", "volume-up", "volume-mute"])
|
|
self.any_press_ignored_keys = set()
|
|
|
|
def suppress(self):
|
|
self.suppressed = True
|
|
|
|
def unsuppress(self):
|
|
self.suppressed = False
|
|
|
|
def is_suppressed(self):
|
|
'''
|
|
Return True if input is suppressed
|
|
'''
|
|
return self.suppressed
|
|
|
|
def unsuppress_any_on_mods(self):
|
|
'''
|
|
Prevent modifier keys from triggering an any key event
|
|
'''
|
|
self.suppressed_any_key_on_mods = False
|
|
|
|
def suppress_any_key_on_mods(self):
|
|
'''
|
|
Allow modifier keys to trigger an any key event
|
|
'''
|
|
self.suppressed_any_key_on_mods = True
|
|
|
|
def subscribe_to_events(self):
|
|
'''
|
|
Tell Delegate to send keyboard, joystick and mouse buttons
|
|
'''
|
|
self.subscribe(self.translate_key, KEYDOWN)
|
|
self.subscribe(self.translate_key, KEYUP)
|
|
self.subscribe(self.translate_joy_button, JOYBUTTONDOWN)
|
|
self.subscribe(self.translate_joy_button, JOYBUTTONUP)
|
|
self.subscribe(self.translate_axis_motion, JOYAXISMOTION)
|
|
self.subscribe(self.translate_mouse_input, MOUSEBUTTONDOWN)
|
|
self.subscribe(self.translate_mouse_input, MOUSEBUTTONUP)
|
|
|
|
def build_key_map(self):
|
|
key_map = {}
|
|
for command, keys in self.key_commands:
|
|
key_map[command] = []
|
|
if type(keys) == str:
|
|
keys = [keys]
|
|
for key in keys:
|
|
key_map[command].append(globals()[key])
|
|
self.key_map = key_map
|
|
|
|
def build_joy_button_map(self):
|
|
self.joy_button_map = self.get_configuration("joy")
|
|
|
|
def translate_key(self, event):
|
|
if not self.suppressed:
|
|
cancel = event.type == KEYUP
|
|
posted = None
|
|
key = event.key
|
|
for cmd, keys in self.key_map.items():
|
|
if key in keys:
|
|
self.post_command(cmd, cancel=cancel)
|
|
posted = cmd
|
|
if (not posted or posted not in self.any_press_ignored) and \
|
|
key not in self.any_press_ignored_keys and \
|
|
(not self.suppressed_any_key_on_mods or \
|
|
(not get_mods() & KMOD_CTRL and not get_mods() & KMOD_ALT)):
|
|
self.post_any_command(key, cancel)
|
|
|
|
def post_command(self, cmd, **attributes):
|
|
self.delegate.post(cmd, **attributes)
|
|
|
|
def post_any_command(self, id, cancel=False):
|
|
self.post_command("any", id=id, cancel=cancel)
|
|
|
|
def translate_joy_button(self, event):
|
|
if not self.suppressed:
|
|
cancel = event.type == JOYBUTTONUP
|
|
posted = None
|
|
for command, button in self.joy_button_map.items():
|
|
if int(button) == event.button:
|
|
self.post_command(command, cancel=cancel)
|
|
posted = command
|
|
if not posted or posted not in self.any_press_ignored:
|
|
self.post_any_command(event.button, cancel)
|
|
|
|
def translate_axis_motion(self, event):
|
|
if not self.suppressed and not self.check_command_line("-disable-joy-axis"):
|
|
axis = event.axis
|
|
value = event.value
|
|
single_xy = self.get_configuration("joy", "single-xy")
|
|
command = None
|
|
if -.01 < value < .01:
|
|
for direction in "up", "right", "down", "left":
|
|
if not self.axes_cancelled[direction]:
|
|
self.post_command(direction, cancel=True)
|
|
if direction not in self.any_press_ignored:
|
|
self.post_any_command(direction, True)
|
|
self.axes_cancelled[direction] = True
|
|
if single_xy:
|
|
if direction == "up" and self.joystick.is_direction_pressed(Joystick.down):
|
|
command = "down"
|
|
elif direction == "down" and self.joystick.is_direction_pressed(Joystick.up):
|
|
command = "up"
|
|
elif direction == "right" and self.joystick.is_direction_pressed(Joystick.left):
|
|
command = "left"
|
|
elif direction == "left" and self.joystick.is_direction_pressed(Joystick.right):
|
|
command = "right"
|
|
else:
|
|
if axis == self.get_configuration("joy", "vertical-axis"):
|
|
if value < 0:
|
|
if not single_xy or not self.joystick.is_direction_pressed(Joystick.down):
|
|
command = "up"
|
|
elif value > 0:
|
|
if not single_xy or not self.joystick.is_direction_pressed(Joystick.up):
|
|
command = "down"
|
|
elif axis == self.get_configuration("joy", "horizontal-axis"):
|
|
if value > 0:
|
|
if not single_xy or not self.joystick.is_direction_pressed(Joystick.left):
|
|
command = "right"
|
|
elif value < 0:
|
|
if not single_xy or not self.joystick.is_direction_pressed(Joystick.right):
|
|
command = "left"
|
|
if command is not None:
|
|
delay = self.get_configuration("joy", "delay-axis")
|
|
secs = get_secs()
|
|
if not delay or secs - self.last_command_post_time > delay:
|
|
self.post_command(command)
|
|
if command not in self.any_press_ignored:
|
|
self.post_any_command(command)
|
|
self.axes_cancelled[command] = False
|
|
self.last_command_post_time = secs
|
|
|
|
def is_command_active(self, command):
|
|
if not self.suppressed:
|
|
if self.is_key_pressed(command):
|
|
return True
|
|
joystick = self.joystick
|
|
joy_map = self.joy_button_map
|
|
if command in joy_map and joystick.get_button(int(joy_map[command])):
|
|
return True
|
|
if command == "up":
|
|
return joystick.is_direction_pressed(Joystick.up)
|
|
elif command == "right":
|
|
return joystick.is_direction_pressed(Joystick.right)
|
|
elif command == "down":
|
|
return joystick.is_direction_pressed(Joystick.down)
|
|
elif command == "left":
|
|
return joystick.is_direction_pressed(Joystick.left)
|
|
|
|
def is_key_pressed(self, command):
|
|
poll = get_pressed()
|
|
for key in self.key_map[command]:
|
|
if poll[key]:
|
|
return True
|
|
|
|
def translate_mouse_input(self, event):
|
|
button = event.button
|
|
pos = event.pos
|
|
post = self.post_command
|
|
if event.type == MOUSEBUTTONDOWN:
|
|
if button == 1:
|
|
last = self.last_mouse_down_left
|
|
if last:
|
|
limit = self.double_click_time_limit
|
|
if get_secs() - last < limit:
|
|
post("mouse-double-click-left", pos=pos)
|
|
last = get_secs()
|
|
self.last_mouse_down_left = last
|
|
if "mouse" not in self.any_press_ignored:
|
|
self.post_any_command(event.button)
|
|
if event.type == MOUSEBUTTONUP:
|
|
if "mouse" not in self.any_press_ignored:
|
|
self.post_any_command(event.button, True)
|
|
|
|
def get_axes(self):
|
|
axes = {}
|
|
for direction in "up", "right", "down", "left":
|
|
axes[direction] = self.is_command_active(direction)
|
|
return axes
|
|
|
|
def register_any_press_ignore(self, *args, **attributes):
|
|
self.any_press_ignored.update(args)
|
|
self.any_press_ignored_keys.update(self.extract_keys(attributes))
|
|
|
|
def extract_keys(self, attributes):
|
|
keys = []
|
|
if "keys" in attributes:
|
|
keys = attributes["keys"]
|
|
if type(keys) == int:
|
|
keys = [keys]
|
|
return keys
|
|
|
|
def unregister_any_press_ignore(self, *args, **attributes):
|
|
self.any_press_ignored.difference_update(args)
|
|
self.any_press_ignored_keys.difference_update(
|
|
self.extract_keys(attributes))
|
|
|
|
|
|
class Joystick:
|
|
|
|
(up, right, down, left) = range(4)
|
|
|
|
def __init__(self):
|
|
js = None
|
|
if joy.get_count() > 0:
|
|
js = joy.Joystick(0)
|
|
js.init()
|
|
self.js = js
|
|
|
|
def is_direction_pressed(self, direction, margin=0.01):
|
|
js = self.js
|
|
if not js or direction > 4:
|
|
return False
|
|
if direction == 0:
|
|
return js.get_axis(1) < 0 - margin
|
|
elif direction == 1:
|
|
return js.get_axis(0) > 0 + margin
|
|
elif direction == 2:
|
|
return js.get_axis(1) > 0 + margin
|
|
elif direction == 3:
|
|
return js.get_axis(0) < 0 - margin
|
|
|
|
def get_button(self, id):
|
|
if self.js:
|
|
return self.js.get_button(id)
|