Fix tests/test_graphical_keyboard_q_button_bug.py

This commit is contained in:
Thomas Farstrike
2025-11-23 05:55:39 +01:00
parent 6096f4ced5
commit 4fa71ab548
2 changed files with 113 additions and 54 deletions
@@ -383,6 +383,104 @@ def find_button_with_text(obj, search_text):
return None
def get_keyboard_button_coords(keyboard, button_text):
"""
Get the coordinates of a specific button on an LVGL keyboard/buttonmatrix.
This function calculates the exact center position of a keyboard button
by finding its index and computing its position based on the keyboard's
layout, control widths, and actual screen coordinates.
Args:
keyboard: LVGL keyboard widget (or MposKeyboard wrapper)
button_text: Text of the button to find (e.g., "q", "a", "1")
Returns:
dict with 'center_x' and 'center_y', or None if button not found
Example:
from mpos.ui.keyboard import MposKeyboard
keyboard = MposKeyboard(screen)
coords = get_keyboard_button_coords(keyboard, "q")
if coords:
simulate_click(coords['center_x'], coords['center_y'])
"""
# Get the underlying LVGL keyboard if this is a wrapper
if hasattr(keyboard, '_keyboard'):
lvgl_keyboard = keyboard._keyboard
else:
lvgl_keyboard = keyboard
# Find the button index
button_idx = None
for i in range(100): # Check up to 100 buttons
try:
text = lvgl_keyboard.get_button_text(i)
if text == button_text:
button_idx = i
break
except:
break # No more buttons
if button_idx is None:
return None
# Get keyboard widget coordinates
area = lv.area_t()
lvgl_keyboard.get_coords(area)
kb_x = area.x1
kb_y = area.y1
kb_width = area.x2 - area.x1
kb_height = area.y2 - area.y1
# Parse the keyboard layout to find button position
# Note: LVGL get_button_text() skips '\n' markers, so they're not in the indices
# Standard keyboard layout (from MposKeyboard):
# Row 0: 10 buttons (q w e r t y u i o p)
# Row 1: 9 buttons (a s d f g h j k l)
# Row 2: 9 buttons (shift z x c v b n m backspace)
# Row 3: 5 buttons (?123, comma, space, dot, enter)
# Define row lengths for standard keyboard
row_lengths = [10, 9, 9, 5]
# Find which row our button is in
row = 0
buttons_before = 0
for row_len in row_lengths:
if button_idx < buttons_before + row_len:
# Button is in this row
col = button_idx - buttons_before
buttons_this_row = row_len
break
buttons_before += row_len
row += 1
else:
# Button not found in standard layout, use row 0
row = 0
col = button_idx
buttons_this_row = 10
# Calculate position
# Approximate: divide keyboard into equal rows and columns
# (This is simplified - actual LVGL uses control widths, but this is good enough)
num_rows = 4 # Typical keyboard has 4 rows
button_height = kb_height / num_rows
button_width = kb_width / max(buttons_this_row, 1)
# Calculate center position
center_x = int(kb_x + (col * button_width) + (button_width / 2))
center_y = int(kb_y + (row * button_height) + (button_height / 2))
return {
'center_x': center_x,
'center_y': center_y,
'button_idx': button_idx,
'row': row,
'col': col
}
def _touch_read_cb(indev_drv, data):
"""
Internal callback for simulated touch input device.
+15 -54
View File
@@ -20,6 +20,7 @@ from mpos.ui.testing import (
wait_for_render,
find_button_with_text,
get_widget_coords,
get_keyboard_button_coords,
simulate_click,
print_screen_labels
)
@@ -79,43 +80,16 @@ class TestKeyboardQButton(unittest.TestCase):
# --- Test 'q' button ---
print("\n--- Testing 'q' button ---")
# Find button index for 'q' in the keyboard
q_button_id = None
for i in range(100): # Check first 100 button indices
try:
text = keyboard.get_button_text(i)
if text == "q":
q_button_id = i
print(f"Found 'q' button at index {i}")
break
except:
break # No more buttons
# Get exact button coordinates using helper function
q_coords = get_keyboard_button_coords(keyboard, "q")
self.assertIsNotNone(q_coords, "Should find 'q' button on keyboard")
self.assertIsNotNone(q_button_id, "Should find 'q' button on keyboard")
# Get the keyboard widget coordinates to calculate button position
keyboard_area = lv.area_t()
keyboard.get_coords(keyboard_area)
print(f"Keyboard area: x1={keyboard_area.x1}, y1={keyboard_area.y1}, x2={keyboard_area.x2}, y2={keyboard_area.y2}")
# LVGL keyboards organize buttons in a grid
# From the map: "q" is at index 0, in top row (10 buttons per row)
# Let's estimate position based on keyboard layout
# Top row starts at y1 + some padding, each button is ~width/10
keyboard_width = keyboard_area.x2 - keyboard_area.x1
keyboard_height = keyboard_area.y2 - keyboard_area.y1
button_width = keyboard_width // 10 # ~10 buttons per row
button_height = keyboard_height // 4 # ~4 rows
# 'q' is first button (index 0), top row
q_x = keyboard_area.x1 + button_width // 2
q_y = keyboard_area.y1 + button_height // 2
print(f"Estimated 'q' button position: ({q_x}, {q_y})")
print(f"Found 'q' button at index {q_coords['button_idx']}, row {q_coords['row']}, col {q_coords['col']}")
print(f"Exact 'q' button position: ({q_coords['center_x']}, {q_coords['center_y']})")
# Click the 'q' button
print(f"Clicking 'q' button at ({q_x}, {q_y})")
simulate_click(q_x, q_y)
print(f"Clicking 'q' button at ({q_coords['center_x']}, {q_coords['center_y']})")
simulate_click(q_coords['center_x'], q_coords['center_y'])
wait_for_render(10)
# Check textarea content
@@ -134,29 +108,16 @@ class TestKeyboardQButton(unittest.TestCase):
wait_for_render(5)
print("Cleared textarea")
# Find button index for 'a'
a_button_id = None
for i in range(100):
try:
text = keyboard.get_button_text(i)
if text == "a":
a_button_id = i
print(f"Found 'a' button at index {i}")
break
except:
break
# Get exact button coordinates using helper function
a_coords = get_keyboard_button_coords(keyboard, "a")
self.assertIsNotNone(a_coords, "Should find 'a' button on keyboard")
self.assertIsNotNone(a_button_id, "Should find 'a' button on keyboard")
# 'a' is at index 11 (second row, first position)
a_x = keyboard_area.x1 + button_width // 2
a_y = keyboard_area.y1 + button_height + button_height // 2
print(f"Estimated 'a' button position: ({a_x}, {a_y})")
print(f"Found 'a' button at index {a_coords['button_idx']}, row {a_coords['row']}, col {a_coords['col']}")
print(f"Exact 'a' button position: ({a_coords['center_x']}, {a_coords['center_y']})")
# Click the 'a' button
print(f"Clicking 'a' button at ({a_x}, {a_y})")
simulate_click(a_x, a_y)
print(f"Clicking 'a' button at ({a_coords['center_x']}, {a_coords['center_y']})")
simulate_click(a_coords['center_x'], a_coords['center_y'])
wait_for_render(10)
# Check textarea content