sc7-default-firmware/keyboardcb.py

122 lines
4.1 KiB
Python

import keyleds
import keyboardio
import asyncio
class KeyboardCB(keyboardio.KeyboardIO):
"""
A class that provides a single callback for a key or group of keys.
It can use a single callback or a dictionary to have different callbacks for different keys.
It can also filter repeating keys
Attributes:
callback (dict or function): A dictionary of callback functions or a single callback function.
filter (list): A list of keys to filter (default none, or use keys from callback when callback is a dictionary)
single_key_mode (bool): A flag to indicate if only single key press events should be handled.
attach (bool): A flag to indicate if the keyboard should be attached during initialization.
active (bool): A flag to indicate if the keyboard is active.
"""
def __init__(self, callback={}, filter=[], single_key_mode=True, attach=True):
"""
The constructor for KeyboardCB class.
Args:
callback (dict or function): A dictionary of callback functions or a single callback function.
Default is an empty dictionary (no callbacks).
filter (list): A list of keys to filter. Default is an empty list.
single_key_mode (bool): A flag to indicate if only single key press events should be handled. Default is True.
attach (bool): A flag to indicate if the keyboard should be attached during initialization. Default is True.
"""
super().__init__(attach=attach)
if isinstance(filter,list):
self.filter=filter
else:
self.filter=[ filter ]
self._cb=callback
self.single_key_mode=single_key_mode
self.active=True
def set_callback(self,func_or_dict):
"""
Function to set a non-default callback.
Args:
func_or_dict (function or dict): The function or dictionary to set as the callback.
"""
self._cb=func_or_dict
async def _do_callback(self,cb,k):
try:
await cb(k) # async if possible
except TypeError: # well, it was really a sync call, np...
pass
async def key(self, b):
"""
Function to handle key press events.
This function checks if the keyboard is active and if the pressed key is in the filter.
If it is, it calls the appropriate callback function.
Args:
b (int): The keycodes of the pressed keys as a list.
"""
# if you specify a filter, use it
# if not but you use a dictionary callback, use its keys as a filter
# otherwise, no filter
if self.active==False:
return
if self.filter!=[]:
flt=self.filter
else:
if isinstance(self._cb,dict):
flt=self._cb.keys()
else:
flt=[]
# remove all not in filter here first
if flt!=[]:
b1=[ item for item in b if item in flt ]
else:
b1=b
if (b1!=[] and self.single_key_mode==True): # single keypress mode
b1=[ item for item in b1 if item not in self._prev ]
if b1:
for k in b1:
if flt!=[]:
if k not in flt:
continue
if isinstance(self._cb,dict):
asyncio.create_task(self._do_callback(self._cb[k],k))
else:
asyncio.create_task(self._do_callback(self._cb,k))
def replace_chord(b,chord,value):
"""
Helper function to find chords (two or more keys) and replace them with one key.
Args:
b (list): The list of pressed keys.
chord (list): The list of keys that form a chord.
value (int): The keycode of the key that will replace the chord.
Returns:
list: The list of pressed keys with the chord replaced by the value.
"""
b1=b
if all(item in b1 for item in chord):
for item in chord:
b1.remove(item)
b1.append(value)
return b1