Skip to content

Commit a270a94

Browse files
Add InputManager
1 parent 39d9d93 commit a270a94

File tree

2 files changed

+242
-0
lines changed

2 files changed

+242
-0
lines changed

docs/frameworks/input-manager.md

Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
# InputManager
2+
3+
InputManager is a singleton framework that provides a unified API for managing input device interactions, including pointer/touch coordinates and focus management.
4+
5+
## Overview
6+
7+
InputManager centralizes all input-related operations in a single class with class methods. This provides:
8+
9+
- **Unified API** - Single class for all input management
10+
- **Clean Namespace** - No scattered functions cluttering imports
11+
- **Testable** - InputManager can be tested independently
12+
- **Focus Control** - Emulate focus on specific UI objects
13+
- **Pointer Access** - Get current touch/pointer coordinates
14+
15+
## Architecture
16+
17+
InputManager is implemented as a singleton using class variables and class methods:
18+
19+
```python
20+
class InputManager:
21+
@classmethod
22+
def pointer_xy(cls):
23+
"""Get current pointer/touch coordinates."""
24+
import lvgl as lv
25+
indev = lv.indev_active()
26+
if indev:
27+
p = lv.point_t()
28+
indev.get_point(p)
29+
return p.x, p.y
30+
return -1, -1
31+
32+
@classmethod
33+
def emulate_focus_obj(cls, focusgroup, target):
34+
"""Emulate setting focus to a specific object."""
35+
# ... implementation
36+
```
37+
38+
No instance creation is needed - all methods are class methods that operate on class variables.
39+
40+
## Usage
41+
42+
### Getting Pointer Coordinates
43+
44+
```python
45+
from mpos import InputManager
46+
47+
# Get current pointer/touch position
48+
x, y = InputManager.pointer_xy()
49+
if x == -1 and y == -1:
50+
print("No active input device")
51+
else:
52+
print(f"Pointer at ({x}, {y})")
53+
```
54+
55+
### Managing Focus
56+
57+
```python
58+
from mpos import InputManager
59+
import lvgl as lv
60+
61+
# Get the default focus group
62+
focusgroup = lv.group_get_default()
63+
64+
# Set focus to a specific button
65+
if focusgroup:
66+
InputManager.emulate_focus_obj(focusgroup, my_button)
67+
```
68+
69+
## API Reference
70+
71+
### Class Methods
72+
73+
#### `pointer_xy()`
74+
Get current pointer/touch coordinates from the active input device.
75+
76+
**Returns:** tuple - (x, y) coordinates, or (-1, -1) if no active input device
77+
78+
**Example:**
79+
```python
80+
x, y = InputManager.pointer_xy()
81+
if x != -1:
82+
print(f"Touch at ({x}, {y})")
83+
```
84+
85+
#### `emulate_focus_obj(focusgroup, target)`
86+
Emulate setting focus to a specific object in the focus group.
87+
88+
This method is needed because LVGL doesn't have a direct `set_focus()` method. It cycles through the focus group until it finds the target object.
89+
90+
**Parameters:**
91+
- `focusgroup` (lv.group): The focus group to operate on
92+
- `target` (lv.obj): The object to focus on
93+
94+
**Returns:** None
95+
96+
**Example:**
97+
```python
98+
focusgroup = lv.group_get_default()
99+
if focusgroup:
100+
InputManager.emulate_focus_obj(focusgroup, my_button)
101+
```
102+
103+
## Practical Examples
104+
105+
### Touch Event Handling
106+
107+
```python
108+
from mpos import InputManager, DisplayMetrics
109+
import lvgl as lv
110+
111+
def handle_scroll(event):
112+
"""Handle scroll event with pointer coordinates."""
113+
x, y = InputManager.pointer_xy()
114+
115+
if x == -1:
116+
print("No active input device")
117+
return
118+
119+
# Check if touch is in specific region
120+
if x < DisplayMetrics.pct_of_width(50):
121+
print("Touch in left half")
122+
else:
123+
print("Touch in right half")
124+
```
125+
126+
### Focus Management in Dialogs
127+
128+
```python
129+
from mpos import InputManager, Activity
130+
import lvgl as lv
131+
132+
class MyDialog(Activity):
133+
def onCreate(self):
134+
screen = lv.obj()
135+
136+
# Create buttons
137+
yes_btn = lv.button(screen)
138+
no_btn = lv.button(screen)
139+
140+
# ... setup buttons ...
141+
142+
# Set focus to "No" button by default
143+
focusgroup = lv.group_get_default()
144+
if focusgroup:
145+
InputManager.emulate_focus_obj(focusgroup, no_btn)
146+
147+
self.setContentView(screen)
148+
```
149+
150+
### Keyboard Navigation
151+
152+
```python
153+
from mpos import InputManager
154+
import lvgl as lv
155+
156+
def navigate_to_button(button):
157+
"""Navigate keyboard focus to a specific button."""
158+
focusgroup = lv.group_get_default()
159+
if focusgroup:
160+
InputManager.emulate_focus_obj(focusgroup, button)
161+
print(f"Focus moved to {button}")
162+
```
163+
164+
## Implementation Details
165+
166+
### File Structure
167+
168+
```
169+
mpos/ui/
170+
├── input_manager.py # Core InputManager class
171+
└── __init__.py # Exports InputManager
172+
```
173+
174+
### Focus Emulation Algorithm
175+
176+
The `emulate_focus_obj()` method works by:
177+
178+
1. Checking if focusgroup and target are valid
179+
2. Iterating through the focus group using `focus_next()`
180+
3. Comparing the currently focused object with the target
181+
4. Stopping when the target is found
182+
5. Printing a warning if the target is not found
183+
184+
```python
185+
def emulate_focus_obj(cls, focusgroup, target):
186+
if not focusgroup or not target:
187+
return
188+
189+
for objnr in range(focusgroup.get_obj_count()):
190+
currently_focused = focusgroup.get_focused()
191+
if currently_focused is target:
192+
return # Found!
193+
else:
194+
focusgroup.focus_next() # Try next
195+
196+
print("WARNING: emulate_focus_obj failed to find target")
197+
```
198+
199+
## Design Patterns
200+
201+
### Singleton Pattern
202+
203+
InputManager uses the singleton pattern with class methods:
204+
205+
```python
206+
class InputManager:
207+
@classmethod
208+
def pointer_xy(cls):
209+
# Direct class method call, no instance needed
210+
return x, y
211+
```
212+
213+
This avoids the need for instance creation while maintaining a single source of truth.
214+
215+
### LVGL Integration
216+
217+
InputManager integrates directly with LVGL's input device and focus group APIs:
218+
219+
```python
220+
# Pointer access
221+
indev = lv.indev_active()
222+
p = lv.point_t()
223+
indev.get_point(p)
224+
225+
# Focus management
226+
focusgroup = lv.group_get_default()
227+
focusgroup.focus_next()
228+
```
229+
230+
## Related Frameworks
231+
232+
- **[DisplayMetrics](display-metrics.md)** - Display properties and pointer coordinates (now uses InputManager)
233+
- **[WidgetAnimator](widget-animator.md)** - UI animation framework
234+
- **[MposKeyboard](../ui/keyboard.md)** - Custom keyboard with focus management
235+
236+
## See Also
237+
238+
- [Architecture Overview](../architecture/overview.md)
239+
- [Frameworks](../architecture/frameworks.md)
240+
- [Creating Apps](../apps/creating-apps.md)
241+
- [LVGL Documentation](https://docs.lvgl.io/)

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ nav:
5555
- DeviceInfo: frameworks/device-info.md
5656
- DisplayMetrics: frameworks/display-metrics.md
5757
- DownloadManager: frameworks/download-manager.md
58+
- InputManager: frameworks/input-manager.md
5859
- LightsManager: frameworks/lights-manager.md
5960
- Preferences: frameworks/preferences.md
6061
- SensorManager: frameworks/sensor-manager.md

0 commit comments

Comments
 (0)