KeyEvent
Overviewβ
The KeyEvent
class represents an event triggered by key input interaction. KeyEvent objects are typically obtained from MatrixOS.KeyPad.Get()
and provide direct access to key state, force, timing, and other input properties.
The Python KeyEvent class is implemented in Applications/Python/PikaPython/MatrixOS_KeyEvent.py with type hints in Applications/Python/PikaPython/_MatrixOS_KeyEvent.pyi.
Methodsβ
ID
β
def ID(self) -> int
Gets the unique identifier for this key event.
Returns:
int
: The key ID
Example:
key_event = MatrixOS.KeyPad.Get(50)
if key_event:
key_id = key_event.ID()
print(f"Key ID: {key_id}")
State
β
def State(self) -> int
Gets the current state of the key.
Returns:
int
: Key state value
Hold
β
def Hold(self) -> bool
Checks if the key is being held.
Returns:
bool
: True if key is held
HoldTime
β
def HoldTime(self) -> int
Gets the time the key has been held in milliseconds.
Returns:
int
: Hold time in milliseconds
Active
β
def Active(self) -> bool
Checks if the key is currently active (pressed).
Returns:
bool
: True if key is active
Force
β
def Force(self) -> float
Gets the force/pressure applied to the key.
Returns:
float
: Force value (0.0 to 1.0)
Value
β
def Value(self, index: int = 0) -> float
Gets a specific value from the key event.
Parameters:
index
(int
, optional): Value index (default: 0)
Returns:
float
: Value at specified index
__bool__
β
def __bool__(self) -> bool
Allows KeyEvent to be used in boolean context.
Returns:
bool
: True if event is valid
Example:
key_event = MatrixOS.KeyPad.Get(50)
if key_event: # Uses __bool__
print("Valid key event received")
Usage Examplesβ
Basic Key Event Handlingβ
def handle_key_events():
"""Basic key event processing"""
print("Key event handler started...")
while True:
key_event = MatrixOS.KeyPad.Get(50) # 50ms timeout
if key_event:
key_id = key_event.ID()
print(f"Key {key_id} event:")
print(f" State: {key_event.State()}")
print(f" Force: {key_event.Force():.2f}")
print(f" Active: {key_event.Active()}")
if key_event.Hold():
print(f" Hold time: {key_event.HoldTime()}ms")
handle_key_events()
Key Event Classificationβ
def classify_key_events():
"""Classify and respond to different types of key events"""
while True:
key_event = MatrixOS.KeyPad.Get(50)
if key_event:
key_id = key_event.ID()
# Convert to XY coordinates for display
xy = MatrixOS.KeyPad.ID2XY(key_id)
if key_event.Active():
# Key is currently pressed
force = key_event.Force()
if force > 0.8:
print(f"Hard press at ({xy.X()},{xy.Y()})")
MatrixOS.LED.SetColor(xy, Color(255, 0, 0))
elif force > 0.4:
print(f"Medium press at ({xy.X()},{xy.Y()})")
MatrixOS.LED.SetColor(xy, Color(255, 255, 0))
else:
print(f"Soft press at ({xy.X()},{xy.Y()})")
MatrixOS.LED.SetColor(xy, Color(0, 255, 0))
if key_event.Hold():
hold_time = key_event.HoldTime()
if hold_time > 1000: # Held for more than 1 second
print(f"Long hold detected: {hold_time}ms")
MatrixOS.LED.SetColor(xy, Color(255, 255, 255))
else:
# Key was released
print(f"Key released at ({xy.X()},{xy.Y()})")
MatrixOS.LED.SetColor(xy, Color(0, 0, 0))
MatrixOS.LED.Update()
classify_key_events()
Event-Driven Applicationβ
def event_driven_app():
"""Event-driven application using KeyEvent objects"""
app_state = {
"mode": "normal",
"selected_key": None,
"last_event_time": 0
}
def handle_normal_mode(key_event):
"""Handle events in normal mode"""
key_id = key_event.ID()
xy = MatrixOS.KeyPad.ID2XY(key_id)
if key_event.Active():
app_state["selected_key"] = key_id
MatrixOS.LED.SetColor(xy, Color(0, 255, 255))
# Check for mode switch (long press)
if key_event.Hold() and key_event.HoldTime() > 2000:
app_state["mode"] = "config"
MatrixOS.LED.Fill(Color(255, 0, 255))
print("Switched to config mode")
else:
MatrixOS.LED.SetColor(xy, Color(0, 0, 0))
def handle_config_mode(key_event):
"""Handle events in configuration mode"""
key_id = key_event.ID()
if key_event.Active():
if key_id == 0: # Top-left corner to exit
app_state["mode"] = "normal"
MatrixOS.LED.Fill(Color(0, 0, 0))
print("Switched to normal mode")
else:
# Configuration actions
xy = MatrixOS.KeyPad.ID2XY(key_id)
MatrixOS.LED.SetColor(xy, Color(255, 255, 0))
print(f"Config action: key {key_id}")
print("Event-driven app started")
print("Long press any key for config mode")
while True:
key_event = MatrixOS.KeyPad.Get(50)
if key_event:
app_state["last_event_time"] = MatrixOS.SYS.Millis()
if app_state["mode"] == "normal":
handle_normal_mode(key_event)
elif app_state["mode"] == "config":
handle_config_mode(key_event)
MatrixOS.LED.Update()
# Auto-return to normal mode if no activity
if (app_state["mode"] == "config" and
MatrixOS.SYS.Millis() - app_state["last_event_time"] > 10000):
app_state["mode"] = "normal"
MatrixOS.LED.Fill(Color(0, 0, 0))
MatrixOS.LED.Update()
print("Auto-returned to normal mode")
event_driven_app()
Force-Sensitive Drawingβ
def force_drawing():
"""Draw with different colors based on key force"""
print("Force-sensitive drawing active")
print("Press keys with different pressure levels")
while True:
key_event = MatrixOS.KeyPad.Get(50)
if key_event:
xy = MatrixOS.KeyPad.ID2XY(key_event.ID())
if key_event.Active():
force = key_event.Force()
# Map force to color intensity
if force > 0.9:
color = Color(255, 255, 255) # White for maximum force
elif force > 0.7:
color = Color(255, 0, 0) # Red for high force
elif force > 0.5:
color = Color(255, 128, 0) # Orange for medium force
elif force > 0.3:
color = Color(255, 255, 0) # Yellow for light force
else:
color = Color(0, 255, 0) # Green for minimal force
MatrixOS.LED.SetColor(xy, color)
print(f"Drawing at ({xy.X()},{xy.Y()}) with force {force:.2f}")
else:
# Keep the drawing when key is released
pass
MatrixOS.LED.Update()
force_drawing()
Multi-Key Gesture Detectionβ
def gesture_detector():
"""Detect multi-key gestures using KeyEvent timing"""
active_keys = {}
gesture_threshold = 200 # ms
def detect_gesture(active_keys):
"""Analyze active keys for gesture patterns"""
key_ids = list(active_keys.keys())
if len(key_ids) == 2:
# Two-key gestures
key1_xy = MatrixOS.KeyPad.ID2XY(key_ids[0])
key2_xy = MatrixOS.KeyPad.ID2XY(key_ids[1])
# Horizontal swipe
if key1_xy.Y() == key2_xy.Y() and abs(key1_xy.X() - key2_xy.X()) == 1:
return "horizontal_swipe"
# Vertical swipe
elif key1_xy.X() == key2_xy.X() and abs(key1_xy.Y() - key2_xy.Y()) == 1:
return "vertical_swipe"
# Corner tap
elif (key1_xy.X() == 0 and key1_xy.Y() == 0) or (key1_xy.X() == 7 and key1_xy.Y() == 7):
return "corner_combo"
elif len(key_ids) == 4:
# Four corners
corners = [(0,0), (0,7), (7,0), (7,7)]
key_positions = [(MatrixOS.KeyPad.ID2XY(kid).X(), MatrixOS.KeyPad.ID2XY(kid).Y()) for kid in key_ids]
if all(pos in corners for pos in key_positions):
return "four_corners"
return None
print("Gesture detector active")
print("Try: two adjacent keys, four corners, etc.")
while True:
key_event = MatrixOS.KeyPad.Get(50)
if key_event:
key_id = key_event.ID()
current_time = MatrixOS.SYS.Millis()
if key_event.Active():
active_keys[key_id] = {
"start_time": current_time,
"event": key_event
}
# Light up active keys
xy = MatrixOS.KeyPad.ID2XY(key_id)
MatrixOS.LED.SetColor(xy, Color(0, 255, 0))
else:
# Key released
if key_id in active_keys:
del active_keys[key_id]
xy = MatrixOS.KeyPad.ID2XY(key_id)
MatrixOS.LED.SetColor(xy, Color(0, 0, 0))
# Check for gestures when multiple keys are active
if len(active_keys) >= 2:
gesture = detect_gesture(active_keys)
if gesture:
print(f"Gesture detected: {gesture}")
# Visual feedback
MatrixOS.LED.Fill(Color(255, 255, 255))
MatrixOS.LED.Update()
MatrixOS.SYS.DelayMs(200)
# Clear gesture state
active_keys.clear()
MatrixOS.LED.Fill(Color(0, 0, 0))
MatrixOS.LED.Update()
gesture_detector()
Performance Monitoringβ
def key_performance_monitor():
"""Monitor key performance and timing"""
key_stats = {}
while True:
key_event = MatrixOS.KeyPad.Get(50)
if key_event:
key_id = key_event.ID()
if key_id not in key_stats:
key_stats[key_id] = {
"presses": 0,
"total_force": 0.0,
"max_force": 0.0,
"total_hold_time": 0
}
stats = key_stats[key_id]
if key_event.Active():
force = key_event.Force()
stats["total_force"] += force
stats["max_force"] = max(stats["max_force"], force)
if key_event.Hold():
hold_time = key_event.HoldTime()
if hold_time > stats.get("last_hold_time", 0):
stats["total_hold_time"] = hold_time
stats["last_hold_time"] = hold_time
else:
# Key released
stats["presses"] += 1
# Print stats every 10 presses
if stats["presses"] % 10 == 0:
avg_force = stats["total_force"] / stats["presses"]
xy = MatrixOS.KeyPad.ID2XY(key_id)
print(f"Key ({xy.X()},{xy.Y()}) - Presses: {stats['presses']}, "
f"Avg Force: {avg_force:.2f}, Max Force: {stats['max_force']:.2f}")
key_performance_monitor()
Common Patternsβ
Event Validationβ
# Check if event is valid
key_event = MatrixOS.KeyPad.Get(50)
if key_event: # Uses __bool__ method
# Process event
pass
# Alternative explicit check
if key_event is not None:
# Process event
pass
Force-Based Actionsβ
def force_based_action(key_event):
"""Perform different actions based on key force"""
force = key_event.Force()
if force > 0.8:
return "strong_action"
elif force > 0.5:
return "medium_action"
else:
return "light_action"
Hold Detectionβ
def check_hold_duration(key_event):
"""Check for different hold durations"""
if key_event.Hold():
hold_time = key_event.HoldTime()
if hold_time > 3000:
return "extra_long_hold"
elif hold_time > 1000:
return "long_hold"
elif hold_time > 500:
return "short_hold"
return "no_hold"
Comments