Skip to content

Commit b714ad8

Browse files
Fix double text entry bug
1 parent 428ad5e commit b714ad8

File tree

2 files changed

+68
-2
lines changed

2 files changed

+68
-2
lines changed

internal_filesystem/lib/mpos/ui/keyboard.py

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ def __init__(self, parent):
5656
# Create underlying LVGL keyboard widget
5757
self._keyboard = lv.keyboard(parent)
5858

59+
# Store textarea reference (we DON'T pass it to LVGL to avoid double-typing)
60+
self._textarea = None
61+
5962
# Configure layouts
6063
self._setup_layouts()
6164

@@ -118,12 +121,21 @@ def _handle_events(self, event):
118121
Args:
119122
event: LVGL event object
120123
"""
124+
# Only process VALUE_CHANGED events
125+
event_code = event.get_code()
126+
if event_code != lv.EVENT.VALUE_CHANGED:
127+
return
128+
121129
# Get the pressed button and its text
122130
button = self._keyboard.get_selected_button()
123131
text = self._keyboard.get_button_text(button)
124132

125-
# Get current textarea content
126-
ta = self._keyboard.get_textarea()
133+
# Ignore if no valid button text (can happen during initialization)
134+
if text is None:
135+
return
136+
137+
# Get current textarea content (from our own reference, not LVGL's)
138+
ta = self._textarea
127139
if not ta:
128140
return
129141

@@ -179,6 +191,31 @@ def _handle_events(self, event):
179191
# Update textarea
180192
ta.set_text(new_text)
181193

194+
def set_textarea(self, textarea):
195+
"""
196+
Set the textarea that this keyboard types into.
197+
198+
IMPORTANT: We store the textarea reference ourselves and DON'T pass
199+
it to the underlying LVGL keyboard. This prevents LVGL's built-in
200+
automatic character insertion, which would cause double-character bugs
201+
(LVGL inserts + our handler inserts = double characters).
202+
203+
Args:
204+
textarea: The lv.textarea widget to type into, or None to disconnect
205+
"""
206+
self._textarea = textarea
207+
# NOTE: We deliberately DO NOT call self._keyboard.set_textarea()
208+
# to avoid LVGL's automatic character insertion
209+
210+
def get_textarea(self):
211+
"""
212+
Get the textarea that this keyboard types into.
213+
214+
Returns:
215+
The lv.textarea widget, or None if not connected
216+
"""
217+
return self._textarea
218+
182219
def set_mode(self, mode):
183220
"""
184221
Set keyboard mode with proper map configuration.

tests/test_graphical_keyboard_mode_switch.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,35 @@ def test_switch_modes_multiple_times(self):
123123
except Exception as e:
124124
self.fail(f" CRASH: Switching to {mode_name} caused exception: {e}")
125125

126+
def test_event_handler_exists(self):
127+
"""
128+
Verify that the event handler exists and is properly connected.
129+
130+
The _handle_events method should filter events to only process
131+
VALUE_CHANGED events. This prevents duplicate characters from being
132+
typed when other events (like PRESSED, RELEASED, etc.) are fired.
133+
134+
The fix ensures:
135+
1. Only VALUE_CHANGED events are processed
136+
2. None/invalid button text is ignored
137+
3. Each button press results in exactly ONE character being added
138+
"""
139+
print("\n=== Verifying event handler exists ===")
140+
141+
keyboard = MposKeyboard(self.screen)
142+
keyboard.set_textarea(self.textarea)
143+
keyboard.align(lv.ALIGN.BOTTOM_MID, 0, 0)
144+
wait_for_render(10)
145+
146+
# Verify the event handler method exists and is callable
147+
self.assertTrue(hasattr(keyboard, '_handle_events'),
148+
"Keyboard should have _handle_events method")
149+
self.assertTrue(callable(keyboard._handle_events),
150+
"_handle_events should be callable")
151+
152+
print("SUCCESS: Event handler exists and is properly set up")
153+
print("Note: The handler filters for VALUE_CHANGED events only")
154+
126155

127156
if __name__ == "__main__":
128157
unittest.main()

0 commit comments

Comments
 (0)