diff options
-rw-r--r-- | minui/events.cpp | 4 | ||||
-rw-r--r-- | minui/minui.h | 9 | ||||
-rw-r--r-- | recovery.cpp | 6 | ||||
-rw-r--r-- | screen_ui.cpp | 11 | ||||
-rw-r--r-- | screen_ui.h | 6 | ||||
-rw-r--r-- | ui.cpp | 79 | ||||
-rw-r--r-- | ui.h | 29 |
7 files changed, 96 insertions, 48 deletions
diff --git a/minui/events.cpp b/minui/events.cpp index 2c41eb8a..daa10c6c 100644 --- a/minui/events.cpp +++ b/minui/events.cpp | |||
@@ -201,7 +201,7 @@ int ev_sync_key_state(ev_set_key_callback set_key_cb, void* data) { | |||
201 | return 0; | 201 | return 0; |
202 | } | 202 | } |
203 | 203 | ||
204 | void ev_iterate_available_keys(ev_key_callback cb, void* data) { | 204 | void ev_iterate_available_keys(std::function<void(int)> f) { |
205 | unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)]; | 205 | unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)]; |
206 | unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)]; | 206 | unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)]; |
207 | 207 | ||
@@ -224,7 +224,7 @@ void ev_iterate_available_keys(ev_key_callback cb, void* data) { | |||
224 | 224 | ||
225 | for (int key_code = 0; key_code <= KEY_MAX; ++key_code) { | 225 | for (int key_code = 0; key_code <= KEY_MAX; ++key_code) { |
226 | if (test_bit(key_code, key_bits)) { | 226 | if (test_bit(key_code, key_bits)) { |
227 | cb(key_code, data); | 227 | f(key_code); |
228 | } | 228 | } |
229 | } | 229 | } |
230 | } | 230 | } |
diff --git a/minui/minui.h b/minui/minui.h index 8f2ff113..82abb8a6 100644 --- a/minui/minui.h +++ b/minui/minui.h | |||
@@ -68,13 +68,11 @@ struct input_event; | |||
68 | 68 | ||
69 | typedef int (*ev_callback)(int fd, uint32_t epevents, void* data); | 69 | typedef int (*ev_callback)(int fd, uint32_t epevents, void* data); |
70 | typedef int (*ev_set_key_callback)(int code, int value, void* data); | 70 | typedef int (*ev_set_key_callback)(int code, int value, void* data); |
71 | typedef void (*ev_key_callback)(int code, void* data); | ||
72 | 71 | ||
73 | int ev_init(ev_callback input_cb, void* data); | 72 | int ev_init(ev_callback input_cb, void* data); |
74 | void ev_exit(void); | 73 | void ev_exit(void); |
75 | int ev_add_fd(int fd, ev_callback cb, void* data); | 74 | int ev_add_fd(int fd, ev_callback cb, void* data); |
76 | int ev_sync_key_state(ev_set_key_callback set_key_cb, void* data); | 75 | int ev_sync_key_state(ev_set_key_callback set_key_cb, void* data); |
77 | void ev_iterate_available_keys(ev_key_callback cb, void* data); | ||
78 | 76 | ||
79 | // 'timeout' has the same semantics as poll(2). | 77 | // 'timeout' has the same semantics as poll(2). |
80 | // 0 : don't block | 78 | // 0 : don't block |
@@ -130,4 +128,11 @@ void res_free_surface(gr_surface surface); | |||
130 | } | 128 | } |
131 | #endif | 129 | #endif |
132 | 130 | ||
131 | #ifdef __cplusplus | ||
132 | |||
133 | #include <functional> | ||
134 | void ev_iterate_available_keys(std::function<void(int)> f); | ||
135 | |||
136 | #endif | ||
137 | |||
133 | #endif | 138 | #endif |
diff --git a/recovery.cpp b/recovery.cpp index cdbb598e..43a42eab 100644 --- a/recovery.cpp +++ b/recovery.cpp | |||
@@ -545,12 +545,10 @@ get_menu_selection(const char* const * headers, const char* const * items, | |||
545 | if (action < 0) { | 545 | if (action < 0) { |
546 | switch (action) { | 546 | switch (action) { |
547 | case Device::kHighlightUp: | 547 | case Device::kHighlightUp: |
548 | --selected; | 548 | selected = ui->SelectMenu(--selected); |
549 | selected = ui->SelectMenu(selected); | ||
550 | break; | 549 | break; |
551 | case Device::kHighlightDown: | 550 | case Device::kHighlightDown: |
552 | ++selected; | 551 | selected = ui->SelectMenu(++selected); |
553 | selected = ui->SelectMenu(selected); | ||
554 | break; | 552 | break; |
555 | case Device::kInvokeItem: | 553 | case Device::kInvokeItem: |
556 | chosen_item = selected; | 554 | chosen_item = selected; |
diff --git a/screen_ui.cpp b/screen_ui.cpp index 6d8df68b..b62417f5 100644 --- a/screen_ui.cpp +++ b/screen_ui.cpp | |||
@@ -185,6 +185,9 @@ void ScreenRecoveryUI::SetColor(UIElement e) { | |||
185 | case MENU_SEL_BG: | 185 | case MENU_SEL_BG: |
186 | gr_color(0, 106, 157, 255); | 186 | gr_color(0, 106, 157, 255); |
187 | break; | 187 | break; |
188 | case MENU_SEL_BG_ACTIVE: | ||
189 | gr_color(0, 156, 100, 255); | ||
190 | break; | ||
188 | case MENU_SEL_FG: | 191 | case MENU_SEL_FG: |
189 | gr_color(255, 255, 255, 255); | 192 | gr_color(255, 255, 255, 255); |
190 | break; | 193 | break; |
@@ -220,7 +223,7 @@ void ScreenRecoveryUI::draw_screen_locked() { | |||
220 | 223 | ||
221 | if (i == menu_top + menu_sel) { | 224 | if (i == menu_top + menu_sel) { |
222 | // draw the highlight bar | 225 | // draw the highlight bar |
223 | SetColor(MENU_SEL_BG); | 226 | SetColor(IsLongPress() ? MENU_SEL_BG_ACTIVE : MENU_SEL_BG); |
224 | gr_fill(0, y-2, gr_fb_width(), y+char_height+2); | 227 | gr_fill(0, y-2, gr_fb_width(), y+char_height+2); |
225 | // white text of selected item | 228 | // white text of selected item |
226 | SetColor(MENU_SEL_FG); | 229 | SetColor(MENU_SEL_FG); |
@@ -638,3 +641,9 @@ void ScreenRecoveryUI::Redraw() { | |||
638 | update_screen_locked(); | 641 | update_screen_locked(); |
639 | pthread_mutex_unlock(&updateMutex); | 642 | pthread_mutex_unlock(&updateMutex); |
640 | } | 643 | } |
644 | |||
645 | void ScreenRecoveryUI::KeyLongPress(int) { | ||
646 | // Redraw so that if we're in the menu, the highlight | ||
647 | // will change color to indicate a successful long press. | ||
648 | Redraw(); | ||
649 | } | ||
diff --git a/screen_ui.h b/screen_ui.h index 41ff4af1..ea1a95be 100644 --- a/screen_ui.h +++ b/screen_ui.h | |||
@@ -56,10 +56,12 @@ class ScreenRecoveryUI : public RecoveryUI { | |||
56 | int SelectMenu(int sel); | 56 | int SelectMenu(int sel); |
57 | void EndMenu(); | 57 | void EndMenu(); |
58 | 58 | ||
59 | void KeyLongPress(int); | ||
60 | |||
59 | void Redraw(); | 61 | void Redraw(); |
60 | 62 | ||
61 | enum UIElement { HEADER, MENU, MENU_SEL_BG, MENU_SEL_FG, LOG, TEXT_FILL }; | 63 | enum UIElement { HEADER, MENU, MENU_SEL_BG, MENU_SEL_BG_ACTIVE, MENU_SEL_FG, LOG, TEXT_FILL }; |
62 | virtual void SetColor(UIElement e); | 64 | void SetColor(UIElement e); |
63 | 65 | ||
64 | private: | 66 | private: |
65 | Icon currentIcon; | 67 | Icon currentIcon; |
@@ -51,26 +51,40 @@ RecoveryUI::RecoveryUI() | |||
51 | key_down_count(0), | 51 | key_down_count(0), |
52 | enable_reboot(true), | 52 | enable_reboot(true), |
53 | consecutive_power_keys(0), | 53 | consecutive_power_keys(0), |
54 | last_key(-1) { | 54 | last_key(-1), |
55 | has_power_key(false), | ||
56 | has_up_key(false), | ||
57 | has_down_key(false) { | ||
55 | pthread_mutex_init(&key_queue_mutex, NULL); | 58 | pthread_mutex_init(&key_queue_mutex, NULL); |
56 | pthread_cond_init(&key_queue_cond, NULL); | 59 | pthread_cond_init(&key_queue_cond, NULL); |
57 | self = this; | 60 | self = this; |
58 | memset(key_pressed, 0, sizeof(key_pressed)); | 61 | memset(key_pressed, 0, sizeof(key_pressed)); |
59 | } | 62 | } |
60 | 63 | ||
64 | void RecoveryUI::OnKeyDetected(int key_code) { | ||
65 | if (key_code == KEY_POWER) { | ||
66 | has_power_key = true; | ||
67 | } else if (key_code == KEY_DOWN || key_code == KEY_VOLUMEDOWN) { | ||
68 | has_down_key = true; | ||
69 | } else if (key_code == KEY_UP || key_code == KEY_VOLUMEUP) { | ||
70 | has_up_key = true; | ||
71 | } | ||
72 | } | ||
73 | |||
61 | void RecoveryUI::Init() { | 74 | void RecoveryUI::Init() { |
62 | ev_init(input_callback, NULL); | 75 | ev_init(input_callback, NULL); |
76 | |||
77 | using namespace std::placeholders; | ||
78 | ev_iterate_available_keys(std::bind(&RecoveryUI::OnKeyDetected, this, _1)); | ||
79 | |||
63 | pthread_create(&input_t, NULL, input_thread, NULL); | 80 | pthread_create(&input_t, NULL, input_thread, NULL); |
64 | } | 81 | } |
65 | 82 | ||
66 | |||
67 | int RecoveryUI::input_callback(int fd, uint32_t epevents, void* data) { | 83 | int RecoveryUI::input_callback(int fd, uint32_t epevents, void* data) { |
68 | struct input_event ev; | 84 | struct input_event ev; |
69 | int ret; | 85 | if (ev_get_input(fd, epevents, &ev) == -1) { |
70 | |||
71 | ret = ev_get_input(fd, epevents, &ev); | ||
72 | if (ret) | ||
73 | return -1; | 86 | return -1; |
87 | } | ||
74 | 88 | ||
75 | if (ev.type == EV_SYN) { | 89 | if (ev.type == EV_SYN) { |
76 | return 0; | 90 | return 0; |
@@ -95,8 +109,9 @@ int RecoveryUI::input_callback(int fd, uint32_t epevents, void* data) { | |||
95 | self->rel_sum = 0; | 109 | self->rel_sum = 0; |
96 | } | 110 | } |
97 | 111 | ||
98 | if (ev.type == EV_KEY && ev.code <= KEY_MAX) | 112 | if (ev.type == EV_KEY && ev.code <= KEY_MAX) { |
99 | self->process_key(ev.code, ev.value); | 113 | self->process_key(ev.code, ev.value); |
114 | } | ||
100 | 115 | ||
101 | return 0; | 116 | return 0; |
102 | } | 117 | } |
@@ -142,8 +157,7 @@ void RecoveryUI::process_key(int key_code, int updown) { | |||
142 | pthread_mutex_unlock(&key_queue_mutex); | 157 | pthread_mutex_unlock(&key_queue_mutex); |
143 | 158 | ||
144 | if (register_key) { | 159 | if (register_key) { |
145 | NextCheckKeyIsLong(long_press); | 160 | switch (CheckKey(key_code, long_press)) { |
146 | switch (CheckKey(key_code)) { | ||
147 | case RecoveryUI::IGNORE: | 161 | case RecoveryUI::IGNORE: |
148 | break; | 162 | break; |
149 | 163 | ||
@@ -257,23 +271,44 @@ bool RecoveryUI::IsKeyPressed(int key) { | |||
257 | return pressed; | 271 | return pressed; |
258 | } | 272 | } |
259 | 273 | ||
274 | bool RecoveryUI::IsLongPress() { | ||
275 | pthread_mutex_lock(&key_queue_mutex); | ||
276 | bool result = key_long_press; | ||
277 | pthread_mutex_unlock(&key_queue_mutex); | ||
278 | return result; | ||
279 | } | ||
280 | |||
260 | void RecoveryUI::FlushKeys() { | 281 | void RecoveryUI::FlushKeys() { |
261 | pthread_mutex_lock(&key_queue_mutex); | 282 | pthread_mutex_lock(&key_queue_mutex); |
262 | key_queue_len = 0; | 283 | key_queue_len = 0; |
263 | pthread_mutex_unlock(&key_queue_mutex); | 284 | pthread_mutex_unlock(&key_queue_mutex); |
264 | } | 285 | } |
265 | 286 | ||
266 | // The default CheckKey implementation assumes the device has power, | 287 | RecoveryUI::KeyAction RecoveryUI::CheckKey(int key, bool is_long_press) { |
267 | // volume up, and volume down keys. | 288 | pthread_mutex_lock(&key_queue_mutex); |
268 | // | 289 | key_long_press = false; |
269 | // - Hold power and press vol-up to toggle display. | 290 | pthread_mutex_unlock(&key_queue_mutex); |
270 | // - Press power seven times in a row to reboot. | 291 | |
271 | // - Alternate vol-up and vol-down seven times to mount /system. | 292 | // If we have power and volume up keys, that chord is the signal to toggle the text display. |
272 | RecoveryUI::KeyAction RecoveryUI::CheckKey(int key) { | 293 | if (has_power_key && has_up_key) { |
273 | if ((IsKeyPressed(KEY_POWER) && key == KEY_VOLUMEUP) || key == KEY_HOME) { | 294 | if (key == KEY_VOLUMEUP && IsKeyPressed(KEY_POWER)) { |
274 | return TOGGLE; | 295 | return TOGGLE; |
296 | } | ||
297 | } else { | ||
298 | // Otherwise long press of any button toggles to the text display, | ||
299 | // and there's no way to toggle back (but that's pretty useless anyway). | ||
300 | if (is_long_press && !IsTextVisible()) { | ||
301 | return TOGGLE; | ||
302 | } | ||
303 | |||
304 | // Also, for button-limited devices, a long press is translated to KEY_ENTER. | ||
305 | if (is_long_press && IsTextVisible()) { | ||
306 | EnqueueKey(KEY_ENTER); | ||
307 | return IGNORE; | ||
308 | } | ||
275 | } | 309 | } |
276 | 310 | ||
311 | // Press power seven times in a row to reboot. | ||
277 | if (key == KEY_POWER) { | 312 | if (key == KEY_POWER) { |
278 | pthread_mutex_lock(&key_queue_mutex); | 313 | pthread_mutex_lock(&key_queue_mutex); |
279 | bool reboot_enabled = enable_reboot; | 314 | bool reboot_enabled = enable_reboot; |
@@ -290,14 +325,10 @@ RecoveryUI::KeyAction RecoveryUI::CheckKey(int key) { | |||
290 | } | 325 | } |
291 | 326 | ||
292 | last_key = key; | 327 | last_key = key; |
293 | 328 | return IsTextVisible() ? ENQUEUE : IGNORE; | |
294 | return ENQUEUE; | ||
295 | } | ||
296 | |||
297 | void RecoveryUI::NextCheckKeyIsLong(bool is_long_press) { | ||
298 | } | 329 | } |
299 | 330 | ||
300 | void RecoveryUI::KeyLongPress(int key) { | 331 | void RecoveryUI::KeyLongPress(int) { |
301 | } | 332 | } |
302 | 333 | ||
303 | void RecoveryUI::SetEnableReboot(bool enabled) { | 334 | void RecoveryUI::SetEnableReboot(bool enabled) { |
@@ -69,30 +69,27 @@ class RecoveryUI { | |||
69 | 69 | ||
70 | // --- key handling --- | 70 | // --- key handling --- |
71 | 71 | ||
72 | // Wait for keypress and return it. May return -1 after timeout. | 72 | // Wait for a key and return it. May return -1 after timeout. |
73 | virtual int WaitKey(); | 73 | virtual int WaitKey(); |
74 | 74 | ||
75 | virtual bool IsKeyPressed(int key); | 75 | virtual bool IsKeyPressed(int key); |
76 | virtual bool IsLongPress(); | ||
76 | 77 | ||
77 | // Erase any queued-up keys. | 78 | // Erase any queued-up keys. |
78 | virtual void FlushKeys(); | 79 | virtual void FlushKeys(); |
79 | 80 | ||
80 | // Called on each keypress, even while operations are in progress. | 81 | // Called on each key press, even while operations are in progress. |
81 | // Return value indicates whether an immediate operation should be | 82 | // Return value indicates whether an immediate operation should be |
82 | // triggered (toggling the display, rebooting the device), or if | 83 | // triggered (toggling the display, rebooting the device), or if |
83 | // the key should be enqueued for use by the main thread. | 84 | // the key should be enqueued for use by the main thread. |
84 | enum KeyAction { ENQUEUE, TOGGLE, REBOOT, IGNORE }; | 85 | enum KeyAction { ENQUEUE, TOGGLE, REBOOT, IGNORE }; |
85 | virtual KeyAction CheckKey(int key); | 86 | virtual KeyAction CheckKey(int key, bool is_long_press); |
86 | |||
87 | // Called immediately before each call to CheckKey(), tell you if | ||
88 | // the key was long-pressed. | ||
89 | virtual void NextCheckKeyIsLong(bool is_long_press); | ||
90 | 87 | ||
91 | // Called when a key is held down long enough to have been a | 88 | // Called when a key is held down long enough to have been a |
92 | // long-press (but before the key is released). This means that | 89 | // long-press (but before the key is released). This means that |
93 | // if the key is eventually registered (released without any other | 90 | // if the key is eventually registered (released without any other |
94 | // keys being pressed in the meantime), NextCheckKeyIsLong() will | 91 | // keys being pressed in the meantime), CheckKey will be called with |
95 | // be called with "true". | 92 | // 'is_long_press' true. |
96 | virtual void KeyLongPress(int key); | 93 | virtual void KeyLongPress(int key); |
97 | 94 | ||
98 | // Normally in recovery there's a key sequence that triggers | 95 | // Normally in recovery there's a key sequence that triggers |
@@ -110,8 +107,8 @@ class RecoveryUI { | |||
110 | virtual void StartMenu(const char* const * headers, const char* const * items, | 107 | virtual void StartMenu(const char* const * headers, const char* const * items, |
111 | int initial_selection) = 0; | 108 | int initial_selection) = 0; |
112 | 109 | ||
113 | // Set the menu highlight to the given index, and return it (capped to | 110 | // Set the menu highlight to the given index, wrapping if necessary. |
114 | // the range [0..numitems). | 111 | // Returns the actual item selected. |
115 | virtual int SelectMenu(int sel) = 0; | 112 | virtual int SelectMenu(int sel) = 0; |
116 | 113 | ||
117 | // End menu mode, resetting the text overlay so that ui_print() | 114 | // End menu mode, resetting the text overlay so that ui_print() |
@@ -136,14 +133,20 @@ private: | |||
136 | int consecutive_power_keys; | 133 | int consecutive_power_keys; |
137 | int last_key; | 134 | int last_key; |
138 | 135 | ||
139 | typedef struct { | 136 | bool has_power_key; |
137 | bool has_up_key; | ||
138 | bool has_down_key; | ||
139 | |||
140 | struct key_timer_t { | ||
140 | RecoveryUI* ui; | 141 | RecoveryUI* ui; |
141 | int key_code; | 142 | int key_code; |
142 | int count; | 143 | int count; |
143 | } key_timer_t; | 144 | }; |
144 | 145 | ||
145 | pthread_t input_t; | 146 | pthread_t input_t; |
146 | 147 | ||
148 | void OnKeyDetected(int key_code); | ||
149 | |||
147 | static void* input_thread(void* cookie); | 150 | static void* input_thread(void* cookie); |
148 | static int input_callback(int fd, uint32_t epevents, void* data); | 151 | static int input_callback(int fd, uint32_t epevents, void* data); |
149 | void process_key(int key_code, int updown); | 152 | void process_key(int key_code, int updown); |