summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Android (Google) Code Review <android-gerrit@google.com> 2009-07-15 09:05:23 -0700
committer Android (Google) Code Review <android-gerrit@google.com> 2009-07-15 09:05:23 -0700
commit85d1f158267d64b5660e86fab0baf0432c1dcfbd (patch)
tree05c7ccd6fe0f43616538366bd52973c4ad22dccd
parent1f872d4e8675b918dafdd730100df7e865d9ce0b (diff)
parente3dd884815b2aaeec4241859722ab603e0b1466b (diff)
Merge change 7353
* changes: Implement virtual button support.
-rw-r--r--include/ui/EventHub.h5
-rw-r--r--libs/ui/EventHub.cpp29
-rw-r--r--services/java/com/android/server/InputDevice.java118
-rw-r--r--services/java/com/android/server/KeyInputQueue.java245
-rw-r--r--services/jni/com_android_server_KeyInputQueue.cpp19
5 files changed, 348 insertions, 68 deletions
diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h
index e12c4f13ea0d..d9c0af211703 100644
--- a/include/ui/EventHub.h
+++ b/include/ui/EventHub.h
@@ -73,6 +73,9 @@ public:
int getKeycodeState(int key) const;
int getKeycodeState(int32_t deviceId, int key) const;
+ status_t scancodeToKeycode(int32_t deviceId, int scancode,
+ int32_t* outKeycode, uint32_t* outFlags) const;
+
// special type codes when devices are added/removed.
enum {
DEVICE_ADDED = 0x10000000,
@@ -121,7 +124,7 @@ private:
mutable Mutex mLock;
bool mHaveFirstKeyboard;
- int32_t mFirstKeyboardId; // the API is that the build in keyboard is id 0, so map it
+ int32_t mFirstKeyboardId; // the API is that the built-in keyboard is id 0, so map it
struct device_ent {
device_t* device;
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index 13c30a795cb2..a72f055c388c 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -240,6 +240,35 @@ int EventHub::getKeycodeState(int32_t deviceId, int code) const
return 0;
}
+status_t EventHub::scancodeToKeycode(int32_t deviceId, int scancode,
+ int32_t* outKeycode, uint32_t* outFlags) const
+{
+ AutoMutex _l(mLock);
+ device_t* device = getDevice(deviceId);
+
+ if (device != NULL && device->layoutMap != NULL) {
+ status_t err = device->layoutMap->map(scancode, outKeycode, outFlags);
+ if (err == NO_ERROR) {
+ return NO_ERROR;
+ }
+ }
+
+ if (mHaveFirstKeyboard) {
+ device = getDevice(mFirstKeyboardId);
+
+ if (device != NULL && device->layoutMap != NULL) {
+ status_t err = device->layoutMap->map(scancode, outKeycode, outFlags);
+ if (err == NO_ERROR) {
+ return NO_ERROR;
+ }
+ }
+ }
+
+ *outKeycode = 0;
+ *outFlags = 0;
+ return NAME_NOT_FOUND;
+}
+
EventHub::device_t* EventHub::getDevice(int32_t deviceId) const
{
if (deviceId == 0) deviceId = mFirstKeyboardId;
diff --git a/services/java/com/android/server/InputDevice.java b/services/java/com/android/server/InputDevice.java
index 9c1f9421a818..a71c39a0b3b5 100644
--- a/services/java/com/android/server/InputDevice.java
+++ b/services/java/com/android/server/InputDevice.java
@@ -66,19 +66,56 @@ public class InputDevice {
MotionEvent generateMotion(InputDevice device, long curTime, long curTimeNano,
boolean isAbs, Display display, int orientation,
int metaState) {
- if (!changed) {
- return null;
- }
-
float scaledX = x;
float scaledY = y;
float temp;
float scaledPressure = 1.0f;
float scaledSize = 0;
int edgeFlags = 0;
+
+ int action;
+ if (down != lastDown) {
+ if (isAbs) {
+ final AbsoluteInfo absX = device.absX;
+ final AbsoluteInfo absY = device.absY;
+ if (down && absX != null && absY != null) {
+ // We don't let downs start unless we are
+ // inside of the screen. There are two reasons for
+ // this: to avoid spurious touches when holding
+ // the edges of the device near the touchscreen,
+ // and to avoid reporting events if there are virtual
+ // keys on the touchscreen outside of the display
+ // area.
+ if (scaledX < absX.minValue || scaledX > absX.maxValue
+ || scaledY < absY.minValue || scaledY > absY.maxValue) {
+ if (false) Log.v("InputDevice", "Rejecting (" + scaledX + ","
+ + scaledY + "): outside of ("
+ + absX.minValue + "," + absY.minValue
+ + ")-(" + absX.maxValue + ","
+ + absY.maxValue + ")");
+ return null;
+ }
+ }
+ } else {
+ x = y = 0;
+ }
+ lastDown = down;
+ if (down) {
+ action = MotionEvent.ACTION_DOWN;
+ downTime = curTime;
+ } else {
+ action = MotionEvent.ACTION_UP;
+ }
+ currentMove = null;
+ } else {
+ action = MotionEvent.ACTION_MOVE;
+ }
+
if (isAbs) {
- int w = display.getWidth()-1;
- int h = display.getHeight()-1;
+ final int dispW = display.getWidth()-1;
+ final int dispH = display.getHeight()-1;
+ int w = dispW;
+ int h = dispH;
if (orientation == Surface.ROTATION_90
|| orientation == Surface.ROTATION_270) {
int tmp = w;
@@ -120,16 +157,17 @@ public class InputDevice {
break;
}
- if (scaledX == 0) {
- edgeFlags += MotionEvent.EDGE_LEFT;
- } else if (scaledX == display.getWidth() - 1.0f) {
- edgeFlags += MotionEvent.EDGE_RIGHT;
- }
-
- if (scaledY == 0) {
- edgeFlags += MotionEvent.EDGE_TOP;
- } else if (scaledY == display.getHeight() - 1.0f) {
- edgeFlags += MotionEvent.EDGE_BOTTOM;
+ if (action != MotionEvent.ACTION_DOWN) {
+ if (scaledX <= 0) {
+ edgeFlags += MotionEvent.EDGE_LEFT;
+ } else if (scaledX >= dispW) {
+ edgeFlags += MotionEvent.EDGE_RIGHT;
+ }
+ if (scaledY <= 0) {
+ edgeFlags += MotionEvent.EDGE_TOP;
+ } else if (scaledY >= dispH) {
+ edgeFlags += MotionEvent.EDGE_BOTTOM;
+ }
}
} else {
@@ -153,41 +191,25 @@ public class InputDevice {
}
}
- changed = false;
- if (down != lastDown) {
- int action;
- lastDown = down;
- if (down) {
- action = MotionEvent.ACTION_DOWN;
- downTime = curTime;
- } else {
- action = MotionEvent.ACTION_UP;
- }
- currentMove = null;
- if (!isAbs) {
- x = y = 0;
- }
- return MotionEvent.obtainNano(downTime, curTime, curTimeNano, action,
- scaledX, scaledY, scaledPressure, scaledSize, metaState,
- xPrecision, yPrecision, device.id, edgeFlags);
- } else {
- if (currentMove != null) {
- if (false) Log.i("InputDevice", "Adding batch x=" + scaledX
- + " y=" + scaledY + " to " + currentMove);
- currentMove.addBatch(curTime, scaledX, scaledY,
- scaledPressure, scaledSize, metaState);
- if (WindowManagerPolicy.WATCH_POINTER) {
- Log.i("KeyInputQueue", "Updating: " + currentMove);
- }
- return null;
+ if (currentMove != null) {
+ if (false) Log.i("InputDevice", "Adding batch x=" + scaledX
+ + " y=" + scaledY + " to " + currentMove);
+ currentMove.addBatch(curTime, scaledX, scaledY,
+ scaledPressure, scaledSize, metaState);
+ if (WindowManagerPolicy.WATCH_POINTER) {
+ Log.i("KeyInputQueue", "Updating: " + currentMove);
}
- MotionEvent me = MotionEvent.obtainNano(downTime, curTime, curTimeNano,
- MotionEvent.ACTION_MOVE, scaledX, scaledY,
- scaledPressure, scaledSize, metaState,
- xPrecision, yPrecision, device.id, edgeFlags);
+ return null;
+ }
+
+ MotionEvent me = MotionEvent.obtainNano(downTime, curTime,
+ curTimeNano, action, scaledX, scaledY,
+ scaledPressure, scaledSize, metaState,
+ xPrecision, yPrecision, device.id, edgeFlags);
+ if (action == MotionEvent.ACTION_MOVE) {
currentMove = me;
- return me;
}
+ return me;
}
}
diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java
index 78cdf8b97eef..fd6b813e7ada 100644
--- a/services/java/com/android/server/KeyInputQueue.java
+++ b/services/java/com/android/server/KeyInputQueue.java
@@ -30,10 +30,20 @@ import android.view.RawInputEvent;
import android.view.Surface;
import android.view.WindowManagerPolicy;
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+
public abstract class KeyInputQueue {
static final String TAG = "KeyInputQueue";
- SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>();
+ static final boolean DEBUG_VIRTUAL_KEYS = false;
+
+ final SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>();
+ final ArrayList<VirtualKey> mVirtualKeys = new ArrayList<VirtualKey>();
int mGlobalMetaState = 0;
boolean mHaveGlobalMetaState = false;
@@ -44,10 +54,14 @@ public abstract class KeyInputQueue {
int mCacheCount;
Display mDisplay = null;
+ int mDisplayWidth;
+ int mDisplayHeight;
int mOrientation = Surface.ROTATION_0;
int[] mKeyRotationMap = null;
+ VirtualKey mPressedVirtualKey = null;
+
PowerManager.WakeLock mWakeLock;
static final int[] KEY_90_MAP = new int[] {
@@ -110,11 +124,106 @@ public abstract class KeyInputQueue {
QueuedEvent next;
}
+ /**
+ * A key that exists as a part of the touch-screen, outside of the normal
+ * display area of the screen.
+ */
+ static class VirtualKey {
+ int scancode;
+ int centerx;
+ int centery;
+ int width;
+ int height;
+
+ int hitLeft;
+ int hitTop;
+ int hitRight;
+ int hitBottom;
+
+ InputDevice lastDevice;
+ int lastKeycode;
+
+ boolean checkHit(int x, int y) {
+ return (x >= hitLeft && x <= hitRight
+ && y >= hitTop && y <= hitBottom);
+ }
+
+ void computeHitRect(InputDevice dev, int dw, int dh) {
+ if (dev == lastDevice) {
+ return;
+ }
+
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "computeHitRect for " + scancode
+ + ": dev=" + dev + " absX=" + dev.absX + " absY=" + dev.absY);
+
+ lastDevice = dev;
+
+ int minx = dev.absX.minValue;
+ int maxx = dev.absX.maxValue;
+
+ int halfw = width/2;
+ int left = centerx - halfw;
+ int right = centerx + halfw;
+ hitLeft = minx + ((left*maxx-minx)/dw);
+ hitRight = minx + ((right*maxx-minx)/dw);
+
+ int miny = dev.absY.minValue;
+ int maxy = dev.absY.maxValue;
+
+ int halfh = height/2;
+ int top = centery - halfh;
+ int bottom = centery + halfh;
+ hitTop = miny + ((top*maxy-miny)/dh);
+ hitBottom = miny + ((bottom*maxy-miny)/dh);
+ }
+ }
+
KeyInputQueue(Context context) {
if (MEASURE_LATENCY) {
lt = new LatencyTimer(100, 1000);
}
+ try {
+ FileInputStream fis = new FileInputStream(
+ "/sys/board_properties/virtualkeys.synaptics-rmi-touchscreen");
+ InputStreamReader isr = new InputStreamReader(fis);
+ BufferedReader br = new BufferedReader(isr);
+ String str = br.readLine();
+ if (str != null) {
+ String[] it = str.split(":");
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "***** VIRTUAL KEYS: " + it);
+ final int N = it.length-6;
+ for (int i=0; i<=N; i+=6) {
+ if (!"0x01".equals(it[i])) {
+ Log.w(TAG, "Unknown virtual key type at elem #" + i
+ + ": " + it[i]);
+ continue;
+ }
+ try {
+ VirtualKey sb = new VirtualKey();
+ sb.scancode = Integer.parseInt(it[i+1]);
+ sb.centerx = Integer.parseInt(it[i+2]);
+ sb.centery = Integer.parseInt(it[i+3]);
+ sb.width = Integer.parseInt(it[i+4]);
+ sb.height = Integer.parseInt(it[i+5]);
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Virtual key "
+ + sb.scancode + ": center=" + sb.centerx + ","
+ + sb.centery + " size=" + sb.width + "x"
+ + sb.height);
+ mVirtualKeys.add(sb);
+ } catch (NumberFormatException e) {
+ Log.w(TAG, "Bad number at region " + i + " in: "
+ + str, e);
+ }
+ }
+ }
+ br.close();
+ } catch (FileNotFoundException e) {
+ Log.i(TAG, "No virtual keys found");
+ } catch (IOException e) {
+ Log.w(TAG, "Error reading virtual keys", e);
+ }
+
PowerManager pm = (PowerManager)context.getSystemService(
Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
@@ -131,6 +240,12 @@ public abstract class KeyInputQueue {
public void setDisplay(Display display) {
mDisplay = display;
+
+ // We assume at this point that the display dimensions reflect the
+ // natural, unrotated display. We will perform hit tests for soft
+ // buttons based on that display.
+ mDisplayWidth = display.getWidth();
+ mDisplayHeight = display.getHeight();
}
public void getInputConfiguration(Configuration config) {
@@ -173,6 +288,7 @@ public abstract class KeyInputQueue {
public static native int getScancodeState(int deviceId, int sw);
public static native int getKeycodeState(int sw);
public static native int getKeycodeState(int deviceId, int sw);
+ public static native int scancodeToKeycode(int deviceId, int scancode);
public static native boolean hasKeys(int[] keycodes, boolean[] keyExists);
public static KeyEvent newKeyEvent(InputDevice device, long downTime,
@@ -339,36 +455,127 @@ public abstract class KeyInputQueue {
}
MotionEvent me;
- me = di.mAbs.generateMotion(di, curTime, curTimeNano, true,
- mDisplay, mOrientation, mGlobalMetaState);
- if (false) Log.v(TAG, "Absolute: x=" + di.mAbs.x
- + " y=" + di.mAbs.y + " ev=" + me);
- if (me != null) {
- if (WindowManagerPolicy.WATCH_POINTER) {
- Log.i(TAG, "Enqueueing: " + me);
+
+ InputDevice.MotionState ms = di.mAbs;
+ if (ms.changed) {
+ ms.changed = false;
+
+ boolean doMotion = true;
+
+ // Look for virtual buttons.
+ VirtualKey vk = mPressedVirtualKey;
+ if (vk != null) {
+ doMotion = false;
+ if (!ms.down) {
+ mPressedVirtualKey = null;
+ ms.lastDown = ms.down;
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG,
+ "Generate key up for: " + vk.scancode);
+ addLocked(di, curTimeNano, ev.flags,
+ RawInputEvent.CLASS_KEYBOARD,
+ newKeyEvent(di, di.mDownTime,
+ curTime, false,
+ vk.lastKeycode,
+ 0, vk.scancode, 0));
+ }
+ } else if (ms.down && !ms.lastDown) {
+ vk = findSoftButton(di);
+ if (vk != null) {
+ doMotion = false;
+ mPressedVirtualKey = vk;
+ vk.lastKeycode = scancodeToKeycode(
+ di.id, vk.scancode);
+ ms.lastDown = ms.down;
+ di.mDownTime = curTime;
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG,
+ "Generate key down for: " + vk.scancode
+ + " (keycode=" + vk.lastKeycode + ")");
+ addLocked(di, curTimeNano, ev.flags,
+ RawInputEvent.CLASS_KEYBOARD,
+ newKeyEvent(di, di.mDownTime,
+ curTime, true,
+ vk.lastKeycode, 0,
+ vk.scancode, 0));
+ }
+ }
+
+ if (doMotion) {
+ me = ms.generateMotion(di, curTime,
+ curTimeNano, true, mDisplay,
+ mOrientation, mGlobalMetaState);
+ if (false) Log.v(TAG, "Absolute: x=" + di.mAbs.x
+ + " y=" + di.mAbs.y + " ev=" + me);
+ if (me != null) {
+ if (WindowManagerPolicy.WATCH_POINTER) {
+ Log.i(TAG, "Enqueueing: " + me);
+ }
+ addLocked(di, curTimeNano, ev.flags,
+ RawInputEvent.CLASS_TOUCHSCREEN, me);
+ }
}
- addLocked(di, curTimeNano, ev.flags,
- RawInputEvent.CLASS_TOUCHSCREEN, me);
}
- me = di.mRel.generateMotion(di, curTime, curTimeNano, false,
- mDisplay, mOrientation, mGlobalMetaState);
- if (false) Log.v(TAG, "Relative: x=" + di.mRel.x
- + " y=" + di.mRel.y + " ev=" + me);
- if (me != null) {
- addLocked(di, curTimeNano, ev.flags,
- RawInputEvent.CLASS_TRACKBALL, me);
+
+ ms = di.mRel;
+ if (ms.changed) {
+ ms.changed = false;
+
+ me = ms.generateMotion(di, curTime,
+ curTimeNano, false, mDisplay,
+ mOrientation, mGlobalMetaState);
+ if (false) Log.v(TAG, "Relative: x=" + di.mRel.x
+ + " y=" + di.mRel.y + " ev=" + me);
+ if (me != null) {
+ addLocked(di, curTimeNano, ev.flags,
+ RawInputEvent.CLASS_TRACKBALL, me);
+ }
}
}
}
}
}
- }
- catch (RuntimeException exc) {
+
+ } catch (RuntimeException exc) {
Log.e(TAG, "InputReaderThread uncaught exception", exc);
}
}
};
+ private VirtualKey findSoftButton(InputDevice dev) {
+ final int N = mVirtualKeys.size();
+ if (N <= 0) {
+ return null;
+ }
+
+ final InputDevice.AbsoluteInfo absx = dev.absX;
+ final InputDevice.AbsoluteInfo absy = dev.absY;
+ final InputDevice.MotionState absm = dev.mAbs;
+ if (absx == null || absy == null || absm == null) {
+ return null;
+ }
+
+ if (absm.x >= absx.minValue && absm.x <= absx.maxValue
+ && absm.y >= absy.minValue && absm.y <= absy.maxValue) {
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Input (" + absm.x
+ + "," + absm.y + ") inside of display");
+ return null;
+ }
+
+ for (int i=0; i<N; i++) {
+ VirtualKey sb = mVirtualKeys.get(i);
+ sb.computeHitRect(dev, mDisplayWidth, mDisplayHeight);
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Hit test (" + absm.x + ","
+ + absm.y + ") in code " + sb.scancode + " - (" + sb.hitLeft
+ + "," + sb.hitTop + ")-(" + sb.hitRight + ","
+ + sb.hitBottom + ")");
+ if (sb.checkHit(absm.x, absm.y)) {
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Hit!");
+ return sb;
+ }
+ }
+
+ return null;
+ }
+
/**
* Returns a new meta state for the given keys and old state.
*/
diff --git a/services/jni/com_android_server_KeyInputQueue.cpp b/services/jni/com_android_server_KeyInputQueue.cpp
index 63830d59c24a..afca1f7ec34f 100644
--- a/services/jni/com_android_server_KeyInputQueue.cpp
+++ b/services/jni/com_android_server_KeyInputQueue.cpp
@@ -205,6 +205,23 @@ android_server_KeyInputQueue_getKeycodeStateDevice(JNIEnv* env, jobject clazz,
return st;
}
+static jint
+android_server_KeyInputQueue_scancodeToKeycode(JNIEnv* env, jobject clazz,
+ jint deviceId, jint scancode)
+{
+ jint res = 0;
+ gLock.lock();
+ if (gHub != NULL) {
+ int32_t keycode;
+ uint32_t flags;
+ gHub->scancodeToKeycode(deviceId, scancode, &keycode, &flags);
+ res = keycode;
+ }
+ gLock.unlock();
+
+ return res;
+}
+
static jboolean
android_server_KeyInputQueue_hasKeys(JNIEnv* env, jobject clazz,
jintArray keyCodes, jbooleanArray outFlags)
@@ -254,6 +271,8 @@ static JNINativeMethod gInputMethods[] = {
(void*) android_server_KeyInputQueue_getKeycodeStateDevice },
{ "hasKeys", "([I[Z)Z",
(void*) android_server_KeyInputQueue_hasKeys },
+ { "scancodeToKeycode", "(II)I",
+ (void*) android_server_KeyInputQueue_scancodeToKeycode },
};
int register_android_server_KeyInputQueue(JNIEnv* env)