|
| 1 | +""" |
| 2 | +Test comparing default LVGL keyboard with custom MposKeyboard. |
| 3 | +
|
| 4 | +This test helps identify the differences between the two keyboard types |
| 5 | +so we can properly detect when the bug occurs (switching to default instead of custom). |
| 6 | +
|
| 7 | +Usage: |
| 8 | + Desktop: ./tests/unittest.sh tests/test_graphical_keyboard_default_vs_custom.py |
| 9 | +""" |
| 10 | + |
| 11 | +import unittest |
| 12 | +import lvgl as lv |
| 13 | +from mpos.ui.keyboard import MposKeyboard |
| 14 | +from graphical_test_helper import wait_for_render |
| 15 | + |
| 16 | + |
| 17 | +class TestDefaultVsCustomKeyboard(unittest.TestCase): |
| 18 | + """Compare default LVGL keyboard with custom MposKeyboard.""" |
| 19 | + |
| 20 | + def setUp(self): |
| 21 | + """Set up test fixtures.""" |
| 22 | + self.screen = lv.obj() |
| 23 | + self.screen.set_size(320, 240) |
| 24 | + lv.screen_load(self.screen) |
| 25 | + wait_for_render(5) |
| 26 | + |
| 27 | + def tearDown(self): |
| 28 | + """Clean up.""" |
| 29 | + lv.screen_load(lv.obj()) |
| 30 | + wait_for_render(5) |
| 31 | + |
| 32 | + def test_default_lvgl_keyboard_layout(self): |
| 33 | + """ |
| 34 | + Examine the default LVGL keyboard to understand its layout. |
| 35 | +
|
| 36 | + This helps us know what we're looking for when detecting the bug. |
| 37 | + """ |
| 38 | + print("\n=== Examining DEFAULT LVGL keyboard ===") |
| 39 | + |
| 40 | + # Create textarea |
| 41 | + textarea = lv.textarea(self.screen) |
| 42 | + textarea.set_size(280, 40) |
| 43 | + textarea.align(lv.ALIGN.TOP_MID, 0, 10) |
| 44 | + textarea.set_one_line(True) |
| 45 | + wait_for_render(5) |
| 46 | + |
| 47 | + # Create DEFAULT LVGL keyboard |
| 48 | + keyboard = lv.keyboard(self.screen) |
| 49 | + keyboard.set_textarea(textarea) |
| 50 | + keyboard.align(lv.ALIGN.BOTTOM_MID, 0, 0) |
| 51 | + wait_for_render(10) |
| 52 | + |
| 53 | + print("\nDefault LVGL keyboard buttons (first 40):") |
| 54 | + found_special_labels = {} |
| 55 | + for i in range(40): |
| 56 | + try: |
| 57 | + text = keyboard.get_button_text(i) |
| 58 | + if text and text not in ["\n", ""]: |
| 59 | + print(f" Index {i}: '{text}'") |
| 60 | + # Track special labels |
| 61 | + if text in ["ABC", "abc", "1#", "?123", "#+=", lv.SYMBOL.UP, lv.SYMBOL.DOWN]: |
| 62 | + found_special_labels[text] = i |
| 63 | + except: |
| 64 | + pass |
| 65 | + |
| 66 | + print("\n--- DEFAULT LVGL keyboard has these special labels ---") |
| 67 | + for label, idx in found_special_labels.items(): |
| 68 | + print(f" '{label}' at index {idx}") |
| 69 | + |
| 70 | + print("\n--- Characteristics of DEFAULT LVGL keyboard ---") |
| 71 | + if "ABC" in found_special_labels: |
| 72 | + print(" ✓ Has 'ABC' (uppercase label)") |
| 73 | + if "1#" in found_special_labels: |
| 74 | + print(" ✓ Has '1#' (numbers label)") |
| 75 | + if "#+" in found_special_labels or "#+=" in found_special_labels: |
| 76 | + print(" ✓ Has '#+=/-' type labels") |
| 77 | + |
| 78 | + def test_custom_mpos_keyboard_layout(self): |
| 79 | + """ |
| 80 | + Examine our custom MposKeyboard to understand its layout. |
| 81 | +
|
| 82 | + This shows what the CORRECT layout should look like. |
| 83 | + """ |
| 84 | + print("\n=== Examining CUSTOM MposKeyboard ===") |
| 85 | + |
| 86 | + # Create textarea |
| 87 | + textarea = lv.textarea(self.screen) |
| 88 | + textarea.set_size(280, 40) |
| 89 | + textarea.align(lv.ALIGN.TOP_MID, 0, 10) |
| 90 | + textarea.set_one_line(True) |
| 91 | + wait_for_render(5) |
| 92 | + |
| 93 | + # Create CUSTOM MposKeyboard |
| 94 | + keyboard = MposKeyboard(self.screen) |
| 95 | + keyboard.set_textarea(textarea) |
| 96 | + keyboard.align(lv.ALIGN.BOTTOM_MID, 0, 0) |
| 97 | + wait_for_render(10) |
| 98 | + |
| 99 | + print("\nCustom MposKeyboard buttons (first 40):") |
| 100 | + found_special_labels = {} |
| 101 | + for i in range(40): |
| 102 | + try: |
| 103 | + text = keyboard.get_button_text(i) |
| 104 | + if text and text not in ["\n", ""]: |
| 105 | + print(f" Index {i}: '{text}'") |
| 106 | + # Track special labels |
| 107 | + if text in ["ABC", "abc", "1#", "?123", "=\\<", lv.SYMBOL.UP, lv.SYMBOL.DOWN]: |
| 108 | + found_special_labels[text] = i |
| 109 | + except: |
| 110 | + pass |
| 111 | + |
| 112 | + print("\n--- CUSTOM MposKeyboard has these special labels ---") |
| 113 | + for label, idx in found_special_labels.items(): |
| 114 | + print(f" '{label}' at index {idx}") |
| 115 | + |
| 116 | + print("\n--- Characteristics of CUSTOM MposKeyboard ---") |
| 117 | + if "?123" in found_special_labels: |
| 118 | + print(" ✓ Has '?123' (numbers label)") |
| 119 | + if "=\\<" in found_special_labels: |
| 120 | + print(" ✓ Has '=\\<' (specials label)") |
| 121 | + if lv.SYMBOL.UP in found_special_labels: |
| 122 | + print(" ✓ Has UP symbol (shift to uppercase)") |
| 123 | + |
| 124 | + def test_mode_switching_bug_reproduction(self): |
| 125 | + """ |
| 126 | + Try to reproduce the bug: numbers -> abc -> wrong layout. |
| 127 | + """ |
| 128 | + print("\n=== Attempting to reproduce the bug ===") |
| 129 | + |
| 130 | + textarea = lv.textarea(self.screen) |
| 131 | + textarea.set_size(280, 40) |
| 132 | + textarea.align(lv.ALIGN.TOP_MID, 0, 10) |
| 133 | + textarea.set_one_line(True) |
| 134 | + wait_for_render(5) |
| 135 | + |
| 136 | + keyboard = MposKeyboard(self.screen) |
| 137 | + keyboard.set_textarea(textarea) |
| 138 | + keyboard.align(lv.ALIGN.BOTTOM_MID, 0, 0) |
| 139 | + wait_for_render(10) |
| 140 | + |
| 141 | + # Step 1: Start in lowercase |
| 142 | + print("\nStep 1: Initial lowercase mode") |
| 143 | + labels_step1 = self._get_special_labels(keyboard) |
| 144 | + print(f" Labels: {list(labels_step1.keys())}") |
| 145 | + self.assertIn("?123", labels_step1, "Should start with custom lowercase (?123)") |
| 146 | + |
| 147 | + # Step 2: Switch to numbers |
| 148 | + print("\nStep 2: Switch to numbers mode") |
| 149 | + keyboard.set_mode(MposKeyboard.MODE_NUMBERS) |
| 150 | + wait_for_render(5) |
| 151 | + labels_step2 = self._get_special_labels(keyboard) |
| 152 | + print(f" Labels: {list(labels_step2.keys())}") |
| 153 | + self.assertIn("abc", labels_step2, "Should have 'abc' in numbers mode") |
| 154 | + |
| 155 | + # Step 3: Switch back to lowercase (this is where bug might happen) |
| 156 | + print("\nStep 3: Switch back to lowercase via set_mode()") |
| 157 | + keyboard.set_mode(MposKeyboard.MODE_LOWERCASE) |
| 158 | + wait_for_render(5) |
| 159 | + labels_step3 = self._get_special_labels(keyboard) |
| 160 | + print(f" Labels: {list(labels_step3.keys())}") |
| 161 | + |
| 162 | + # Check for bug |
| 163 | + if "ABC" in labels_step3 or "1#" in labels_step3: |
| 164 | + print(" ❌ BUG DETECTED: Got default LVGL keyboard!") |
| 165 | + print(f" Found these labels: {list(labels_step3.keys())}") |
| 166 | + self.fail("BUG: Switched to default LVGL keyboard instead of custom") |
| 167 | + |
| 168 | + if "?123" not in labels_step3: |
| 169 | + print(" ❌ BUG DETECTED: Missing '?123' label!") |
| 170 | + print(f" Found these labels: {list(labels_step3.keys())}") |
| 171 | + self.fail("BUG: Missing '?123' label from custom keyboard") |
| 172 | + |
| 173 | + print(" ✓ Correct: Has custom layout with '?123'") |
| 174 | + |
| 175 | + def _get_special_labels(self, keyboard): |
| 176 | + """Helper to get special labels from keyboard.""" |
| 177 | + labels = {} |
| 178 | + for i in range(100): |
| 179 | + try: |
| 180 | + text = keyboard.get_button_text(i) |
| 181 | + if text in ["ABC", "abc", "1#", "?123", "=\\<", "#+=", lv.SYMBOL.UP, lv.SYMBOL.DOWN]: |
| 182 | + labels[text] = i |
| 183 | + except: |
| 184 | + pass |
| 185 | + return labels |
| 186 | + |
| 187 | + |
| 188 | +if __name__ == "__main__": |
| 189 | + unittest.main() |
0 commit comments