pgfw/pgfw/Input.py

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)