Skip to content

Commit

Permalink
initial experiemental API for supporting joypad buttons, #53
Browse files Browse the repository at this point in the history
  • Loading branch information
WayneKeenan committed Jun 22, 2017
1 parent 5529202 commit 2d9d8e7
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 14 deletions.
37 changes: 37 additions & 0 deletions examples/buttons.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/usr/bin/python3

# Example of the experimental joypad button API, subject to change.

from picraftzero import Joystick, Button, start

joystick = Joystick() # use the first available controller's rightmost joystick (required)

button0 = Button(0) # attach some buttons by id
button1 = Button(1)
button2 = Button(2)
button3 = Button(3)


def button0_pressed():
print('button0_pressed')

def button0_released():
print('button0_released')

def button1_pressed():
print('button1_pressed')

def button2_pressed():
print('button2_pressed')

def button3_pressed():
print('button3_pressed')

button0.when_pressed = button0_pressed
button0.when_released= button0_released
button1.when_pressed = button1_pressed
button2.when_pressed = button2_pressed
button3.when_pressed = button3_pressed


start()
75 changes: 65 additions & 10 deletions picraftzero/inputs/joystick.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
import threading
from picraftzero.utils import arduino_map
from picraftzero.log import logger
from gpiozero.mixins import SourceMixin,SharedMixin, EventsMixin
from gpiozero.devices import Device


USE_EVENT = True
USE_PYGAME = True
Expand All @@ -21,7 +24,7 @@
# ---------------------------------------------------------------------------------------------------------
# Look for Event support first (Linux) then PyGame (Linux, Windows, Mac, other)
try:
from evdev import InputDevice, categorize, AbsEvent, list_devices
from evdev import InputDevice, categorize, AbsEvent, KeyEvent, list_devices
from evdev.ecodes import KEY, SYN, REL, ABS
HAVE_EVENT = True
except ImportError:
Expand Down Expand Up @@ -78,6 +81,10 @@ def add_listener(self, func):
'ly': {'event_name': 'ABS_Y', 'mapfunc': lambda x: arduino_map(x, 0, 255, 100, -100) if abs(x-128) > ROCKCANDY_AXIS_DEADZONE else 0},
'rx': {'event_name': 'ABS_Z', 'mapfunc': lambda x: arduino_map(x, 0, 255, -100, 100) if abs(x-128) > ROCKCANDY_AXIS_DEADZONE else 0},
'ry': {'event_name': 'ABS_RZ','mapfunc': lambda x: arduino_map(x, 0, 255, 100, -100) if abs(x-128) > ROCKCANDY_AXIS_DEADZONE else 0},
'BTN_A': 0,
'BTN_B': 1,
'BTN_C': 2,
'BTN_X': 3,
}

AFTERGLOW_MAPPING = ROCKCANDY_MAPPING
Expand Down Expand Up @@ -144,6 +151,16 @@ def _start(self):
self.controller_state[axis_key] = axis_val
if self._listener:
self._listener(self)
elif isinstance(cat_event, KeyEvent):
#logger.info("KeyEvent, keycode={}, scancode={}, keystate={}".format(cat_event.keycode, cat_event.scancode, cat_event.keystate))
button_id = self._get_button_id(cat_event.keycode)
if button_id is not None:
Button(button_id).value = 1 if bool(cat_event.keystate) else 0

#else:
#logger.info("{}, {}".format(event, cat_event))


if not self.keep_running:
break

Expand All @@ -164,6 +181,16 @@ def get_value(self, name):

return value

def _get_button_id(self, keycodes):
if not isinstance(keycodes, list):
keycodes = [keycodes]
for keycode in keycodes:
if keycode in self.mapping:
return self.mapping[keycode]

return None


# ---------------------------------------------------------------------------------------------------------
elif HAVE_PYGAME and USE_PYGAME:
logger.info("Using PyGame implementation")
Expand Down Expand Up @@ -286,17 +313,9 @@ def stop(self):
def _start(self):
logger.info("Using Joystick : {}".format(self.joystick.get_name()))

# do a quick sanity test
try:
pygame.event.get()
except pygame.error as e:
logger.error("PyGame init error, joysticks will not be working, cause: {}".format(e))
self.keep_running = False

while self.keep_running:
mainthread_dispatch(lambda: self._process_events(pygame.event.get()))
sleep(0.01)

def _process_events(self, events):
# TODO: to play nicely with other toys in the future this really should be fed from a global event loop
for e in events:
Expand All @@ -309,6 +328,12 @@ def _process_events(self, events):
self.controller_state[axis_key] = axis_val
if self._listener:
self._listener(self)
elif e.type == JOYBUTTONDOWN:
Button(e.button).value = 1
elif e.type == JOYBUTTONUP:
Button(e.button).value = 0
else:
logger.debug(e)

def add_listener(self, func):
self._listener = func
Expand Down Expand Up @@ -339,4 +364,34 @@ def get_value(self, name):
return 0

def add_listener(self, func):
pass
pass


# Button handling (experimental)

class Button(SharedMixin, SourceMixin, Device, EventsMixin):
def __init__(self, button_id=0, **args):
super(Button, self).__init__(**args)
self._button_id = button_id
self._value = 0

# There will ensure there will only ever be one instance of this class per button_id
@classmethod
def _shared_key(cls, button_id):
return button_id

@property
def value(self):
return self._value

@value.setter
def value(self, value):
self._value = value
self._fire_events()

Button.is_pressed = Button.is_active
Button.pressed_time = Button.active_time
Button.when_pressed = Button.when_activated
Button.when_released = Button.when_deactivated
Button.wait_for_press = Button.wait_for_active
Button.wait_for_release = Button.wait_for_inactive
6 changes: 4 additions & 2 deletions picraftzero/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ def i2c_scan(bus_num=1):



# Must run some activvites on the main thread, e.g. PyGame event polling
# Must run some activites on the main thread, e.g. PyGame event polling

import queue
import threading
Expand All @@ -231,15 +231,17 @@ def wait_nonblocking():
while _keep_running:
try:
callback = callback_queue.get(False) #doesn't block
callback()
except queue.Empty:
break
callback()



def main_loop():
global _keep_running
while _keep_running:
wait_blocking()
#wait_nonblocking()


def exit_main():
Expand Down
4 changes: 2 additions & 2 deletions picraftzero/zero.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

from picraftzero.config import get_config
from picraftzero.version import build_string
from picraftzero.inputs.joystick import Button

logger.info("picraftzero, version={}".format(build_string))

Expand Down Expand Up @@ -315,8 +316,7 @@ def value(self):

@value.setter
def value(self, value):
if value:
print("SourcePrinter({}): '{}'".format(self._name, value))
logger.info("{}: '{}'".format(self._name, value))



Expand Down

0 comments on commit 2d9d8e7

Please sign in to comment.