minui: events: refactor event acquisition

Events are now delivered through a callback mechanism during
a call to ev_dispatch(). This will allow us to extend the events
code to handle other devices/fds, not just input. One such example
is the ability to process uevents.

During initialization, we provide an input callback to ev_init
that gets called when a new event is encountered during dispatch.

ev_get has been removed and replaced with ev_get_input() helper
function that can be called from inside the callback to attempt
to get an input event.

The existing client of ev_get in recovery has been split up such
that the input thread just calls ev_wait(); ev_dispatch(); and
the input_callback handles individual events by using the
ev_get_input() helper.

Change-Id: I24d8e71bd1533876b4ab1ae751ba200fea43c049
Signed-off-by: Dima Zavin <dima@android.com>
diff --git a/minui/events.c b/minui/events.c
index 3aed2a8..eca3bc7 100644
--- a/minui/events.c
+++ b/minui/events.c
@@ -26,10 +26,18 @@
 
 #define MAX_DEVICES 16
 
-static struct pollfd ev_fds[MAX_DEVICES];
-static unsigned ev_count = 0;
+struct fd_info {
+    ev_callback cb;
+    void *data;
+};
 
-int ev_init(void)
+static struct pollfd ev_fds[MAX_DEVICES];
+static struct fd_info ev_fdinfo[MAX_DEVICES];
+
+static unsigned ev_count = 0;
+static unsigned ev_dev_count = 0;
+
+int ev_init(ev_callback input_cb, void *data)
 {
     DIR *dir;
     struct dirent *de;
@@ -45,6 +53,8 @@
 
             ev_fds[ev_count].fd = fd;
             ev_fds[ev_count].events = POLLIN;
+            ev_fdinfo[ev_count].cb = input_cb;
+            ev_fdinfo[ev_count].data = data;
             ev_count++;
             if(ev_count == MAX_DEVICES) break;
         }
@@ -60,23 +70,36 @@
     }
 }
 
-int ev_get(struct input_event *ev, unsigned dont_wait)
+int ev_wait(int timeout)
 {
     int r;
+
+    r = poll(ev_fds, ev_count, timeout);
+    if (r <= 0)
+        return -1;
+    return 0;
+}
+
+void ev_dispatch(void)
+{
     unsigned n;
+    int ret;
 
-    do {
-        r = poll(ev_fds, ev_count, dont_wait ? 0 : -1);
+    for (n = 0; n < ev_count; n++) {
+        ev_callback cb = ev_fdinfo[n].cb;
+        if (cb && (ev_fds[n].revents & ev_fds[n].events))
+            cb(ev_fds[n].fd, ev_fds[n].revents, ev_fdinfo[n].data);
+    }
+}
 
-        if(r > 0) {
-            for(n = 0; n < ev_count; n++) {
-                if(ev_fds[n].revents & POLLIN) {
-                    r = read(ev_fds[n].fd, ev, sizeof(*ev));
-                    if(r == sizeof(*ev)) return 0;
-                }
-            }
-        }
-    } while(dont_wait == 0);
+int ev_get_input(int fd, short revents, struct input_event *ev)
+{
+    int r;
 
+    if (revents & POLLIN) {
+        r = read(fd, ev, sizeof(*ev));
+        if (r == sizeof(*ev))
+            return 0;
+    }
     return -1;
 }
diff --git a/minui/minui.h b/minui/minui.h
index 2284a33..5a4168c 100644
--- a/minui/minui.h
+++ b/minui/minui.h
@@ -45,9 +45,20 @@
 // see http://www.mjmwired.net/kernel/Documentation/input/ for info.
 struct input_event;
 
-int ev_init(void);
+typedef int (*ev_callback)(int fd, short revents, void *data);
+
+int ev_init(ev_callback input_cb, void *data);
 void ev_exit(void);
-int ev_get(struct input_event *ev, unsigned dont_wait);
+
+/* timeout has the same semantics as for poll
+ *    0 : don't block
+ *  < 0 : block forever
+ *  > 0 : block for 'timeout' milliseconds
+ */
+int ev_wait(int timeout);
+
+int ev_get_input(int fd, short revents, struct input_event *ev);
+void ev_dispatch(void);
 
 // Resources
 
diff --git a/ui.c b/ui.c
index 4e41bc9..d08f7d3 100644
--- a/ui.c
+++ b/ui.c
@@ -295,71 +295,83 @@
     return NULL;
 }
 
