1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
diff --git a/android/src/org/rockbox/RockboxActivity.java b/android/src/org/rockbox/RockboxActivity.java
index 3be9e3e..c30e302 100644
--- a/android/src/org/rockbox/RockboxActivity.java
+++ b/android/src/org/rockbox/RockboxActivity.java
@@ -113,6 +113,11 @@ public class RockboxActivity extends Activity {
     	super.onDestroy();
     	RockboxService.fb.suspend();
     }
+    
+    @Override
+    public boolean onTrackballEvent(android.view.MotionEvent event) {
+    	return RockboxService.fb.onTrackballEvent(event);
+    };

 	private void LOG(CharSequence text)
 	{
diff --git a/android/src/org/rockbox/RockboxFramebuffer.java b/android/src/org/rockbox/RockboxFramebuffer.java
index ca11de0..606ba55 100644
--- a/android/src/org/rockbox/RockboxFramebuffer.java
+++ b/android/src/org/rockbox/RockboxFramebuffer.java
@@ -70,9 +70,27 @@ public class RockboxFramebuffer extends View

 	private void LOG(CharSequence text)
 	{
-		Log.d("RockboxBootloader", (String) text);
+		Log.d("Rockbox", (String) text);
 	}

+	public boolean onTrackballEvent(MotionEvent me)
+	{
+		switch (me.getAction())
+		{
+		case MotionEvent.ACTION_MOVE:
+			buttonHandler(0, (int)(2*me.getX()), (int)(2*me.getY()));
+			break;
+		case MotionEvent.ACTION_DOWN:
+			buttonHandler(1, 0, 0);
+			break;
+		case MotionEvent.ACTION_UP:
+		case MotionEvent.ACTION_CANCEL:
+			buttonHandler(-1, 0, 0);
+			break;
+		}
+		return true;
+	}
+	
 	public boolean onTouchEvent(MotionEvent me)
 	{
 		LOG("onTouchEvent");
@@ -106,4 +124,5 @@ public class RockboxFramebuffer extends View
 	public native void set_lcd_active(int active);
 	public native void pixelHandler(int x, int y);
 	public native void touchHandler(int down);
+	public native void buttonHandler(int press, int relative_x, int relative_y);
 }
diff --git a/firmware/target/hosted/android/app/button-target.h b/firmware/target/hosted/android/app/button-target.h
index 329ed65..3ecb00e 100644
--- a/firmware/target/hosted/android/app/button-target.h
+++ b/firmware/target/hosted/android/app/button-target.h
@@ -40,6 +40,7 @@ int button_read_device(int *data);
 #define BUTTON_RIGHT BUTTON_MIDRIGHT
 #define BUTTON_UP    BUTTON_TOPMIDDLE
 #define BUTTON_DOWN  BUTTON_BOTTOMMIDDLE
+#define BUTTON_SELECT BUTTON_CENTER

 /* Touch Screen Area Buttons */
 #define BUTTON_TOPLEFT      0x00000010
diff --git a/firmware/target/hosted/android/button-android.c b/firmware/target/hosted/android/button-android.c
index 1172880..4f93d12 100644
--- a/firmware/target/hosted/android/button-android.c
+++ b/firmware/target/hosted/android/button-android.c
@@ -26,9 +26,11 @@
 #include "kernel.h"
 #include "system.h"
 #include "touchscreen.h"
+#include "button.h"

 static int last_y, last_x;
-
+static int last_button;
+static int last_button_tick;
 static enum {
     STATE_UNKNOWN,
     STATE_UP,
@@ -64,13 +66,55 @@ Java_org_rockbox_RockboxFramebuffer_touchHandler(JNIEnv*env, jobject this,
         last_state = STATE_UP;
 }

+/*
+ * this notifies us in an interrupt-like fashion when a hardware button is pressed */
+JNIEXPORT void JNICALL
+Java_org_rockbox_RockboxFramebuffer_buttonHandler(JNIEnv*env, jobject this,
+                                                   jint press, jint relative_x, jint relative_y)
+{
+    (void)env;
+    (void)this;
+    int btn = last_button&BUTTON_SELECT;
+
+    LOG("%s(): %d:%d:%d\n", __func__, press, relative_x, relative_y);
+    if (press > 0)
+        btn |= BUTTON_SELECT;
+    else if (press < 0)
+        btn &= ~BUTTON_SELECT;
+
+    if (relative_y < 0)
+        btn |= BUTTON_UP;
+    else if (relative_y > 0)
+        btn |= BUTTON_DOWN;
+
+    if (relative_x > 0)
+        btn |= BUTTON_RIGHT;
+    else if (relative_x < 0)
+        btn |= BUTTON_LEFT;
+
+    last_button = btn;
+    last_button_tick = current_tick;
+}
+
 void button_init_device(void)
 {
+    last_button = BUTTON_NONE;
+    last_button_tick = current_tick;
 }

 int button_read_device(int *data)
 {
-    /* get grid button/coordinates based on the current touchscreen mode */
-    int btn = touchscreen_to_pixels(last_x, last_y, data);
-    return (last_state == STATE_DOWN ? btn : 0);
+    int btn;
+    if (last_button == BUTTON_NONE)
+    {
+        /* get grid button/coordinates based on the current touchscreen mode */
+        btn = touchscreen_to_pixels(last_x, last_y, data);
+        return (last_state == STATE_DOWN ? btn : 0);
+    }
+    else
+    {
+        if (TIME_AFTER(current_tick, last_button_tick+5))
+            last_button &= BUTTON_SELECT;
+        return last_button;
+    }
 }