Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion arduino/arduino.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from time import sleep_ms, ticks_us
from random import randrange
from math import sin, cos, radians, floor, ceil
from sys import exit
from .key_handler import KeyHandler

OUTPUT = Pin.OUT
INPUT = Pin.IN
Expand Down Expand Up @@ -110,13 +110,40 @@ def copy_sketch(source_path = '', destination_path = '.', name = None, overwrite
return create_sketch(sketch_name = name, destination_path = destination_path, overwrite = overwrite, source_path = source_path)

# RUNTIME

# KEY EVENTS IN REPL
KEY_UP = KeyHandler.UP
KEY_DOWN = KeyHandler.DOWN
KEY_LEFT = KeyHandler.LEFT
KEY_RIGHT = KeyHandler.RIGHT
KEY_ESC = KeyHandler.ESC
KEY_ENTER = KeyHandler.ENTER
KEY_SPACE = KeyHandler.SPACE

_key_handler = KeyHandler()
def add_key_listener(key, callback, *params):
_key_handler.add_key_listener(key, callback, *params)

def remove_key_listener(key = None):
if key is None:
return _key_handler.remove_all_listeners()
return _key_handler.remove_key_listener(key)

def read_keys():
_key_handler.read_keys()


# RUN LOOP

def start(setup=None, loop=None, cleanup = None, preload = None):
remove_key_listener()
if preload is not None:
preload()
if setup is not None:
setup()
try:
while True:
read_keys()
if loop is not None:
loop()
if not NON_BLOCKING:
Expand Down
57 changes: 57 additions & 0 deletions arduino/examples/03_keyboard_REPL.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Keyboard use in REPL
# by Ubi de Feo
#
# This demo code shows how to implement interactive behaviour in REPL.
# When running this code in a REPL session, using keys can trigger actions.
#
# Simply add a listener for a key (KEY_UP, KEY_DOWN, ENTER, ESC, etc.) and a callback.
# Supports variable arguments which must be handled by the callback (see setup())

from arduino import *

item_selected = None

def inventory(open = True):
if open:
print('- open inventory -')
print('(a) Potion - Get more energy')
print('(b) Key - Open a door')
print('(c) Sword - Defend from enemy')
else:
print('- closing inventory -')

def select_item(item, description):
global item_selected
item_selected = item
print(f'Item selected: {item}')
print(f'Description: {description}')

def use_item():
print(f'using {item_selected}')

def player_move(direction):
print(f'Player moving {direction}')

def setup():
add_key_listener(KEY_ESC, inventory, False)
add_key_listener(KEY_ENTER, inventory)
add_key_listener(KEY_SPACE, use_item)
add_key_listener(KEY_UP, player_move, 'UP')
add_key_listener(KEY_DOWN, player_move, 'DOWN')
add_key_listener(KEY_LEFT, player_move, 'LEFT')
add_key_listener(KEY_RIGHT, player_move, 'RIGHT')
add_key_listener('a', select_item, 'potion', 'get more energy')
add_key_listener('b', select_item, 'key', 'open a door')
add_key_listener('c', select_item, 'sword', 'defend from enemy')
print('starting...')
print('Arrows: move')
print('Enter: open inventory')
print('ESC: close inventory')
print('a: select potion')
print('b: select key')
print('c: select sword')

def loop():
delay(10)

start(setup, loop)
77 changes: 77 additions & 0 deletions arduino/key_handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import select
from sys import stdin

class KeyHandler:
UP = "arrow_up"
DOWN = "arrow_down"
LEFT = "arrow_left"
RIGHT = "arrow_right"
ESC = "esc"
ENTER = "enter"
SPACE = " "
ESCAPE_SEQUENCE_TIMEOUT = 0.01
def __init__(self):
self._key_events = {}

def add_key_listener(self, key, callback, *params):
key_event = KeyEvent(key, callback, params if params else None)
self._key_events[key] = key_event

def remove_key_listener(self, key):
if key in self._key_events:
del self._key_events[key]
return True
return False

def remove_all_listeners(self):
self._key_events.clear()
return True

def _key_is_down(self):
if stdin in select.select([stdin], [], [], KeyHandler.ESCAPE_SEQUENCE_TIMEOUT)[0]:
ch = stdin.read(1)

if ch == '\n' or ch == '\r':
return self.ENTER

if ch == '\x1b':
# Wait briefly for escape sequence
if stdin in select.select([stdin], [], [], KeyHandler.ESCAPE_SEQUENCE_TIMEOUT)[0]:
next_ch = stdin.read(1)
if next_ch == '[':
if stdin in select.select([stdin], [], [], KeyHandler.ESCAPE_SEQUENCE_TIMEOUT)[0]:
arrow_ch = stdin.read(1)
if arrow_ch == 'A':
return self.UP
elif arrow_ch == 'B':
return self.DOWN
elif arrow_ch == 'C':
return self.RIGHT
elif arrow_ch == 'D':
return self.LEFT
return self.ESC

return ch

return None

def read_keys(self):
while True:
detected_key = self._key_is_down()
if detected_key is None:
break
if detected_key in self._key_events:
self._key_events[detected_key].trigger()


class KeyEvent:
def __init__(self, key=None, callback=None, args=None):
self.key = key
self.callback = callback
self.callback_arguments = args

def trigger(self):
if self.callback_arguments is None:
self.callback()
else:
self.callback(*self.callback_arguments)
22 changes: 22 additions & 0 deletions arduino/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# The following functions are used for testing only
# and provide a faux implementation of the user's functions
from arduino import *

def preload():
print('preload')

def setup():
add_key_listener(KEY_UP, print, 'key:', 'up')
add_key_listener(KEY_DOWN, print, 'key:', 'down')
add_key_listener(KEY_LEFT, print, 'key:', 'left')
add_key_listener(KEY_RIGHT, print, 'key:', 'right')
print('setup')

def loop():
print('loop')
delay(100)

def cleanup():
print('cleanup')

start(setup, loop, cleanup, preload)