+static int rel_sum = 0;
+
+static int input_callback(int fd, short revents, void *data)
+{
+    struct input_event ev;
+    int ret;
+    int fake_key = 0;
+
+    ret = ev_get_input(fd, revents, &ev);
+    if (ret)
+        return -1;
+
+    if (ev.type == EV_SYN) {
+        return 0;
+    } else if (ev.type == EV_REL) {
+        if (ev.code == REL_Y) {
+            // accumulate the up or down motion reported by
+            // the trackball.  When it exceeds a threshold
+            // (positive or negative), fake an up/down
+            // key event.
+            rel_sum += ev.value;
+            if (rel_sum > 3) {
+                fake_key = 1;
+                ev.type = EV_KEY;
+                ev.code = KEY_DOWN;
+                ev.value = 1;
+                rel_sum = 0;
+            } else if (rel_sum < -3) {
+                fake_key = 1;
+                ev.type = EV_KEY;
+                ev.code = KEY_UP;
+                ev.value = 1;
+                rel_sum = 0;
+            }
+        }
+    } else {
+        rel_sum = 0;
+    }
+
+    if (ev.type != EV_KEY || ev.code > KEY_MAX)
+        return 0;
+
+    pthread_mutex_lock(&key_queue_mutex);
+    if (!fake_key) {
+        // our "fake" keys only report a key-down event (no
+        // key-up), so don't record them in the key_pressed
+        // table.
+        key_pressed[ev.code] = ev.value;
+    }
+    const int queue_max = sizeof(key_queue) / sizeof(key_queue[0]);
+    if (ev.value > 0 && key_queue_len < queue_max) {
+        key_queue[key_queue_len++] = ev.code;
+        pthread_cond_signal(&key_queue_cond);
+    }
+    pthread_mutex_unlock(&key_queue_mutex);
+
+    if (ev.value > 0 && device_toggle_display(key_pressed, ev.code)) {
+        pthread_mutex_lock(&gUpdateMutex);
+        show_text = !show_text;
+        if (show_text) show_text_ever = 1;
+        update_screen_locked();
+        pthread_mutex_unlock(&gUpdateMutex);
+    }
+
+    if (ev.value > 0 && device_reboot_now(key_pressed, ev.code)) {
+        android_reboot(ANDROID_RB_RESTART, 0, 0);
+    }
+
+    return 0;
+}
+
 // Reads input events, handles special hot keys, and adds to the key queue.
 static void *input_thread(void *cookie)
 {
-    int rel_sum = 0;
-    int fake_key = 0;
     for (;;) {
-        // wait for the next key event
-        struct input_event ev;
-        do {
-            ev_get(&ev, 0);
-
-            if (ev.type == EV_SYN) {
-                continue;
-            } else if (ev.type == EV_REL) {
-                if (ev.code == REL_Y) {
-                    // accumulate the up or down motion reported by
-                    // the trackball.  When it exceeds a threshold
-                    // (positive or negative), fake an up/down
-                    // key event.
-                    rel_sum += ev.value;
-                    if (rel_sum > 3) {
-                        fake_key = 1;
-                        ev.type = EV_KEY;
-                        ev.code = KEY_DOWN;
-                        ev.value = 1;
-                        rel_sum = 0;
-                    } else if (rel_sum < -3) {
-                        fake_key = 1;
-                        ev.type = EV_KEY;
-                        ev.code = KEY_UP;
-                        ev.value = 1;
-                        rel_sum = 0;
-                    }
-                }
-            } else {
-                rel_sum = 0;
-            }
-        } while (ev.type != EV_KEY || ev.code > KEY_MAX);
-
-        pthread_mutex_lock(&key_queue_mutex);
-        if (!fake_key) {
-            // our "fake" keys only report a key-down event (no
-            // key-up), so don't record them in the key_pressed
-            // table.
-            key_pressed[ev.code] = ev.value;
-        }
-        fake_key = 0;
-        const int queue_max = sizeof(key_queue) / sizeof(key_queue[0]);
-        if (ev.value > 0 && key_queue_len < queue_max) {
-            key_queue[key_queue_len++] = ev.code;
-            pthread_cond_signal(&key_queue_cond);
-        }
-        pthread_mutex_unlock(&key_queue_mutex);
-
-        if (ev.value > 0 && device_toggle_display(key_pressed, ev.code)) {
-            pthread_mutex_lock(&gUpdateMutex);
-            show_text = !show_text;
-            if (show_text) show_text_ever = 1;
-            update_screen_locked();
-            pthread_mutex_unlock(&gUpdateMutex);
-        }
-
-        if (ev.value > 0 && device_reboot_now(key_pressed, ev.code)) {
-            android_reboot(ANDROID_RB_RESTART, 0, 0);
-        }
+        if (!ev_wait(-1))
+            ev_dispatch();
     }
     return NULL;
 }
@@ -367,7 +379,7 @@
 void ui_init(void)
 {
     gr_init();
-    ev_init();
+    ev_init(input_callback, NULL);
 
     text_col = text_row = 0;
     text_rows = gr_fb_height() / CHAR_HEIGHT;