aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--minui/events.cpp4
-rw-r--r--minui/minui.h9
-rw-r--r--recovery.cpp6
-rw-r--r--screen_ui.cpp11
-rw-r--r--screen_ui.h6
-rw-r--r--ui.cpp79
-rw-r--r--ui.h29
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
204void ev_iterate_available_keys(ev_key_callback cb, void* data) { 204void 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
69typedef int (*ev_callback)(int fd, uint32_t epevents, void* data); 69typedef int (*ev_callback)(int fd, uint32_t epevents, void* data);
70typedef int (*ev_set_key_callback)(int code, int value, void* data); 70typedef int (*ev_set_key_callback)(int code, int value, void* data);
71typedef void (*ev_key_callback)(int code, void* data);
72 71
73int ev_init(ev_callback input_cb, void* data); 72int ev_init(ev_callback input_cb, void* data);
74void ev_exit(void); 73void ev_exit(void);
75int ev_add_fd(int fd, ev_callback cb, void* data); 74int ev_add_fd(int fd, ev_callback cb, void* data);
76int ev_sync_key_state(ev_set_key_callback set_key_cb, void* data); 75int ev_sync_key_state(ev_set_key_callback set_key_cb, void* data);
77void 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>
134void 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
645void 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;
diff --git a/ui.cpp b/ui.cpp
index 87162452..064890ea 100644
--- a/ui.cpp
+++ b/ui.cpp
@@ -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
64void 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
61void RecoveryUI::Init() { 74void 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
67int RecoveryUI::input_callback(int fd, uint32_t epevents, void* data) { 83int 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
274bool 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
260void RecoveryUI::FlushKeys() { 281void 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, 287RecoveryUI::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.
272RecoveryUI::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
297void RecoveryUI::NextCheckKeyIsLong(bool is_long_press) {
298} 329}
299 330
300void RecoveryUI::KeyLongPress(int key) { 331void RecoveryUI::KeyLongPress(int) {
301} 332}
302 333
303void RecoveryUI::SetEnableReboot(bool enabled) { 334void RecoveryUI::SetEnableReboot(bool enabled) {
diff --git a/ui.h b/ui.h
index bc728b05..0d5ab557 100644
--- a/ui.h
+++ b/ui.h
@@ -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);