summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.xml55
-rwxr-xr-xcore/java/android/view/InputDevice.java32
-rw-r--r--core/java/android/view/MotionEvent.java34
-rw-r--r--include/ui/EventHub.h76
-rw-r--r--include/ui/Input.h83
-rw-r--r--include/ui/InputDevice.h353
-rw-r--r--include/ui/InputManager.h49
-rw-r--r--include/ui/InputReader.h753
-rw-r--r--libs/ui/Android.mk1
-rw-r--r--libs/ui/EventHub.cpp233
-rw-r--r--libs/ui/Input.cpp59
-rw-r--r--libs/ui/InputDevice.cpp729
-rw-r--r--libs/ui/InputManager.cpp33
-rw-r--r--libs/ui/InputReader.cpp2942
-rw-r--r--native/android/input.cpp78
-rw-r--r--native/include/android/input.h94
-rw-r--r--services/java/com/android/server/InputManager.java121
-rw-r--r--services/java/com/android/server/WindowManagerService.java22
-rw-r--r--services/jni/com_android_server_InputManager.cpp144
19 files changed, 3460 insertions, 2431 deletions
diff --git a/api/current.xml b/api/current.xml
index ae7ba60..1b7254f 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -173756,6 +173756,17 @@
visibility="public"
>
</method>
+<method name="getKeyboardType"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getMotionRange"
return="android.view.InputDevice.MotionRange"
abstract="false"
@@ -173804,6 +173815,39 @@
<parameter name="keyCode" type="int">
</parameter>
</method>
+<field name="KEYBOARD_TYPE_ALPHABETIC"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYBOARD_TYPE_NONE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYBOARD_TYPE_NON_ALPHABETIC"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="MOTION_RANGE_ORIENTATION"
type="int"
transient="false"
@@ -173903,6 +173947,17 @@
visibility="public"
>
</field>
+<field name="SOURCE_ANY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-256"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="SOURCE_CLASS_BUTTON"
type="int"
transient="false"
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 21c2976..d5b2121 100755
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -30,11 +30,13 @@ package android.view;
* As a further wrinkle, different kinds of input sources uses different coordinate systems
* to describe motion events. Refer to the comments on the input source constants for
* the appropriate interpretation.
+ * </p>
*/
public final class InputDevice {
private int mId;
private String mName;
private int mSources;
+ private int mKeyboardType;
/**
* A mask for input source classes.
@@ -173,6 +175,12 @@ public final class InputDevice {
* @see #SOURCE_CLASS_JOYSTICK
*/
public static final int SOURCE_JOYSTICK_RIGHT = 0x02000000 | SOURCE_CLASS_JOYSTICK;
+
+ /**
+ * A special input source constant that is used when filtering input devices
+ * to match devices that provide any type of input source.
+ */
+ public static final int SOURCE_ANY = 0xffffff00;
/**
* Constant for retrieving the range of values for {@link MotionEvent.PointerCoords#x}.
@@ -237,6 +245,22 @@ public final class InputDevice {
* @see #getMotionRange
*/
public static final int MOTION_RANGE_ORIENTATION = 8;
+
+ /**
+ * There is no keyboard.
+ */
+ public static final int KEYBOARD_TYPE_NONE = 0;
+
+ /**
+ * The keyboard is not fully alphabetic. It may be a numeric keypad or an assortment
+ * of buttons that are not mapped as alphabetic keys suitable for text input.
+ */
+ public static final int KEYBOARD_TYPE_NON_ALPHABETIC = 1;
+
+ /**
+ * The keyboard supports a complement of alphabetic keys.
+ */
+ public static final int KEYBOARD_TYPE_ALPHABETIC = 2;
/**
* Gets information about the input device with the specified id.
@@ -265,6 +289,14 @@ public final class InputDevice {
}
/**
+ * Gets the keyboard type.
+ * @return The keyboard type.
+ */
+ public int getKeyboardType() {
+ return mKeyboardType;
+ }
+
+ /**
* Gets the key character map associated with this input device.
* @return The key character map.
*/
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 13360d9..0e78570 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -181,61 +181,61 @@ public final class MotionEvent extends InputEvent implements Parcelable {
* Offset for the sample's X coordinate.
* @hide
*/
- static public final int SAMPLE_X = 0;
+ static private final int SAMPLE_X = 0;
/**
* Offset for the sample's Y coordinate.
* @hide
*/
- static public final int SAMPLE_Y = 1;
+ static private final int SAMPLE_Y = 1;
/**
* Offset for the sample's pressure.
* @hide
*/
- static public final int SAMPLE_PRESSURE = 2;
+ static private final int SAMPLE_PRESSURE = 2;
/**
* Offset for the sample's size
* @hide
*/
- static public final int SAMPLE_SIZE = 3;
+ static private final int SAMPLE_SIZE = 3;
/**
* Offset for the sample's touch major axis length.
* @hide
*/
- static public final int SAMPLE_TOUCH_MAJOR = 4;
+ static private final int SAMPLE_TOUCH_MAJOR = 4;
/**
* Offset for the sample's touch minor axis length.
* @hide
*/
- static public final int SAMPLE_TOUCH_MINOR = 5;
+ static private final int SAMPLE_TOUCH_MINOR = 5;
/**
* Offset for the sample's tool major axis length.
* @hide
*/
- static public final int SAMPLE_TOOL_MAJOR = 6;
+ static private final int SAMPLE_TOOL_MAJOR = 6;
/**
* Offset for the sample's tool minor axis length.
* @hide
*/
- static public final int SAMPLE_TOOL_MINOR = 7;
+ static private final int SAMPLE_TOOL_MINOR = 7;
/**
* Offset for the sample's orientation.
* @hide
*/
- static public final int SAMPLE_ORIENTATION = 8;
+ static private final int SAMPLE_ORIENTATION = 8;
/**
* Number of data items for each sample.
* @hide
*/
- static public final int NUM_SAMPLE_DATA = 9;
+ static private final int NUM_SAMPLE_DATA = 9;
/**
* Number of possible pointers.
@@ -918,7 +918,7 @@ public final class MotionEvent extends InputEvent implements Parcelable {
* upwards, is perfectly circular or is of unknown orientation. A positive angle
* indicates that the major axis of contact is oriented to the right. A negative angle
* indicates that the major axis of contact is oriented to the left.
- * The full range is from -PI/4 radians (finger pointing fully left) to PI/4 radians
+ * The full range is from -PI/2 radians (finger pointing fully left) to PI/2 radians
* (finger pointing fully right).
* @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
* (the first pointer that is down) to {@link #getPointerCount()}-1.
@@ -1614,28 +1614,28 @@ public final class MotionEvent extends InputEvent implements Parcelable {
* upwards, is perfectly circular or is of unknown orientation. A positive angle
* indicates that the major axis of contact is oriented to the right. A negative angle
* indicates that the major axis of contact is oriented to the left.
- * The full range is from -PI/4 radians (finger pointing fully left) to PI/4 radians
+ * The full range is from -PI/2 radians (finger pointing fully left) to PI/2 radians
* (finger pointing fully right).
*/
public float orientation;
/*
- private static final float PI_8 = (float) (Math.PI / 8);
+ private static final float PI_4 = (float) (Math.PI / 4);
public float getTouchWidth() {
- return Math.abs(orientation) > PI_8 ? touchMajor : touchMinor;
+ return Math.abs(orientation) > PI_4 ? touchMajor : touchMinor;
}
public float getTouchHeight() {
- return Math.abs(orientation) > PI_8 ? touchMinor : touchMajor;
+ return Math.abs(orientation) > PI_4 ? touchMinor : touchMajor;
}
public float getToolWidth() {
- return Math.abs(orientation) > PI_8 ? toolMajor : toolMinor;
+ return Math.abs(orientation) > PI_4 ? toolMajor : toolMinor;
}
public float getToolHeight() {
- return Math.abs(orientation) > PI_8 ? toolMinor : toolMajor;
+ return Math.abs(orientation) > PI_4 ? toolMinor : toolMajor;
}
*/
}
diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h
index 5be17d3..dab35b3 100644
--- a/include/ui/EventHub.h
+++ b/include/ui/EventHub.h
@@ -60,6 +60,31 @@ namespace android {
class KeyLayoutMap;
/*
+ * A raw event as retrieved from the EventHub.
+ */
+struct RawEvent {
+ nsecs_t when;
+ int32_t deviceId;
+ int32_t type;
+ int32_t scanCode;
+ int32_t keyCode;
+ int32_t value;
+ uint32_t flags;
+};
+
+/* Describes an absolute axis. */
+struct RawAbsoluteAxisInfo {
+ bool valid; // true if the information is valid, false otherwise
+
+ int32_t minValue; // minimum value
+ int32_t maxValue; // maximum value
+ int32_t flat; // center flat position, eg. flat == 8 means center is between -8 and 8
+ int32_t fuzz; // error tolerance, eg. fuzz == 4 means value is +/- 4 due to noise
+
+ inline int32_t getRange() { return maxValue - minValue; }
+};
+
+/*
* Input device classes.
*/
enum {
@@ -82,7 +107,10 @@ enum {
INPUT_DEVICE_CLASS_DPAD = 0x00000020,
/* The input device is a gamepad (implies keyboard). */
- INPUT_DEVICE_CLASS_GAMEPAD = 0x00000040
+ INPUT_DEVICE_CLASS_GAMEPAD = 0x00000040,
+
+ /* The input device has switches. */
+ INPUT_DEVICE_CLASS_SWITCH = 0x00000080,
};
/*
@@ -114,8 +142,8 @@ public:
virtual String8 getDeviceName(int32_t deviceId) const = 0;
- virtual int getAbsoluteInfo(int32_t deviceId, int axis, int *outMinValue,
- int* outMaxValue, int* outFlat, int* outFuzz) const = 0;
+ virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
+ RawAbsoluteAxisInfo* outAxisInfo) const = 0;
virtual status_t scancodeToKeycode(int32_t deviceId, int scancode,
int32_t* outKeycode, uint32_t* outFlags) const = 0;
@@ -131,26 +159,19 @@ public:
* If the device needs to remain awake longer than that, then the caller is responsible
* for taking care of it (say, by poking the power manager user activity timer).
*/
- virtual bool getEvent(int32_t* outDeviceId, int32_t* outType,
- int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,
- int32_t* outValue, nsecs_t* outWhen) = 0;
+ virtual bool getEvent(RawEvent* outEvent) = 0;
/*
* Query current input state.
- * deviceId may be -1 to search for the device automatically, filtered by class.
- * deviceClasses may be -1 to ignore device class while searching.
*/
- virtual int32_t getScanCodeState(int32_t deviceId, int32_t deviceClasses,
- int32_t scanCode) const = 0;
- virtual int32_t getKeyCodeState(int32_t deviceId, int32_t deviceClasses,
- int32_t keyCode) const = 0;
- virtual int32_t getSwitchState(int32_t deviceId, int32_t deviceClasses,
- int32_t sw) const = 0;
+ virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const = 0;
+ virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const = 0;
+ virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const = 0;
/*
* Examine key input devices for specific framework keycode support
*/
- virtual bool hasKeys(size_t numCodes, const int32_t* keyCodes,
+ virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes,
uint8_t* outFlags) const = 0;
};
@@ -165,33 +186,28 @@ public:
virtual String8 getDeviceName(int32_t deviceId) const;
- virtual int getAbsoluteInfo(int32_t deviceId, int axis, int *outMinValue,
- int* outMaxValue, int* outFlat, int* outFuzz) const;
-
+ virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
+ RawAbsoluteAxisInfo* outAxisInfo) const;
+
virtual status_t scancodeToKeycode(int32_t deviceId, int scancode,
int32_t* outKeycode, uint32_t* outFlags) const;
virtual void addExcludedDevice(const char* deviceName);
- virtual int32_t getScanCodeState(int32_t deviceId, int32_t deviceClasses,
- int32_t scanCode) const;
- virtual int32_t getKeyCodeState(int32_t deviceId, int32_t deviceClasses,
- int32_t keyCode) const;
- virtual int32_t getSwitchState(int32_t deviceId, int32_t deviceClasses,
- int32_t sw) const;
+ virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const;
+ virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const;
+ virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const;
- virtual bool hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const;
+ virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes,
+ const int32_t* keyCodes, uint8_t* outFlags) const;
- virtual bool getEvent(int32_t* outDeviceId, int32_t* outType,
- int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,
- int32_t* outValue, nsecs_t* outWhen);
+ virtual bool getEvent(RawEvent* outEvent);
protected:
virtual ~EventHub();
private:
bool openPlatformInput(void);
- int32_t convertDeviceKey_TI_P2(int code);
int open_device(const char *device);
int close_device(const char *device);
@@ -220,6 +236,8 @@ private:
int32_t getScanCodeStateLocked(device_t* device, int32_t scanCode) const;
int32_t getKeyCodeStateLocked(device_t* device, int32_t keyCode) const;
int32_t getSwitchStateLocked(device_t* device, int32_t sw) const;
+ bool markSupportedKeyCodesLocked(device_t* device, size_t numCodes,
+ const int32_t* keyCodes, uint8_t* outFlags) const;
// Protect all internal state.
mutable Mutex mLock;
diff --git a/include/ui/Input.h b/include/ui/Input.h
index d9b1091..2385973 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -23,7 +23,10 @@
#include <android/input.h>
#include <utils/Vector.h>
+#include <utils/KeyedVector.h>
#include <utils/Timers.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
/*
* Additional private constants not defined in ndk/ui/input.h.
@@ -47,21 +50,16 @@ struct AInputEvent {
virtual ~AInputEvent() { }
};
-namespace android {
-
/*
- * A raw event as retrieved from the EventHub.
+ * Declare a concrete type for the NDK's input device forward declaration.
*/
-struct RawEvent {
- nsecs_t when;
- int32_t deviceId;
- int32_t type;
- int32_t scanCode;
- int32_t keyCode;
- int32_t value;
- uint32_t flags;
+struct AInputDevice {
+ virtual ~AInputDevice() { }
};
+
+namespace android {
+
/*
* Flags that flow alongside events in the input dispatch system to help with certain
* policy decisions such as waking from device sleep.
@@ -424,6 +422,69 @@ private:
MotionEvent mMotionEvent;
};
+/*
+ * Describes the characteristics and capabilities of an input device.
+ */
+class InputDeviceInfo {
+public:
+ InputDeviceInfo();
+ InputDeviceInfo(const InputDeviceInfo& other);
+ ~InputDeviceInfo();
+
+ struct MotionRange {
+ float min;
+ float max;
+ float flat;
+ float fuzz;
+ };
+
+ void initialize(int32_t id, const String8& name);
+
+ inline int32_t getId() const { return mId; }
+ inline const String8 getName() const { return mName; }
+ inline uint32_t getSources() const { return mSources; }
+
+ const MotionRange* getMotionRange(int32_t rangeType) const;
+
+ void addSource(uint32_t source);
+ void addMotionRange(int32_t rangeType, float min, float max, float flat, float fuzz);
+ void addMotionRange(int32_t rangeType, const MotionRange& range);
+
+ inline void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; }
+ inline int32_t getKeyboardType() const { return mKeyboardType; }
+
+private:
+ int32_t mId;
+ String8 mName;
+ uint32_t mSources;
+ int32_t mKeyboardType;
+
+ KeyedVector<int32_t, MotionRange> mMotionRanges;
+};
+
+/*
+ * Provides remote access to information about an input device.
+ *
+ * Note: This is essentially a wrapper for Binder calls into the Window Manager Service.
+ */
+class InputDeviceProxy : public RefBase, public AInputDevice {
+protected:
+ InputDeviceProxy();
+ virtual ~InputDeviceProxy();
+
+public:
+ static void getDeviceIds(Vector<int32_t>& outIds);
+
+ static sp<InputDeviceProxy> getDevice(int32_t id);
+
+ inline const InputDeviceInfo* getInfo() { return & mInfo; }
+
+ // TODO add hasKeys, keymap, etc...
+
+private:
+ InputDeviceInfo mInfo;
+};
+
} // namespace android
diff --git a/include/ui/InputDevice.h b/include/ui/InputDevice.h
deleted file mode 100644
index 3b9c70e..0000000
--- a/include/ui/InputDevice.h
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _UI_INPUT_DEVICE_H
-#define _UI_INPUT_DEVICE_H
-
-#include <ui/EventHub.h>
-#include <ui/Input.h>
-#include <utils/KeyedVector.h>
-#include <utils/threads.h>
-#include <utils/Timers.h>
-#include <utils/RefBase.h>
-#include <utils/String8.h>
-#include <utils/BitSet.h>
-
-#include <stddef.h>
-#include <unistd.h>
-
-/* Maximum pointer id value supported.
- * (This is limited by our use of BitSet32 to track pointer assignments.) */
-#define MAX_POINTER_ID 31
-
-/* Maximum number of historical samples to average. */
-#define AVERAGING_HISTORY_SIZE 5
-
-
-namespace android {
-
-extern int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState);
-extern int32_t rotateKeyCode(int32_t keyCode, int32_t orientation);
-
-
-/*
- * An input device structure tracks the state of a single input device.
- *
- * This structure is only used by ReaderThread and is not intended to be shared with
- * DispatcherThread (because that would require locking). This works out fine because
- * DispatcherThread is only interested in cooked event data anyways and does not need
- * any of the low-level data from InputDevice.
- */
-struct InputDevice {
- struct AbsoluteAxisInfo {
- bool valid; // set to true if axis parameters are known, false otherwise
-
- int32_t minValue; // minimum value
- int32_t maxValue; // maximum value
- int32_t range; // range of values, equal to maxValue - minValue
- int32_t flat; // center flat position, eg. flat == 8 means center is between -8 and 8
- int32_t fuzz; // error tolerance, eg. fuzz == 4 means value is +/- 4 due to noise
- };
-
- struct VirtualKey {
- int32_t keyCode;
- int32_t scanCode;
- uint32_t flags;
-
- // computed hit box, specified in touch screen coords based on known display size
- int32_t hitLeft;
- int32_t hitTop;
- int32_t hitRight;
- int32_t hitBottom;
-
- inline bool isHit(int32_t x, int32_t y) const {
- return x >= hitLeft && x <= hitRight && y >= hitTop && y <= hitBottom;
- }
- };
-
- struct KeyboardState {
- struct Current {
- int32_t metaState;
- nsecs_t downTime; // time of most recent key down
- } current;
-
- void reset();
- };
-
- struct TrackballState {
- struct Accumulator {
- enum {
- FIELD_BTN_MOUSE = 1,
- FIELD_REL_X = 2,
- FIELD_REL_Y = 4
- };
-
- uint32_t fields;
-
- bool btnMouse;
- int32_t relX;
- int32_t relY;
-
- inline void clear() {
- fields = 0;
- }
-
- inline bool isDirty() {
- return fields != 0;
- }
- } accumulator;
-
- struct Current {
- bool down;
- nsecs_t downTime;
- } current;
-
- struct Precalculated {
- float xScale;
- float yScale;
- float xPrecision;
- float yPrecision;
- } precalculated;
-
- void reset();
- };
-
- struct SingleTouchScreenState {
- struct Accumulator {
- enum {
- FIELD_BTN_TOUCH = 1,
- FIELD_ABS_X = 2,
- FIELD_ABS_Y = 4,
- FIELD_ABS_PRESSURE = 8,
- FIELD_ABS_TOOL_WIDTH = 16
- };
-
- uint32_t fields;
-
- bool btnTouch;
- int32_t absX;
- int32_t absY;
- int32_t absPressure;
- int32_t absToolWidth;
-
- inline void clear() {
- fields = 0;
- }
-
- inline bool isDirty() {
- return fields != 0;
- }
- } accumulator;
-
- struct Current {
- bool down;
- int32_t x;
- int32_t y;
- int32_t pressure;
- int32_t size;
- } current;
-
- void reset();
- };
-
- struct MultiTouchScreenState {
- struct Accumulator {
- enum {
- FIELD_ABS_MT_POSITION_X = 1,
- FIELD_ABS_MT_POSITION_Y = 2,
- FIELD_ABS_MT_TOUCH_MAJOR = 4,
- FIELD_ABS_MT_TOUCH_MINOR = 8,
- FIELD_ABS_MT_WIDTH_MAJOR = 16,
- FIELD_ABS_MT_WIDTH_MINOR = 32,
- FIELD_ABS_MT_ORIENTATION = 64,
- FIELD_ABS_MT_TRACKING_ID = 128
- };
-
- uint32_t pointerCount;
- struct Pointer {
- uint32_t fields;
-
- int32_t absMTPositionX;
- int32_t absMTPositionY;
- int32_t absMTTouchMajor;
- int32_t absMTTouchMinor;
- int32_t absMTWidthMajor;
- int32_t absMTWidthMinor;
- int32_t absMTOrientation;
- int32_t absMTTrackingId;
-
- inline void clear() {
- fields = 0;
- }
- } pointers[MAX_POINTERS + 1]; // + 1 to remove the need for extra range checks
-
- inline void clear() {
- pointerCount = 0;
- pointers[0].clear();
- }
-
- inline bool isDirty() {
- return pointerCount != 0;
- }
- } accumulator;
-
- void reset();
- };
-
- struct PointerData {
- uint32_t id;
- int32_t x;
- int32_t y;
- int32_t pressure;
- int32_t size;
- int32_t touchMajor;
- int32_t touchMinor;
- int32_t toolMajor;
- int32_t toolMinor;
- int32_t orientation;
- };
-
- struct TouchData {
- uint32_t pointerCount;
- PointerData pointers[MAX_POINTERS];
- BitSet32 idBits;
- uint32_t idToIndex[MAX_POINTER_ID + 1];
-
- void copyFrom(const TouchData& other);
-
- inline void clear() {
- pointerCount = 0;
- idBits.clear();
- }
- };
-
- // common state used for both single-touch and multi-touch screens after the initial
- // touch decoding has been performed
- struct TouchScreenState {
- Vector<VirtualKey> virtualKeys;
-
- struct Parameters {
- bool useBadTouchFilter;
- bool useJumpyTouchFilter;
- bool useAveragingTouchFilter;
-
- AbsoluteAxisInfo xAxis;
- AbsoluteAxisInfo yAxis;
- AbsoluteAxisInfo pressureAxis;
- AbsoluteAxisInfo sizeAxis;
- AbsoluteAxisInfo orientationAxis;
- } parameters;
-
- // The touch data of the current sample being processed.
- TouchData currentTouch;
-
- // The touch data of the previous sample that was processed. This is updated
- // incrementally while the current sample is being processed.
- TouchData lastTouch;
-
- // The time the primary pointer last went down.
- nsecs_t downTime;
-
- struct CurrentVirtualKeyState {
- enum Status {
- STATUS_UP,
- STATUS_DOWN,
- STATUS_CANCELED
- };
-
- Status status;
- nsecs_t downTime;
- int32_t keyCode;
- int32_t scanCode;
- } currentVirtualKey;
-
- struct AveragingTouchFilterState {
- // Individual history tracks are stored by pointer id
- uint32_t historyStart[MAX_POINTERS];
- uint32_t historyEnd[MAX_POINTERS];
- struct {
- struct {
- int32_t x;
- int32_t y;
- int32_t pressure;
- } pointers[MAX_POINTERS];
- } historyData[AVERAGING_HISTORY_SIZE];
- } averagingTouchFilter;
-
- struct JumpTouchFilterState {
- int32_t jumpyPointsDropped;
- } jumpyTouchFilter;
-
- struct Precalculated {
- int32_t xOrigin;
- float xScale;
-
- int32_t yOrigin;
- float yScale;
-
- int32_t pressureOrigin;
- float pressureScale;
-
- int32_t sizeOrigin;
- float sizeScale;
-
- float orientationScale;
- } precalculated;
-
- void reset();
-
- bool applyBadTouchFilter();
- bool applyJumpyTouchFilter();
- void applyAveragingTouchFilter();
- void calculatePointerIds();
-
- bool isPointInsideDisplay(int32_t x, int32_t y) const;
- const InputDevice::VirtualKey* findVirtualKeyHit() const;
- };
-
- InputDevice(int32_t id, uint32_t classes, String8 name);
-
- int32_t id;
- uint32_t classes;
- String8 name;
- bool ignored;
-
- KeyboardState keyboard;
- TrackballState trackball;
- TouchScreenState touchScreen;
- union {
- SingleTouchScreenState singleTouchScreen;
- MultiTouchScreenState multiTouchScreen;
- };
-
- void reset();
-
- inline bool isKeyboard() const { return classes & INPUT_DEVICE_CLASS_KEYBOARD; }
- inline bool isAlphaKey() const { return classes & INPUT_DEVICE_CLASS_ALPHAKEY; }
- inline bool isTrackball() const { return classes & INPUT_DEVICE_CLASS_TRACKBALL; }
- inline bool isDPad() const { return classes & INPUT_DEVICE_CLASS_DPAD; }
- inline bool isSingleTouchScreen() const { return (classes
- & (INPUT_DEVICE_CLASS_TOUCHSCREEN | INPUT_DEVICE_CLASS_TOUCHSCREEN_MT))
- == INPUT_DEVICE_CLASS_TOUCHSCREEN; }
- inline bool isMultiTouchScreen() const { return classes
- & INPUT_DEVICE_CLASS_TOUCHSCREEN_MT; }
- inline bool isTouchScreen() const { return classes
- & (INPUT_DEVICE_CLASS_TOUCHSCREEN | INPUT_DEVICE_CLASS_TOUCHSCREEN_MT); }
-};
-
-} // namespace android
-
-#endif // _UI_INPUT_DEVICE_H
diff --git a/include/ui/InputManager.h b/include/ui/InputManager.h
index e755238..7ebec10 100644
--- a/include/ui/InputManager.h
+++ b/include/ui/InputManager.h
@@ -96,22 +96,28 @@ public:
virtual void preemptInputDispatch() = 0;
/* Gets input device configuration. */
- virtual void getInputConfiguration(InputConfiguration* outConfiguration) const = 0;
+ virtual void getInputConfiguration(InputConfiguration* outConfiguration) = 0;
- /*
- * Queries current input state.
- * deviceId may be -1 to search for the device automatically, filtered by class.
- * deviceClasses may be -1 to ignore device class while searching.
+ /* Gets information about the specified input device.
+ * Returns OK if the device information was obtained or NAME_NOT_FOUND if there
+ * was no such device.
*/
- virtual int32_t getScanCodeState(int32_t deviceId, int32_t deviceClasses,
- int32_t scanCode) const = 0;
- virtual int32_t getKeyCodeState(int32_t deviceId, int32_t deviceClasses,
- int32_t keyCode) const = 0;
- virtual int32_t getSwitchState(int32_t deviceId, int32_t deviceClasses,
- int32_t sw) const = 0;
+ virtual status_t getInputDeviceInfo(int32_t deviceId, InputDeviceInfo* outDeviceInfo) = 0;
+
+ /* Gets the list of all registered device ids. */
+ virtual void getInputDeviceIds(Vector<int32_t>& outDeviceIds) = 0;
+
+ /* Queries current input state. */
+ virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask,
+ int32_t scanCode) = 0;
+ virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask,
+ int32_t keyCode) = 0;
+ virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask,
+ int32_t sw) = 0;
/* Determines whether physical keys exist for the given framework-domain key codes. */
- virtual bool hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const = 0;
+ virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask,
+ size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) = 0;
};
class InputManager : public InputManagerInterface {
@@ -140,14 +146,17 @@ public:
virtual void preemptInputDispatch();
- virtual void getInputConfiguration(InputConfiguration* outConfiguration) const;
- virtual int32_t getScanCodeState(int32_t deviceId, int32_t deviceClasses,
- int32_t scanCode) const;
- virtual int32_t getKeyCodeState(int32_t deviceId, int32_t deviceClasses,
- int32_t keyCode) const;
- virtual int32_t getSwitchState(int32_t deviceId, int32_t deviceClasses,
- int32_t sw) const;
- virtual bool hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const;
+ virtual void getInputConfiguration(InputConfiguration* outConfiguration);
+ virtual status_t getInputDeviceInfo(int32_t deviceId, InputDeviceInfo* outDeviceInfo);
+ virtual void getInputDeviceIds(Vector<int32_t>& outDeviceIds);
+ virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask,
+ int32_t scanCode);
+ virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask,
+ int32_t keyCode);
+ virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask,
+ int32_t sw);
+ virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask,
+ size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags);
private:
sp<InputReaderInterface> mReader;
diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h
index 14bea65..d7ec8ea 100644
--- a/include/ui/InputReader.h
+++ b/include/ui/InputReader.h
@@ -19,7 +19,6 @@
#include <ui/EventHub.h>
#include <ui/Input.h>
-#include <ui/InputDevice.h>
#include <ui/InputDispatcher.h>
#include <utils/KeyedVector.h>
#include <utils/threads.h>
@@ -33,6 +32,10 @@
namespace android {
+class InputDevice;
+class InputMapper;
+
+
/*
* Input reader policy interface.
*
@@ -68,14 +71,6 @@ public:
// The input dispatcher should perform special filtering in preparation for
// a pending app switch.
ACTION_APP_SWITCH_COMING = 0x00000002,
-
- // The input dispatcher should add POLICY_FLAG_WOKE_HERE to the policy flags it
- // passes through the dispatch pipeline.
- ACTION_WOKE_HERE = 0x00000004,
-
- // The input dispatcher should add POLICY_FLAG_BRIGHT_HERE to the policy flags it
- // passes through the dispatch pipeline.
- ACTION_BRIGHT_HERE = 0x00000008,
};
/* Describes a virtual key. */
@@ -101,38 +96,30 @@ public:
/* Intercepts a key event.
* The policy can use this method as an opportunity to perform power management functions
- * and early event preprocessing.
+ * and early event preprocessing such as updating policy flags.
*
* Returns a policy action constant such as ACTION_DISPATCH.
*/
virtual int32_t interceptKey(nsecs_t when, int32_t deviceId,
- bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags) = 0;
+ bool down, int32_t keyCode, int32_t scanCode, uint32_t& policyFlags) = 0;
- /* Intercepts a trackball event.
+ /* Intercepts a switch event.
* The policy can use this method as an opportunity to perform power management functions
- * and early event preprocessing.
+ * and early event preprocessing such as updating policy flags.
*
- * Returns a policy action constant such as ACTION_DISPATCH.
+ * Switches are not dispatched to applications so this method should
+ * usually return ACTION_NONE.
*/
- virtual int32_t interceptTrackball(nsecs_t when, bool buttonChanged, bool buttonDown,
- bool rolled) = 0;
+ virtual int32_t interceptSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue,
+ uint32_t& policyFlags) = 0;
- /* Intercepts a touch event.
+ /* Intercepts a generic touch, trackball or other event.
* The policy can use this method as an opportunity to perform power management functions
- * and early event preprocessing.
+ * and early event preprocessing such as updating policy flags.
*
* Returns a policy action constant such as ACTION_DISPATCH.
*/
- virtual int32_t interceptTouch(nsecs_t when) = 0;
-
- /* Intercepts a switch event.
- * The policy can use this method as an opportunity to perform power management functions
- * and early event preprocessing.
- *
- * Switches are not dispatched to applications so this method should
- * usually return ACTION_NONE.
- */
- virtual int32_t interceptSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue) = 0;
+ virtual int32_t interceptGeneric(nsecs_t when, uint32_t& policyFlags) = 0;
/* Determines whether to turn on some hacks we have to improve the touch interaction with a
* certain device whose screen currently is not all that good.
@@ -167,32 +154,52 @@ public:
*/
virtual void loopOnce() = 0;
- /* Gets the current virtual key. Returns false if not down.
+ /* Gets the current input device configuration.
*
* This method may be called on any thread (usually by the input manager).
*/
- virtual bool getCurrentVirtualKey(int32_t* outKeyCode, int32_t* outScanCode) const = 0;
+ virtual void getInputConfiguration(InputConfiguration* outConfiguration) = 0;
- /* Gets the current input device configuration.
+ /* Gets information about the specified input device.
+ * Returns OK if the device information was obtained or NAME_NOT_FOUND if there
+ * was no such device.
*
* This method may be called on any thread (usually by the input manager).
*/
- virtual void getCurrentInputConfiguration(InputConfiguration* outConfiguration) const = 0;
+ virtual status_t getInputDeviceInfo(int32_t deviceId, InputDeviceInfo* outDeviceInfo) = 0;
- /*
- * Query current input state.
- * deviceId may be -1 to search for the device automatically, filtered by class.
- * deviceClasses may be -1 to ignore device class while searching.
- */
- virtual int32_t getCurrentScanCodeState(int32_t deviceId, int32_t deviceClasses,
- int32_t scanCode) const = 0;
- virtual int32_t getCurrentKeyCodeState(int32_t deviceId, int32_t deviceClasses,
- int32_t keyCode) const = 0;
- virtual int32_t getCurrentSwitchState(int32_t deviceId, int32_t deviceClasses,
- int32_t sw) const = 0;
+ /* Gets the list of all registered device ids. */
+ virtual void getInputDeviceIds(Vector<int32_t>& outDeviceIds) = 0;
+
+ /* Query current input state. */
+ virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask,
+ int32_t scanCode) = 0;
+ virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask,
+ int32_t keyCode) = 0;
+ virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask,
+ int32_t sw) = 0;
/* Determine whether physical keys exist for the given framework-domain key codes. */
- virtual bool hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const = 0;
+ virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask,
+ size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) = 0;
+};
+
+
+/* Internal interface used by individual input devices to access global input device state
+ * and parameters maintained by the input reader.
+ */
+class InputReaderContext {
+protected:
+ InputReaderContext() { }
+ virtual ~InputReaderContext() { }
+
+public:
+ virtual void updateGlobalMetaState() = 0;
+ virtual int32_t getGlobalMetaState() = 0;
+
+ virtual InputReaderPolicyInterface* getPolicy() = 0;
+ virtual InputDispatcherInterface* getDispatcher() = 0;
+ virtual EventHubInterface* getEventHub() = 0;
};
@@ -201,10 +208,11 @@ public:
* event filtering in low power states, are controlled by a separate policy object.
*
* IMPORTANT INVARIANT:
- * Because the policy can potentially block or cause re-entrance into the input reader,
- * the input reader never calls into the policy while holding its internal locks.
+ * Because the policy and dispatcher can potentially block or cause re-entrance into
+ * the input reader, the input reader never calls into other components while holding
+ * an exclusive internal lock.
*/
-class InputReader : public InputReaderInterface {
+class InputReader : public InputReaderInterface, private InputReaderContext {
public:
InputReader(const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& policy,
@@ -213,107 +221,69 @@ public:
virtual void loopOnce();
- virtual bool getCurrentVirtualKey(int32_t* outKeyCode, int32_t* outScanCode) const;
+ virtual void getInputConfiguration(InputConfiguration* outConfiguration);
- virtual void getCurrentInputConfiguration(InputConfiguration* outConfiguration) const;
+ virtual status_t getInputDeviceInfo(int32_t deviceId, InputDeviceInfo* outDeviceInfo);
+ virtual void getInputDeviceIds(Vector<int32_t>& outDeviceIds);
- virtual int32_t getCurrentScanCodeState(int32_t deviceId, int32_t deviceClasses,
- int32_t scanCode) const;
- virtual int32_t getCurrentKeyCodeState(int32_t deviceId, int32_t deviceClasses,
- int32_t keyCode) const;
- virtual int32_t getCurrentSwitchState(int32_t deviceId, int32_t deviceClasses,
- int32_t sw) const;
+ virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask,
+ int32_t scanCode);
+ virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask,
+ int32_t keyCode);
+ virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask,
+ int32_t sw);
- virtual bool hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const;
+ virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask,
+ size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags);
private:
- // Lock that must be acquired while manipulating state that may be concurrently accessed
- // from other threads by input state query methods. It should be held for as short a
- // time as possible.
- //
- // Exported state:
- // - global virtual key code and scan code
- // - device list and immutable properties of devices such as id, name, and class
- // (but not other internal device state)
- mutable Mutex mExportedStateLock;
-
- // current virtual key information (lock mExportedStateLock)
- int32_t mExportedVirtualKeyCode;
- int32_t mExportedVirtualScanCode;
-
- // current input configuration (lock mExportedStateLock)
- InputConfiguration mExportedInputConfiguration;
-
- // combined key meta state
- int32_t mGlobalMetaState;
-
sp<EventHubInterface> mEventHub;
sp<InputReaderPolicyInterface> mPolicy;
sp<InputDispatcherInterface> mDispatcher;
+ virtual InputReaderPolicyInterface* getPolicy() { return mPolicy.get(); }
+ virtual InputDispatcherInterface* getDispatcher() { return mDispatcher.get(); }
+ virtual EventHubInterface* getEventHub() { return mEventHub.get(); }
+
+ // This reader/writer lock guards the list of input devices.
+ // The writer lock must be held whenever the list of input devices is modified
+ // and then promptly released.
+ // The reader lock must be held whenever the list of input devices is traversed or an
+ // input device in the list is accessed.
+ // This lock only protects the registry and prevents inadvertent deletion of device objects
+ // that are in use. Individual devices are responsible for guarding their own internal state
+ // as needed for concurrent operation.
+ RWLock mDeviceRegistryLock;
KeyedVector<int32_t, InputDevice*> mDevices;
- // display properties needed to translate touch screen coordinates into display coordinates
- int32_t mDisplayOrientation;
- int32_t mDisplayWidth;
- int32_t mDisplayHeight;
-
- // low-level input event decoding
+ // low-level input event decoding and device management
void process(const RawEvent* rawEvent);
- void handleDeviceAdded(const RawEvent* rawEvent);
- void handleDeviceRemoved(const RawEvent* rawEvent);
- void handleSync(const RawEvent* rawEvent);
- void handleKey(const RawEvent* rawEvent);
- void handleRelativeMotion(const RawEvent* rawEvent);
- void handleAbsoluteMotion(const RawEvent* rawEvent);
- void handleSwitch(const RawEvent* rawEvent);
-
- // input policy processing and dispatch
- void onKey(nsecs_t when, InputDevice* device, bool down,
- int32_t keyCode, int32_t scanCode, uint32_t policyFlags);
- void onSwitch(nsecs_t when, InputDevice* device, int32_t switchCode, int32_t switchValue);
- void onSingleTouchScreenStateChanged(nsecs_t when, InputDevice* device);
- void onMultiTouchScreenStateChanged(nsecs_t when, InputDevice* device);
- void onTouchScreenChanged(nsecs_t when, InputDevice* device, bool havePointerIds);
- void onTrackballStateChanged(nsecs_t when, InputDevice* device);
- void onConfigurationChanged(nsecs_t when);
-
- bool applyStandardInputDispatchPolicyActions(nsecs_t when,
- int32_t policyActions, uint32_t* policyFlags);
-
- bool consumeVirtualKeyTouches(nsecs_t when, InputDevice* device, uint32_t policyFlags);
- void dispatchVirtualKey(nsecs_t when, InputDevice* device, uint32_t policyFlags,
- int32_t keyEventAction, int32_t keyEventFlags);
- void dispatchTouches(nsecs_t when, InputDevice* device, uint32_t policyFlags);
- void dispatchTouch(nsecs_t when, InputDevice* device, uint32_t policyFlags,
- InputDevice::TouchData* touch, BitSet32 idBits, uint32_t changedId,
- int32_t motionEventAction);
-
- // display
- void resetDisplayProperties();
- bool refreshDisplayProperties();
-
- // device management
- InputDevice* getDevice(int32_t deviceId);
- InputDevice* getNonIgnoredDevice(int32_t deviceId);
+
void addDevice(nsecs_t when, int32_t deviceId);
- void removeDevice(nsecs_t when, InputDevice* device);
- void configureDevice(InputDevice* device);
- void configureDeviceForCurrentDisplaySize(InputDevice* device);
- void configureVirtualKeys(InputDevice* device);
- void configureAbsoluteAxisInfo(InputDevice* device, int axis, const char* name,
- InputDevice::AbsoluteAxisInfo* out);
+ void removeDevice(nsecs_t when, int32_t deviceId);
+ InputDevice* createDevice(int32_t deviceId, const String8& name, uint32_t classes);
void configureExcludedDevices();
- // global meta state management for all devices
- void resetGlobalMetaState();
- int32_t globalMetaState();
+ void consumeEvent(const RawEvent* rawEvent);
+
+ void handleConfigurationChanged(nsecs_t when);
- // virtual key management
- void updateExportedVirtualKeyState();
+ // state management for all devices
+ Mutex mStateLock;
- // input configuration management
- void updateExportedInputConfiguration();
+ int32_t mGlobalMetaState;
+ virtual void updateGlobalMetaState();
+ virtual int32_t getGlobalMetaState();
+
+ InputConfiguration mInputConfiguration;
+ void updateInputConfiguration();
+
+ // state queries
+ typedef int32_t (InputDevice::*GetStateFunc)(uint32_t sourceMask, int32_t code);
+ int32_t getState(int32_t deviceId, uint32_t sourceMask, int32_t code,
+ GetStateFunc getStateFunc);
+ bool markSupportedKeyCodes(int32_t deviceId, uint32_t sourceMask, size_t numCodes,
+ const int32_t* keyCodes, uint8_t* outFlags);
};
@@ -329,6 +299,527 @@ private:
virtual bool threadLoop();
};
+
+/* Represents the state of a single input device. */
+class InputDevice {
+public:
+ InputDevice(InputReaderContext* context, int32_t id, const String8& name);
+ ~InputDevice();
+
+ inline InputReaderContext* getContext() { return mContext; }
+ inline int32_t getId() { return mId; }
+ inline const String8& getName() { return mName; }
+ inline uint32_t getSources() { return mSources; }
+
+ inline bool isIgnored() { return mMappers.isEmpty(); }
+
+ void addMapper(InputMapper* mapper);
+ void configure();
+ void reset();
+ void process(const RawEvent* rawEvent);
+
+ void getDeviceInfo(InputDeviceInfo* outDeviceInfo);
+ int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode);
+ int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode);
+ int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode);
+ bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
+ const int32_t* keyCodes, uint8_t* outFlags);
+
+ int32_t getMetaState();
+
+private:
+ InputReaderContext* mContext;
+ int32_t mId;
+
+ Vector<InputMapper*> mMappers;
+
+ String8 mName;
+ uint32_t mSources;
+
+ typedef int32_t (InputMapper::*GetStateFunc)(uint32_t sourceMask, int32_t code);
+ int32_t getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc);
+};
+
+
+/* An input mapper transforms raw input events into cooked event data.
+ * A single input device can have multiple associated input mappers in order to interpret
+ * different classes of events.
+ */
+class InputMapper {
+public:
+ InputMapper(InputDevice* device);
+ virtual ~InputMapper();
+
+ inline InputDevice* getDevice() { return mDevice; }
+ inline int32_t getDeviceId() { return mDevice->getId(); }
+ inline const String8 getDeviceName() { return mDevice->getName(); }
+ inline InputReaderContext* getContext() { return mContext; }
+ inline InputReaderPolicyInterface* getPolicy() { return mContext->getPolicy(); }
+ inline InputDispatcherInterface* getDispatcher() { return mContext->getDispatcher(); }
+ inline EventHubInterface* getEventHub() { return mContext->getEventHub(); }
+
+ virtual uint32_t getSources() = 0;
+ virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
+ virtual void configure();
+ virtual void reset();
+ virtual void process(const RawEvent* rawEvent) = 0;
+
+ virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode);
+ virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode);
+ virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode);
+ virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
+ const int32_t* keyCodes, uint8_t* outFlags);
+
+ virtual int32_t getMetaState();
+
+protected:
+ InputDevice* mDevice;
+ InputReaderContext* mContext;
+
+ bool applyStandardPolicyActions(nsecs_t when, int32_t policyActions);
+};
+
+
+class SwitchInputMapper : public InputMapper {
+public:
+ SwitchInputMapper(InputDevice* device);
+ virtual ~SwitchInputMapper();
+
+ virtual uint32_t getSources();
+ virtual void process(const RawEvent* rawEvent);
+
+ virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode);
+
+private:
+ void processSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue);
+};
+
+
+class KeyboardInputMapper : public InputMapper {
+public:
+ KeyboardInputMapper(InputDevice* device, int32_t associatedDisplayId, uint32_t sources,
+ int32_t keyboardType);
+ virtual ~KeyboardInputMapper();
+
+ virtual uint32_t getSources();
+ virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
+ virtual void reset();
+ virtual void process(const RawEvent* rawEvent);
+
+ virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode);
+ virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode);
+ virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
+ const int32_t* keyCodes, uint8_t* outFlags);
+
+ virtual int32_t getMetaState();
+
+private:
+ struct KeyDown {
+ int32_t keyCode;
+ int32_t scanCode;
+ };
+
+ int32_t mAssociatedDisplayId;
+ uint32_t mSources;
+ int32_t mKeyboardType;
+
+ Vector<KeyDown> mKeyDowns; // keys that are down
+ int32_t mMetaState;
+ nsecs_t mDownTime; // time of most recent key down
+
+ void initialize();
+
+ bool isKeyboardOrGamepadKey(int32_t scanCode);
+ void processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode,
+ uint32_t policyFlags);
+
+ ssize_t findKeyDown(int32_t scanCode);
+};
+
+
+class TrackballInputMapper : public InputMapper {
+public:
+ TrackballInputMapper(InputDevice* device, int32_t associatedDisplayId);
+ virtual ~TrackballInputMapper();
+
+ virtual uint32_t getSources();
+ virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
+ virtual void reset();
+ virtual void process(const RawEvent* rawEvent);
+
+private:
+ // Amount that trackball needs to move in order to generate a key event.
+ static const int32_t TRACKBALL_MOVEMENT_THRESHOLD = 6;
+
+ int32_t mAssociatedDisplayId;
+
+ struct Accumulator {
+ enum {
+ FIELD_BTN_MOUSE = 1,
+ FIELD_REL_X = 2,
+ FIELD_REL_Y = 4
+ };
+
+ uint32_t fields;
+
+ bool btnMouse;
+ int32_t relX;
+ int32_t relY;
+
+ inline void clear() {
+ fields = 0;
+ }
+
+ inline bool isDirty() {
+ return fields != 0;
+ }
+ } mAccumulator;
+
+ bool mDown;
+ nsecs_t mDownTime;
+
+ float mXScale;
+ float mYScale;
+ float mXPrecision;
+ float mYPrecision;
+
+ void initialize();
+
+ void sync(nsecs_t when);
+};
+
+
+class TouchInputMapper : public InputMapper {
+public:
+ TouchInputMapper(InputDevice* device, int32_t associatedDisplayId);
+ virtual ~TouchInputMapper();
+
+ virtual uint32_t getSources();
+ virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
+ virtual void configure();
+ virtual void reset();
+
+ virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode);
+ virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode);
+ virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
+ const int32_t* keyCodes, uint8_t* outFlags);
+
+protected:
+ /* Maximum pointer id value supported.
+ * (This is limited by our use of BitSet32 to track pointer assignments.) */
+ static const uint32_t MAX_POINTER_ID = 31;
+
+ struct VirtualKey {
+ int32_t keyCode;
+ int32_t scanCode;
+ uint32_t flags;
+
+ // computed hit box, specified in touch screen coords based on known display size
+ int32_t hitLeft;
+ int32_t hitTop;
+ int32_t hitRight;
+ int32_t hitBottom;
+
+ inline bool isHit(int32_t x, int32_t y) const {
+ return x >= hitLeft && x <= hitRight && y >= hitTop && y <= hitBottom;
+ }
+ };
+
+ struct PointerData {
+ uint32_t id;
+ int32_t x;
+ int32_t y;
+ int32_t pressure;
+ int32_t size;
+ int32_t touchMajor;
+ int32_t touchMinor;
+ int32_t toolMajor;
+ int32_t toolMinor;
+ int32_t orientation;
+ };
+
+ struct TouchData {
+ uint32_t pointerCount;
+ PointerData pointers[MAX_POINTERS];
+ BitSet32 idBits;
+ uint32_t idToIndex[MAX_POINTER_ID + 1];
+
+ void copyFrom(const TouchData& other) {
+ pointerCount = other.pointerCount;
+ idBits = other.idBits;
+
+ for (uint32_t i = 0; i < pointerCount; i++) {
+ pointers[i] = other.pointers[i];
+ idToIndex[i] = other.idToIndex[i];
+ }
+ }
+
+ inline void clear() {
+ pointerCount = 0;
+ idBits.clear();
+ }
+ };
+
+ int32_t mAssociatedDisplayId;
+ Vector<VirtualKey> mVirtualKeys;
+
+ // Immutable configuration parameters.
+ struct Parameters {
+ bool useBadTouchFilter;
+ bool useJumpyTouchFilter;
+ bool useAveragingTouchFilter;
+ } mParameters;
+
+ // Raw axis information.
+ struct Axes {
+ RawAbsoluteAxisInfo x;
+ RawAbsoluteAxisInfo y;
+ RawAbsoluteAxisInfo pressure;
+ RawAbsoluteAxisInfo size;
+ RawAbsoluteAxisInfo touchMajor;
+ RawAbsoluteAxisInfo touchMinor;
+ RawAbsoluteAxisInfo toolMajor;
+ RawAbsoluteAxisInfo toolMinor;
+ RawAbsoluteAxisInfo orientation;
+ } mAxes;
+
+ // The surface orientation and width and height set by configureSurface().
+ int32_t mSurfaceOrientation;
+ int32_t mSurfaceWidth, mSurfaceHeight;
+
+ // Translation and scaling factors, orientation-independent.
+ int32_t mXOrigin;
+ float mXScale;
+ float mXPrecision;
+
+ int32_t mYOrigin;
+ float mYScale;
+ float mYPrecision;
+
+ int32_t mPressureOrigin;
+ float mPressureScale;
+
+ int32_t mSizeOrigin;
+ float mSizeScale;
+
+ float mOrientationScale;
+
+ // Oriented motion ranges for input device info.
+ struct OrientedRanges {
+ InputDeviceInfo::MotionRange x;
+ InputDeviceInfo::MotionRange y;
+ InputDeviceInfo::MotionRange pressure;
+ InputDeviceInfo::MotionRange size;
+ InputDeviceInfo::MotionRange touchMajor;
+ InputDeviceInfo::MotionRange touchMinor;
+ InputDeviceInfo::MotionRange toolMajor;
+ InputDeviceInfo::MotionRange toolMinor;
+ InputDeviceInfo::MotionRange orientation;
+ } mOrientedRanges;
+
+ // Oriented dimensions and precision.
+ float mOrientedSurfaceWidth, mOrientedSurfaceHeight;
+ float mOrientedXPrecision, mOrientedYPrecision;
+
+ // The touch data of the current sample being processed.
+ TouchData mCurrentTouch;
+
+ // The touch data of the previous sample that was processed. This is updated
+ // incrementally while the current sample is being processed.
+ TouchData mLastTouch;
+
+ // The time the primary pointer last went down.
+ nsecs_t mDownTime;
+
+ struct CurrentVirtualKeyState {
+ bool down;
+ nsecs_t downTime;
+ int32_t keyCode;
+ int32_t scanCode;
+ } mCurrentVirtualKey;
+
+ // Lock for virtual key state.
+ Mutex mVirtualKeyLock; // methods use "Lvk" suffix
+
+ virtual void configureAxes();
+ virtual bool configureSurface();
+ virtual void configureVirtualKeys();
+
+ enum TouchResult {
+ // Dispatch the touch normally.
+ DISPATCH_TOUCH,
+ // Do not dispatch the touch, but keep tracking the current stroke.
+ SKIP_TOUCH,
+ // Do not dispatch the touch, and drop all information associated with the current stoke
+ // so the next movement will appear as a new down.
+ DROP_STROKE
+ };
+
+ void syncTouch(nsecs_t when, bool havePointerIds);
+
+private:
+ /* Maximum number of historical samples to average. */
+ static const uint32_t AVERAGING_HISTORY_SIZE = 5;
+
+ /* Slop distance for jumpy pointer detection.
+ * The vertical range of the screen divided by this is our epsilon value. */
+ static const uint32_t JUMPY_EPSILON_DIVISOR = 212;
+
+ /* Number of jumpy points to drop for touchscreens that need it. */
+ static const uint32_t JUMPY_TRANSITION_DROPS = 3;
+ static const uint32_t JUMPY_DROP_LIMIT = 3;
+
+ /* Maximum squared distance for averaging.
+ * If moving farther than this, turn of averaging to avoid lag in response. */
+ static const uint64_t AVERAGING_DISTANCE_LIMIT = 75 * 75;
+
+ struct AveragingTouchFilterState {
+ // Individual history tracks are stored by pointer id
+ uint32_t historyStart[MAX_POINTERS];
+ uint32_t historyEnd[MAX_POINTERS];
+ struct {
+ struct {
+ int32_t x;
+ int32_t y;
+ int32_t pressure;
+ } pointers[MAX_POINTERS];
+ } historyData[AVERAGING_HISTORY_SIZE];
+ } mAveragingTouchFilter;
+
+ struct JumpTouchFilterState {
+ uint32_t jumpyPointsDropped;
+ } mJumpyTouchFilter;
+
+ struct PointerDistanceHeapElement {
+ uint32_t currentPointerIndex : 8;
+ uint32_t lastPointerIndex : 8;
+ uint64_t distance : 48; // squared distance
+ };
+
+ void initialize();
+
+ TouchResult consumeOffScreenTouches(nsecs_t when, uint32_t policyFlags);
+ void dispatchTouches(nsecs_t when, uint32_t policyFlags);
+ void dispatchTouch(nsecs_t when, uint32_t policyFlags, TouchData* touch,
+ BitSet32 idBits, uint32_t changedId, int32_t motionEventAction);
+
+ bool isPointInsideSurface(int32_t x, int32_t y);
+ const VirtualKey* findVirtualKeyHitLvk(int32_t x, int32_t y);
+
+ bool applyBadTouchFilter();
+ bool applyJumpyTouchFilter();
+ void applyAveragingTouchFilter();
+ void calculatePointerIds();
+};
+
+
+class SingleTouchInputMapper : public TouchInputMapper {
+public:
+ SingleTouchInputMapper(InputDevice* device, int32_t associatedDisplayId);
+ virtual ~SingleTouchInputMapper();
+
+ virtual void reset();
+ virtual void process(const RawEvent* rawEvent);
+
+protected:
+ virtual void configureAxes();
+
+private:
+ struct Accumulator {
+ enum {
+ FIELD_BTN_TOUCH = 1,
+ FIELD_ABS_X = 2,
+ FIELD_ABS_Y = 4,
+ FIELD_ABS_PRESSURE = 8,
+ FIELD_ABS_TOOL_WIDTH = 16
+ };
+
+ uint32_t fields;
+
+ bool btnTouch;
+ int32_t absX;
+ int32_t absY;
+ int32_t absPressure;
+ int32_t absToolWidth;
+
+ inline void clear() {
+ fields = 0;
+ }
+
+ inline bool isDirty() {
+ return fields != 0;
+ }
+ } mAccumulator;
+
+ bool mDown;
+ int32_t mX;
+ int32_t mY;
+ int32_t mPressure;
+ int32_t mSize;
+
+ void initialize();
+
+ void sync(nsecs_t when);
+};
+
+
+class MultiTouchInputMapper : public TouchInputMapper {
+public:
+ MultiTouchInputMapper(InputDevice* device, int32_t associatedDisplayId);
+ virtual ~MultiTouchInputMapper();
+
+ virtual void reset();
+ virtual void process(const RawEvent* rawEvent);
+
+protected:
+ virtual void configureAxes();
+
+private:
+ struct Accumulator {
+ enum {
+ FIELD_ABS_MT_POSITION_X = 1,
+ FIELD_ABS_MT_POSITION_Y = 2,
+ FIELD_ABS_MT_TOUCH_MAJOR = 4,
+ FIELD_ABS_MT_TOUCH_MINOR = 8,
+ FIELD_ABS_MT_WIDTH_MAJOR = 16,
+ FIELD_ABS_MT_WIDTH_MINOR = 32,
+ FIELD_ABS_MT_ORIENTATION = 64,
+ FIELD_ABS_MT_TRACKING_ID = 128
+ };
+
+ uint32_t pointerCount;
+ struct Pointer {
+ uint32_t fields;
+
+ int32_t absMTPositionX;
+ int32_t absMTPositionY;
+ int32_t absMTTouchMajor;
+ int32_t absMTTouchMinor;
+ int32_t absMTWidthMajor;
+ int32_t absMTWidthMinor;
+ int32_t absMTOrientation;
+ int32_t absMTTrackingId;
+
+ inline void clear() {
+ fields = 0;
+ }
+ } pointers[MAX_POINTERS + 1]; // + 1 to remove the need for extra range checks
+
+ inline void clear() {
+ pointerCount = 0;
+ pointers[0].clear();
+ }
+
+ inline bool isDirty() {
+ return pointerCount != 0;
+ }
+ } mAccumulator;
+
+ void initialize();
+
+ void sync(nsecs_t when);
+};
+
} // namespace android
#endif // _UI_INPUT_READER_H
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index 4243bbf..9f49348 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -12,7 +12,6 @@ LOCAL_SRC_FILES:= \
KeyLayoutMap.cpp \
KeyCharacterMap.cpp \
Input.cpp \
- InputDevice.cpp \
InputDispatcher.cpp \
InputManager.cpp \
InputReader.cpp \
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index 33dd373..124f7b3 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -137,9 +137,14 @@ uint32_t EventHub::getDeviceClasses(int32_t deviceId) const
return device->classes;
}
-int EventHub::getAbsoluteInfo(int32_t deviceId, int axis, int *outMinValue,
- int* outMaxValue, int* outFlat, int* outFuzz) const
-{
+status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis,
+ RawAbsoluteAxisInfo* outAxisInfo) const {
+ outAxisInfo->valid = false;
+ outAxisInfo->minValue = 0;
+ outAxisInfo->maxValue = 0;
+ outAxisInfo->flat = 0;
+ outAxisInfo->fuzz = 0;
+
AutoMutex _l(mLock);
device_t* device = getDevice(deviceId);
if (device == NULL) return -1;
@@ -147,38 +152,28 @@ int EventHub::getAbsoluteInfo(int32_t deviceId, int axis, int *outMinValue,
struct input_absinfo info;
if(ioctl(mFDs[id_to_index(device->id)].fd, EVIOCGABS(axis), &info)) {
- LOGE("Error reading absolute controller %d for device %s fd %d\n",
+ LOGW("Error reading absolute controller %d for device %s fd %d\n",
axis, device->name.string(), mFDs[id_to_index(device->id)].fd);
- return -1;
+ return -errno;
}
- *outMinValue = info.minimum;
- *outMaxValue = info.maximum;
- *outFlat = info.flat;
- *outFuzz = info.fuzz;
- return 0;
+
+ if (info.minimum != info.maximum) {
+ outAxisInfo->valid = true;
+ outAxisInfo->minValue = info.minimum;
+ outAxisInfo->maxValue = info.maximum;
+ outAxisInfo->flat = info.flat;
+ outAxisInfo->fuzz = info.fuzz;
+ }
+ return OK;
}
-int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t deviceClasses,
- int32_t scanCode) const {
+int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const {
if (scanCode >= 0 && scanCode <= KEY_MAX) {
AutoMutex _l(mLock);
- if (deviceId == -1) {
- for (int i = 0; i < mNumDevicesById; i++) {
- device_t* device = mDevicesById[i].device;
- if (device != NULL && (device->classes & deviceClasses) != 0) {
- int32_t result = getScanCodeStateLocked(device, scanCode);
- if (result >= AKEY_STATE_DOWN) {
- return result;
- }
- }
- }
- return AKEY_STATE_UP;
- } else {
- device_t* device = getDevice(deviceId);
- if (device != NULL) {
- return getScanCodeStateLocked(device, scanCode);
- }
+ device_t* device = getDevice(deviceId);
+ if (device != NULL) {
+ return getScanCodeStateLocked(device, scanCode);
}
}
return AKEY_STATE_UNKNOWN;
@@ -194,25 +189,12 @@ int32_t EventHub::getScanCodeStateLocked(device_t* device, int32_t scanCode) con
return AKEY_STATE_UNKNOWN;
}
-int32_t EventHub::getKeyCodeState(int32_t deviceId, int32_t deviceClasses,
- int32_t keyCode) const {
+int32_t EventHub::getKeyCodeState(int32_t deviceId, int32_t keyCode) const {
+ AutoMutex _l(mLock);
- if (deviceId == -1) {
- for (int i = 0; i < mNumDevicesById; i++) {
- device_t* device = mDevicesById[i].device;
- if (device != NULL && (device->classes & deviceClasses) != 0) {
- int32_t result = getKeyCodeStateLocked(device, keyCode);
- if (result >= AKEY_STATE_DOWN) {
- return result;
- }
- }
- }
- return AKEY_STATE_UP;
- } else {
- device_t* device = getDevice(deviceId);
- if (device != NULL) {
- return getKeyCodeStateLocked(device, keyCode);
- }
+ device_t* device = getDevice(deviceId);
+ if (device != NULL) {
+ return getKeyCodeStateLocked(device, keyCode);
}
return AKEY_STATE_UNKNOWN;
}
@@ -243,24 +225,15 @@ int32_t EventHub::getKeyCodeStateLocked(device_t* device, int32_t keyCode) const
return AKEY_STATE_UNKNOWN;
}
-int32_t EventHub::getSwitchState(int32_t deviceId, int32_t deviceClasses, int32_t sw) const {
+int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const {
#ifdef EV_SW
if (sw >= 0 && sw <= SW_MAX) {
AutoMutex _l(mLock);
- if (deviceId == -1) {
- deviceId = mSwitches[sw];
- if (deviceId == 0) {
- return AKEY_STATE_UNKNOWN;
- }
- }
-
device_t* device = getDevice(deviceId);
- if (device == NULL) {
- return AKEY_STATE_UNKNOWN;
+ if (device != NULL) {
+ return getSwitchStateLocked(device, sw);
}
-
- return getSwitchStateLocked(device, sw);
}
#endif
return AKEY_STATE_UNKNOWN;
@@ -276,6 +249,42 @@ int32_t EventHub::getSwitchStateLocked(device_t* device, int32_t sw) const {
return AKEY_STATE_UNKNOWN;
}
+bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes,
+ const int32_t* keyCodes, uint8_t* outFlags) const {
+ AutoMutex _l(mLock);
+
+ device_t* device = getDevice(deviceId);
+ if (device != NULL) {
+ return markSupportedKeyCodesLocked(device, numCodes, keyCodes, outFlags);
+ }
+ return false;
+}
+
+bool EventHub::markSupportedKeyCodesLocked(device_t* device, size_t numCodes,
+ const int32_t* keyCodes, uint8_t* outFlags) const {
+ if (device->layoutMap == NULL || device->keyBitmask == NULL) {
+ return false;
+ }
+
+ Vector<int32_t> scanCodes;
+ for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) {
+ scanCodes.clear();
+
+ status_t err = device->layoutMap->findScancodes(keyCodes[codeIndex], &scanCodes);
+ if (! err) {
+ // check the possible scan codes identified by the layout map against the
+ // map of codes actually emitted by the driver
+ for (size_t sc = 0; sc < scanCodes.size(); sc++) {
+ if (test_bit(scanCodes[sc], device->keyBitmask)) {
+ outFlags[codeIndex] = 1;
+ break;
+ }
+ }
+ }
+ }
+ return true;
+}
+
status_t EventHub::scancodeToKeycode(int32_t deviceId, int scancode,
int32_t* outKeycode, uint32_t* outFlags) const
{
@@ -324,17 +333,15 @@ EventHub::device_t* EventHub::getDevice(int32_t deviceId) const
return NULL;
}
-bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType,
- int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,
- int32_t* outValue, nsecs_t* outWhen)
+bool EventHub::getEvent(RawEvent* outEvent)
{
- *outDeviceId = 0;
- *outType = 0;
- *outScancode = 0;
- *outKeycode = 0;
- *outFlags = 0;
- *outValue = 0;
- *outWhen = 0;
+ outEvent->deviceId = 0;
+ outEvent->type = 0;
+ outEvent->scanCode = 0;
+ outEvent->keyCode = 0;
+ outEvent->flags = 0;
+ outEvent->value = 0;
+ outEvent->when = 0;
status_t err;
@@ -359,20 +366,27 @@ bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType,
LOGV("Reporting device closed: id=0x%x, name=%s\n",
device->id, device->path.string());
mClosingDevices = device->next;
- *outDeviceId = device->id;
- if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0;
- *outType = DEVICE_REMOVED;
+ if (device->id == mFirstKeyboardId) {
+ outEvent->deviceId = 0;
+ } else {
+ outEvent->deviceId = device->id;
+ }
+ outEvent->type = DEVICE_REMOVED;
delete device;
return true;
}
+
if (mOpeningDevices != NULL) {
device_t* device = mOpeningDevices;
LOGV("Reporting device opened: id=0x%x, name=%s\n",
device->id, device->path.string());
mOpeningDevices = device->next;
- *outDeviceId = device->id;
- if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0;
- *outType = DEVICE_ADDED;
+ if (device->id == mFirstKeyboardId) {
+ outEvent->deviceId = 0;
+ } else {
+ outEvent->deviceId = device->id;
+ }
+ outEvent->type = DEVICE_ADDED;
return true;
}
@@ -399,27 +413,36 @@ bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType,
if(mFDs[i].revents & POLLIN) {
res = read(mFDs[i].fd, &iev, sizeof(iev));
if (res == sizeof(iev)) {
+ device_t* device = mDevices[i];
LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d",
- mDevices[i]->path.string(),
+ device->path.string(),
(int) iev.time.tv_sec, (int) iev.time.tv_usec,
iev.type, iev.code, iev.value);
- *outDeviceId = mDevices[i]->id;
- if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0;
- *outType = iev.type;
- *outScancode = iev.code;
+ if (device->id == mFirstKeyboardId) {
+ outEvent->deviceId = 0;
+ } else {
+ outEvent->deviceId = device->id;
+ }
+ outEvent->type = iev.type;
+ outEvent->scanCode = iev.code;
if (iev.type == EV_KEY) {
- err = mDevices[i]->layoutMap->map(iev.code, outKeycode, outFlags);
- LOGV("iev.code=%d outKeycode=%d outFlags=0x%08x err=%d\n",
- iev.code, *outKeycode, *outFlags, err);
+ err = device->layoutMap->map(iev.code,
+ & outEvent->keyCode, & outEvent->flags);
+ LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n",
+ iev.code, outEvent->keyCode, outEvent->flags, err);
if (err != 0) {
- *outKeycode = AKEYCODE_UNKNOWN;
- *outFlags = 0;
+ outEvent->keyCode = AKEYCODE_UNKNOWN;
+ outEvent->flags = 0;
}
} else {
- *outKeycode = iev.code;
+ outEvent->keyCode = iev.code;
}
- *outValue = iev.value;
- *outWhen = s2ns(iev.time.tv_sec) + us2ns(iev.time.tv_usec);
+ outEvent->value = iev.value;
+
+ // Use an event timestamp in the same timebase as
+ // java.lang.System.nanoTime() and android.os.SystemClock.uptimeMillis()
+ // as expected by the rest of the system.
+ outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
return true;
} else {
if (res<0) {
@@ -479,37 +502,6 @@ bool EventHub::openPlatformInput(void)
return true;
}
-/*
- * Inspect the known devices to determine whether physical keys exist for the given
- * framework-domain key codes.
- */
-bool EventHub::hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const {
- for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) {
- outFlags[codeIndex] = 0;
-
- // check each available hardware device for support for this keycode
- Vector<int32_t> scanCodes;
- for (int n = 0; (n < mFDCount) && (outFlags[codeIndex] == 0); n++) {
- if (mDevices[n]) {
- status_t err = mDevices[n]->layoutMap->findScancodes(
- keyCodes[codeIndex], &scanCodes);
- if (!err) {
- // check the possible scan codes identified by the layout map against the
- // map of codes actually emitted by the driver
- for (size_t sc = 0; sc < scanCodes.size(); sc++) {
- if (test_bit(scanCodes[sc], mDevices[n]->keyBitmask)) {
- outFlags[codeIndex] = 1;
- break;
- }
- }
- }
- }
- }
- }
-
- return true;
-}
-
// ----------------------------------------------------------------------------
static bool containsNonZeroByte(const uint8_t* array, uint32_t startIndex, uint32_t endIndex) {
@@ -715,16 +707,21 @@ int EventHub::open_device(const char *deviceName)
// figure out the switches this device reports
uint8_t sw_bitmask[sizeof_bit_array(SW_MAX + 1)];
memset(sw_bitmask, 0, sizeof(sw_bitmask));
+ bool hasSwitches = false;
if (ioctl(fd, EVIOCGBIT(EV_SW, sizeof(sw_bitmask)), sw_bitmask) >= 0) {
for (int i=0; i<EV_SW; i++) {
//LOGI("Device 0x%x sw %d: has=%d", device->id, i, test_bit(i, sw_bitmask));
if (test_bit(i, sw_bitmask)) {
+ hasSwitches = true;
if (mSwitches[i] == 0) {
mSwitches[i] = device->id;
}
}
}
}
+ if (hasSwitches) {
+ device->classes |= INPUT_DEVICE_CLASS_SWITCH;
+ }
#endif
if ((device->classes & INPUT_DEVICE_CLASS_KEYBOARD) != 0) {
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index 5253c72..5fbaf09 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -168,4 +168,63 @@ void MotionEvent::offsetLocation(float xOffset, float yOffset) {
mYOffset += yOffset;
}
+// class InputDeviceInfo
+
+InputDeviceInfo::InputDeviceInfo() {
+ initialize(-1, String8("uninitialized device info"));
+}
+
+InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) :
+ mId(other.mId), mName(other.mName), mSources(other.mSources),
+ mKeyboardType(other.mKeyboardType),
+ mMotionRanges(other.mMotionRanges) {
+}
+
+InputDeviceInfo::~InputDeviceInfo() {
+}
+
+void InputDeviceInfo::initialize(int32_t id, const String8& name) {
+ mId = id;
+ mName = name;
+ mSources = 0;
+ mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE;
+ mMotionRanges.clear();
+}
+
+const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange(int32_t rangeType) const {
+ ssize_t index = mMotionRanges.indexOfKey(rangeType);
+ return index >= 0 ? & mMotionRanges.valueAt(index) : NULL;
+}
+
+void InputDeviceInfo::addSource(uint32_t source) {
+ mSources |= source;
+}
+
+void InputDeviceInfo::addMotionRange(int32_t rangeType, float min, float max,
+ float flat, float fuzz) {
+ MotionRange range = { min, max, flat, fuzz };
+ addMotionRange(rangeType, range);
+}
+
+void InputDeviceInfo::addMotionRange(int32_t rangeType, const MotionRange& range) {
+ mMotionRanges.add(rangeType, range);
+}
+
+// class InputDeviceProxy
+
+InputDeviceProxy::InputDeviceProxy() {
+}
+
+InputDeviceProxy::~InputDeviceProxy() {
+}
+
+void InputDeviceProxy::getDeviceIds(Vector<int32_t>& outIds) {
+ // TODO use Binder
+}
+
+sp<InputDeviceProxy> InputDeviceProxy::getDevice(int32_t id) {
+ // TODO use Binder
+ return NULL;
+}
+
} // namespace android
diff --git a/libs/ui/InputDevice.cpp b/libs/ui/InputDevice.cpp
deleted file mode 100644
index b2a4d6c..0000000
--- a/libs/ui/InputDevice.cpp
+++ /dev/null
@@ -1,729 +0,0 @@
-//
-// Copyright 2010 The Android Open Source Project
-//
-// The input reader.
-//
-#define LOG_TAG "InputDevice"
-
-//#define LOG_NDEBUG 0
-
-// Log debug messages for each raw event received from the EventHub.
-#define DEBUG_RAW_EVENTS 0
-
-// Log debug messages about touch screen filtering hacks.
-#define DEBUG_HACKS 0
-
-// Log debug messages about virtual key processing.
-#define DEBUG_VIRTUAL_KEYS 0
-
-// Log debug messages about pointers.
-#define DEBUG_POINTERS 0
-
-// Log debug messages about pointer assignment calculations.
-#define DEBUG_POINTER_ASSIGNMENT 0
-
-#include <cutils/log.h>
-#include <ui/InputDevice.h>
-
-#include <stddef.h>
-#include <unistd.h>
-#include <errno.h>
-#include <limits.h>
-
-/* Slop distance for jumpy pointer detection.
- * The vertical range of the screen divided by this is our epsilon value. */
-#define JUMPY_EPSILON_DIVISOR 212
-
-/* Number of jumpy points to drop for touchscreens that need it. */
-#define JUMPY_TRANSITION_DROPS 3
-#define JUMPY_DROP_LIMIT 3
-
-/* Maximum squared distance for averaging.
- * If moving farther than this, turn of averaging to avoid lag in response. */
-#define AVERAGING_DISTANCE_LIMIT (75 * 75)
-
-
-namespace android {
-
-// --- Static Functions ---
-
-template<typename T>
-inline static T abs(const T& value) {
- return value < 0 ? - value : value;
-}
-
-template<typename T>
-inline static T min(const T& a, const T& b) {
- return a < b ? a : b;
-}
-
-template<typename T>
-inline static void swap(T& a, T& b) {
- T temp = a;
- a = b;
- b = temp;
-}
-
-
-// --- InputDevice ---
-
-InputDevice::InputDevice(int32_t id, uint32_t classes, String8 name) :
- id(id), classes(classes), name(name), ignored(false) {
-}
-
-void InputDevice::reset() {
- if (isKeyboard()) {
- keyboard.reset();
- }
-
- if (isTrackball()) {
- trackball.reset();
- }
-
- if (isMultiTouchScreen()) {
- multiTouchScreen.reset();
- } else if (isSingleTouchScreen()) {
- singleTouchScreen.reset();
- }
-
- if (isTouchScreen()) {
- touchScreen.reset();
- }
-}
-
-
-// --- InputDevice::TouchData ---
-
-void InputDevice::TouchData::copyFrom(const TouchData& other) {
- pointerCount = other.pointerCount;
- idBits = other.idBits;
-
- for (uint32_t i = 0; i < pointerCount; i++) {
- pointers[i] = other.pointers[i];
- idToIndex[i] = other.idToIndex[i];
- }
-}
-
-
-// --- InputDevice::KeyboardState ---
-
-void InputDevice::KeyboardState::reset() {
- current.metaState = AMETA_NONE;
- current.downTime = 0;
-}
-
-
-// --- InputDevice::TrackballState ---
-
-void InputDevice::TrackballState::reset() {
- accumulator.clear();
- current.down = false;
- current.downTime = 0;
-}
-
-
-// --- InputDevice::TouchScreenState ---
-
-void InputDevice::TouchScreenState::reset() {
- lastTouch.clear();
- downTime = 0;
- currentVirtualKey.status = CurrentVirtualKeyState::STATUS_UP;
-
- for (uint32_t i = 0; i < MAX_POINTERS; i++) {
- averagingTouchFilter.historyStart[i] = 0;
- averagingTouchFilter.historyEnd[i] = 0;
- }
-
- jumpyTouchFilter.jumpyPointsDropped = 0;
-}
-
-struct PointerDistanceHeapElement {
- uint32_t currentPointerIndex : 8;
- uint32_t lastPointerIndex : 8;
- uint64_t distance : 48; // squared distance
-};
-
-void InputDevice::TouchScreenState::calculatePointerIds() {
- uint32_t currentPointerCount = currentTouch.pointerCount;
- uint32_t lastPointerCount = lastTouch.pointerCount;
-
- if (currentPointerCount == 0) {
- // No pointers to assign.
- currentTouch.idBits.clear();
- } else if (lastPointerCount == 0) {
- // All pointers are new.
- currentTouch.idBits.clear();
- for (uint32_t i = 0; i < currentPointerCount; i++) {
- currentTouch.pointers[i].id = i;
- currentTouch.idToIndex[i] = i;
- currentTouch.idBits.markBit(i);
- }
- } else if (currentPointerCount == 1 && lastPointerCount == 1) {
- // Only one pointer and no change in count so it must have the same id as before.
- uint32_t id = lastTouch.pointers[0].id;
- currentTouch.pointers[0].id = id;
- currentTouch.idToIndex[id] = 0;
- currentTouch.idBits.value = BitSet32::valueForBit(id);
- } else {
- // General case.
- // We build a heap of squared euclidean distances between current and last pointers
- // associated with the current and last pointer indices. Then, we find the best
- // match (by distance) for each current pointer.
- PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS];
-
- uint32_t heapSize = 0;
- for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount;
- currentPointerIndex++) {
- for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount;
- lastPointerIndex++) {
- int64_t deltaX = currentTouch.pointers[currentPointerIndex].x
- - lastTouch.pointers[lastPointerIndex].x;
- int64_t deltaY = currentTouch.pointers[currentPointerIndex].y
- - lastTouch.pointers[lastPointerIndex].y;
-
- uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY);
-
- // Insert new element into the heap (sift up).
- heap[heapSize].currentPointerIndex = currentPointerIndex;
- heap[heapSize].lastPointerIndex = lastPointerIndex;
- heap[heapSize].distance = distance;
- heapSize += 1;
- }
- }
-
- // Heapify
- for (uint32_t startIndex = heapSize / 2; startIndex != 0; ) {
- startIndex -= 1;
- for (uint32_t parentIndex = startIndex; ;) {
- uint32_t childIndex = parentIndex * 2 + 1;
- if (childIndex >= heapSize) {
- break;
- }
-
- if (childIndex + 1 < heapSize
- && heap[childIndex + 1].distance < heap[childIndex].distance) {
- childIndex += 1;
- }
-
- if (heap[parentIndex].distance <= heap[childIndex].distance) {
- break;
- }
-
- swap(heap[parentIndex], heap[childIndex]);
- parentIndex = childIndex;
- }
- }
-
-#if DEBUG_POINTER_ASSIGNMENT
- LOGD("calculatePointerIds - initial distance min-heap: size=%d", heapSize);
- for (size_t i = 0; i < heapSize; i++) {
- LOGD(" heap[%d]: cur=%d, last=%d, distance=%lld",
- i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
- heap[i].distance);
- }
-#endif
-
- // Pull matches out by increasing order of distance.
- // To avoid reassigning pointers that have already been matched, the loop keeps track
- // of which last and current pointers have been matched using the matchedXXXBits variables.
- // It also tracks the used pointer id bits.
- BitSet32 matchedLastBits(0);
- BitSet32 matchedCurrentBits(0);
- BitSet32 usedIdBits(0);
- bool first = true;
- for (uint32_t i = min(currentPointerCount, lastPointerCount); i > 0; i--) {
- for (;;) {
- if (first) {
- // The first time through the loop, we just consume the root element of
- // the heap (the one with smallest distance).
- first = false;
- } else {
- // Previous iterations consumed the root element of the heap.
- // Pop root element off of the heap (sift down).
- heapSize -= 1;
- assert(heapSize > 0);
-
- // Sift down.
- heap[0] = heap[heapSize];
- for (uint32_t parentIndex = 0; ;) {
- uint32_t childIndex = parentIndex * 2 + 1;
- if (childIndex >= heapSize) {
- break;
- }
-
- if (childIndex + 1 < heapSize
- && heap[childIndex + 1].distance < heap[childIndex].distance) {
- childIndex += 1;
- }
-
- if (heap[parentIndex].distance <= heap[childIndex].distance) {
- break;
- }
-
- swap(heap[parentIndex], heap[childIndex]);
- parentIndex = childIndex;
- }
-
-#if DEBUG_POINTER_ASSIGNMENT
- LOGD("calculatePointerIds - reduced distance min-heap: size=%d", heapSize);
- for (size_t i = 0; i < heapSize; i++) {
- LOGD(" heap[%d]: cur=%d, last=%d, distance=%lld",
- i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
- heap[i].distance);
- }
-#endif
- }
-
- uint32_t currentPointerIndex = heap[0].currentPointerIndex;
- if (matchedCurrentBits.hasBit(currentPointerIndex)) continue; // already matched
-
- uint32_t lastPointerIndex = heap[0].lastPointerIndex;
- if (matchedLastBits.hasBit(lastPointerIndex)) continue; // already matched
-
- matchedCurrentBits.markBit(currentPointerIndex);
- matchedLastBits.markBit(lastPointerIndex);
-
- uint32_t id = lastTouch.pointers[lastPointerIndex].id;
- currentTouch.pointers[currentPointerIndex].id = id;
- currentTouch.idToIndex[id] = currentPointerIndex;
- usedIdBits.markBit(id);
-
-#if DEBUG_POINTER_ASSIGNMENT
- LOGD("calculatePointerIds - matched: cur=%d, last=%d, id=%d, distance=%lld",
- lastPointerIndex, currentPointerIndex, id, heap[0].distance);
-#endif
- break;
- }
- }
-
- // Assign fresh ids to new pointers.
- if (currentPointerCount > lastPointerCount) {
- for (uint32_t i = currentPointerCount - lastPointerCount; ;) {
- uint32_t currentPointerIndex = matchedCurrentBits.firstUnmarkedBit();
- uint32_t id = usedIdBits.firstUnmarkedBit();
-
- currentTouch.pointers[currentPointerIndex].id = id;
- currentTouch.idToIndex[id] = currentPointerIndex;
- usedIdBits.markBit(id);
-
-#if DEBUG_POINTER_ASSIGNMENT
- LOGD("calculatePointerIds - assigned: cur=%d, id=%d",
- currentPointerIndex, id);
-#endif
-
- if (--i == 0) break; // done
- matchedCurrentBits.markBit(currentPointerIndex);
- }
- }
-
- // Fix id bits.
- currentTouch.idBits = usedIdBits;
- }
-}
-
-/* Special hack for devices that have bad screen data: if one of the
- * points has moved more than a screen height from the last position,
- * then drop it. */
-bool InputDevice::TouchScreenState::applyBadTouchFilter() {
- // This hack requires valid axis parameters.
- if (! parameters.yAxis.valid) {
- return false;
- }
-
- uint32_t pointerCount = currentTouch.pointerCount;
-
- // Nothing to do if there are no points.
- if (pointerCount == 0) {
- return false;
- }
-
- // Don't do anything if a finger is going down or up. We run
- // here before assigning pointer IDs, so there isn't a good
- // way to do per-finger matching.
- if (pointerCount != lastTouch.pointerCount) {
- return false;
- }
-
- // We consider a single movement across more than a 7/16 of
- // the long size of the screen to be bad. This was a magic value
- // determined by looking at the maximum distance it is feasible
- // to actually move in one sample.
- int32_t maxDeltaY = parameters.yAxis.range * 7 / 16;
-
- // XXX The original code in InputDevice.java included commented out
- // code for testing the X axis. Note that when we drop a point
- // we don't actually restore the old X either. Strange.
- // The old code also tries to track when bad points were previously
- // detected but it turns out that due to the placement of a "break"
- // at the end of the loop, we never set mDroppedBadPoint to true
- // so it is effectively dead code.
- // Need to figure out if the old code is busted or just overcomplicated
- // but working as intended.
-
- // Look through all new points and see if any are farther than
- // acceptable from all previous points.
- for (uint32_t i = pointerCount; i-- > 0; ) {
- int32_t y = currentTouch.pointers[i].y;
- int32_t closestY = INT_MAX;
- int32_t closestDeltaY = 0;
-
-#if DEBUG_HACKS
- LOGD("BadTouchFilter: Looking at next point #%d: y=%d", i, y);
-#endif
-
- for (uint32_t j = pointerCount; j-- > 0; ) {
- int32_t lastY = lastTouch.pointers[j].y;
- int32_t deltaY = abs(y - lastY);
-
-#if DEBUG_HACKS
- LOGD("BadTouchFilter: Comparing with last point #%d: y=%d deltaY=%d",
- j, lastY, deltaY);
-#endif
-
- if (deltaY < maxDeltaY) {
- goto SkipSufficientlyClosePoint;
- }
- if (deltaY < closestDeltaY) {
- closestDeltaY = deltaY;
- closestY = lastY;
- }
- }
-
- // Must not have found a close enough match.
-#if DEBUG_HACKS
- LOGD("BadTouchFilter: Dropping bad point #%d: newY=%d oldY=%d deltaY=%d maxDeltaY=%d",
- i, y, closestY, closestDeltaY, maxDeltaY);
-#endif
-
- currentTouch.pointers[i].y = closestY;
- return true; // XXX original code only corrects one point
-
- SkipSufficientlyClosePoint: ;
- }
-
- // No change.
- return false;
-}
-
-/* Special hack for devices that have bad screen data: drop points where
- * the coordinate value for one axis has jumped to the other pointer's location.
- */
-bool InputDevice::TouchScreenState::applyJumpyTouchFilter() {
- // This hack requires valid axis parameters.
- if (! parameters.yAxis.valid) {
- return false;
- }
-
- uint32_t pointerCount = currentTouch.pointerCount;
- if (lastTouch.pointerCount != pointerCount) {
-#if DEBUG_HACKS
- LOGD("JumpyTouchFilter: Different pointer count %d -> %d",
- lastTouch.pointerCount, pointerCount);
- for (uint32_t i = 0; i < pointerCount; i++) {
- LOGD(" Pointer %d (%d, %d)", i,
- currentTouch.pointers[i].x, currentTouch.pointers[i].y);
- }
-#endif
-
- if (jumpyTouchFilter.jumpyPointsDropped < JUMPY_TRANSITION_DROPS) {
- if (lastTouch.pointerCount == 1 && pointerCount == 2) {
- // Just drop the first few events going from 1 to 2 pointers.
- // They're bad often enough that they're not worth considering.
- currentTouch.pointerCount = 1;
- jumpyTouchFilter.jumpyPointsDropped += 1;
-
-#if DEBUG_HACKS
- LOGD("JumpyTouchFilter: Pointer 2 dropped");
-#endif
- return true;
- } else if (lastTouch.pointerCount == 2 && pointerCount == 1) {
- // The event when we go from 2 -> 1 tends to be messed up too
- currentTouch.pointerCount = 2;
- currentTouch.pointers[0] = lastTouch.pointers[0];
- currentTouch.pointers[1] = lastTouch.pointers[1];
- jumpyTouchFilter.jumpyPointsDropped += 1;
-
-#if DEBUG_HACKS
- for (int32_t i = 0; i < 2; i++) {
- LOGD("JumpyTouchFilter: Pointer %d replaced (%d, %d)", i,
- currentTouch.pointers[i].x, currentTouch.pointers[i].y);
- }
-#endif
- return true;
- }
- }
- // Reset jumpy points dropped on other transitions or if limit exceeded.
- jumpyTouchFilter.jumpyPointsDropped = 0;
-
-#if DEBUG_HACKS
- LOGD("JumpyTouchFilter: Transition - drop limit reset");
-#endif
- return false;
- }
-
- // We have the same number of pointers as last time.
- // A 'jumpy' point is one where the coordinate value for one axis
- // has jumped to the other pointer's location. No need to do anything
- // else if we only have one pointer.
- if (pointerCount < 2) {
- return false;
- }
-
- if (jumpyTouchFilter.jumpyPointsDropped < JUMPY_DROP_LIMIT) {
- int jumpyEpsilon = parameters.yAxis.range / JUMPY_EPSILON_DIVISOR;
-
- // We only replace the single worst jumpy point as characterized by pointer distance
- // in a single axis.
- int32_t badPointerIndex = -1;
- int32_t badPointerReplacementIndex = -1;
- int32_t badPointerDistance = INT_MIN; // distance to be corrected
-
- for (uint32_t i = pointerCount; i-- > 0; ) {
- int32_t x = currentTouch.pointers[i].x;
- int32_t y = currentTouch.pointers[i].y;
-
-#if DEBUG_HACKS
- LOGD("JumpyTouchFilter: Point %d (%d, %d)", i, x, y);
-#endif
-
- // Check if a touch point is too close to another's coordinates
- bool dropX = false, dropY = false;
- for (uint32_t j = 0; j < pointerCount; j++) {
- if (i == j) {
- continue;
- }
-
- if (abs(x - currentTouch.pointers[j].x) <= jumpyEpsilon) {
- dropX = true;
- break;
- }
-
- if (abs(y - currentTouch.pointers[j].y) <= jumpyEpsilon) {
- dropY = true;
- break;
- }
- }
- if (! dropX && ! dropY) {
- continue; // not jumpy
- }
-
- // Find a replacement candidate by comparing with older points on the
- // complementary (non-jumpy) axis.
- int32_t distance = INT_MIN; // distance to be corrected
- int32_t replacementIndex = -1;
-
- if (dropX) {
- // X looks too close. Find an older replacement point with a close Y.
- int32_t smallestDeltaY = INT_MAX;
- for (uint32_t j = 0; j < pointerCount; j++) {
- int32_t deltaY = abs(y - lastTouch.pointers[j].y);
- if (deltaY < smallestDeltaY) {
- smallestDeltaY = deltaY;
- replacementIndex = j;
- }
- }
- distance = abs(x - lastTouch.pointers[replacementIndex].x);
- } else {
- // Y looks too close. Find an older replacement point with a close X.
- int32_t smallestDeltaX = INT_MAX;
- for (uint32_t j = 0; j < pointerCount; j++) {
- int32_t deltaX = abs(x - lastTouch.pointers[j].x);
- if (deltaX < smallestDeltaX) {
- smallestDeltaX = deltaX;
- replacementIndex = j;
- }
- }
- distance = abs(y - lastTouch.pointers[replacementIndex].y);
- }
-
- // If replacing this pointer would correct a worse error than the previous ones
- // considered, then use this replacement instead.
- if (distance > badPointerDistance) {
- badPointerIndex = i;
- badPointerReplacementIndex = replacementIndex;
- badPointerDistance = distance;
- }
- }
-
- // Correct the jumpy pointer if one was found.
- if (badPointerIndex >= 0) {
-#if DEBUG_HACKS
- LOGD("JumpyTouchFilter: Replacing bad pointer %d with (%d, %d)",
- badPointerIndex,
- lastTouch.pointers[badPointerReplacementIndex].x,
- lastTouch.pointers[badPointerReplacementIndex].y);
-#endif
-
- currentTouch.pointers[badPointerIndex].x =
- lastTouch.pointers[badPointerReplacementIndex].x;
- currentTouch.pointers[badPointerIndex].y =
- lastTouch.pointers[badPointerReplacementIndex].y;
- jumpyTouchFilter.jumpyPointsDropped += 1;
- return true;
- }
- }
-
- jumpyTouchFilter.jumpyPointsDropped = 0;
- return false;
-}
-
-/* Special hack for devices that have bad screen data: aggregate and
- * compute averages of the coordinate data, to reduce the amount of
- * jitter seen by applications. */
-void InputDevice::TouchScreenState::applyAveragingTouchFilter() {
- for (uint32_t currentIndex = 0; currentIndex < currentTouch.pointerCount; currentIndex++) {
- uint32_t id = currentTouch.pointers[currentIndex].id;
- int32_t x = currentTouch.pointers[currentIndex].x;
- int32_t y = currentTouch.pointers[currentIndex].y;
- int32_t pressure = currentTouch.pointers[currentIndex].pressure;
-
- if (lastTouch.idBits.hasBit(id)) {
- // Pointer was down before and is still down now.
- // Compute average over history trace.
- uint32_t start = averagingTouchFilter.historyStart[id];
- uint32_t end = averagingTouchFilter.historyEnd[id];
-
- int64_t deltaX = x - averagingTouchFilter.historyData[end].pointers[id].x;
- int64_t deltaY = y - averagingTouchFilter.historyData[end].pointers[id].y;
- uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY);
-
-#if DEBUG_HACKS
- LOGD("AveragingTouchFilter: Pointer id %d - Distance from last sample: %lld",
- id, distance);
-#endif
-
- if (distance < AVERAGING_DISTANCE_LIMIT) {
- // Increment end index in preparation for recording new historical data.
- end += 1;
- if (end > AVERAGING_HISTORY_SIZE) {
- end = 0;
- }
-
- // If the end index has looped back to the start index then we have filled
- // the historical trace up to the desired size so we drop the historical
- // data at the start of the trace.
- if (end == start) {
- start += 1;
- if (start > AVERAGING_HISTORY_SIZE) {
- start = 0;
- }
- }
-
- // Add the raw data to the historical trace.
- averagingTouchFilter.historyStart[id] = start;
- averagingTouchFilter.historyEnd[id] = end;
- averagingTouchFilter.historyData[end].pointers[id].x = x;
- averagingTouchFilter.historyData[end].pointers[id].y = y;
- averagingTouchFilter.historyData[end].pointers[id].pressure = pressure;
-
- // Average over all historical positions in the trace by total pressure.
- int32_t averagedX = 0;
- int32_t averagedY = 0;
- int32_t totalPressure = 0;
- for (;;) {
- int32_t historicalX = averagingTouchFilter.historyData[start].pointers[id].x;
- int32_t historicalY = averagingTouchFilter.historyData[start].pointers[id].y;
- int32_t historicalPressure = averagingTouchFilter.historyData[start]
- .pointers[id].pressure;
-
- averagedX += historicalX * historicalPressure;
- averagedY += historicalY * historicalPressure;
- totalPressure += historicalPressure;
-
- if (start == end) {
- break;
- }
-
- start += 1;
- if (start > AVERAGING_HISTORY_SIZE) {
- start = 0;
- }
- }
-
- averagedX /= totalPressure;
- averagedY /= totalPressure;
-
-#if DEBUG_HACKS
- LOGD("AveragingTouchFilter: Pointer id %d - "
- "totalPressure=%d, averagedX=%d, averagedY=%d", id, totalPressure,
- averagedX, averagedY);
-#endif
-
- currentTouch.pointers[currentIndex].x = averagedX;
- currentTouch.pointers[currentIndex].y = averagedY;
- } else {
-#if DEBUG_HACKS
- LOGD("AveragingTouchFilter: Pointer id %d - Exceeded max distance", id);
-#endif
- }
- } else {
-#if DEBUG_HACKS
- LOGD("AveragingTouchFilter: Pointer id %d - Pointer went up", id);
-#endif
- }
-
- // Reset pointer history.
- averagingTouchFilter.historyStart[id] = 0;
- averagingTouchFilter.historyEnd[id] = 0;
- averagingTouchFilter.historyData[0].pointers[id].x = x;
- averagingTouchFilter.historyData[0].pointers[id].y = y;
- averagingTouchFilter.historyData[0].pointers[id].pressure = pressure;
- }
-}
-
-bool InputDevice::TouchScreenState::isPointInsideDisplay(int32_t x, int32_t y) const {
- if (! parameters.xAxis.valid || ! parameters.yAxis.valid) {
- // Assume all points on a touch screen without valid axis parameters are
- // inside the display.
- return true;
- }
-
- return x >= parameters.xAxis.minValue
- && x <= parameters.xAxis.maxValue
- && y >= parameters.yAxis.minValue
- && y <= parameters.yAxis.maxValue;
-}
-
-const InputDevice::VirtualKey* InputDevice::TouchScreenState::findVirtualKeyHit() const {
- int32_t x = currentTouch.pointers[0].x;
- int32_t y = currentTouch.pointers[0].y;
- for (size_t i = 0; i < virtualKeys.size(); i++) {
- const InputDevice::VirtualKey& virtualKey = virtualKeys[i];
-
-#if DEBUG_VIRTUAL_KEYS
- LOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, "
- "left=%d, top=%d, right=%d, bottom=%d",
- x, y,
- virtualKey.keyCode, virtualKey.scanCode,
- virtualKey.hitLeft, virtualKey.hitTop,
- virtualKey.hitRight, virtualKey.hitBottom);
-#endif
-
- if (virtualKey.isHit(x, y)) {
- return & virtualKey;
- }
- }
-
- return NULL;
-}
-
-
-// --- InputDevice::SingleTouchScreenState ---
-
-void InputDevice::SingleTouchScreenState::reset() {
- accumulator.clear();
- current.down = false;
- current.x = 0;
- current.y = 0;
- current.pressure = 0;
- current.size = 0;
-}
-
-
-// --- InputDevice::MultiTouchScreenState ---
-
-void InputDevice::MultiTouchScreenState::reset() {
- accumulator.clear();
-}
-
-} // namespace android
diff --git a/libs/ui/InputManager.cpp b/libs/ui/InputManager.cpp
index e1d15a4..bf23479 100644
--- a/libs/ui/InputManager.cpp
+++ b/libs/ui/InputManager.cpp
@@ -89,26 +89,35 @@ void InputManager::preemptInputDispatch() {
mDispatcher->preemptInputDispatch();
}
-void InputManager::getInputConfiguration(InputConfiguration* outConfiguration) const {
- mReader->getCurrentInputConfiguration(outConfiguration);
+void InputManager::getInputConfiguration(InputConfiguration* outConfiguration) {
+ mReader->getInputConfiguration(outConfiguration);
}
-int32_t InputManager::getScanCodeState(int32_t deviceId, int32_t deviceClasses,
- int32_t scanCode) const {
- return mReader->getCurrentScanCodeState(deviceId, deviceClasses, scanCode);
+status_t InputManager::getInputDeviceInfo(int32_t deviceId, InputDeviceInfo* outDeviceInfo) {
+ return mReader->getInputDeviceInfo(deviceId, outDeviceInfo);
}
-int32_t InputManager::getKeyCodeState(int32_t deviceId, int32_t deviceClasses,
- int32_t keyCode) const {
- return mReader->getCurrentKeyCodeState(deviceId, deviceClasses, keyCode);
+void InputManager::getInputDeviceIds(Vector<int32_t>& outDeviceIds) {
+ mReader->getInputDeviceIds(outDeviceIds);
}
-int32_t InputManager::getSwitchState(int32_t deviceId, int32_t deviceClasses, int32_t sw) const {
- return mReader->getCurrentSwitchState(deviceId, deviceClasses, sw);
+int32_t InputManager::getScanCodeState(int32_t deviceId, uint32_t sourceMask,
+ int32_t scanCode) {
+ return mReader->getScanCodeState(deviceId, sourceMask, scanCode);
}
-bool InputManager::hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const {
- return mReader->hasKeys(numCodes, keyCodes, outFlags);
+int32_t InputManager::getKeyCodeState(int32_t deviceId, uint32_t sourceMask,
+ int32_t keyCode) {
+ return mReader->getKeyCodeState(deviceId, sourceMask, keyCode);
+}
+
+int32_t InputManager::getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t sw) {
+ return mReader->getSwitchState(deviceId, sourceMask, sw);
+}
+
+bool InputManager::hasKeys(int32_t deviceId, uint32_t sourceMask,
+ size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) {
+ return mReader->hasKeys(deviceId, sourceMask, numCodes, keyCodes, outFlags);
}
} // namespace android
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 30e391f..c5183e4 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -31,10 +31,6 @@
#include <limits.h>
#include <math.h>
-/** Amount that trackball needs to move in order to generate a key event. */
-#define TRACKBALL_MOVEMENT_THRESHOLD 6
-
-
namespace android {
// --- Static Functions ---
@@ -115,17 +111,21 @@ int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) {
return keyCode;
}
+static inline bool sourcesMatchMask(uint32_t sources, uint32_t sourceMask) {
+ return (sources & sourceMask & ~ AINPUT_SOURCE_CLASS_MASK) != 0;
+}
+
// --- InputReader ---
InputReader::InputReader(const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& policy,
const sp<InputDispatcherInterface>& dispatcher) :
- mEventHub(eventHub), mPolicy(policy), mDispatcher(dispatcher) {
+ mEventHub(eventHub), mPolicy(policy), mDispatcher(dispatcher),
+ mGlobalMetaState(0) {
configureExcludedDevices();
- resetGlobalMetaState();
- resetDisplayProperties();
- updateExportedVirtualKeyState();
+ updateGlobalMetaState();
+ updateInputConfiguration();
}
InputReader::~InputReader() {
@@ -136,12 +136,7 @@ InputReader::~InputReader() {
void InputReader::loopOnce() {
RawEvent rawEvent;
- mEventHub->getEvent(& rawEvent.deviceId, & rawEvent.type, & rawEvent.scanCode,
- & rawEvent.keyCode, & rawEvent.flags, & rawEvent.value, & rawEvent.when);
-
- // Replace the event timestamp so it is in same timebase as java.lang.System.nanoTime()
- // and android.os.SystemClock.uptimeMillis() as expected by the rest of the system.
- rawEvent.when = systemTime(SYSTEM_TIME_MONOTONIC);
+ mEventHub->getEvent(& rawEvent);
#if DEBUG_RAW_EVENTS
LOGD("Input event: device=0x%x type=0x%x scancode=%d keycode=%d value=%d",
@@ -155,621 +150,1371 @@ void InputReader::loopOnce() {
void InputReader::process(const RawEvent* rawEvent) {
switch (rawEvent->type) {
case EventHubInterface::DEVICE_ADDED:
- handleDeviceAdded(rawEvent);
+ addDevice(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::DEVICE_REMOVED:
- handleDeviceRemoved(rawEvent);
+ removeDevice(rawEvent->when, rawEvent->deviceId);
break;
- case EV_SYN:
- handleSync(rawEvent);
+ default:
+ consumeEvent(rawEvent);
break;
+ }
+}
- case EV_KEY:
- handleKey(rawEvent);
- break;
+void InputReader::addDevice(nsecs_t when, int32_t deviceId) {
+ String8 name = mEventHub->getDeviceName(deviceId);
+ uint32_t classes = mEventHub->getDeviceClasses(deviceId);
- case EV_REL:
- handleRelativeMotion(rawEvent);
- break;
+ InputDevice* device = createDevice(deviceId, name, classes);
+ device->configure();
- case EV_ABS:
- handleAbsoluteMotion(rawEvent);
- break;
+ bool added = false;
+ { // acquire device registry writer lock
+ RWLock::AutoWLock _wl(mDeviceRegistryLock);
- case EV_SW:
- handleSwitch(rawEvent);
- break;
+ ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
+ if (deviceIndex < 0) {
+ mDevices.add(deviceId, device);
+ added = true;
+ }
+ } // release device registry writer lock
+
+ if (! added) {
+ LOGW("Ignoring spurious device added event for deviceId %d.", deviceId);
+ delete device;
+ return;
}
+
+ if (device->isIgnored()) {
+ LOGI("Device added: id=0x%x, name=%s (ignored non-input device)",
+ deviceId, name.string());
+ } else {
+ LOGI("Device added: id=0x%x, name=%s, sources=%08x",
+ deviceId, name.string(), device->getSources());
+ }
+
+ handleConfigurationChanged(when);
}
-void InputReader::handleDeviceAdded(const RawEvent* rawEvent) {
- InputDevice* device = getDevice(rawEvent->deviceId);
- if (device) {
- LOGW("Ignoring spurious device added event for deviceId %d.", rawEvent->deviceId);
+void InputReader::removeDevice(nsecs_t when, int32_t deviceId) {
+ bool removed = false;
+ InputDevice* device = NULL;
+ { // acquire device registry writer lock
+ RWLock::AutoWLock _wl(mDeviceRegistryLock);
+
+ ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
+ if (deviceIndex >= 0) {
+ device = mDevices.valueAt(deviceIndex);
+ mDevices.removeItemsAt(deviceIndex, 1);
+ removed = true;
+ }
+ } // release device registry writer lock
+
+ if (! removed) {
+ LOGW("Ignoring spurious device removed event for deviceId %d.", deviceId);
return;
}
- addDevice(rawEvent->when, rawEvent->deviceId);
+ device->reset();
+
+ if (device->isIgnored()) {
+ LOGI("Device removed: id=0x%x, name=%s (ignored non-input device)",
+ device->getId(), device->getName().string());
+ } else {
+ LOGI("Device removed: id=0x%x, name=%s, sources=%08x",
+ device->getId(), device->getName().string(), device->getSources());
+ }
+
+ delete device;
+
+ handleConfigurationChanged(when);
}
-void InputReader::handleDeviceRemoved(const RawEvent* rawEvent) {
- InputDevice* device = getDevice(rawEvent->deviceId);
- if (! device) {
- LOGW("Ignoring spurious device removed event for deviceId %d.", rawEvent->deviceId);
- return;
+InputDevice* InputReader::createDevice(int32_t deviceId, const String8& name, uint32_t classes) {
+ InputDevice* device = new InputDevice(this, deviceId, name);
+
+ const int32_t associatedDisplayId = 0; // FIXME: hardcoded for current single-display devices
+
+ // Switch-like devices.
+ if (classes & INPUT_DEVICE_CLASS_SWITCH) {
+ device->addMapper(new SwitchInputMapper(device));
}
- removeDevice(rawEvent->when, device);
+ // Keyboard-like devices.
+ uint32_t keyboardSources = 0;
+ int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;
+ if (classes & INPUT_DEVICE_CLASS_KEYBOARD) {
+ keyboardSources |= AINPUT_SOURCE_KEYBOARD;
+ }
+ if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) {
+ keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;
+ }
+ if (classes & INPUT_DEVICE_CLASS_DPAD) {
+ keyboardSources |= AINPUT_SOURCE_DPAD;
+ }
+ if (classes & INPUT_DEVICE_CLASS_GAMEPAD) {
+ keyboardSources |= AINPUT_SOURCE_GAMEPAD;
+ }
+
+ if (keyboardSources != 0) {
+ device->addMapper(new KeyboardInputMapper(device,
+ associatedDisplayId, keyboardSources, keyboardType));
+ }
+
+ // Trackball-like devices.
+ if (classes & INPUT_DEVICE_CLASS_TRACKBALL) {
+ device->addMapper(new TrackballInputMapper(device, associatedDisplayId));
+ }
+
+ // Touchscreen-like devices.
+ if (classes & INPUT_DEVICE_CLASS_TOUCHSCREEN_MT) {
+ device->addMapper(new MultiTouchInputMapper(device, associatedDisplayId));
+ } else if (classes & INPUT_DEVICE_CLASS_TOUCHSCREEN) {
+ device->addMapper(new SingleTouchInputMapper(device, associatedDisplayId));
+ }
+
+ return device;
}
-void InputReader::handleSync(const RawEvent* rawEvent) {
- InputDevice* device = getNonIgnoredDevice(rawEvent->deviceId);
- if (! device) return;
+void InputReader::consumeEvent(const RawEvent* rawEvent) {
+ int32_t deviceId = rawEvent->deviceId;
- if (rawEvent->scanCode == SYN_MT_REPORT) {
- // MultiTouch Sync: The driver has returned all data for *one* of the pointers.
- // We drop pointers with pressure <= 0 since that indicates they are not down.
- if (device->isMultiTouchScreen()) {
- uint32_t pointerIndex = device->multiTouchScreen.accumulator.pointerCount;
+ { // acquire device registry reader lock
+ RWLock::AutoRLock _rl(mDeviceRegistryLock);
- if (device->multiTouchScreen.accumulator.pointers[pointerIndex].fields) {
- if (pointerIndex == MAX_POINTERS) {
- LOGW("MultiTouch device driver returned more than maximum of %d pointers.",
- MAX_POINTERS);
- } else {
- pointerIndex += 1;
- device->multiTouchScreen.accumulator.pointerCount = pointerIndex;
+ ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
+ if (deviceIndex < 0) {
+ LOGW("Discarding event for unknown deviceId %d.", deviceId);
+ return;
+ }
+
+ InputDevice* device = mDevices.valueAt(deviceIndex);
+ if (device->isIgnored()) {
+ //LOGD("Discarding event for ignored deviceId %d.", deviceId);
+ return;
+ }
+
+ device->process(rawEvent);
+ } // release device registry reader lock
+}
+
+void InputReader::handleConfigurationChanged(nsecs_t when) {
+ // Reset global meta state because it depends on the list of all configured devices.
+ updateGlobalMetaState();
+
+ // Update input configuration.
+ updateInputConfiguration();
+
+ // Enqueue configuration changed.
+ mDispatcher->notifyConfigurationChanged(when);
+}
+
+void InputReader::configureExcludedDevices() {
+ Vector<String8> excludedDeviceNames;
+ mPolicy->getExcludedDeviceNames(excludedDeviceNames);
+
+ for (size_t i = 0; i < excludedDeviceNames.size(); i++) {
+ mEventHub->addExcludedDevice(excludedDeviceNames[i]);
+ }
+}
+
+void InputReader::updateGlobalMetaState() {
+ { // acquire state lock
+ AutoMutex _l(mStateLock);
+
+ mGlobalMetaState = 0;
+
+ { // acquire device registry reader lock
+ RWLock::AutoRLock _rl(mDeviceRegistryLock);
+
+ for (size_t i = 0; i < mDevices.size(); i++) {
+ InputDevice* device = mDevices.valueAt(i);
+ mGlobalMetaState |= device->getMetaState();
+ }
+ } // release device registry reader lock
+ } // release state lock
+}
+
+int32_t InputReader::getGlobalMetaState() {
+ { // acquire state lock
+ AutoMutex _l(mStateLock);
+
+ return mGlobalMetaState;
+ } // release state lock
+}
+
+void InputReader::updateInputConfiguration() {
+ { // acquire state lock
+ AutoMutex _l(mStateLock);
+
+ int32_t touchScreenConfig = InputConfiguration::TOUCHSCREEN_NOTOUCH;
+ int32_t keyboardConfig = InputConfiguration::KEYBOARD_NOKEYS;
+ int32_t navigationConfig = InputConfiguration::NAVIGATION_NONAV;
+ { // acquire device registry reader lock
+ RWLock::AutoRLock _rl(mDeviceRegistryLock);
+
+ InputDeviceInfo deviceInfo;
+ for (size_t i = 0; i < mDevices.size(); i++) {
+ InputDevice* device = mDevices.valueAt(i);
+ device->getDeviceInfo(& deviceInfo);
+ uint32_t sources = deviceInfo.getSources();
+
+ if ((sources & AINPUT_SOURCE_TOUCHSCREEN) == AINPUT_SOURCE_TOUCHSCREEN) {
+ touchScreenConfig = InputConfiguration::TOUCHSCREEN_FINGER;
+ }
+ if ((sources & AINPUT_SOURCE_TRACKBALL) == AINPUT_SOURCE_TRACKBALL) {
+ navigationConfig = InputConfiguration::NAVIGATION_TRACKBALL;
+ } else if ((sources & AINPUT_SOURCE_DPAD) == AINPUT_SOURCE_DPAD) {
+ navigationConfig = InputConfiguration::NAVIGATION_DPAD;
+ }
+ if (deviceInfo.getKeyboardType() == AINPUT_KEYBOARD_TYPE_ALPHABETIC) {
+ keyboardConfig = InputConfiguration::KEYBOARD_QWERTY;
}
}
+ } // release device registry reader lock
+
+ mInputConfiguration.touchScreen = touchScreenConfig;
+ mInputConfiguration.keyboard = keyboardConfig;
+ mInputConfiguration.navigation = navigationConfig;
+ } // release state lock
+}
+
+void InputReader::getInputConfiguration(InputConfiguration* outConfiguration) {
+ { // acquire state lock
+ AutoMutex _l(mStateLock);
+
+ *outConfiguration = mInputConfiguration;
+ } // release state lock
+}
+
+status_t InputReader::getInputDeviceInfo(int32_t deviceId, InputDeviceInfo* outDeviceInfo) {
+ { // acquire device registry reader lock
+ RWLock::AutoRLock _rl(mDeviceRegistryLock);
- device->multiTouchScreen.accumulator.pointers[pointerIndex].clear();
+ ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
+ if (deviceIndex < 0) {
+ return NAME_NOT_FOUND;
}
- } else if (rawEvent->scanCode == SYN_REPORT) {
- // General Sync: The driver has returned all data for the current event update.
- if (device->isMultiTouchScreen()) {
- if (device->multiTouchScreen.accumulator.isDirty()) {
- onMultiTouchScreenStateChanged(rawEvent->when, device);
- device->multiTouchScreen.accumulator.clear();
+
+ InputDevice* device = mDevices.valueAt(deviceIndex);
+ if (device->isIgnored()) {
+ return NAME_NOT_FOUND;
+ }
+
+ device->getDeviceInfo(outDeviceInfo);
+ return OK;
+ } // release device registy reader lock
+}
+
+void InputReader::getInputDeviceIds(Vector<int32_t>& outDeviceIds) {
+ outDeviceIds.clear();
+
+ { // acquire device registry reader lock
+ RWLock::AutoRLock _rl(mDeviceRegistryLock);
+
+ size_t numDevices = mDevices.size();
+ for (size_t i = 0; i < numDevices; i++) {
+ InputDevice* device = mDevices.valueAt(i);
+ if (! device->isIgnored()) {
+ outDeviceIds.add(device->getId());
}
- } else if (device->isSingleTouchScreen()) {
- if (device->singleTouchScreen.accumulator.isDirty()) {
- onSingleTouchScreenStateChanged(rawEvent->when, device);
- device->singleTouchScreen.accumulator.clear();
+ }
+ } // release device registy reader lock
+}
+
+int32_t InputReader::getKeyCodeState(int32_t deviceId, uint32_t sourceMask,
+ int32_t keyCode) {
+ return getState(deviceId, sourceMask, keyCode, & InputDevice::getKeyCodeState);
+}
+
+int32_t InputReader::getScanCodeState(int32_t deviceId, uint32_t sourceMask,
+ int32_t scanCode) {
+ return getState(deviceId, sourceMask, scanCode, & InputDevice::getScanCodeState);
+}
+
+int32_t InputReader::getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t switchCode) {
+ return getState(deviceId, sourceMask, switchCode, & InputDevice::getSwitchState);
+}
+
+int32_t InputReader::getState(int32_t deviceId, uint32_t sourceMask, int32_t code,
+ GetStateFunc getStateFunc) {
+ { // acquire device registry reader lock
+ RWLock::AutoRLock _rl(mDeviceRegistryLock);
+
+ int32_t result = AKEY_STATE_UNKNOWN;
+ if (deviceId >= 0) {
+ ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
+ if (deviceIndex >= 0) {
+ InputDevice* device = mDevices.valueAt(deviceIndex);
+ if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
+ result = (device->*getStateFunc)(sourceMask, code);
+ }
+ }
+ } else {
+ size_t numDevices = mDevices.size();
+ for (size_t i = 0; i < numDevices; i++) {
+ InputDevice* device = mDevices.valueAt(i);
+ if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
+ result = (device->*getStateFunc)(sourceMask, code);
+ if (result >= AKEY_STATE_DOWN) {
+ return result;
+ }
+ }
}
}
+ return result;
+ } // release device registy reader lock
+}
+
+bool InputReader::hasKeys(int32_t deviceId, uint32_t sourceMask,
+ size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) {
+ memset(outFlags, 0, numCodes);
+ return markSupportedKeyCodes(deviceId, sourceMask, numCodes, keyCodes, outFlags);
+}
- if (device->trackball.accumulator.isDirty()) {
- onTrackballStateChanged(rawEvent->when, device);
- device->trackball.accumulator.clear();
+bool InputReader::markSupportedKeyCodes(int32_t deviceId, uint32_t sourceMask, size_t numCodes,
+ const int32_t* keyCodes, uint8_t* outFlags) {
+ { // acquire device registry reader lock
+ RWLock::AutoRLock _rl(mDeviceRegistryLock);
+ bool result = false;
+ if (deviceId >= 0) {
+ ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
+ if (deviceIndex >= 0) {
+ InputDevice* device = mDevices.valueAt(deviceIndex);
+ if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
+ result = device->markSupportedKeyCodes(sourceMask,
+ numCodes, keyCodes, outFlags);
+ }
+ }
+ } else {
+ size_t numDevices = mDevices.size();
+ for (size_t i = 0; i < numDevices; i++) {
+ InputDevice* device = mDevices.valueAt(i);
+ if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
+ result |= device->markSupportedKeyCodes(sourceMask,
+ numCodes, keyCodes, outFlags);
+ }
+ }
}
- }
+ return result;
+ } // release device registy reader lock
}
-void InputReader::handleKey(const RawEvent* rawEvent) {
- InputDevice* device = getNonIgnoredDevice(rawEvent->deviceId);
- if (! device) return;
- bool down = rawEvent->value != 0;
- int32_t scanCode = rawEvent->scanCode;
+// --- InputReaderThread ---
- if (device->isSingleTouchScreen()) {
- switch (rawEvent->scanCode) {
- case BTN_TOUCH:
- device->singleTouchScreen.accumulator.fields |=
- InputDevice::SingleTouchScreenState::Accumulator::FIELD_BTN_TOUCH;
- device->singleTouchScreen.accumulator.btnTouch = down;
- return;
- }
+InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
+ Thread(/*canCallJava*/ true), mReader(reader) {
+}
+
+InputReaderThread::~InputReaderThread() {
+}
+
+bool InputReaderThread::threadLoop() {
+ mReader->loopOnce();
+ return true;
+}
+
+
+// --- InputDevice ---
+
+InputDevice::InputDevice(InputReaderContext* context, int32_t id, const String8& name) :
+ mContext(context), mId(id), mName(name), mSources(0) {
+}
+
+InputDevice::~InputDevice() {
+ size_t numMappers = mMappers.size();
+ for (size_t i = 0; i < numMappers; i++) {
+ delete mMappers[i];
}
+ mMappers.clear();
+}
- if (device->isTrackball()) {
- switch (rawEvent->scanCode) {
- case BTN_MOUSE:
- device->trackball.accumulator.fields |=
- InputDevice::TrackballState::Accumulator::FIELD_BTN_MOUSE;
- device->trackball.accumulator.btnMouse = down;
+void InputDevice::addMapper(InputMapper* mapper) {
+ mMappers.add(mapper);
+}
- // Process the trackball change now since we may not receive a sync immediately.
- onTrackballStateChanged(rawEvent->when, device);
- device->trackball.accumulator.clear();
- return;
- }
+void InputDevice::configure() {
+ mSources = 0;
+
+ size_t numMappers = mMappers.size();
+ for (size_t i = 0; i < numMappers; i++) {
+ InputMapper* mapper = mMappers[i];
+ mapper->configure();
+ mSources |= mapper->getSources();
+ }
+}
+
+void InputDevice::reset() {
+ size_t numMappers = mMappers.size();
+ for (size_t i = 0; i < numMappers; i++) {
+ InputMapper* mapper = mMappers[i];
+ mapper->reset();
}
+}
- if (device->isKeyboard()) {
- int32_t keyCode = rawEvent->keyCode;
- onKey(rawEvent->when, device, down, keyCode, scanCode, rawEvent->flags);
+void InputDevice::process(const RawEvent* rawEvent) {
+ size_t numMappers = mMappers.size();
+ for (size_t i = 0; i < numMappers; i++) {
+ InputMapper* mapper = mMappers[i];
+ mapper->process(rawEvent);
}
}
-void InputReader::handleRelativeMotion(const RawEvent* rawEvent) {
- InputDevice* device = getNonIgnoredDevice(rawEvent->deviceId);
- if (! device) return;
+void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) {
+ outDeviceInfo->initialize(mId, mName);
- if (device->isTrackball()) {
- switch (rawEvent->scanCode) {
- case REL_X:
- device->trackball.accumulator.fields |=
- InputDevice::TrackballState::Accumulator::FIELD_REL_X;
- device->trackball.accumulator.relX = rawEvent->value;
- break;
- case REL_Y:
- device->trackball.accumulator.fields |=
- InputDevice::TrackballState::Accumulator::FIELD_REL_Y;
- device->trackball.accumulator.relY = rawEvent->value;
- break;
- }
+ size_t numMappers = mMappers.size();
+ for (size_t i = 0; i < numMappers; i++) {
+ InputMapper* mapper = mMappers[i];
+ mapper->populateDeviceInfo(outDeviceInfo);
}
}
-void InputReader::handleAbsoluteMotion(const RawEvent* rawEvent) {
- InputDevice* device = getNonIgnoredDevice(rawEvent->deviceId);
- if (! device) return;
+int32_t InputDevice::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
+ return getState(sourceMask, keyCode, & InputMapper::getKeyCodeState);
+}
- if (device->isMultiTouchScreen()) {
- uint32_t pointerIndex = device->multiTouchScreen.accumulator.pointerCount;
- InputDevice::MultiTouchScreenState::Accumulator::Pointer* pointer =
- & device->multiTouchScreen.accumulator.pointers[pointerIndex];
+int32_t InputDevice::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
+ return getState(sourceMask, scanCode, & InputMapper::getScanCodeState);
+}
- switch (rawEvent->scanCode) {
- case ABS_MT_POSITION_X:
- pointer->fields |=
- InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_POSITION_X;
- pointer->absMTPositionX = rawEvent->value;
- break;
- case ABS_MT_POSITION_Y:
- pointer->fields |=
- InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_POSITION_Y;
- pointer->absMTPositionY = rawEvent->value;
- break;
- case ABS_MT_TOUCH_MAJOR:
- pointer->fields |=
- InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_TOUCH_MAJOR;
- pointer->absMTTouchMajor = rawEvent->value;
- break;
- case ABS_MT_TOUCH_MINOR:
- pointer->fields |=
- InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_TOUCH_MINOR;
- pointer->absMTTouchMinor = rawEvent->value;
- break;
- case ABS_MT_WIDTH_MAJOR:
- pointer->fields |=
- InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_WIDTH_MAJOR;
- pointer->absMTWidthMajor = rawEvent->value;
- break;
- case ABS_MT_WIDTH_MINOR:
- pointer->fields |=
- InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_WIDTH_MINOR;
- pointer->absMTWidthMinor = rawEvent->value;
- break;
- case ABS_MT_ORIENTATION:
- pointer->fields |=
- InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_ORIENTATION;
- pointer->absMTOrientation = rawEvent->value;
- break;
- case ABS_MT_TRACKING_ID:
- pointer->fields |=
- InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_TRACKING_ID;
- pointer->absMTTrackingId = rawEvent->value;
- break;
+int32_t InputDevice::getSwitchState(uint32_t sourceMask, int32_t switchCode) {
+ return getState(sourceMask, switchCode, & InputMapper::getSwitchState);
+}
+
+int32_t InputDevice::getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc) {
+ int32_t result = AKEY_STATE_UNKNOWN;
+ size_t numMappers = mMappers.size();
+ for (size_t i = 0; i < numMappers; i++) {
+ InputMapper* mapper = mMappers[i];
+ if (sourcesMatchMask(mapper->getSources(), sourceMask)) {
+ result = (mapper->*getStateFunc)(sourceMask, code);
+ if (result >= AKEY_STATE_DOWN) {
+ return result;
+ }
}
- } else if (device->isSingleTouchScreen()) {
- switch (rawEvent->scanCode) {
- case ABS_X:
- device->singleTouchScreen.accumulator.fields |=
- InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_X;
- device->singleTouchScreen.accumulator.absX = rawEvent->value;
- break;
- case ABS_Y:
- device->singleTouchScreen.accumulator.fields |=
- InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_Y;
- device->singleTouchScreen.accumulator.absY = rawEvent->value;
- break;
- case ABS_PRESSURE:
- device->singleTouchScreen.accumulator.fields |=
- InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_PRESSURE;
- device->singleTouchScreen.accumulator.absPressure = rawEvent->value;
- break;
- case ABS_TOOL_WIDTH:
- device->singleTouchScreen.accumulator.fields |=
- InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_TOOL_WIDTH;
- device->singleTouchScreen.accumulator.absToolWidth = rawEvent->value;
- break;
+ }
+ return result;
+}
+
+bool InputDevice::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
+ const int32_t* keyCodes, uint8_t* outFlags) {
+ bool result = false;
+ size_t numMappers = mMappers.size();
+ for (size_t i = 0; i < numMappers; i++) {
+ InputMapper* mapper = mMappers[i];
+ if (sourcesMatchMask(mapper->getSources(), sourceMask)) {
+ result |= mapper->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags);
}
}
+ return result;
+}
+
+int32_t InputDevice::getMetaState() {
+ int32_t result = 0;
+ size_t numMappers = mMappers.size();
+ for (size_t i = 0; i < numMappers; i++) {
+ InputMapper* mapper = mMappers[i];
+ result |= mapper->getMetaState();
+ }
+ return result;
+}
+
+
+// --- InputMapper ---
+
+InputMapper::InputMapper(InputDevice* device) :
+ mDevice(device), mContext(device->getContext()) {
+}
+
+InputMapper::~InputMapper() {
+}
+
+void InputMapper::populateDeviceInfo(InputDeviceInfo* info) {
+ info->addSource(getSources());
+}
+
+void InputMapper::configure() {
+}
+
+void InputMapper::reset() {
+}
+
+int32_t InputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
+ return AKEY_STATE_UNKNOWN;
+}
+
+int32_t InputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
+ return AKEY_STATE_UNKNOWN;
+}
+
+int32_t InputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) {
+ return AKEY_STATE_UNKNOWN;
+}
+
+bool InputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
+ const int32_t* keyCodes, uint8_t* outFlags) {
+ return false;
+}
+
+int32_t InputMapper::getMetaState() {
+ return 0;
+}
+
+bool InputMapper::applyStandardPolicyActions(nsecs_t when, int32_t policyActions) {
+ if (policyActions & InputReaderPolicyInterface::ACTION_APP_SWITCH_COMING) {
+ getDispatcher()->notifyAppSwitchComing(when);
+ }
+
+ return policyActions & InputReaderPolicyInterface::ACTION_DISPATCH;
}
-void InputReader::handleSwitch(const RawEvent* rawEvent) {
- InputDevice* device = getNonIgnoredDevice(rawEvent->deviceId);
- if (! device) return;
- onSwitch(rawEvent->when, device, rawEvent->scanCode, rawEvent->value);
+// --- SwitchInputMapper ---
+
+SwitchInputMapper::SwitchInputMapper(InputDevice* device) :
+ InputMapper(device) {
}
-void InputReader::onKey(nsecs_t when, InputDevice* device,
- bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags) {
- /* Refresh display properties so we can rotate key codes according to display orientation */
+SwitchInputMapper::~SwitchInputMapper() {
+}
- if (! refreshDisplayProperties()) {
- return;
+uint32_t SwitchInputMapper::getSources() {
+ return 0;
+}
+
+void SwitchInputMapper::process(const RawEvent* rawEvent) {
+ switch (rawEvent->type) {
+ case EV_SW:
+ processSwitch(rawEvent->when, rawEvent->scanCode, rawEvent->value);
+ break;
}
+}
- /* Update device state */
+void SwitchInputMapper::processSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue) {
+ uint32_t policyFlags = 0;
+ int32_t policyActions = getPolicy()->interceptSwitch(
+ when, switchCode, switchValue, policyFlags);
- int32_t oldMetaState = device->keyboard.current.metaState;
- int32_t newMetaState = updateMetaState(keyCode, down, oldMetaState);
- if (oldMetaState != newMetaState) {
- device->keyboard.current.metaState = newMetaState;
- resetGlobalMetaState();
+ applyStandardPolicyActions(when, policyActions);
+}
+
+int32_t SwitchInputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) {
+ return getEventHub()->getSwitchState(getDeviceId(), switchCode);
+}
+
+
+// --- KeyboardInputMapper ---
+
+KeyboardInputMapper::KeyboardInputMapper(InputDevice* device, int32_t associatedDisplayId,
+ uint32_t sources, int32_t keyboardType) :
+ InputMapper(device), mAssociatedDisplayId(associatedDisplayId), mSources(sources),
+ mKeyboardType(keyboardType) {
+ initialize();
+}
+
+KeyboardInputMapper::~KeyboardInputMapper() {
+}
+
+void KeyboardInputMapper::initialize() {
+ mMetaState = AMETA_NONE;
+ mDownTime = 0;
+}
+
+uint32_t KeyboardInputMapper::getSources() {
+ return mSources;
+}
+
+void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
+ InputMapper::populateDeviceInfo(info);
+
+ info->setKeyboardType(mKeyboardType);
+}
+
+void KeyboardInputMapper::reset() {
+ // Synthesize key up event on reset if keys are currently down.
+ while (! mKeyDowns.isEmpty()) {
+ const KeyDown& keyDown = mKeyDowns.top();
+ nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC);
+ processKey(when, false, keyDown.keyCode, keyDown.scanCode, 0);
+ }
+
+ InputMapper::reset();
+
+ // Reinitialize.
+ initialize();
+ getContext()->updateGlobalMetaState();
+}
+
+void KeyboardInputMapper::process(const RawEvent* rawEvent) {
+ switch (rawEvent->type) {
+ case EV_KEY: {
+ int32_t scanCode = rawEvent->scanCode;
+ if (isKeyboardOrGamepadKey(scanCode)) {
+ processKey(rawEvent->when, rawEvent->value != 0, rawEvent->keyCode, scanCode,
+ rawEvent->flags);
+ }
+ break;
+ }
}
+}
- // FIXME if we send a down event about a rotated key press we should ensure that we send
- // a corresponding up event about the rotated key press even if the orientation
- // has changed in the meantime
- keyCode = rotateKeyCode(keyCode, mDisplayOrientation);
+bool KeyboardInputMapper::isKeyboardOrGamepadKey(int32_t scanCode) {
+ return scanCode < BTN_MOUSE
+ || scanCode >= KEY_OK
+ || (scanCode >= BTN_GAMEPAD && scanCode < BTN_DIGI);
+}
+void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode,
+ uint32_t policyFlags) {
if (down) {
- device->keyboard.current.downTime = when;
+ // Rotate key codes according to orientation.
+ if (mAssociatedDisplayId >= 0) {
+ int32_t orientation;
+ if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, NULL, NULL, & orientation)) {
+ return;
+ }
+
+ keyCode = rotateKeyCode(keyCode, orientation);
+ }
+
+ // Add key down.
+ ssize_t keyDownIndex = findKeyDown(scanCode);
+ if (keyDownIndex >= 0) {
+ // key repeat, be sure to use same keycode as before in case of rotation
+ keyCode = mKeyDowns.top().keyCode;
+ } else {
+ // key down
+ mKeyDowns.push();
+ KeyDown& keyDown = mKeyDowns.editTop();
+ keyDown.keyCode = keyCode;
+ keyDown.scanCode = scanCode;
+ }
+ } else {
+ // Remove key down.
+ ssize_t keyDownIndex = findKeyDown(scanCode);
+ if (keyDownIndex >= 0) {
+ // key up, be sure to use same keycode as before in case of rotation
+ keyCode = mKeyDowns.top().keyCode;
+ mKeyDowns.removeAt(size_t(keyDownIndex));
+ } else {
+ // key was not actually down
+ LOGI("Dropping key up from device %s because the key was not down. "
+ "keyCode=%d, scanCode=%d",
+ getDeviceName().string(), keyCode, scanCode);
+ return;
+ }
}
- /* Apply policy */
+ int32_t oldMetaState = mMetaState;
+ int32_t newMetaState = updateMetaState(keyCode, down, oldMetaState);
+ if (oldMetaState != newMetaState) {
+ mMetaState = newMetaState;
+ getContext()->updateGlobalMetaState();
+ }
- int32_t policyActions = mPolicy->interceptKey(when, device->id,
- down, keyCode, scanCode, policyFlags);
+ /* Apply policy. */
- if (! applyStandardInputDispatchPolicyActions(when, policyActions, & policyFlags)) {
+ int32_t policyActions = getPolicy()->interceptKey(when,
+ getDeviceId(), down, keyCode, scanCode, policyFlags);
+
+ if (! applyStandardPolicyActions(when, policyActions)) {
return; // event dropped
}
- /* Enqueue key event for dispatch */
+ /* Enqueue key event for dispatch. */
int32_t keyEventAction;
if (down) {
- device->keyboard.current.downTime = when;
+ mDownTime = when;
keyEventAction = AKEY_EVENT_ACTION_DOWN;
} else {
keyEventAction = AKEY_EVENT_ACTION_UP;
}
int32_t keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM;
- if (policyActions & InputReaderPolicyInterface::ACTION_WOKE_HERE) {
+ if (policyFlags & POLICY_FLAG_WOKE_HERE) {
keyEventFlags = keyEventFlags | AKEY_EVENT_FLAG_WOKE_HERE;
}
- mDispatcher->notifyKey(when, device->id, AINPUT_SOURCE_KEYBOARD, policyFlags,
+ getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
keyEventAction, keyEventFlags, keyCode, scanCode,
- device->keyboard.current.metaState,
- device->keyboard.current.downTime);
+ mMetaState, mDownTime);
}
-void InputReader::onSwitch(nsecs_t when, InputDevice* device, int32_t switchCode,
- int32_t switchValue) {
- int32_t policyActions = mPolicy->interceptSwitch(when, switchCode, switchValue);
+ssize_t KeyboardInputMapper::findKeyDown(int32_t scanCode) {
+ size_t n = mKeyDowns.size();
+ for (size_t i = 0; i < n; i++) {
+ if (mKeyDowns[i].scanCode == scanCode) {
+ return i;
+ }
+ }
+ return -1;
+}
- uint32_t policyFlags = 0;
- applyStandardInputDispatchPolicyActions(when, policyActions, & policyFlags);
+int32_t KeyboardInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
+ return getEventHub()->getKeyCodeState(getDeviceId(), keyCode);
}
-void InputReader::onMultiTouchScreenStateChanged(nsecs_t when,
- InputDevice* device) {
- static const uint32_t REQUIRED_FIELDS =
- InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_POSITION_X
- | InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_POSITION_Y
- | InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_TOUCH_MAJOR
- | InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_WIDTH_MAJOR;
+int32_t KeyboardInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
+ return getEventHub()->getScanCodeState(getDeviceId(), scanCode);
+}
- /* Refresh display properties so we can map touch screen coords into display coords */
+bool KeyboardInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
+ const int32_t* keyCodes, uint8_t* outFlags) {
+ return getEventHub()->markSupportedKeyCodes(getDeviceId(), numCodes, keyCodes, outFlags);
+}
- if (! refreshDisplayProperties()) {
- return;
+int32_t KeyboardInputMapper::getMetaState() {
+ return mMetaState;
+}
+
+
+// --- TrackballInputMapper ---
+
+TrackballInputMapper::TrackballInputMapper(InputDevice* device, int32_t associatedDisplayId) :
+ InputMapper(device), mAssociatedDisplayId(associatedDisplayId) {
+ mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
+ mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
+ mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
+ mYScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
+
+ initialize();
+}
+
+TrackballInputMapper::~TrackballInputMapper() {
+}
+
+uint32_t TrackballInputMapper::getSources() {
+ return AINPUT_SOURCE_TRACKBALL;
+}
+
+void TrackballInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
+ InputMapper::populateDeviceInfo(info);
+
+ info->addMotionRange(AINPUT_MOTION_RANGE_X, -1.0f, 1.0f, 0.0f, mXScale);
+ info->addMotionRange(AINPUT_MOTION_RANGE_Y, -1.0f, 1.0f, 0.0f, mYScale);
+}
+
+void TrackballInputMapper::initialize() {
+ mAccumulator.clear();
+
+ mDown = false;
+ mDownTime = 0;
+}
+
+void TrackballInputMapper::reset() {
+ // Synthesize trackball button up event on reset if trackball button is currently down.
+ if (mDown) {
+ nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC);
+ mAccumulator.fields |= Accumulator::FIELD_BTN_MOUSE;
+ mAccumulator.btnMouse = false;
+ sync(when);
}
- /* Update device state */
+ InputMapper::reset();
- InputDevice::MultiTouchScreenState* in = & device->multiTouchScreen;
- InputDevice::TouchData* out = & device->touchScreen.currentTouch;
+ // Reinitialize.
+ initialize();
+}
- uint32_t inCount = in->accumulator.pointerCount;
- uint32_t outCount = 0;
- bool havePointerIds = true;
+void TrackballInputMapper::process(const RawEvent* rawEvent) {
+ switch (rawEvent->type) {
+ case EV_KEY:
+ switch (rawEvent->scanCode) {
+ case BTN_MOUSE:
+ mAccumulator.fields |= Accumulator::FIELD_BTN_MOUSE;
+ mAccumulator.btnMouse = rawEvent->value != 0;
- out->clear();
+ sync(rawEvent->when);
+ mAccumulator.clear();
+ break;
+ }
+ break;
- for (uint32_t inIndex = 0; inIndex < inCount; inIndex++) {
- uint32_t fields = in->accumulator.pointers[inIndex].fields;
+ case EV_REL:
+ switch (rawEvent->scanCode) {
+ case REL_X:
+ mAccumulator.fields |= Accumulator::FIELD_REL_X;
+ mAccumulator.relX = rawEvent->value;
+ break;
+ case REL_Y:
+ mAccumulator.fields |= Accumulator::FIELD_REL_Y;
+ mAccumulator.relY = rawEvent->value;
+ break;
+ }
+ break;
- if ((fields & REQUIRED_FIELDS) != REQUIRED_FIELDS) {
-#if DEBUG_POINTERS
- LOGD("Pointers: Missing required multitouch pointer fields: index=%d, fields=%d",
- inIndex, fields);
- continue;
-#endif
+ case EV_SYN:
+ switch (rawEvent->scanCode) {
+ case SYN_REPORT:
+ if (mAccumulator.isDirty()) {
+ sync(rawEvent->when);
+ mAccumulator.clear();
+ }
+ break;
}
+ break;
+ }
+}
- if (in->accumulator.pointers[inIndex].absMTTouchMajor <= 0) {
- // Pointer is not down. Drop it.
- continue;
+void TrackballInputMapper::sync(nsecs_t when) {
+ /* Get display properties so for rotation based on display orientation. */
+
+ int32_t orientation;
+ if (mAssociatedDisplayId >= 0) {
+ if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, NULL, NULL, & orientation)) {
+ return;
}
+ } else {
+ orientation = InputReaderPolicyInterface::ROTATION_0;
+ }
- out->pointers[outCount].x = in->accumulator.pointers[inIndex].absMTPositionX;
- out->pointers[outCount].y = in->accumulator.pointers[inIndex].absMTPositionY;
+ /* Update saved trackball state */
- out->pointers[outCount].touchMajor = in->accumulator.pointers[inIndex].absMTTouchMajor;
- out->pointers[outCount].touchMinor = (fields
- & InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_TOUCH_MINOR) != 0
- ? in->accumulator.pointers[inIndex].absMTTouchMinor
- : in->accumulator.pointers[inIndex].absMTTouchMajor;
+ uint32_t fields = mAccumulator.fields;
+ bool downChanged = fields & Accumulator::FIELD_BTN_MOUSE;
- out->pointers[outCount].toolMajor = in->accumulator.pointers[inIndex].absMTWidthMajor;
- out->pointers[outCount].toolMinor = (fields
- & InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_WIDTH_MINOR) != 0
- ? in->accumulator.pointers[inIndex].absMTWidthMinor
- : in->accumulator.pointers[inIndex].absMTWidthMajor;
+ if (downChanged) {
+ if (mAccumulator.btnMouse) {
+ mDown = true;
+ mDownTime = when;
+ } else {
+ mDown = false;
+ }
+ }
- out->pointers[outCount].orientation = (fields
- & InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_ORIENTATION) != 0
- ? in->accumulator.pointers[inIndex].absMTOrientation : 0;
+ /* Apply policy */
- // Derive an approximation of pressure and size.
- // FIXME assignment of pressure may be incorrect, probably better to let
- // pressure = touch / width. Later on we pass width to MotionEvent as a size, which
- // isn't quite right either. Should be using touch for that.
- out->pointers[outCount].pressure = in->accumulator.pointers[inIndex].absMTTouchMajor;
- out->pointers[outCount].size = in->accumulator.pointers[inIndex].absMTWidthMajor;
+ uint32_t policyFlags = 0;
+ int32_t policyActions = getPolicy()->interceptGeneric(when, policyFlags);
- if (havePointerIds) {
- if (fields & InputDevice::MultiTouchScreenState::Accumulator::
- FIELD_ABS_MT_TRACKING_ID) {
- uint32_t id = uint32_t(in->accumulator.pointers[inIndex].absMTTrackingId);
+ if (! applyStandardPolicyActions(when, policyActions)) {
+ return; // event dropped
+ }
- if (id > MAX_POINTER_ID) {
-#if DEBUG_POINTERS
- LOGD("Pointers: Ignoring driver provided pointer id %d because "
- "it is larger than max supported id %d for optimizations",
- id, MAX_POINTER_ID);
-#endif
- havePointerIds = false;
- }
- else {
- out->pointers[outCount].id = id;
- out->idToIndex[id] = outCount;
- out->idBits.markBit(id);
- }
- } else {
- havePointerIds = false;
- }
- }
+ /* Enqueue motion event for dispatch. */
- outCount += 1;
+ int32_t motionEventAction;
+ if (downChanged) {
+ motionEventAction = mDown ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
+ } else {
+ motionEventAction = AMOTION_EVENT_ACTION_MOVE;
+ }
+
+ int32_t pointerId = 0;
+ PointerCoords pointerCoords;
+ pointerCoords.x = fields & Accumulator::FIELD_REL_X
+ ? mAccumulator.relX * mXScale : 0;
+ pointerCoords.y = fields & Accumulator::FIELD_REL_Y
+ ? mAccumulator.relY * mYScale : 0;
+ pointerCoords.pressure = 1.0f; // XXX Consider making this 1.0f if down, 0 otherwise.
+ pointerCoords.size = 0;
+ pointerCoords.touchMajor = 0;
+ pointerCoords.touchMinor = 0;
+ pointerCoords.toolMajor = 0;
+ pointerCoords.toolMinor = 0;
+ pointerCoords.orientation = 0;
+
+ float temp;
+ switch (orientation) {
+ case InputReaderPolicyInterface::ROTATION_90:
+ temp = pointerCoords.x;
+ pointerCoords.x = pointerCoords.y;
+ pointerCoords.y = - temp;
+ break;
+
+ case InputReaderPolicyInterface::ROTATION_180:
+ pointerCoords.x = - pointerCoords.x;
+ pointerCoords.y = - pointerCoords.y;
+ break;
+
+ case InputReaderPolicyInterface::ROTATION_270:
+ temp = pointerCoords.x;
+ pointerCoords.x = - pointerCoords.y;
+ pointerCoords.y = temp;
+ break;
}
- out->pointerCount = outCount;
+ int32_t metaState = mContext->getGlobalMetaState();
+ getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_TRACKBALL, policyFlags,
+ motionEventAction, metaState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ 1, & pointerId, & pointerCoords, mXPrecision, mYPrecision, mDownTime);
+}
+
- onTouchScreenChanged(when, device, havePointerIds);
+// --- TouchInputMapper ---
+
+TouchInputMapper::TouchInputMapper(InputDevice* device, int32_t associatedDisplayId) :
+ InputMapper(device), mAssociatedDisplayId(associatedDisplayId),
+ mSurfaceOrientation(-1), mSurfaceWidth(-1), mSurfaceHeight(-1) {
+ initialize();
}
-void InputReader::onSingleTouchScreenStateChanged(nsecs_t when,
- InputDevice* device) {
- /* Refresh display properties so we can map touch screen coords into display coords */
+TouchInputMapper::~TouchInputMapper() {
+}
- if (! refreshDisplayProperties()) {
- return;
+uint32_t TouchInputMapper::getSources() {
+ return mAssociatedDisplayId >= 0 ? AINPUT_SOURCE_TOUCHSCREEN : AINPUT_SOURCE_TOUCHPAD;
+}
+
+void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
+ InputMapper::populateDeviceInfo(info);
+
+ // FIXME: Should ensure the surface information is up to date so that orientation changes
+ // are noticed immediately. Unfortunately we will need to add some extra locks here
+ // to prevent race conditions.
+ // configureSurface();
+
+ info->addMotionRange(AINPUT_MOTION_RANGE_X, mOrientedRanges.x);
+ info->addMotionRange(AINPUT_MOTION_RANGE_Y, mOrientedRanges.y);
+ info->addMotionRange(AINPUT_MOTION_RANGE_PRESSURE, mOrientedRanges.pressure);
+ info->addMotionRange(AINPUT_MOTION_RANGE_SIZE, mOrientedRanges.size);
+ info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MAJOR, mOrientedRanges.touchMajor);
+ info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MINOR, mOrientedRanges.touchMinor);
+ info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MAJOR, mOrientedRanges.toolMajor);
+ info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MINOR, mOrientedRanges.toolMinor);
+ info->addMotionRange(AINPUT_MOTION_RANGE_ORIENTATION, mOrientedRanges.orientation);
+}
+
+void TouchInputMapper::initialize() {
+ mLastTouch.clear();
+ mDownTime = 0;
+ mCurrentVirtualKey.down = false;
+
+ for (uint32_t i = 0; i < MAX_POINTERS; i++) {
+ mAveragingTouchFilter.historyStart[i] = 0;
+ mAveragingTouchFilter.historyEnd[i] = 0;
}
- /* Update device state */
+ mJumpyTouchFilter.jumpyPointsDropped = 0;
+}
- InputDevice::SingleTouchScreenState* in = & device->singleTouchScreen;
- InputDevice::TouchData* out = & device->touchScreen.currentTouch;
+void TouchInputMapper::configure() {
+ InputMapper::configure();
- uint32_t fields = in->accumulator.fields;
+ // Configure basic parameters.
+ mParameters.useBadTouchFilter = getPolicy()->filterTouchEvents();
+ mParameters.useAveragingTouchFilter = getPolicy()->filterTouchEvents();
+ mParameters.useJumpyTouchFilter = getPolicy()->filterJumpyTouchEvents();
- if (fields & InputDevice::SingleTouchScreenState::Accumulator::FIELD_BTN_TOUCH) {
- in->current.down = in->accumulator.btnTouch;
+ // Configure absolute axis information.
+ configureAxes();
+
+ // Configure pressure factors.
+ if (mAxes.pressure.valid) {
+ mPressureOrigin = mAxes.pressure.minValue;
+ mPressureScale = 1.0f / mAxes.pressure.getRange();
+ } else {
+ mPressureOrigin = 0;
+ mPressureScale = 1.0f;
}
- if (fields & InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_X) {
- in->current.x = in->accumulator.absX;
+ mOrientedRanges.pressure.min = 0.0f;
+ mOrientedRanges.pressure.max = 1.0f;
+ mOrientedRanges.pressure.flat = 0.0f;
+ mOrientedRanges.pressure.fuzz = mPressureScale;
+
+ // Configure size factors.
+ if (mAxes.size.valid) {
+ mSizeOrigin = mAxes.size.minValue;
+ mSizeScale = 1.0f / mAxes.size.getRange();
+ } else {
+ mSizeOrigin = 0;
+ mSizeScale = 1.0f;
}
- if (fields & InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_Y) {
- in->current.y = in->accumulator.absY;
+ mOrientedRanges.size.min = 0.0f;
+ mOrientedRanges.size.max = 1.0f;
+ mOrientedRanges.size.flat = 0.0f;
+ mOrientedRanges.size.fuzz = mSizeScale;
+
+ // Configure orientation factors.
+ if (mAxes.orientation.valid && mAxes.orientation.maxValue > 0) {
+ mOrientationScale = float(M_PI_2) / mAxes.orientation.maxValue;
+ } else {
+ mOrientationScale = 0.0f;
}
- if (fields & InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_PRESSURE) {
- in->current.pressure = in->accumulator.absPressure;
+ mOrientedRanges.orientation.min = - M_PI_2;
+ mOrientedRanges.orientation.max = M_PI_2;
+ mOrientedRanges.orientation.flat = 0;
+ mOrientedRanges.orientation.fuzz = mOrientationScale;
+
+ // Configure surface dimensions and orientation.
+ configureSurface();
+}
+
+void TouchInputMapper::configureAxes() {
+ mAxes.x.valid = false;
+ mAxes.y.valid = false;
+ mAxes.pressure.valid = false;
+ mAxes.size.valid = false;
+ mAxes.touchMajor.valid = false;
+ mAxes.touchMinor.valid = false;
+ mAxes.toolMajor.valid = false;
+ mAxes.toolMinor.valid = false;
+ mAxes.orientation.valid = false;
+}
+
+bool TouchInputMapper::configureSurface() {
+ // Update orientation and dimensions if needed.
+ int32_t orientation;
+ int32_t width, height;
+ if (mAssociatedDisplayId >= 0) {
+ if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, & width, & height, & orientation)) {
+ return false;
+ }
+ } else {
+ orientation = InputReaderPolicyInterface::ROTATION_0;
+ width = mAxes.x.getRange();
+ height = mAxes.y.getRange();
}
- if (fields & InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_TOOL_WIDTH) {
- in->current.size = in->accumulator.absToolWidth;
+ bool orientationChanged = mSurfaceOrientation != orientation;
+ if (orientationChanged) {
+ mSurfaceOrientation = orientation;
}
- out->clear();
+ bool sizeChanged = mSurfaceWidth != width || mSurfaceHeight != height;
+ if (sizeChanged) {
+ mSurfaceWidth = width;
+ mSurfaceHeight = height;
+
+ // Compute size-dependent translation and scaling factors and place virtual keys.
+ if (mAxes.x.valid && mAxes.y.valid) {
+ mXOrigin = mAxes.x.minValue;
+ mYOrigin = mAxes.y.minValue;
+
+ LOGI("Device configured: id=0x%x, name=%s (display size was changed)",
+ getDeviceId(), getDeviceName().string());
+
+ mXScale = float(width) / mAxes.x.getRange();
+ mYScale = float(height) / mAxes.y.getRange();
+ mXPrecision = 1.0f / mXScale;
+ mYPrecision = 1.0f / mYScale;
+
+ configureVirtualKeys();
+ } else {
+ mXOrigin = 0;
+ mYOrigin = 0;
+ mXScale = 1.0f;
+ mYScale = 1.0f;
+ mXPrecision = 1.0f;
+ mYPrecision = 1.0f;
+ }
+
+ // Configure touch and tool area ranges.
+ float diagonal = sqrt(float(width * width + height * height));
+ float diagonalFuzz = sqrt(mXScale * mXScale + mYScale * mYScale);
+
+ mOrientedRanges.touchMajor.min = 0.0f;
+ mOrientedRanges.touchMajor.max = diagonal;
+ mOrientedRanges.touchMajor.flat = 0.0f;
+ mOrientedRanges.touchMajor.fuzz = diagonalFuzz;
+ mOrientedRanges.touchMinor = mOrientedRanges.touchMajor;
+
+ mOrientedRanges.toolMinor = mOrientedRanges.toolMajor = mOrientedRanges.touchMajor;
+ }
+
+ if (orientationChanged || sizeChanged) {
+ // Compute oriented surface dimensions, precision, and scales.
+ float orientedXScale, orientedYScale;
+ switch (mSurfaceOrientation) {
+ case InputReaderPolicyInterface::ROTATION_90:
+ case InputReaderPolicyInterface::ROTATION_270:
+ mOrientedSurfaceWidth = mSurfaceHeight;
+ mOrientedSurfaceHeight = mSurfaceWidth;
+ mOrientedXPrecision = mYPrecision;
+ mOrientedYPrecision = mXPrecision;
+ orientedXScale = mYScale;
+ orientedYScale = mXScale;
+ break;
+ default:
+ mOrientedSurfaceWidth = mSurfaceWidth;
+ mOrientedSurfaceHeight = mSurfaceHeight;
+ mOrientedXPrecision = mXPrecision;
+ mOrientedYPrecision = mYPrecision;
+ orientedXScale = mXScale;
+ orientedYScale = mYScale;
+ break;
+ }
+
+ // Configure position ranges.
+ mOrientedRanges.x.min = 0;
+ mOrientedRanges.x.max = mOrientedSurfaceWidth;
+ mOrientedRanges.x.flat = 0;
+ mOrientedRanges.x.fuzz = orientedXScale;
- if (in->current.down) {
- out->pointerCount = 1;
- out->pointers[0].id = 0;
- out->pointers[0].x = in->current.x;
- out->pointers[0].y = in->current.y;
- out->pointers[0].pressure = in->current.pressure;
- out->pointers[0].size = in->current.size;
- out->pointers[0].touchMajor = in->current.pressure;
- out->pointers[0].touchMinor = in->current.pressure;
- out->pointers[0].toolMajor = in->current.size;
- out->pointers[0].toolMinor = in->current.size;
- out->pointers[0].orientation = 0;
- out->idToIndex[0] = 0;
- out->idBits.markBit(0);
+ mOrientedRanges.y.min = 0;
+ mOrientedRanges.y.max = mOrientedSurfaceHeight;
+ mOrientedRanges.y.flat = 0;
+ mOrientedRanges.y.fuzz = orientedYScale;
}
- onTouchScreenChanged(when, device, true);
+ return true;
}
-void InputReader::onTouchScreenChanged(nsecs_t when,
- InputDevice* device, bool havePointerIds) {
- /* Apply policy */
+void TouchInputMapper::configureVirtualKeys() {
+ assert(mAxes.x.valid && mAxes.y.valid);
+
+ Vector<InputReaderPolicyInterface::VirtualKeyDefinition> virtualKeyDefinitions;
+ getPolicy()->getVirtualKeyDefinitions(getDeviceName(), virtualKeyDefinitions);
+
+ { // acquire virtual key lock
+ AutoMutex _l(mVirtualKeyLock);
+
+ mVirtualKeys.clear();
+
+ if (virtualKeyDefinitions.size() == 0) {
+ return;
+ }
+
+ mVirtualKeys.setCapacity(virtualKeyDefinitions.size());
+
+ int32_t touchScreenLeft = mAxes.x.minValue;
+ int32_t touchScreenTop = mAxes.y.minValue;
+ int32_t touchScreenWidth = mAxes.x.getRange();
+ int32_t touchScreenHeight = mAxes.y.getRange();
- int32_t policyActions = mPolicy->interceptTouch(when);
+ for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) {
+ const InputReaderPolicyInterface::VirtualKeyDefinition& virtualKeyDefinition =
+ virtualKeyDefinitions[i];
+
+ mVirtualKeys.add();
+ VirtualKey& virtualKey = mVirtualKeys.editTop();
+
+ virtualKey.scanCode = virtualKeyDefinition.scanCode;
+ int32_t keyCode;
+ uint32_t flags;
+ if (getEventHub()->scancodeToKeycode(getDeviceId(), virtualKey.scanCode,
+ & keyCode, & flags)) {
+ LOGW(" VirtualKey %d: could not obtain key code, ignoring", virtualKey.scanCode);
+ mVirtualKeys.pop(); // drop the key
+ continue;
+ }
+
+ virtualKey.keyCode = keyCode;
+ virtualKey.flags = flags;
+
+ // convert the key definition's display coordinates into touch coordinates for a hit box
+ int32_t halfWidth = virtualKeyDefinition.width / 2;
+ int32_t halfHeight = virtualKeyDefinition.height / 2;
+
+ virtualKey.hitLeft = (virtualKeyDefinition.centerX - halfWidth)
+ * touchScreenWidth / mSurfaceWidth + touchScreenLeft;
+ virtualKey.hitRight= (virtualKeyDefinition.centerX + halfWidth)
+ * touchScreenWidth / mSurfaceWidth + touchScreenLeft;
+ virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight)
+ * touchScreenHeight / mSurfaceHeight + touchScreenTop;
+ virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight)
+ * touchScreenHeight / mSurfaceHeight + touchScreenTop;
+
+ LOGI(" VirtualKey %d: keyCode=%d hitLeft=%d hitRight=%d hitTop=%d hitBottom=%d",
+ virtualKey.scanCode, virtualKey.keyCode,
+ virtualKey.hitLeft, virtualKey.hitRight, virtualKey.hitTop, virtualKey.hitBottom);
+ }
+ } // release virtual key lock
+}
+
+void TouchInputMapper::reset() {
+ // Synthesize touch up event if touch is currently down.
+ // This will also take care of finishing virtual key processing if needed.
+ if (mLastTouch.pointerCount != 0) {
+ nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC);
+ mCurrentTouch.clear();
+ syncTouch(when, true);
+ }
+
+ InputMapper::reset();
+
+ // Reinitialize.
+ initialize();
+}
+
+void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) {
+ /* Refresh associated display information and update our size configuration if needed. */
+
+ if (! configureSurface()) {
+ return;
+ }
+
+ /* Apply policy */
uint32_t policyFlags = 0;
- if (! applyStandardInputDispatchPolicyActions(when, policyActions, & policyFlags)) {
- device->touchScreen.lastTouch.clear();
+ int32_t policyActions = getPolicy()->interceptGeneric(when, policyFlags);
+
+ if (! applyStandardPolicyActions(when, policyActions)) {
+ mLastTouch.clear();
return; // event dropped
}
/* Preprocess pointer data */
- if (device->touchScreen.parameters.useBadTouchFilter) {
- if (device->touchScreen.applyBadTouchFilter()) {
+ if (mParameters.useBadTouchFilter) {
+ if (applyBadTouchFilter()) {
havePointerIds = false;
}
}
- if (device->touchScreen.parameters.useJumpyTouchFilter) {
- if (device->touchScreen.applyJumpyTouchFilter()) {
+ if (mParameters.useJumpyTouchFilter) {
+ if (applyJumpyTouchFilter()) {
havePointerIds = false;
}
}
if (! havePointerIds) {
- device->touchScreen.calculatePointerIds();
+ calculatePointerIds();
}
- InputDevice::TouchData temp;
- InputDevice::TouchData* savedTouch;
- if (device->touchScreen.parameters.useAveragingTouchFilter) {
- temp.copyFrom(device->touchScreen.currentTouch);
+ TouchData temp;
+ TouchData* savedTouch;
+ if (mParameters.useAveragingTouchFilter) {
+ temp.copyFrom(mCurrentTouch);
savedTouch = & temp;
- device->touchScreen.applyAveragingTouchFilter();
+ applyAveragingTouchFilter();
} else {
- savedTouch = & device->touchScreen.currentTouch;
+ savedTouch = & mCurrentTouch;
}
- /* Process virtual keys or touches */
+ /* Process touches and virtual keys */
- if (! consumeVirtualKeyTouches(when, device, policyFlags)) {
- dispatchTouches(when, device, policyFlags);
+ TouchResult touchResult = consumeOffScreenTouches(when, policyFlags);
+ if (touchResult == DISPATCH_TOUCH) {
+ dispatchTouches(when, policyFlags);
}
- // Copy current touch to last touch in preparation for the next cycle.
- device->touchScreen.lastTouch.copyFrom(*savedTouch);
+ /* Copy current touch to last touch in preparation for the next cycle. */
+
+ if (touchResult == DROP_STROKE) {
+ mLastTouch.clear();
+ } else {
+ mLastTouch.copyFrom(*savedTouch);
+ }
}
-bool InputReader::consumeVirtualKeyTouches(nsecs_t when,
- InputDevice* device, uint32_t policyFlags) {
- switch (device->touchScreen.currentVirtualKey.status) {
- case InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_CANCELED:
- if (device->touchScreen.currentTouch.pointerCount == 0) {
- // Pointer went up after virtual key canceled.
- device->touchScreen.currentVirtualKey.status =
- InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_UP;
- }
- return true; // consumed
+TouchInputMapper::TouchResult TouchInputMapper::consumeOffScreenTouches(
+ nsecs_t when, uint32_t policyFlags) {
+ int32_t keyEventAction, keyEventFlags;
+ int32_t keyCode, scanCode, downTime;
+ TouchResult touchResult;
+
+ { // acquire virtual key lock
+ AutoMutex _l(mVirtualKeyLock);
- case InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_DOWN:
- if (device->touchScreen.currentTouch.pointerCount == 0) {
- // Pointer went up while virtual key was down.
- device->touchScreen.currentVirtualKey.status =
- InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_UP;
+ if (mCurrentVirtualKey.down) {
+ if (mCurrentTouch.pointerCount == 0) {
+ // Pointer went up while virtual key was down.
+ mCurrentVirtualKey.down = false;
#if DEBUG_VIRTUAL_KEYS
- LOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d",
- device->touchScreen.currentVirtualKey.keyCode,
- device->touchScreen.currentVirtualKey.scanCode);
+ LOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d",
+ mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode);
#endif
- dispatchVirtualKey(when, device, policyFlags, AKEY_EVENT_ACTION_UP,
- AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY);
- return true; // consumed
- }
+ keyEventAction = AKEY_EVENT_ACTION_UP;
+ keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
+ touchResult = SKIP_TOUCH;
+ goto DispatchVirtualKey;
+ }
- if (device->touchScreen.currentTouch.pointerCount == 1) {
- const InputDevice::VirtualKey* virtualKey = device->touchScreen.findVirtualKeyHit();
- if (virtualKey
- && virtualKey->keyCode == device->touchScreen.currentVirtualKey.keyCode) {
- // Pointer is still within the space of the virtual key.
- return true; // consumed
+ if (mCurrentTouch.pointerCount == 1) {
+ int32_t x = mCurrentTouch.pointers[0].x;
+ int32_t y = mCurrentTouch.pointers[0].y;
+ const VirtualKey* virtualKey = findVirtualKeyHitLvk(x, y);
+ if (virtualKey && virtualKey->keyCode == mCurrentVirtualKey.keyCode) {
+ // Pointer is still within the space of the virtual key.
+ return SKIP_TOUCH;
+ }
}
- }
- // Pointer left virtual key area or another pointer also went down.
- // Send key cancellation.
- device->touchScreen.currentVirtualKey.status =
- InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_CANCELED;
+ // Pointer left virtual key area or another pointer also went down.
+ // Send key cancellation and drop the stroke so subsequent motions will be
+ // considered fresh downs. This is useful when the user swipes away from the
+ // virtual key area into the main display surface.
+ mCurrentVirtualKey.down = false;
#if DEBUG_VIRTUAL_KEYS
- LOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d",
- device->touchScreen.currentVirtualKey.keyCode,
- device->touchScreen.currentVirtualKey.scanCode);
+ LOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d",
+ mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode);
#endif
- dispatchVirtualKey(when, device, policyFlags, AKEY_EVENT_ACTION_UP,
- AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY
- | AKEY_EVENT_FLAG_CANCELED);
- return true; // consumed
-
- default:
- if (device->touchScreen.currentTouch.pointerCount == 1
- && device->touchScreen.lastTouch.pointerCount == 0) {
- // Pointer just went down. Check for virtual key hit.
- const InputDevice::VirtualKey* virtualKey = device->touchScreen.findVirtualKeyHit();
- if (virtualKey) {
- device->touchScreen.currentVirtualKey.status =
- InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_DOWN;
- device->touchScreen.currentVirtualKey.downTime = when;
- device->touchScreen.currentVirtualKey.keyCode = virtualKey->keyCode;
- device->touchScreen.currentVirtualKey.scanCode = virtualKey->scanCode;
+ keyEventAction = AKEY_EVENT_ACTION_UP;
+ keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY
+ | AKEY_EVENT_FLAG_CANCELED;
+ touchResult = DROP_STROKE;
+ goto DispatchVirtualKey;
+ } else {
+ if (mCurrentTouch.pointerCount >= 1 && mLastTouch.pointerCount == 0) {
+ // Pointer just went down. Handle off-screen touches, if needed.
+ int32_t x = mCurrentTouch.pointers[0].x;
+ int32_t y = mCurrentTouch.pointers[0].y;
+ if (! isPointInsideSurface(x, y)) {
+ // If exactly one pointer went down, check for virtual key hit.
+ // Otherwise we will drop the entire stroke.
+ if (mCurrentTouch.pointerCount == 1) {
+ const VirtualKey* virtualKey = findVirtualKeyHitLvk(x, y);
+ if (virtualKey) {
+ mCurrentVirtualKey.down = true;
+ mCurrentVirtualKey.downTime = when;
+ mCurrentVirtualKey.keyCode = virtualKey->keyCode;
+ mCurrentVirtualKey.scanCode = virtualKey->scanCode;
#if DEBUG_VIRTUAL_KEYS
- LOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d",
- device->touchScreen.currentVirtualKey.keyCode,
- device->touchScreen.currentVirtualKey.scanCode);
+ LOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d",
+ mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode);
#endif
- dispatchVirtualKey(when, device, policyFlags, AKEY_EVENT_ACTION_DOWN,
- AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY);
- return true; // consumed
+ keyEventAction = AKEY_EVENT_ACTION_DOWN;
+ keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM
+ | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
+ touchResult = SKIP_TOUCH;
+ goto DispatchVirtualKey;
+ }
+ }
+ return DROP_STROKE;
+ }
}
+ return DISPATCH_TOUCH;
}
- return false; // not consumed
- }
-}
-void InputReader::dispatchVirtualKey(nsecs_t when,
- InputDevice* device, uint32_t policyFlags,
- int32_t keyEventAction, int32_t keyEventFlags) {
- updateExportedVirtualKeyState();
+ DispatchVirtualKey:
+ // Collect remaining state needed to dispatch virtual key.
+ keyCode = mCurrentVirtualKey.keyCode;
+ scanCode = mCurrentVirtualKey.scanCode;
+ downTime = mCurrentVirtualKey.downTime;
+ } // release virtual key lock
- int32_t keyCode = device->touchScreen.currentVirtualKey.keyCode;
- int32_t scanCode = device->touchScreen.currentVirtualKey.scanCode;
- nsecs_t downTime = device->touchScreen.currentVirtualKey.downTime;
- int32_t metaState = globalMetaState();
+ // Dispatch virtual key.
+ int32_t metaState = mContext->getGlobalMetaState();
if (keyEventAction == AKEY_EVENT_ACTION_DOWN) {
- mPolicy->virtualKeyDownFeedback();
+ getPolicy()->virtualKeyDownFeedback();
}
- int32_t policyActions = mPolicy->interceptKey(when, device->id,
+ int32_t policyActions = getPolicy()->interceptKey(when, getDeviceId(),
keyEventAction == AKEY_EVENT_ACTION_DOWN, keyCode, scanCode, policyFlags);
- if (applyStandardInputDispatchPolicyActions(when, policyActions, & policyFlags)) {
- mDispatcher->notifyKey(when, device->id, AINPUT_SOURCE_KEYBOARD, policyFlags,
+ if (applyStandardPolicyActions(when, policyActions)) {
+ getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime);
}
+ return touchResult;
}
-void InputReader::dispatchTouches(nsecs_t when,
- InputDevice* device, uint32_t policyFlags) {
- uint32_t currentPointerCount = device->touchScreen.currentTouch.pointerCount;
- uint32_t lastPointerCount = device->touchScreen.lastTouch.pointerCount;
+void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
+ uint32_t currentPointerCount = mCurrentTouch.pointerCount;
+ uint32_t lastPointerCount = mLastTouch.pointerCount;
if (currentPointerCount == 0 && lastPointerCount == 0) {
return; // nothing to do!
}
- BitSet32 currentIdBits = device->touchScreen.currentTouch.idBits;
- BitSet32 lastIdBits = device->touchScreen.lastTouch.idBits;
+ BitSet32 currentIdBits = mCurrentTouch.idBits;
+ BitSet32 lastIdBits = mLastTouch.idBits;
if (currentIdBits == lastIdBits) {
// No pointer id changes so this is a move event.
// The dispatcher takes care of batching moves so we don't have to deal with that here.
int32_t motionEventAction = AMOTION_EVENT_ACTION_MOVE;
- dispatchTouch(when, device, policyFlags, & device->touchScreen.currentTouch,
+ dispatchTouch(when, policyFlags, & mCurrentTouch,
currentIdBits, -1, motionEventAction);
} else {
// There may be pointers going up and pointers going down at the same time when pointer
@@ -791,7 +1536,7 @@ void InputReader::dispatchTouches(nsecs_t when,
motionEventAction = AMOTION_EVENT_ACTION_POINTER_UP;
}
- dispatchTouch(when, device, policyFlags, & device->touchScreen.lastTouch,
+ dispatchTouch(when, policyFlags, & mLastTouch,
oldActiveIdBits, upId, motionEventAction);
}
@@ -804,40 +1549,24 @@ void InputReader::dispatchTouches(nsecs_t when,
int32_t motionEventAction;
if (oldActiveIdBits.isEmpty()) {
motionEventAction = AMOTION_EVENT_ACTION_DOWN;
- device->touchScreen.downTime = when;
+ mDownTime = when;
} else {
motionEventAction = AMOTION_EVENT_ACTION_POINTER_DOWN;
}
- dispatchTouch(when, device, policyFlags, & device->touchScreen.currentTouch,
+ dispatchTouch(when, policyFlags, & mCurrentTouch,
activeIdBits, downId, motionEventAction);
}
}
}
-void InputReader::dispatchTouch(nsecs_t when, InputDevice* device, uint32_t policyFlags,
- InputDevice::TouchData* touch, BitSet32 idBits, uint32_t changedId,
+void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags,
+ TouchData* touch, BitSet32 idBits, uint32_t changedId,
int32_t motionEventAction) {
- int32_t orientedWidth, orientedHeight;
- switch (mDisplayOrientation) {
- case InputReaderPolicyInterface::ROTATION_90:
- case InputReaderPolicyInterface::ROTATION_270:
- orientedWidth = mDisplayHeight;
- orientedHeight = mDisplayWidth;
- break;
- default:
- orientedWidth = mDisplayWidth;
- orientedHeight = mDisplayHeight;
- break;
- }
-
uint32_t pointerCount = 0;
int32_t pointerIds[MAX_POINTERS];
PointerCoords pointerCoords[MAX_POINTERS];
- const InputDevice::TouchScreenState::Precalculated& precalculated =
- device->touchScreen.precalculated;
-
// Walk through the the active pointers and map touch screen coordinates (TouchData) into
// display coordinates (PointerCoords) and adjust for display orientation.
while (! idBits.isEmpty()) {
@@ -845,55 +1574,57 @@ void InputReader::dispatchTouch(nsecs_t when, InputDevice* device, uint32_t poli
idBits.clearBit(id);
uint32_t index = touch->idToIndex[id];
- float x = float(touch->pointers[index].x
- - precalculated.xOrigin) * precalculated.xScale;
- float y = float(touch->pointers[index].y
- - precalculated.yOrigin) * precalculated.yScale;
- float pressure = float(touch->pointers[index].pressure
- - precalculated.pressureOrigin) * precalculated.pressureScale;
- float size = float(touch->pointers[index].size
- - precalculated.sizeOrigin) * precalculated.sizeScale;
+ float x = float(touch->pointers[index].x - mXOrigin) * mXScale;
+ float y = float(touch->pointers[index].y - mYOrigin) * mYScale;
+ float pressure = float(touch->pointers[index].pressure - mPressureOrigin) * mPressureScale;
+ float size = float(touch->pointers[index].size - mSizeOrigin) * mSizeScale;
- float orientation = float(touch->pointers[index].orientation)
- * precalculated.orientationScale;
+ float orientation = float(touch->pointers[index].orientation) * mOrientationScale;
- bool vertical = abs(orientation) <= M_PI / 8;
+ float touchMajor, touchMinor, toolMajor, toolMinor;
+ if (abs(orientation) <= M_PI_4) {
+ // Nominally vertical orientation: scale major axis by Y, and scale minor axis by X.
+ touchMajor = float(touch->pointers[index].touchMajor) * mYScale;
+ touchMinor = float(touch->pointers[index].touchMinor) * mXScale;
+ toolMajor = float(touch->pointers[index].toolMajor) * mYScale;
+ toolMinor = float(touch->pointers[index].toolMinor) * mXScale;
+ } else {
+ // Nominally horizontal orientation: scale major axis by X, and scale minor axis by Y.
+ touchMajor = float(touch->pointers[index].touchMajor) * mXScale;
+ touchMinor = float(touch->pointers[index].touchMinor) * mYScale;
+ toolMajor = float(touch->pointers[index].toolMajor) * mXScale;
+ toolMinor = float(touch->pointers[index].toolMinor) * mYScale;
+ }
- switch (mDisplayOrientation) {
+ switch (mSurfaceOrientation) {
case InputReaderPolicyInterface::ROTATION_90: {
float xTemp = x;
x = y;
- y = mDisplayWidth - xTemp;
- vertical = ! vertical;
+ y = mOrientedSurfaceWidth - xTemp;
+ orientation -= M_PI_2;
+ if (orientation < - M_PI_2) {
+ orientation += M_PI;
+ }
break;
}
case InputReaderPolicyInterface::ROTATION_180: {
- x = mDisplayWidth - x;
- y = mDisplayHeight - y;
+ x = mOrientedSurfaceWidth - x;
+ y = mOrientedSurfaceHeight - y;
+ orientation = - orientation;
break;
}
case InputReaderPolicyInterface::ROTATION_270: {
float xTemp = x;
- x = mDisplayHeight - y;
+ x = mOrientedSurfaceHeight - y;
y = xTemp;
- vertical = ! vertical;
+ orientation += M_PI_2;
+ if (orientation > M_PI_2) {
+ orientation -= M_PI;
+ }
break;
}
}
- float touchMajor, touchMinor, toolMajor, toolMinor;
- if (vertical) {
- touchMajor = float(touch->pointers[index].touchMajor) * precalculated.yScale;
- touchMinor = float(touch->pointers[index].touchMinor) * precalculated.xScale;
- toolMajor = float(touch->pointers[index].toolMajor) * precalculated.yScale;
- toolMinor = float(touch->pointers[index].toolMinor) * precalculated.xScale;
- } else {
- touchMajor = float(touch->pointers[index].touchMajor) * precalculated.xScale;
- touchMinor = float(touch->pointers[index].touchMinor) * precalculated.yScale;
- toolMajor = float(touch->pointers[index].toolMajor) * precalculated.xScale;
- toolMinor = float(touch->pointers[index].toolMinor) * precalculated.yScale;
- }
-
pointerIds[pointerCount] = int32_t(id);
pointerCoords[pointerCount].x = x;
@@ -919,561 +1650,984 @@ void InputReader::dispatchTouch(nsecs_t when, InputDevice* device, uint32_t poli
if (motionEventAction == AMOTION_EVENT_ACTION_DOWN) {
if (pointerCoords[0].x <= 0) {
motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_LEFT;
- } else if (pointerCoords[0].x >= orientedWidth) {
+ } else if (pointerCoords[0].x >= mOrientedSurfaceWidth) {
motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_RIGHT;
}
if (pointerCoords[0].y <= 0) {
motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_TOP;
- } else if (pointerCoords[0].y >= orientedHeight) {
+ } else if (pointerCoords[0].y >= mOrientedSurfaceHeight) {
motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_BOTTOM;
}
}
- nsecs_t downTime = device->touchScreen.downTime;
- mDispatcher->notifyMotion(when, device->id, AINPUT_SOURCE_TOUCHSCREEN, policyFlags,
- motionEventAction, globalMetaState(), motionEventEdgeFlags,
+ getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_TOUCHSCREEN, policyFlags,
+ motionEventAction, getContext()->getGlobalMetaState(), motionEventEdgeFlags,
pointerCount, pointerIds, pointerCoords,
- 0, 0, downTime);
+ mOrientedXPrecision, mOrientedYPrecision, mDownTime);
}
-void InputReader::onTrackballStateChanged(nsecs_t when,
- InputDevice* device) {
- static const uint32_t DELTA_FIELDS =
- InputDevice::TrackballState::Accumulator::FIELD_REL_X
- | InputDevice::TrackballState::Accumulator::FIELD_REL_Y;
+bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) {
+ if (mAxes.x.valid && mAxes.y.valid) {
+ return x >= mAxes.x.minValue && x <= mAxes.x.maxValue
+ && y >= mAxes.y.minValue && y <= mAxes.y.maxValue;
+ }
+ return true;
+}
- /* Refresh display properties so we can trackball moves according to display orientation */
+const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHitLvk(int32_t x, int32_t y) {
+ for (size_t i = 0; i < mVirtualKeys.size(); i++) {
+ const VirtualKey& virtualKey = mVirtualKeys[i];
- if (! refreshDisplayProperties()) {
- return;
- }
+#if DEBUG_VIRTUAL_KEYS
+ LOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, "
+ "left=%d, top=%d, right=%d, bottom=%d",
+ x, y,
+ virtualKey.keyCode, virtualKey.scanCode,
+ virtualKey.hitLeft, virtualKey.hitTop,
+ virtualKey.hitRight, virtualKey.hitBottom);
+#endif
- /* Update device state */
+ if (virtualKey.isHit(x, y)) {
+ return & virtualKey;
+ }
+ }
- uint32_t fields = device->trackball.accumulator.fields;
- bool downChanged = fields & InputDevice::TrackballState::Accumulator::FIELD_BTN_MOUSE;
- bool deltaChanged = fields & DELTA_FIELDS;
+ return NULL;
+}
- bool down;
- if (downChanged) {
- if (device->trackball.accumulator.btnMouse) {
- device->trackball.current.down = true;
- device->trackball.current.downTime = when;
- down = true;
- } else {
- device->trackball.current.down = false;
- down = false;
+void TouchInputMapper::calculatePointerIds() {
+ uint32_t currentPointerCount = mCurrentTouch.pointerCount;
+ uint32_t lastPointerCount = mLastTouch.pointerCount;
+
+ if (currentPointerCount == 0) {
+ // No pointers to assign.
+ mCurrentTouch.idBits.clear();
+ } else if (lastPointerCount == 0) {
+ // All pointers are new.
+ mCurrentTouch.idBits.clear();
+ for (uint32_t i = 0; i < currentPointerCount; i++) {
+ mCurrentTouch.pointers[i].id = i;
+ mCurrentTouch.idToIndex[i] = i;
+ mCurrentTouch.idBits.markBit(i);
}
+ } else if (currentPointerCount == 1 && lastPointerCount == 1) {
+ // Only one pointer and no change in count so it must have the same id as before.
+ uint32_t id = mLastTouch.pointers[0].id;
+ mCurrentTouch.pointers[0].id = id;
+ mCurrentTouch.idToIndex[id] = 0;
+ mCurrentTouch.idBits.value = BitSet32::valueForBit(id);
} else {
- down = device->trackball.current.down;
- }
+ // General case.
+ // We build a heap of squared euclidean distances between current and last pointers
+ // associated with the current and last pointer indices. Then, we find the best
+ // match (by distance) for each current pointer.
+ PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS];
+
+ uint32_t heapSize = 0;
+ for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount;
+ currentPointerIndex++) {
+ for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount;
+ lastPointerIndex++) {
+ int64_t deltaX = mCurrentTouch.pointers[currentPointerIndex].x
+ - mLastTouch.pointers[lastPointerIndex].x;
+ int64_t deltaY = mCurrentTouch.pointers[currentPointerIndex].y
+ - mLastTouch.pointers[lastPointerIndex].y;
+
+ uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY);
+
+ // Insert new element into the heap (sift up).
+ heap[heapSize].currentPointerIndex = currentPointerIndex;
+ heap[heapSize].lastPointerIndex = lastPointerIndex;
+ heap[heapSize].distance = distance;
+ heapSize += 1;
+ }
+ }
- /* Apply policy */
+ // Heapify
+ for (uint32_t startIndex = heapSize / 2; startIndex != 0; ) {
+ startIndex -= 1;
+ for (uint32_t parentIndex = startIndex; ;) {
+ uint32_t childIndex = parentIndex * 2 + 1;
+ if (childIndex >= heapSize) {
+ break;
+ }
- int32_t policyActions = mPolicy->interceptTrackball(when, downChanged, down, deltaChanged);
+ if (childIndex + 1 < heapSize
+ && heap[childIndex + 1].distance < heap[childIndex].distance) {
+ childIndex += 1;
+ }
- uint32_t policyFlags = 0;
- if (! applyStandardInputDispatchPolicyActions(when, policyActions, & policyFlags)) {
- return; // event dropped
- }
+ if (heap[parentIndex].distance <= heap[childIndex].distance) {
+ break;
+ }
- /* Enqueue motion event for dispatch */
+ swap(heap[parentIndex], heap[childIndex]);
+ parentIndex = childIndex;
+ }
+ }
- int32_t motionEventAction;
- if (downChanged) {
- motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
- } else {
- motionEventAction = AMOTION_EVENT_ACTION_MOVE;
- }
+#if DEBUG_POINTER_ASSIGNMENT
+ LOGD("calculatePointerIds - initial distance min-heap: size=%d", heapSize);
+ for (size_t i = 0; i < heapSize; i++) {
+ LOGD(" heap[%d]: cur=%d, last=%d, distance=%lld",
+ i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
+ heap[i].distance);
+ }
+#endif
- int32_t pointerId = 0;
- PointerCoords pointerCoords;
- pointerCoords.x = fields & InputDevice::TrackballState::Accumulator::FIELD_REL_X
- ? device->trackball.accumulator.relX * device->trackball.precalculated.xScale : 0;
- pointerCoords.y = fields & InputDevice::TrackballState::Accumulator::FIELD_REL_Y
- ? device->trackball.accumulator.relY * device->trackball.precalculated.yScale : 0;
- pointerCoords.pressure = 1.0f; // XXX Consider making this 1.0f if down, 0 otherwise.
- pointerCoords.size = 0;
- pointerCoords.touchMajor = 0;
- pointerCoords.touchMinor = 0;
- pointerCoords.toolMajor = 0;
- pointerCoords.toolMinor = 0;
- pointerCoords.orientation = 0;
+ // Pull matches out by increasing order of distance.
+ // To avoid reassigning pointers that have already been matched, the loop keeps track
+ // of which last and current pointers have been matched using the matchedXXXBits variables.
+ // It also tracks the used pointer id bits.
+ BitSet32 matchedLastBits(0);
+ BitSet32 matchedCurrentBits(0);
+ BitSet32 usedIdBits(0);
+ bool first = true;
+ for (uint32_t i = min(currentPointerCount, lastPointerCount); i > 0; i--) {
+ for (;;) {
+ if (first) {
+ // The first time through the loop, we just consume the root element of
+ // the heap (the one with smallest distance).
+ first = false;
+ } else {
+ // Previous iterations consumed the root element of the heap.
+ // Pop root element off of the heap (sift down).
+ heapSize -= 1;
+ assert(heapSize > 0);
+
+ // Sift down.
+ heap[0] = heap[heapSize];
+ for (uint32_t parentIndex = 0; ;) {
+ uint32_t childIndex = parentIndex * 2 + 1;
+ if (childIndex >= heapSize) {
+ break;
+ }
+
+ if (childIndex + 1 < heapSize
+ && heap[childIndex + 1].distance < heap[childIndex].distance) {
+ childIndex += 1;
+ }
+
+ if (heap[parentIndex].distance <= heap[childIndex].distance) {
+ break;
+ }
+
+ swap(heap[parentIndex], heap[childIndex]);
+ parentIndex = childIndex;
+ }
+
+#if DEBUG_POINTER_ASSIGNMENT
+ LOGD("calculatePointerIds - reduced distance min-heap: size=%d", heapSize);
+ for (size_t i = 0; i < heapSize; i++) {
+ LOGD(" heap[%d]: cur=%d, last=%d, distance=%lld",
+ i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
+ heap[i].distance);
+ }
+#endif
+ }
- float temp;
- switch (mDisplayOrientation) {
- case InputReaderPolicyInterface::ROTATION_90:
- temp = pointerCoords.x;
- pointerCoords.x = pointerCoords.y;
- pointerCoords.y = - temp;
- break;
+ uint32_t currentPointerIndex = heap[0].currentPointerIndex;
+ if (matchedCurrentBits.hasBit(currentPointerIndex)) continue; // already matched
- case InputReaderPolicyInterface::ROTATION_180:
- pointerCoords.x = - pointerCoords.x;
- pointerCoords.y = - pointerCoords.y;
- break;
+ uint32_t lastPointerIndex = heap[0].lastPointerIndex;
+ if (matchedLastBits.hasBit(lastPointerIndex)) continue; // already matched
- case InputReaderPolicyInterface::ROTATION_270:
- temp = pointerCoords.x;
- pointerCoords.x = - pointerCoords.y;
- pointerCoords.y = temp;
- break;
- }
+ matchedCurrentBits.markBit(currentPointerIndex);
+ matchedLastBits.markBit(lastPointerIndex);
- mDispatcher->notifyMotion(when, device->id, AINPUT_SOURCE_TRACKBALL, policyFlags,
- motionEventAction, globalMetaState(), AMOTION_EVENT_EDGE_FLAG_NONE,
- 1, & pointerId, & pointerCoords,
- device->trackball.precalculated.xPrecision,
- device->trackball.precalculated.yPrecision,
- device->trackball.current.downTime);
-}
+ uint32_t id = mLastTouch.pointers[lastPointerIndex].id;
+ mCurrentTouch.pointers[currentPointerIndex].id = id;
+ mCurrentTouch.idToIndex[id] = currentPointerIndex;
+ usedIdBits.markBit(id);
-void InputReader::onConfigurationChanged(nsecs_t when) {
- // Reset global meta state because it depends on the list of all configured devices.
- resetGlobalMetaState();
+#if DEBUG_POINTER_ASSIGNMENT
+ LOGD("calculatePointerIds - matched: cur=%d, last=%d, id=%d, distance=%lld",
+ lastPointerIndex, currentPointerIndex, id, heap[0].distance);
+#endif
+ break;
+ }
+ }
- // Reset virtual keys, just in case.
- updateExportedVirtualKeyState();
+ // Assign fresh ids to new pointers.
+ if (currentPointerCount > lastPointerCount) {
+ for (uint32_t i = currentPointerCount - lastPointerCount; ;) {
+ uint32_t currentPointerIndex = matchedCurrentBits.firstUnmarkedBit();
+ uint32_t id = usedIdBits.firstUnmarkedBit();
- // Update input configuration.
- updateExportedInputConfiguration();
+ mCurrentTouch.pointers[currentPointerIndex].id = id;
+ mCurrentTouch.idToIndex[id] = currentPointerIndex;
+ usedIdBits.markBit(id);
- // Enqueue configuration changed.
- mDispatcher->notifyConfigurationChanged(when);
-}
+#if DEBUG_POINTER_ASSIGNMENT
+ LOGD("calculatePointerIds - assigned: cur=%d, id=%d",
+ currentPointerIndex, id);
+#endif
-bool InputReader::applyStandardInputDispatchPolicyActions(nsecs_t when,
- int32_t policyActions, uint32_t* policyFlags) {
- if (policyActions & InputReaderPolicyInterface::ACTION_APP_SWITCH_COMING) {
- mDispatcher->notifyAppSwitchComing(when);
+ if (--i == 0) break; // done
+ matchedCurrentBits.markBit(currentPointerIndex);
+ }
+ }
+
+ // Fix id bits.
+ mCurrentTouch.idBits = usedIdBits;
}
+}
- if (policyActions & InputReaderPolicyInterface::ACTION_WOKE_HERE) {
- *policyFlags |= POLICY_FLAG_WOKE_HERE;
+/* Special hack for devices that have bad screen data: if one of the
+ * points has moved more than a screen height from the last position,
+ * then drop it. */
+bool TouchInputMapper::applyBadTouchFilter() {
+ // This hack requires valid axis parameters.
+ if (! mAxes.y.valid) {
+ return false;
}
- if (policyActions & InputReaderPolicyInterface::ACTION_BRIGHT_HERE) {
- *policyFlags |= POLICY_FLAG_BRIGHT_HERE;
+ uint32_t pointerCount = mCurrentTouch.pointerCount;
+
+ // Nothing to do if there are no points.
+ if (pointerCount == 0) {
+ return false;
}
- return policyActions & InputReaderPolicyInterface::ACTION_DISPATCH;
-}
+ // Don't do anything if a finger is going down or up. We run
+ // here before assigning pointer IDs, so there isn't a good
+ // way to do per-finger matching.
+ if (pointerCount != mLastTouch.pointerCount) {
+ return false;
+ }
-void InputReader::resetDisplayProperties() {
- mDisplayWidth = mDisplayHeight = -1;
- mDisplayOrientation = -1;
-}
+ // We consider a single movement across more than a 7/16 of
+ // the long size of the screen to be bad. This was a magic value
+ // determined by looking at the maximum distance it is feasible
+ // to actually move in one sample.
+ int32_t maxDeltaY = mAxes.y.getRange() * 7 / 16;
+
+ // XXX The original code in InputDevice.java included commented out
+ // code for testing the X axis. Note that when we drop a point
+ // we don't actually restore the old X either. Strange.
+ // The old code also tries to track when bad points were previously
+ // detected but it turns out that due to the placement of a "break"
+ // at the end of the loop, we never set mDroppedBadPoint to true
+ // so it is effectively dead code.
+ // Need to figure out if the old code is busted or just overcomplicated
+ // but working as intended.
+
+ // Look through all new points and see if any are farther than
+ // acceptable from all previous points.
+ for (uint32_t i = pointerCount; i-- > 0; ) {
+ int32_t y = mCurrentTouch.pointers[i].y;
+ int32_t closestY = INT_MAX;
+ int32_t closestDeltaY = 0;
+
+#if DEBUG_HACKS
+ LOGD("BadTouchFilter: Looking at next point #%d: y=%d", i, y);
+#endif
-bool InputReader::refreshDisplayProperties() {
- int32_t newWidth, newHeight, newOrientation;
- if (mPolicy->getDisplayInfo(0, & newWidth, & newHeight, & newOrientation)) {
- if (newWidth != mDisplayWidth || newHeight != mDisplayHeight) {
- LOGD("Display size changed from %dx%d to %dx%d, updating device configuration",
- mDisplayWidth, mDisplayHeight, newWidth, newHeight);
+ for (uint32_t j = pointerCount; j-- > 0; ) {
+ int32_t lastY = mLastTouch.pointers[j].y;
+ int32_t deltaY = abs(y - lastY);
- mDisplayWidth = newWidth;
- mDisplayHeight = newHeight;
+#if DEBUG_HACKS
+ LOGD("BadTouchFilter: Comparing with last point #%d: y=%d deltaY=%d",
+ j, lastY, deltaY);
+#endif
- for (size_t i = 0; i < mDevices.size(); i++) {
- configureDeviceForCurrentDisplaySize(mDevices.valueAt(i));
+ if (deltaY < maxDeltaY) {
+ goto SkipSufficientlyClosePoint;
+ }
+ if (deltaY < closestDeltaY) {
+ closestDeltaY = deltaY;
+ closestY = lastY;
}
}
- if (newOrientation != mDisplayOrientation) {
- LOGD("Display orientation changed to %d", mDisplayOrientation);
+ // Must not have found a close enough match.
+#if DEBUG_HACKS
+ LOGD("BadTouchFilter: Dropping bad point #%d: newY=%d oldY=%d deltaY=%d maxDeltaY=%d",
+ i, y, closestY, closestDeltaY, maxDeltaY);
+#endif
- mDisplayOrientation = newOrientation;
- }
- return true;
- } else {
- resetDisplayProperties();
- return false;
+ mCurrentTouch.pointers[i].y = closestY;
+ return true; // XXX original code only corrects one point
+
+ SkipSufficientlyClosePoint: ;
}
-}
-InputDevice* InputReader::getDevice(int32_t deviceId) {
- ssize_t index = mDevices.indexOfKey(deviceId);
- return index >= 0 ? mDevices.valueAt((size_t) index) : NULL;
+ // No change.
+ return false;
}
-InputDevice* InputReader::getNonIgnoredDevice(int32_t deviceId) {
- InputDevice* device = getDevice(deviceId);
- return device && ! device->ignored ? device : NULL;
-}
+/* Special hack for devices that have bad screen data: drop points where
+ * the coordinate value for one axis has jumped to the other pointer's location.
+ */
+bool TouchInputMapper::applyJumpyTouchFilter() {
+ // This hack requires valid axis parameters.
+ if (! mAxes.y.valid) {
+ return false;
+ }
-void InputReader::addDevice(nsecs_t when, int32_t deviceId) {
- uint32_t classes = mEventHub->getDeviceClasses(deviceId);
- String8 name = mEventHub->getDeviceName(deviceId);
- InputDevice* device = new InputDevice(deviceId, classes, name);
+ uint32_t pointerCount = mCurrentTouch.pointerCount;
+ if (mLastTouch.pointerCount != pointerCount) {
+#if DEBUG_HACKS
+ LOGD("JumpyTouchFilter: Different pointer count %d -> %d",
+ mLastTouch.pointerCount, pointerCount);
+ for (uint32_t i = 0; i < pointerCount; i++) {
+ LOGD(" Pointer %d (%d, %d)", i,
+ mCurrentTouch.pointers[i].x, mCurrentTouch.pointers[i].y);
+ }
+#endif
- if (classes != 0) {
- LOGI("Device added: id=0x%x, name=%s, classes=%02x", device->id,
- device->name.string(), device->classes);
+ if (mJumpyTouchFilter.jumpyPointsDropped < JUMPY_TRANSITION_DROPS) {
+ if (mLastTouch.pointerCount == 1 && pointerCount == 2) {
+ // Just drop the first few events going from 1 to 2 pointers.
+ // They're bad often enough that they're not worth considering.
+ mCurrentTouch.pointerCount = 1;
+ mJumpyTouchFilter.jumpyPointsDropped += 1;
- configureDevice(device);
- } else {
- LOGI("Device added: id=0x%x, name=%s (ignored non-input device)", device->id,
- device->name.string());
+#if DEBUG_HACKS
+ LOGD("JumpyTouchFilter: Pointer 2 dropped");
+#endif
+ return true;
+ } else if (mLastTouch.pointerCount == 2 && pointerCount == 1) {
+ // The event when we go from 2 -> 1 tends to be messed up too
+ mCurrentTouch.pointerCount = 2;
+ mCurrentTouch.pointers[0] = mLastTouch.pointers[0];
+ mCurrentTouch.pointers[1] = mLastTouch.pointers[1];
+ mJumpyTouchFilter.jumpyPointsDropped += 1;
+
+#if DEBUG_HACKS
+ for (int32_t i = 0; i < 2; i++) {
+ LOGD("JumpyTouchFilter: Pointer %d replaced (%d, %d)", i,
+ mCurrentTouch.pointers[i].x, mCurrentTouch.pointers[i].y);
+ }
+#endif
+ return true;
+ }
+ }
+ // Reset jumpy points dropped on other transitions or if limit exceeded.
+ mJumpyTouchFilter.jumpyPointsDropped = 0;
- device->ignored = true;
+#if DEBUG_HACKS
+ LOGD("JumpyTouchFilter: Transition - drop limit reset");
+#endif
+ return false;
}
- device->reset();
+ // We have the same number of pointers as last time.
+ // A 'jumpy' point is one where the coordinate value for one axis
+ // has jumped to the other pointer's location. No need to do anything
+ // else if we only have one pointer.
+ if (pointerCount < 2) {
+ return false;
+ }
- mDevices.add(deviceId, device);
+ if (mJumpyTouchFilter.jumpyPointsDropped < JUMPY_DROP_LIMIT) {
+ int jumpyEpsilon = mAxes.y.getRange() / JUMPY_EPSILON_DIVISOR;
- if (! device->ignored) {
- onConfigurationChanged(when);
- }
-}
+ // We only replace the single worst jumpy point as characterized by pointer distance
+ // in a single axis.
+ int32_t badPointerIndex = -1;
+ int32_t badPointerReplacementIndex = -1;
+ int32_t badPointerDistance = INT_MIN; // distance to be corrected
-void InputReader::removeDevice(nsecs_t when, InputDevice* device) {
- mDevices.removeItem(device->id);
+ for (uint32_t i = pointerCount; i-- > 0; ) {
+ int32_t x = mCurrentTouch.pointers[i].x;
+ int32_t y = mCurrentTouch.pointers[i].y;
- if (! device->ignored) {
- LOGI("Device removed: id=0x%x, name=%s, classes=%02x", device->id,
- device->name.string(), device->classes);
+#if DEBUG_HACKS
+ LOGD("JumpyTouchFilter: Point %d (%d, %d)", i, x, y);
+#endif
- onConfigurationChanged(when);
- } else {
- LOGI("Device removed: id=0x%x, name=%s (ignored non-input device)", device->id,
- device->name.string());
- }
+ // Check if a touch point is too close to another's coordinates
+ bool dropX = false, dropY = false;
+ for (uint32_t j = 0; j < pointerCount; j++) {
+ if (i == j) {
+ continue;
+ }
- delete device;
-}
+ if (abs(x - mCurrentTouch.pointers[j].x) <= jumpyEpsilon) {
+ dropX = true;
+ break;
+ }
-void InputReader::configureDevice(InputDevice* device) {
- if (device->isMultiTouchScreen()) {
- configureAbsoluteAxisInfo(device, ABS_MT_POSITION_X, "X",
- & device->touchScreen.parameters.xAxis);
- configureAbsoluteAxisInfo(device, ABS_MT_POSITION_Y, "Y",
- & device->touchScreen.parameters.yAxis);
- configureAbsoluteAxisInfo(device, ABS_MT_TOUCH_MAJOR, "Pressure",
- & device->touchScreen.parameters.pressureAxis);
- configureAbsoluteAxisInfo(device, ABS_MT_WIDTH_MAJOR, "Size",
- & device->touchScreen.parameters.sizeAxis);
- configureAbsoluteAxisInfo(device, ABS_MT_ORIENTATION, "Orientation",
- & device->touchScreen.parameters.orientationAxis);
- } else if (device->isSingleTouchScreen()) {
- configureAbsoluteAxisInfo(device, ABS_X, "X",
- & device->touchScreen.parameters.xAxis);
- configureAbsoluteAxisInfo(device, ABS_Y, "Y",
- & device->touchScreen.parameters.yAxis);
- configureAbsoluteAxisInfo(device, ABS_PRESSURE, "Pressure",
- & device->touchScreen.parameters.pressureAxis);
- configureAbsoluteAxisInfo(device, ABS_TOOL_WIDTH, "Size",
- & device->touchScreen.parameters.sizeAxis);
- device->touchScreen.parameters.orientationAxis.valid = false;
- }
-
- if (device->isTouchScreen()) {
- device->touchScreen.parameters.useBadTouchFilter =
- mPolicy->filterTouchEvents();
- device->touchScreen.parameters.useAveragingTouchFilter =
- mPolicy->filterTouchEvents();
- device->touchScreen.parameters.useJumpyTouchFilter =
- mPolicy->filterJumpyTouchEvents();
-
- if (device->touchScreen.parameters.pressureAxis.valid) {
- device->touchScreen.precalculated.pressureOrigin =
- device->touchScreen.parameters.pressureAxis.minValue;
- device->touchScreen.precalculated.pressureScale =
- 1.0f / device->touchScreen.parameters.pressureAxis.range;
- } else {
- device->touchScreen.precalculated.pressureOrigin = 0;
- device->touchScreen.precalculated.pressureScale = 1.0f;
- }
+ if (abs(y - mCurrentTouch.pointers[j].y) <= jumpyEpsilon) {
+ dropY = true;
+ break;
+ }
+ }
+ if (! dropX && ! dropY) {
+ continue; // not jumpy
+ }
- if (device->touchScreen.parameters.sizeAxis.valid) {
- device->touchScreen.precalculated.sizeOrigin =
- device->touchScreen.parameters.sizeAxis.minValue;
- device->touchScreen.precalculated.sizeScale =
- 1.0f / device->touchScreen.parameters.sizeAxis.range;
- } else {
- device->touchScreen.precalculated.sizeOrigin = 0;
- device->touchScreen.precalculated.sizeScale = 1.0f;
- }
+ // Find a replacement candidate by comparing with older points on the
+ // complementary (non-jumpy) axis.
+ int32_t distance = INT_MIN; // distance to be corrected
+ int32_t replacementIndex = -1;
+
+ if (dropX) {
+ // X looks too close. Find an older replacement point with a close Y.
+ int32_t smallestDeltaY = INT_MAX;
+ for (uint32_t j = 0; j < pointerCount; j++) {
+ int32_t deltaY = abs(y - mLastTouch.pointers[j].y);
+ if (deltaY < smallestDeltaY) {
+ smallestDeltaY = deltaY;
+ replacementIndex = j;
+ }
+ }
+ distance = abs(x - mLastTouch.pointers[replacementIndex].x);
+ } else {
+ // Y looks too close. Find an older replacement point with a close X.
+ int32_t smallestDeltaX = INT_MAX;
+ for (uint32_t j = 0; j < pointerCount; j++) {
+ int32_t deltaX = abs(x - mLastTouch.pointers[j].x);
+ if (deltaX < smallestDeltaX) {
+ smallestDeltaX = deltaX;
+ replacementIndex = j;
+ }
+ }
+ distance = abs(y - mLastTouch.pointers[replacementIndex].y);
+ }
- if (device->touchScreen.parameters.orientationAxis.valid
- && device->touchScreen.parameters.orientationAxis.maxValue > 0) {
- device->touchScreen.precalculated.orientationScale =
- M_PI_4 / device->touchScreen.parameters.orientationAxis.maxValue;
- } else {
- device->touchScreen.precalculated.orientationScale = 0.0f;
+ // If replacing this pointer would correct a worse error than the previous ones
+ // considered, then use this replacement instead.
+ if (distance > badPointerDistance) {
+ badPointerIndex = i;
+ badPointerReplacementIndex = replacementIndex;
+ badPointerDistance = distance;
+ }
}
- }
- if (device->isTrackball()) {
- device->trackball.precalculated.xPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
- device->trackball.precalculated.yPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
- device->trackball.precalculated.xScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
- device->trackball.precalculated.yScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
+ // Correct the jumpy pointer if one was found.
+ if (badPointerIndex >= 0) {
+#if DEBUG_HACKS
+ LOGD("JumpyTouchFilter: Replacing bad pointer %d with (%d, %d)",
+ badPointerIndex,
+ mLastTouch.pointers[badPointerReplacementIndex].x,
+ mLastTouch.pointers[badPointerReplacementIndex].y);
+#endif
+
+ mCurrentTouch.pointers[badPointerIndex].x =
+ mLastTouch.pointers[badPointerReplacementIndex].x;
+ mCurrentTouch.pointers[badPointerIndex].y =
+ mLastTouch.pointers[badPointerReplacementIndex].y;
+ mJumpyTouchFilter.jumpyPointsDropped += 1;
+ return true;
+ }
}
- configureDeviceForCurrentDisplaySize(device);
+ mJumpyTouchFilter.jumpyPointsDropped = 0;
+ return false;
}
-void InputReader::configureDeviceForCurrentDisplaySize(InputDevice* device) {
- if (device->isTouchScreen()) {
- if (device->touchScreen.parameters.xAxis.valid
- && device->touchScreen.parameters.yAxis.valid) {
- device->touchScreen.precalculated.xOrigin =
- device->touchScreen.parameters.xAxis.minValue;
- device->touchScreen.precalculated.yOrigin =
- device->touchScreen.parameters.yAxis.minValue;
+/* Special hack for devices that have bad screen data: aggregate and
+ * compute averages of the coordinate data, to reduce the amount of
+ * jitter seen by applications. */
+void TouchInputMapper::applyAveragingTouchFilter() {
+ for (uint32_t currentIndex = 0; currentIndex < mCurrentTouch.pointerCount; currentIndex++) {
+ uint32_t id = mCurrentTouch.pointers[currentIndex].id;
+ int32_t x = mCurrentTouch.pointers[currentIndex].x;
+ int32_t y = mCurrentTouch.pointers[currentIndex].y;
+ int32_t pressure = mCurrentTouch.pointers[currentIndex].pressure;
+
+ if (mLastTouch.idBits.hasBit(id)) {
+ // Pointer was down before and is still down now.
+ // Compute average over history trace.
+ uint32_t start = mAveragingTouchFilter.historyStart[id];
+ uint32_t end = mAveragingTouchFilter.historyEnd[id];
+
+ int64_t deltaX = x - mAveragingTouchFilter.historyData[end].pointers[id].x;
+ int64_t deltaY = y - mAveragingTouchFilter.historyData[end].pointers[id].y;
+ uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY);
+
+#if DEBUG_HACKS
+ LOGD("AveragingTouchFilter: Pointer id %d - Distance from last sample: %lld",
+ id, distance);
+#endif
- if (mDisplayWidth < 0) {
- LOGD("Skipping part of touch screen configuration since display size is unknown.");
+ if (distance < AVERAGING_DISTANCE_LIMIT) {
+ // Increment end index in preparation for recording new historical data.
+ end += 1;
+ if (end > AVERAGING_HISTORY_SIZE) {
+ end = 0;
+ }
- device->touchScreen.precalculated.xScale = 1.0f;
- device->touchScreen.precalculated.yScale = 1.0f;
- } else {
- LOGI("Device configured: id=0x%x, name=%s (display size was changed)", device->id,
- device->name.string());
+ // If the end index has looped back to the start index then we have filled
+ // the historical trace up to the desired size so we drop the historical
+ // data at the start of the trace.
+ if (end == start) {
+ start += 1;
+ if (start > AVERAGING_HISTORY_SIZE) {
+ start = 0;
+ }
+ }
- device->touchScreen.precalculated.xScale =
- float(mDisplayWidth) / device->touchScreen.parameters.xAxis.range;
- device->touchScreen.precalculated.yScale =
- float(mDisplayHeight) / device->touchScreen.parameters.yAxis.range;
+ // Add the raw data to the historical trace.
+ mAveragingTouchFilter.historyStart[id] = start;
+ mAveragingTouchFilter.historyEnd[id] = end;
+ mAveragingTouchFilter.historyData[end].pointers[id].x = x;
+ mAveragingTouchFilter.historyData[end].pointers[id].y = y;
+ mAveragingTouchFilter.historyData[end].pointers[id].pressure = pressure;
+
+ // Average over all historical positions in the trace by total pressure.
+ int32_t averagedX = 0;
+ int32_t averagedY = 0;
+ int32_t totalPressure = 0;
+ for (;;) {
+ int32_t historicalX = mAveragingTouchFilter.historyData[start].pointers[id].x;
+ int32_t historicalY = mAveragingTouchFilter.historyData[start].pointers[id].y;
+ int32_t historicalPressure = mAveragingTouchFilter.historyData[start]
+ .pointers[id].pressure;
+
+ averagedX += historicalX * historicalPressure;
+ averagedY += historicalY * historicalPressure;
+ totalPressure += historicalPressure;
+
+ if (start == end) {
+ break;
+ }
+
+ start += 1;
+ if (start > AVERAGING_HISTORY_SIZE) {
+ start = 0;
+ }
+ }
+
+ averagedX /= totalPressure;
+ averagedY /= totalPressure;
+
+#if DEBUG_HACKS
+ LOGD("AveragingTouchFilter: Pointer id %d - "
+ "totalPressure=%d, averagedX=%d, averagedY=%d", id, totalPressure,
+ averagedX, averagedY);
+#endif
- configureVirtualKeys(device);
+ mCurrentTouch.pointers[currentIndex].x = averagedX;
+ mCurrentTouch.pointers[currentIndex].y = averagedY;
+ } else {
+#if DEBUG_HACKS
+ LOGD("AveragingTouchFilter: Pointer id %d - Exceeded max distance", id);
+#endif
}
} else {
- device->touchScreen.precalculated.xOrigin = 0;
- device->touchScreen.precalculated.xScale = 1.0f;
- device->touchScreen.precalculated.yOrigin = 0;
- device->touchScreen.precalculated.yScale = 1.0f;
+#if DEBUG_HACKS
+ LOGD("AveragingTouchFilter: Pointer id %d - Pointer went up", id);
+#endif
}
+
+ // Reset pointer history.
+ mAveragingTouchFilter.historyStart[id] = 0;
+ mAveragingTouchFilter.historyEnd[id] = 0;
+ mAveragingTouchFilter.historyData[0].pointers[id].x = x;
+ mAveragingTouchFilter.historyData[0].pointers[id].y = y;
+ mAveragingTouchFilter.historyData[0].pointers[id].pressure = pressure;
}
}
-void InputReader::configureVirtualKeys(InputDevice* device) {
- assert(device->touchScreen.parameters.xAxis.valid
- && device->touchScreen.parameters.yAxis.valid);
-
- device->touchScreen.virtualKeys.clear();
-
- Vector<InputReaderPolicyInterface::VirtualKeyDefinition> virtualKeyDefinitions;
- mPolicy->getVirtualKeyDefinitions(device->name, virtualKeyDefinitions);
- if (virtualKeyDefinitions.size() == 0) {
- return;
- }
+int32_t TouchInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
+ { // acquire virtual key lock
+ AutoMutex _l(mVirtualKeyLock);
- device->touchScreen.virtualKeys.setCapacity(virtualKeyDefinitions.size());
+ if (mCurrentVirtualKey.down && mCurrentVirtualKey.keyCode == keyCode) {
+ return AKEY_STATE_VIRTUAL;
+ }
- int32_t touchScreenLeft = device->touchScreen.parameters.xAxis.minValue;
- int32_t touchScreenTop = device->touchScreen.parameters.yAxis.minValue;
- int32_t touchScreenWidth = device->touchScreen.parameters.xAxis.range;
- int32_t touchScreenHeight = device->touchScreen.parameters.yAxis.range;
+ for (size_t i = 0; i < mVirtualKeys.size(); i++) {
+ const VirtualKey& virtualKey = mVirtualKeys[i];
+ if (virtualKey.keyCode == keyCode) {
+ return AKEY_STATE_UP;
+ }
+ }
+ } // release virtual key lock
- for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) {
- const InputReaderPolicyInterface::VirtualKeyDefinition& virtualKeyDefinition =
- virtualKeyDefinitions[i];
+ return AKEY_STATE_UNKNOWN;
+}
- device->touchScreen.virtualKeys.add();
- InputDevice::VirtualKey& virtualKey =
- device->touchScreen.virtualKeys.editTop();
+int32_t TouchInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
+ { // acquire virtual key lock
+ AutoMutex _l(mVirtualKeyLock);
- virtualKey.scanCode = virtualKeyDefinition.scanCode;
- int32_t keyCode;
- uint32_t flags;
- if (mEventHub->scancodeToKeycode(device->id, virtualKey.scanCode,
- & keyCode, & flags)) {
- LOGW(" VirtualKey %d: could not obtain key code, ignoring", virtualKey.scanCode);
- device->touchScreen.virtualKeys.pop(); // drop the key
- continue;
+ if (mCurrentVirtualKey.down && mCurrentVirtualKey.scanCode == scanCode) {
+ return AKEY_STATE_VIRTUAL;
}
- virtualKey.keyCode = keyCode;
- virtualKey.flags = flags;
+ for (size_t i = 0; i < mVirtualKeys.size(); i++) {
+ const VirtualKey& virtualKey = mVirtualKeys[i];
+ if (virtualKey.scanCode == scanCode) {
+ return AKEY_STATE_UP;
+ }
+ }
+ } // release virtual key lock
- // convert the key definition's display coordinates into touch coordinates for a hit box
- int32_t halfWidth = virtualKeyDefinition.width / 2;
- int32_t halfHeight = virtualKeyDefinition.height / 2;
+ return AKEY_STATE_UNKNOWN;
+}
- virtualKey.hitLeft = (virtualKeyDefinition.centerX - halfWidth)
- * touchScreenWidth / mDisplayWidth + touchScreenLeft;
- virtualKey.hitRight= (virtualKeyDefinition.centerX + halfWidth)
- * touchScreenWidth / mDisplayWidth + touchScreenLeft;
- virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight)
- * touchScreenHeight / mDisplayHeight + touchScreenTop;
- virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight)
- * touchScreenHeight / mDisplayHeight + touchScreenTop;
+bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
+ const int32_t* keyCodes, uint8_t* outFlags) {
+ { // acquire virtual key lock
+ AutoMutex _l(mVirtualKeyLock);
- LOGI(" VirtualKey %d: keyCode=%d hitLeft=%d hitRight=%d hitTop=%d hitBottom=%d",
- virtualKey.scanCode, virtualKey.keyCode,
- virtualKey.hitLeft, virtualKey.hitRight, virtualKey.hitTop, virtualKey.hitBottom);
- }
-}
+ for (size_t i = 0; i < mVirtualKeys.size(); i++) {
+ const VirtualKey& virtualKey = mVirtualKeys[i];
-void InputReader::configureAbsoluteAxisInfo(InputDevice* device,
- int axis, const char* name, InputDevice::AbsoluteAxisInfo* out) {
- if (! mEventHub->getAbsoluteInfo(device->id, axis,
- & out->minValue, & out->maxValue, & out->flat, &out->fuzz)) {
- out->range = out->maxValue - out->minValue;
- if (out->range != 0) {
- LOGI(" %s: min=%d max=%d flat=%d fuzz=%d",
- name, out->minValue, out->maxValue, out->flat, out->fuzz);
- out->valid = true;
- return;
+ for (size_t i = 0; i < numCodes; i++) {
+ if (virtualKey.keyCode == keyCodes[i]) {
+ outFlags[i] = 1;
+ }
+ }
}
- }
+ } // release virtual key lock
- out->valid = false;
- out->minValue = 0;
- out->maxValue = 0;
- out->flat = 0;
- out->fuzz = 0;
- out->range = 0;
- LOGI(" %s: unknown axis values, marking as invalid", name);
+ return true;
}
-void InputReader::configureExcludedDevices() {
- Vector<String8> excludedDeviceNames;
- mPolicy->getExcludedDeviceNames(excludedDeviceNames);
- for (size_t i = 0; i < excludedDeviceNames.size(); i++) {
- mEventHub->addExcludedDevice(excludedDeviceNames[i]);
- }
+// --- SingleTouchInputMapper ---
+
+SingleTouchInputMapper::SingleTouchInputMapper(InputDevice* device, int32_t associatedDisplayId) :
+ TouchInputMapper(device, associatedDisplayId) {
+ initialize();
}
-void InputReader::resetGlobalMetaState() {
- mGlobalMetaState = -1;
+SingleTouchInputMapper::~SingleTouchInputMapper() {
}
-int32_t InputReader::globalMetaState() {
- if (mGlobalMetaState == -1) {
- mGlobalMetaState = 0;
- for (size_t i = 0; i < mDevices.size(); i++) {
- InputDevice* device = mDevices.valueAt(i);
- if (device->isKeyboard()) {
- mGlobalMetaState |= device->keyboard.current.metaState;
+void SingleTouchInputMapper::initialize() {
+ mAccumulator.clear();
+
+ mDown = false;
+ mX = 0;
+ mY = 0;
+ mPressure = 0;
+ mSize = 0;
+}
+
+void SingleTouchInputMapper::reset() {
+ TouchInputMapper::reset();
+
+ // Reinitialize.
+ initialize();
+ }
+
+void SingleTouchInputMapper::process(const RawEvent* rawEvent) {
+ switch (rawEvent->type) {
+ case EV_KEY:
+ switch (rawEvent->scanCode) {
+ case BTN_TOUCH:
+ mAccumulator.fields |= Accumulator::FIELD_BTN_TOUCH;
+ mAccumulator.btnTouch = rawEvent->value != 0;
+
+ sync(rawEvent->when);
+ mAccumulator.clear();
+ break;
+ }
+ break;
+
+ case EV_ABS:
+ switch (rawEvent->scanCode) {
+ case ABS_X:
+ mAccumulator.fields |= Accumulator::FIELD_ABS_X;
+ mAccumulator.absX = rawEvent->value;
+ break;
+ case ABS_Y:
+ mAccumulator.fields |= Accumulator::FIELD_ABS_Y;
+ mAccumulator.absY = rawEvent->value;
+ break;
+ case ABS_PRESSURE:
+ mAccumulator.fields |= Accumulator::FIELD_ABS_PRESSURE;
+ mAccumulator.absPressure = rawEvent->value;
+ break;
+ case ABS_TOOL_WIDTH:
+ mAccumulator.fields |= Accumulator::FIELD_ABS_TOOL_WIDTH;
+ mAccumulator.absToolWidth = rawEvent->value;
+ break;
+ }
+ break;
+
+ case EV_SYN:
+ switch (rawEvent->scanCode) {
+ case SYN_REPORT:
+ if (mAccumulator.isDirty()) {
+ sync(rawEvent->when);
+ mAccumulator.clear();
}
+ break;
}
+ break;
}
- return mGlobalMetaState;
}
-void InputReader::updateExportedVirtualKeyState() {
- int32_t keyCode = -1, scanCode = -1;
+void SingleTouchInputMapper::sync(nsecs_t when) {
+ /* Update device state */
- for (size_t i = 0; i < mDevices.size(); i++) {
- InputDevice* device = mDevices.valueAt(i);
- if (device->isTouchScreen()) {
- if (device->touchScreen.currentVirtualKey.status
- == InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_DOWN) {
- keyCode = device->touchScreen.currentVirtualKey.keyCode;
- scanCode = device->touchScreen.currentVirtualKey.scanCode;
- }
- }
+ uint32_t fields = mAccumulator.fields;
+
+ if (fields & Accumulator::FIELD_BTN_TOUCH) {
+ mDown = mAccumulator.btnTouch;
+ }
+
+ if (fields & Accumulator::FIELD_ABS_X) {
+ mX = mAccumulator.absX;
}
- { // acquire exported state lock
- AutoMutex _l(mExportedStateLock);
+ if (fields & Accumulator::FIELD_ABS_Y) {
+ mY = mAccumulator.absY;
+ }
- mExportedVirtualKeyCode = keyCode;
- mExportedVirtualScanCode = scanCode;
- } // release exported state lock
+ if (fields & Accumulator::FIELD_ABS_PRESSURE) {
+ mPressure = mAccumulator.absPressure;
+ }
+
+ if (fields & Accumulator::FIELD_ABS_TOOL_WIDTH) {
+ mSize = mAccumulator.absToolWidth;
+ }
+
+ mCurrentTouch.clear();
+
+ if (mDown) {
+ mCurrentTouch.pointerCount = 1;
+ mCurrentTouch.pointers[0].id = 0;
+ mCurrentTouch.pointers[0].x = mX;
+ mCurrentTouch.pointers[0].y = mY;
+ mCurrentTouch.pointers[0].pressure = mPressure;
+ mCurrentTouch.pointers[0].size = mSize;
+ mCurrentTouch.pointers[0].touchMajor = mPressure;
+ mCurrentTouch.pointers[0].touchMinor = mPressure;
+ mCurrentTouch.pointers[0].toolMajor = mSize;
+ mCurrentTouch.pointers[0].toolMinor = mSize;
+ mCurrentTouch.pointers[0].orientation = 0;
+ mCurrentTouch.idToIndex[0] = 0;
+ mCurrentTouch.idBits.markBit(0);
+ }
+
+ syncTouch(when, true);
}
-bool InputReader::getCurrentVirtualKey(int32_t* outKeyCode, int32_t* outScanCode) const {
- { // acquire exported state lock
- AutoMutex _l(mExportedStateLock);
+void SingleTouchInputMapper::configureAxes() {
+ TouchInputMapper::configureAxes();
- *outKeyCode = mExportedVirtualKeyCode;
- *outScanCode = mExportedVirtualScanCode;
- return mExportedVirtualKeyCode != -1;
- } // release exported state lock
+ // The axes are aliased to take into account the manner in which they are presented
+ // as part of the TouchData during the sync.
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_X, & mAxes.x);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_Y, & mAxes.y);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_PRESSURE, & mAxes.pressure);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_TOOL_WIDTH, & mAxes.size);
+
+ mAxes.touchMajor = mAxes.pressure;
+ mAxes.touchMinor = mAxes.pressure;
+ mAxes.toolMajor = mAxes.size;
+ mAxes.toolMinor = mAxes.size;
}
-void InputReader::updateExportedInputConfiguration() {
- int32_t touchScreenConfig = InputConfiguration::TOUCHSCREEN_NOTOUCH;
- int32_t keyboardConfig = InputConfiguration::KEYBOARD_NOKEYS;
- int32_t navigationConfig = InputConfiguration::NAVIGATION_NONAV;
- for (size_t i = 0; i < mDevices.size(); i++) {
- InputDevice* device = mDevices.valueAt(i);
- int32_t deviceClasses = device->classes;
+// --- MultiTouchInputMapper ---
+
+MultiTouchInputMapper::MultiTouchInputMapper(InputDevice* device, int32_t associatedDisplayId) :
+ TouchInputMapper(device, associatedDisplayId) {
+ initialize();
+}
+
+MultiTouchInputMapper::~MultiTouchInputMapper() {
+}
+
+void MultiTouchInputMapper::initialize() {
+ mAccumulator.clear();
+}
+
+void MultiTouchInputMapper::reset() {
+ TouchInputMapper::reset();
- if (deviceClasses & INPUT_DEVICE_CLASS_TOUCHSCREEN) {
- touchScreenConfig = InputConfiguration::TOUCHSCREEN_FINGER;
+ // Reinitialize.
+ initialize();
+}
+
+void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
+ switch (rawEvent->type) {
+ case EV_ABS: {
+ uint32_t pointerIndex = mAccumulator.pointerCount;
+ Accumulator::Pointer* pointer = & mAccumulator.pointers[pointerIndex];
+
+ switch (rawEvent->scanCode) {
+ case ABS_MT_POSITION_X:
+ pointer->fields |= Accumulator::FIELD_ABS_MT_POSITION_X;
+ pointer->absMTPositionX = rawEvent->value;
+ break;
+ case ABS_MT_POSITION_Y:
+ pointer->fields |= Accumulator::FIELD_ABS_MT_POSITION_Y;
+ pointer->absMTPositionY = rawEvent->value;
+ break;
+ case ABS_MT_TOUCH_MAJOR:
+ pointer->fields |= Accumulator::FIELD_ABS_MT_TOUCH_MAJOR;
+ pointer->absMTTouchMajor = rawEvent->value;
+ break;
+ case ABS_MT_TOUCH_MINOR:
+ pointer->fields |= Accumulator::FIELD_ABS_MT_TOUCH_MINOR;
+ pointer->absMTTouchMinor = rawEvent->value;
+ break;
+ case ABS_MT_WIDTH_MAJOR:
+ pointer->fields |= Accumulator::FIELD_ABS_MT_WIDTH_MAJOR;
+ pointer->absMTWidthMajor = rawEvent->value;
+ break;
+ case ABS_MT_WIDTH_MINOR:
+ pointer->fields |= Accumulator::FIELD_ABS_MT_WIDTH_MINOR;
+ pointer->absMTWidthMinor = rawEvent->value;
+ break;
+ case ABS_MT_ORIENTATION:
+ pointer->fields |= Accumulator::FIELD_ABS_MT_ORIENTATION;
+ pointer->absMTOrientation = rawEvent->value;
+ break;
+ case ABS_MT_TRACKING_ID:
+ pointer->fields |= Accumulator::FIELD_ABS_MT_TRACKING_ID;
+ pointer->absMTTrackingId = rawEvent->value;
+ break;
}
- if (deviceClasses & INPUT_DEVICE_CLASS_ALPHAKEY) {
- keyboardConfig = InputConfiguration::KEYBOARD_QWERTY;
+ break;
+ }
+
+ case EV_SYN:
+ switch (rawEvent->scanCode) {
+ case SYN_MT_REPORT: {
+ // MultiTouch Sync: The driver has returned all data for *one* of the pointers.
+ uint32_t pointerIndex = mAccumulator.pointerCount;
+
+ if (mAccumulator.pointers[pointerIndex].fields) {
+ if (pointerIndex == MAX_POINTERS) {
+ LOGW("MultiTouch device driver returned more than maximum of %d pointers.",
+ MAX_POINTERS);
+ } else {
+ pointerIndex += 1;
+ mAccumulator.pointerCount = pointerIndex;
+ }
+ }
+
+ mAccumulator.pointers[pointerIndex].clear();
+ break;
}
- if (deviceClasses & INPUT_DEVICE_CLASS_TRACKBALL) {
- navigationConfig = InputConfiguration::NAVIGATION_TRACKBALL;
- } else if (deviceClasses & INPUT_DEVICE_CLASS_DPAD) {
- navigationConfig = InputConfiguration::NAVIGATION_DPAD;
+
+ case SYN_REPORT:
+ if (mAccumulator.isDirty()) {
+ sync(rawEvent->when);
+ mAccumulator.clear();
+ }
+ break;
}
+ break;
}
+}
- { // acquire exported state lock
- AutoMutex _l(mExportedStateLock);
+void MultiTouchInputMapper::sync(nsecs_t when) {
+ static const uint32_t REQUIRED_FIELDS =
+ Accumulator::FIELD_ABS_MT_POSITION_X
+ | Accumulator::FIELD_ABS_MT_POSITION_Y
+ | Accumulator::FIELD_ABS_MT_TOUCH_MAJOR
+ | Accumulator::FIELD_ABS_MT_WIDTH_MAJOR;
- mExportedInputConfiguration.touchScreen = touchScreenConfig;
- mExportedInputConfiguration.keyboard = keyboardConfig;
- mExportedInputConfiguration.navigation = navigationConfig;
- } // release exported state lock
-}
+ /* Update device state */
+
+ uint32_t inCount = mAccumulator.pointerCount;
+ uint32_t outCount = 0;
+ bool havePointerIds = true;
-void InputReader::getCurrentInputConfiguration(InputConfiguration* outConfiguration) const {
- { // acquire exported state lock
- AutoMutex _l(mExportedStateLock);
+ mCurrentTouch.clear();
- *outConfiguration = mExportedInputConfiguration;
- } // release exported state lock
-}
+ for (uint32_t inIndex = 0; inIndex < inCount; inIndex++) {
+ uint32_t fields = mAccumulator.pointers[inIndex].fields;
-int32_t InputReader::getCurrentScanCodeState(int32_t deviceId, int32_t deviceClasses,
- int32_t scanCode) const {
- { // acquire exported state lock
- AutoMutex _l(mExportedStateLock);
+ if ((fields & REQUIRED_FIELDS) != REQUIRED_FIELDS) {
+#if DEBUG_POINTERS
+ LOGD("Pointers: Missing required multitouch pointer fields: index=%d, fields=%d",
+ inIndex, fields);
+ continue;
+#endif
+ }
- if (mExportedVirtualScanCode == scanCode) {
- return AKEY_STATE_VIRTUAL;
+ if (mAccumulator.pointers[inIndex].absMTTouchMajor <= 0) {
+ // Pointer is not down. Drop it.
+ continue;
}
- } // release exported state lock
- return mEventHub->getScanCodeState(deviceId, deviceClasses, scanCode);
-}
+ mCurrentTouch.pointers[outCount].x = mAccumulator.pointers[inIndex].absMTPositionX;
+ mCurrentTouch.pointers[outCount].y = mAccumulator.pointers[inIndex].absMTPositionY;
-int32_t InputReader::getCurrentKeyCodeState(int32_t deviceId, int32_t deviceClasses,
- int32_t keyCode) const {
- { // acquire exported state lock
- AutoMutex _l(mExportedStateLock);
+ mCurrentTouch.pointers[outCount].touchMajor =
+ mAccumulator.pointers[inIndex].absMTTouchMajor;
+ mCurrentTouch.pointers[outCount].touchMinor =
+ (fields & Accumulator::FIELD_ABS_MT_TOUCH_MINOR) != 0
+ ? mAccumulator.pointers[inIndex].absMTTouchMinor
+ : mAccumulator.pointers[inIndex].absMTTouchMajor;
- if (mExportedVirtualKeyCode == keyCode) {
- return AKEY_STATE_VIRTUAL;
+ mCurrentTouch.pointers[outCount].toolMajor =
+ mAccumulator.pointers[inIndex].absMTWidthMajor;
+ mCurrentTouch.pointers[outCount].toolMinor =
+ (fields & Accumulator::FIELD_ABS_MT_WIDTH_MINOR) != 0
+ ? mAccumulator.pointers[inIndex].absMTWidthMinor
+ : mAccumulator.pointers[inIndex].absMTWidthMajor;
+
+ mCurrentTouch.pointers[outCount].orientation =
+ (fields & Accumulator::FIELD_ABS_MT_ORIENTATION) != 0
+ ? mAccumulator.pointers[inIndex].absMTOrientation : 0;
+
+ // Derive an approximation of pressure and size.
+ // FIXME assignment of pressure may be incorrect, probably better to let
+ // pressure = touch / width. Later on we pass width to MotionEvent as a size, which
+ // isn't quite right either. Should be using touch for that.
+ mCurrentTouch.pointers[outCount].pressure = mAccumulator.pointers[inIndex].absMTTouchMajor;
+ mCurrentTouch.pointers[outCount].size = mAccumulator.pointers[inIndex].absMTWidthMajor;
+
+ if (havePointerIds) {
+ if (fields & Accumulator::
+ FIELD_ABS_MT_TRACKING_ID) {
+ uint32_t id = uint32_t(mAccumulator.pointers[inIndex].absMTTrackingId);
+
+ if (id > MAX_POINTER_ID) {
+#if DEBUG_POINTERS
+ LOGD("Pointers: Ignoring driver provided pointer id %d because "
+ "it is larger than max supported id %d for optimizations",
+ id, MAX_POINTER_ID);
+#endif
+ havePointerIds = false;
+ }
+ else {
+ mCurrentTouch.pointers[outCount].id = id;
+ mCurrentTouch.idToIndex[id] = outCount;
+ mCurrentTouch.idBits.markBit(id);
+ }
+ } else {
+ havePointerIds = false;
+ }
}
- } // release exported state lock
- return mEventHub->getKeyCodeState(deviceId, deviceClasses, keyCode);
-}
+ outCount += 1;
+ }
-int32_t InputReader::getCurrentSwitchState(int32_t deviceId, int32_t deviceClasses,
- int32_t sw) const {
- return mEventHub->getSwitchState(deviceId, deviceClasses, sw);
-}
+ mCurrentTouch.pointerCount = outCount;
-bool InputReader::hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const {
- return mEventHub->hasKeys(numCodes, keyCodes, outFlags);
+ syncTouch(when, havePointerIds);
}
+void MultiTouchInputMapper::configureAxes() {
+ TouchInputMapper::configureAxes();
-// --- InputReaderThread ---
+ // The axes are aliased to take into account the manner in which they are presented
+ // as part of the TouchData during the sync.
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_POSITION_X, & mAxes.x);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_POSITION_Y, & mAxes.y);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_TOUCH_MAJOR, & mAxes.touchMajor);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_TOUCH_MINOR, & mAxes.touchMinor);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_WIDTH_MAJOR, & mAxes.toolMajor);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_WIDTH_MINOR, & mAxes.toolMinor);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_ORIENTATION, & mAxes.orientation);
-InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
- Thread(/*canCallJava*/ true), mReader(reader) {
-}
+ if (! mAxes.touchMinor.valid) {
+ mAxes.touchMinor = mAxes.touchMajor;
+ }
-InputReaderThread::~InputReaderThread() {
-}
+ if (! mAxes.toolMinor.valid) {
+ mAxes.toolMinor = mAxes.toolMajor;
+ }
-bool InputReaderThread::threadLoop() {
- mReader->loopOnce();
- return true;
+ mAxes.pressure = mAxes.touchMajor;
+ mAxes.size = mAxes.toolMajor;
}
+
} // namespace android
diff --git a/native/android/input.cpp b/native/android/input.cpp
index 59bf711..a82282d 100644
--- a/native/android/input.cpp
+++ b/native/android/input.cpp
@@ -21,14 +21,21 @@
#include <ui/Input.h>
#include <ui/InputTransport.h>
#include <utils/PollLoop.h>
+#include <utils/RefBase.h>
+#include <utils/Vector.h>
#include <android_runtime/android_app_NativeActivity.h>
#include <poll.h>
+#include <errno.h>
using android::InputEvent;
using android::KeyEvent;
using android::MotionEvent;
+using android::InputDeviceInfo;
+using android::InputDeviceProxy;
+using android::sp;
+using android::Vector;
int32_t AInputEvent_getType(const AInputEvent* event) {
return static_cast<const InputEvent*>(event)->getType();
@@ -263,3 +270,74 @@ int32_t AInputQueue_preDispatchEvent(AInputQueue* queue, AInputEvent* event) {
void AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, int handled) {
queue->finishEvent(event, handled != 0);
}
+
+
+int32_t AInputDevice_getDeviceIds(int32_t* idBuf, size_t nMax, size_t* nActual) {
+ Vector<int32_t> ids;
+ InputDeviceProxy::getDeviceIds(ids);
+
+ if (nActual) {
+ *nActual = ids.size();
+ }
+
+ if (idBuf && ids.size() < nMax) {
+ memcpy(idBuf, ids.array(), ids.size() * sizeof(int32_t));
+ return 0;
+ }
+
+ return -ENOMEM;
+}
+
+AInputDevice* AInputDevice_acquire(int32_t deviceId) {
+ sp<InputDeviceProxy> proxy(InputDeviceProxy::getDevice(deviceId));
+ if (proxy == NULL) {
+ return NULL;
+ }
+ proxy->incStrong((void*)AInputDevice_acquire);
+ return static_cast<AInputDevice*>(proxy.get());
+}
+
+void AInputDevice_release(AInputDevice* device) {
+ if (device) {
+ InputDeviceProxy* proxy = static_cast<InputDeviceProxy*>(device);
+ proxy->decStrong((void*)AInputDevice_acquire);
+ }
+}
+
+const char* AInputDevice_getName(AInputDevice* device) {
+ InputDeviceProxy* proxy = static_cast<InputDeviceProxy*>(device);
+ return proxy->getInfo()->getName().string();
+}
+
+uint32_t AInputDevice_getSources(AInputDevice* device) {
+ InputDeviceProxy* proxy = static_cast<InputDeviceProxy*>(device);
+ return proxy->getInfo()->getSources();
+}
+
+int32_t AInputDevice_getKeyboardType(AInputDevice* device) {
+ InputDeviceProxy* proxy = static_cast<InputDeviceProxy*>(device);
+ return proxy->getInfo()->getKeyboardType();
+}
+
+int32_t AInputDevice_getMotionRange(AInputDevice* device, int32_t rangeType,
+ float* outMin, float* outMax, float* outFlat, float* outFuzz) {
+ InputDeviceProxy* proxy = static_cast<InputDeviceProxy*>(device);
+ const InputDeviceInfo::MotionRange* range = proxy->getInfo()->getMotionRange(rangeType);
+ if (range) {
+ if (outMin) {
+ *outMin = range->min;
+ }
+ if (outMax) {
+ *outMax = range->max;
+ }
+ if (outFlat) {
+ *outFlat = range->flat;
+ }
+ if (outFuzz) {
+ *outFuzz = range->fuzz;
+ }
+ return 0;
+ } else {
+ return -ENOTSUP;
+ }
+}
diff --git a/native/include/android/input.h b/native/include/android/input.h
index 0b8c7e4..9883ac70 100644
--- a/native/include/android/input.h
+++ b/native/include/android/input.h
@@ -268,7 +268,6 @@ enum {
/*
* Input sources.
*
- * The appropriate interpretation for an input event depends on its source.
* Refer to the documentation on android.view.InputDevice for more details about input sources
* and their correct interpretation.
*/
@@ -297,6 +296,37 @@ enum {
};
/*
+ * Keyboard types.
+ *
+ * Refer to the documentation on android.view.InputDevice for more details.
+ */
+enum {
+ AINPUT_KEYBOARD_TYPE_NONE = 0,
+ AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC = 1,
+ AINPUT_KEYBOARD_TYPE_ALPHABETIC = 2,
+};
+
+/*
+ * Constants used to retrieve information about the range of motion for a particular
+ * coordinate of a motion event.
+ *
+ * Refer to the documentation on android.view.InputDevice for more details about input sources
+ * and their correct interpretation.
+ */
+enum {
+ AINPUT_MOTION_RANGE_X = 0,
+ AINPUT_MOTION_RANGE_Y = 1,
+ AINPUT_MOTION_RANGE_PRESSURE = 2,
+ AINPUT_MOTION_RANGE_SIZE = 3,
+ AINPUT_MOTION_RANGE_TOUCH_MAJOR = 4,
+ AINPUT_MOTION_RANGE_TOUCH_MINOR = 5,
+ AINPUT_MOTION_RANGE_TOOL_MAJOR = 6,
+ AINPUT_MOTION_RANGE_TOOL_MINOR = 7,
+ AINPUT_MOTION_RANGE_ORIENTATION = 8,
+};
+
+
+/*
* Input event accessors.
*
* Note that most functions can only be used on input events that are of a given type.
@@ -475,7 +505,7 @@ float AMotionEvent_getToolMinor(const AInputEvent* motion_event, size_t pointer_
* upwards, is perfectly circular or is of unknown orientation. A positive angle
* indicates that the major axis of contact is oriented to the right. A negative angle
* indicates that the major axis of contact is oriented to the left.
- * The full range is from -PI/4 radians (finger pointing fully left) to PI/4 radians
+ * The full range is from -PI/2 radians (finger pointing fully left) to PI/2 radians
* (finger pointing fully right). */
float AMotionEvent_getOrientation(const AInputEvent* motion_event, size_t pointer_index);
@@ -575,7 +605,7 @@ float AMotionEvent_getHistoricalToolMinor(const AInputEvent* motion_event, size_
* upwards, is perfectly circular or is of unknown orientation. A positive angle
* indicates that the major axis of contact is oriented to the right. A negative angle
* indicates that the major axis of contact is oriented to the left.
- * The full range is from -PI/4 radians (finger pointing fully left) to PI/4 radians
+ * The full range is from -PI/2 radians (finger pointing fully left) to PI/2 radians
* (finger pointing fully right). */
float AMotionEvent_getHistoricalOrientation(const AInputEvent* motion_event, size_t pointer_index,
size_t history_index);
@@ -631,6 +661,64 @@ int32_t AInputQueue_preDispatchEvent(AInputQueue* queue, AInputEvent* event);
*/
void AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, int handled);
+/*
+ * Input devices.
+ *
+ * These functions provide a mechanism for querying the set of available input devices
+ * and their characteristics and capabilities.
+ */
+struct AInputDevice;
+typedef struct AInputDevice AInputDevice;
+
+/*
+ * Populates the supplied array with the ids of all input devices in the system.
+ * Sets nActual to the actual number of devices.
+ * Returns zero if enumeration was successful.
+ * Returns non-zero if the actual number of devices is greater than nMax, in which case the
+ * client should call the method again with a larger id buffer.
+ */
+int32_t AInputDevice_getDeviceIds(int32_t* idBuf, size_t nMax, size_t* nActual);
+
+/*
+ * Acquires a device by id.
+ * Returns NULL if the device was not found.
+ *
+ * Note: The returned object must be freed using AInputDevice_release when no longer needed.
+ */
+AInputDevice* AInputDevice_acquire(int32_t deviceId);
+
+/*
+ * Releases a device previously acquired by AInputDevice_acquire.
+ * If device is NULL, this function does nothing.
+ */
+void AInputDevice_release(AInputDevice* device);
+
+/*
+ * Gets the name of an input device.
+ *
+ * Note: The caller should copy the name into a private buffer since the returned pointer
+ * will become invalid when the device object is released.
+ */
+const char* AInputDevice_getName(AInputDevice* device);
+
+/*
+ * Gets the combination of input sources provided by the input device.
+ */
+uint32_t AInputDevice_getSources(AInputDevice* device);
+
+/*
+ * Gets the keyboard type.
+ */
+int32_t AInputDevice_getKeyboardType(AInputDevice* device);
+
+/* Gets the minimum value, maximum value, flat position and error tolerance for a
+ * particular motion coodinate.
+ * Returns zero if the device supports the specified motion range. */
+int32_t AInputDevice_getMotionRange(AInputDevice* device, int32_t rangeType,
+ float* outMin, float* outMax, float* outFlat, float* outFuzz);
+
+//TODO hasKey, keymap stuff, etc...
+
#ifdef __cplusplus
}
#endif
diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java
index b4f46ab..9a1d017 100644
--- a/services/java/com/android/server/InputManager.java
+++ b/services/java/com/android/server/InputManager.java
@@ -66,13 +66,14 @@ public class InputManager {
private static native void nativeSetDisplaySize(int displayId, int width, int height);
private static native void nativeSetDisplayOrientation(int displayId, int rotation);
- private static native int nativeGetScanCodeState(int deviceId, int deviceClasses,
+ private static native int nativeGetScanCodeState(int deviceId, int sourceMask,
int scanCode);
- private static native int nativeGetKeyCodeState(int deviceId, int deviceClasses,
+ private static native int nativeGetKeyCodeState(int deviceId, int sourceMask,
int keyCode);
- private static native int nativeGetSwitchState(int deviceId, int deviceClasses,
+ private static native int nativeGetSwitchState(int deviceId, int sourceMask,
int sw);
- private static native boolean nativeHasKeys(int[] keyCodes, boolean[] keyExists);
+ private static native boolean nativeHasKeys(int deviceId, int sourceMask,
+ int[] keyCodes, boolean[] keyExists);
private static native void nativeRegisterInputChannel(InputChannel inputChannel);
private static native void nativeUnregisterInputChannel(InputChannel inputChannel);
private static native int nativeInjectKeyEvent(KeyEvent event,
@@ -85,20 +86,28 @@ public class InputManager {
private static native void nativePreemptInputDispatch();
private static native String nativeDump();
- // Device class as defined by EventHub.
- private static final int CLASS_KEYBOARD = 0x00000001;
- private static final int CLASS_ALPHAKEY = 0x00000002;
- private static final int CLASS_TOUCHSCREEN = 0x00000004;
- private static final int CLASS_TRACKBALL = 0x00000008;
- private static final int CLASS_TOUCHSCREEN_MT = 0x00000010;
- private static final int CLASS_DPAD = 0x00000020;
-
// Input event injection constants defined in InputDispatcher.h.
static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0;
static final int INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1;
static final int INPUT_EVENT_INJECTION_FAILED = 2;
static final int INPUT_EVENT_INJECTION_TIMED_OUT = 3;
+ // Key states (may be returned by queries about the current state of a
+ // particular key code, scan code or switch).
+
+ /** The key state is unknown or the requested key itself is not supported. */
+ public static final int KEY_STATE_UNKNOWN = -1;
+
+ /** The key is up. /*/
+ public static final int KEY_STATE_UP = 0;
+
+ /** The key is down. */
+ public static final int KEY_STATE_DOWN = 1;
+
+ /** The key is down but is a virtual key press that is being emulated by the system. */
+ public static final int KEY_STATE_VIRTUAL = 2;
+
+
public InputManager(Context context, WindowManagerService windowManagerService) {
this.mContext = context;
this.mWindowManagerService = windowManagerService;
@@ -150,55 +159,67 @@ public class InputManager {
config.navigation = mNavigationConfig;
}
- public int getScancodeState(int code) {
- return nativeGetScanCodeState(0, -1, code);
- }
-
- public int getScancodeState(int deviceId, int code) {
- return nativeGetScanCodeState(deviceId, -1, code);
- }
-
- public int getTrackballScancodeState(int code) {
- return nativeGetScanCodeState(-1, CLASS_TRACKBALL, code);
- }
-
- public int getDPadScancodeState(int code) {
- return nativeGetScanCodeState(-1, CLASS_DPAD, code);
- }
-
- public int getKeycodeState(int code) {
- return nativeGetKeyCodeState(0, -1, code);
- }
-
- public int getKeycodeState(int deviceId, int code) {
- return nativeGetKeyCodeState(deviceId, -1, code);
- }
-
- public int getTrackballKeycodeState(int code) {
- return nativeGetKeyCodeState(-1, CLASS_TRACKBALL, code);
+ /**
+ * Gets the current state of a key or button by key code.
+ * @param deviceId The input device id, or -1 to consult all devices.
+ * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
+ * consider all input sources. An input device is consulted if at least one of its
+ * non-class input source bits matches the specified source mask.
+ * @param keyCode The key code to check.
+ * @return The key state.
+ */
+ public int getKeyCodeState(int deviceId, int sourceMask, int keyCode) {
+ return nativeGetKeyCodeState(deviceId, sourceMask, keyCode);
}
- public int getDPadKeycodeState(int code) {
- return nativeGetKeyCodeState(-1, CLASS_DPAD, code);
- }
-
- public int getSwitchState(int sw) {
- return nativeGetSwitchState(-1, -1, sw);
+ /**
+ * Gets the current state of a key or button by scan code.
+ * @param deviceId The input device id, or -1 to consult all devices.
+ * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
+ * consider all input sources. An input device is consulted if at least one of its
+ * non-class input source bits matches the specified source mask.
+ * @param scanCode The scan code to check.
+ * @return The key state.
+ */
+ public int getScanCodeState(int deviceId, int sourceMask, int scanCode) {
+ return nativeGetScanCodeState(deviceId, sourceMask, scanCode);
}
- public int getSwitchState(int deviceId, int sw) {
- return nativeGetSwitchState(deviceId, -1, sw);
+ /**
+ * Gets the current state of a switch by switch code.
+ * @param deviceId The input device id, or -1 to consult all devices.
+ * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
+ * consider all input sources. An input device is consulted if at least one of its
+ * non-class input source bits matches the specified source mask.
+ * @param switchCode The switch code to check.
+ * @return The switch state.
+ */
+ public int getSwitchState(int deviceId, int sourceMask, int switchCode) {
+ return nativeGetSwitchState(deviceId, sourceMask, switchCode);
}
- public boolean hasKeys(int[] keyCodes, boolean[] keyExists) {
+ /**
+ * Determines whether the specified key codes are supported by a particular device.
+ * @param deviceId The input device id, or -1 to consult all devices.
+ * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
+ * consider all input sources. An input device is consulted if at least one of its
+ * non-class input source bits matches the specified source mask.
+ * @param keyCodes The array of key codes to check.
+ * @param keyExists An array at least as large as keyCodes whose entries will be set
+ * to true or false based on the presence or absence of support for the corresponding
+ * key codes.
+ * @return True if the lookup was successful, false otherwise.
+ */
+ public boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists) {
if (keyCodes == null) {
throw new IllegalArgumentException("keyCodes must not be null.");
}
- if (keyExists == null) {
- throw new IllegalArgumentException("keyExists must not be null.");
+ if (keyExists == null || keyExists.length < keyCodes.length) {
+ throw new IllegalArgumentException("keyExists must not be null and must be at "
+ + "least as large as keyCodes.");
}
- return nativeHasKeys(keyCodes, keyExists);
+ return nativeHasKeys(deviceId, sourceMask, keyCodes, keyExists);
}
public void registerInputChannel(InputChannel inputChannel) {
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 2e28afb..eb0f343 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -4307,7 +4307,7 @@ public class WindowManagerService extends IWindowManager.Stub
"getSwitchState()")) {
throw new SecurityException("Requires READ_INPUT_STATE permission");
}
- return mInputManager.getSwitchState(sw);
+ return mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, sw);
}
public int getSwitchStateForDevice(int devid, int sw) {
@@ -4315,7 +4315,7 @@ public class WindowManagerService extends IWindowManager.Stub
"getSwitchStateForDevice()")) {
throw new SecurityException("Requires READ_INPUT_STATE permission");
}
- return mInputManager.getSwitchState(devid, sw);
+ return mInputManager.getSwitchState(devid, InputDevice.SOURCE_ANY, sw);
}
public int getScancodeState(int sw) {
@@ -4323,7 +4323,7 @@ public class WindowManagerService extends IWindowManager.Stub
"getScancodeState()")) {
throw new SecurityException("Requires READ_INPUT_STATE permission");
}
- return mInputManager.getScancodeState(sw);
+ return mInputManager.getScanCodeState(-1, InputDevice.SOURCE_ANY, sw);
}
public int getScancodeStateForDevice(int devid, int sw) {
@@ -4331,7 +4331,7 @@ public class WindowManagerService extends IWindowManager.Stub
"getScancodeStateForDevice()")) {
throw new SecurityException("Requires READ_INPUT_STATE permission");
}
- return mInputManager.getScancodeState(devid, sw);
+ return mInputManager.getScanCodeState(devid, InputDevice.SOURCE_ANY, sw);
}
public int getTrackballScancodeState(int sw) {
@@ -4339,7 +4339,7 @@ public class WindowManagerService extends IWindowManager.Stub
"getTrackballScancodeState()")) {
throw new SecurityException("Requires READ_INPUT_STATE permission");
}
- return mInputManager.getTrackballScancodeState(sw);
+ return mInputManager.getScanCodeState(-1, InputDevice.SOURCE_TRACKBALL, sw);
}
public int getDPadScancodeState(int sw) {
@@ -4347,7 +4347,7 @@ public class WindowManagerService extends IWindowManager.Stub
"getDPadScancodeState()")) {
throw new SecurityException("Requires READ_INPUT_STATE permission");
}
- return mInputManager.getDPadScancodeState(sw);
+ return mInputManager.getScanCodeState(-1, InputDevice.SOURCE_DPAD, sw);
}
public int getKeycodeState(int sw) {
@@ -4355,7 +4355,7 @@ public class WindowManagerService extends IWindowManager.Stub
"getKeycodeState()")) {
throw new SecurityException("Requires READ_INPUT_STATE permission");
}
- return mInputManager.getKeycodeState(sw);
+ return mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY, sw);
}
public int getKeycodeStateForDevice(int devid, int sw) {
@@ -4363,7 +4363,7 @@ public class WindowManagerService extends IWindowManager.Stub
"getKeycodeStateForDevice()")) {
throw new SecurityException("Requires READ_INPUT_STATE permission");
}
- return mInputManager.getKeycodeState(devid, sw);
+ return mInputManager.getKeyCodeState(devid, InputDevice.SOURCE_ANY, sw);
}
public int getTrackballKeycodeState(int sw) {
@@ -4371,7 +4371,7 @@ public class WindowManagerService extends IWindowManager.Stub
"getTrackballKeycodeState()")) {
throw new SecurityException("Requires READ_INPUT_STATE permission");
}
- return mInputManager.getTrackballKeycodeState(sw);
+ return mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_TRACKBALL, sw);
}
public int getDPadKeycodeState(int sw) {
@@ -4379,11 +4379,11 @@ public class WindowManagerService extends IWindowManager.Stub
"getDPadKeycodeState()")) {
throw new SecurityException("Requires READ_INPUT_STATE permission");
}
- return mInputManager.getDPadKeycodeState(sw);
+ return mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_DPAD, sw);
}
public boolean hasKeys(int[] keycodes, boolean[] keyExists) {
- return mInputManager.hasKeys(keycodes, keyExists);
+ return mInputManager.hasKeys(-1, InputDevice.SOURCE_ANY, keycodes, keyExists);
}
public void enableScreenAfterBoot() {
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index 0992b33..a332376 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -219,11 +219,10 @@ public:
int32_t* width, int32_t* height, int32_t* orientation);
virtual void virtualKeyDownFeedback();
virtual int32_t interceptKey(nsecs_t when, int32_t deviceId,
- bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags);
- virtual int32_t interceptTrackball(nsecs_t when, bool buttonChanged, bool buttonDown,
- bool rolled);
- virtual int32_t interceptTouch(nsecs_t when);
- virtual int32_t interceptSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue);
+ bool down, int32_t keyCode, int32_t scanCode, uint32_t& policyFlags);
+ virtual int32_t interceptSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue,
+ uint32_t& policyFlags);
+ virtual int32_t interceptGeneric(nsecs_t when, uint32_t& policyFlags);
virtual bool filterTouchEvents();
virtual bool filterJumpyTouchEvents();
virtual void getVirtualKeyDefinitions(const String8& deviceName,
@@ -343,6 +342,7 @@ private:
InputApplication* mFocusedApplication;
InputApplication mFocusedApplicationStorage; // preallocated storage for mFocusedApplication
+ void dumpDeviceInfo(String8& dump);
void dumpDispatchStateLd(String8& dump);
void logDispatchStateLd();
@@ -409,12 +409,16 @@ NativeInputManager::~NativeInputManager() {
String8 NativeInputManager::dump() {
String8 dump;
- dump.append("Native Input Dispatcher State:\n");
-
{ // acquire lock
AutoMutex _l(mDisplayLock);
+ dump.append("Native Input Dispatcher State:\n");
dumpDispatchStateLd(dump);
+ dump.append("\n");
} // release lock
+
+ dump.append("Input Devices:\n");
+ dumpDeviceInfo(dump);
+
return dump;
}
@@ -566,9 +570,15 @@ bool NativeInputManager::getDisplayInfo(int32_t displayId,
AutoMutex _l(mDisplayLock);
if (mDisplayWidth > 0) {
- *width = mDisplayWidth;
- *height = mDisplayHeight;
- *orientation = mDisplayOrientation;
+ if (width) {
+ *width = mDisplayWidth;
+ }
+ if (height) {
+ *height = mDisplayHeight;
+ }
+ if (orientation) {
+ *orientation = mDisplayOrientation;
+ }
result = true;
}
}
@@ -595,7 +605,7 @@ void NativeInputManager::virtualKeyDownFeedback() {
}
int32_t NativeInputManager::interceptKey(nsecs_t when,
- int32_t deviceId, bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags) {
+ int32_t deviceId, bool down, int32_t keyCode, int32_t scanCode, uint32_t& policyFlags) {
#if DEBUG_INPUT_READER_POLICY
LOGD("interceptKey - when=%lld, deviceId=%d, down=%d, keyCode=%d, scanCode=%d, "
"policyFlags=0x%x",
@@ -626,12 +636,12 @@ int32_t NativeInputManager::interceptKey(nsecs_t when,
int32_t actions = InputReaderPolicyInterface::ACTION_NONE;
if (! isScreenOn) {
// Key presses and releases wake the device.
- actions |= InputReaderPolicyInterface::ACTION_WOKE_HERE;
+ policyFlags |= POLICY_FLAG_WOKE_HERE;
}
if (! isScreenBright) {
// Key presses and releases brighten the screen if dimmed.
- actions |= InputReaderPolicyInterface::ACTION_BRIGHT_HERE;
+ policyFlags |= POLICY_FLAG_BRIGHT_HERE;
}
if (wmActions & WM_ACTION_GO_TO_SLEEP) {
@@ -658,42 +668,20 @@ int32_t NativeInputManager::interceptKey(nsecs_t when,
return actions;
}
-int32_t NativeInputManager::interceptTouch(nsecs_t when) {
+int32_t NativeInputManager::interceptGeneric(nsecs_t when, uint32_t& policyFlags) {
#if DEBUG_INPUT_READER_POLICY
- LOGD("interceptTouch - when=%lld", when);
+ LOGD("interceptGeneric - when=%lld, policyFlags=0x%x", when, policyFlags);
#endif
int32_t actions = InputReaderPolicyInterface::ACTION_NONE;
if (isScreenOn()) {
- // Only dispatch touch events when the device is awake.
+ // Only dispatch events when the device is awake.
// Do not wake the device.
actions |= InputReaderPolicyInterface::ACTION_DISPATCH;
if (! isScreenBright()) {
// Brighten the screen if dimmed.
- actions |= InputReaderPolicyInterface::ACTION_BRIGHT_HERE;
- }
- }
-
- return actions;
-}
-
-int32_t NativeInputManager::interceptTrackball(nsecs_t when,
- bool buttonChanged, bool buttonDown, bool rolled) {
-#if DEBUG_INPUT_READER_POLICY
- LOGD("interceptTrackball - when=%lld, buttonChanged=%d, buttonDown=%d, rolled=%d",
- when, buttonChanged, buttonDown, rolled);
-#endif
-
- int32_t actions = InputReaderPolicyInterface::ACTION_NONE;
- if (isScreenOn()) {
- // Only dispatch trackball events when the device is awake.
- // Do not wake the device.
- actions |= InputReaderPolicyInterface::ACTION_DISPATCH;
-
- if (! isScreenBright()) {
- // Brighten the screen if dimmed.
- actions |= InputReaderPolicyInterface::ACTION_BRIGHT_HERE;
+ policyFlags |= POLICY_FLAG_BRIGHT_HERE;
}
}
@@ -701,10 +689,10 @@ int32_t NativeInputManager::interceptTrackball(nsecs_t when,
}
int32_t NativeInputManager::interceptSwitch(nsecs_t when, int32_t switchCode,
- int32_t switchValue) {
+ int32_t switchValue, uint32_t& policyFlags) {
#if DEBUG_INPUT_READER_POLICY
- LOGD("interceptSwitch - when=%lld, switchCode=%d, switchValue=%d",
- when, switchCode, switchValue);
+ LOGD("interceptSwitch - when=%lld, switchCode=%d, switchValue=%d, policyFlags=0x%x",
+ when, switchCode, switchValue, policyFlags);
#endif
JNIEnv* env = jniEnv();
@@ -1718,6 +1706,56 @@ void NativeInputManager::pokeUserActivity(nsecs_t eventTime, int32_t eventType)
android_server_PowerManagerService_userActivity(eventTime, eventType);
}
+static void dumpMotionRange(String8& dump,
+ const char* name, const InputDeviceInfo::MotionRange* range) {
+ if (range) {
+ dump.appendFormat(" %s = { min: %0.3f, max: %0.3f, flat: %0.3f, fuzz: %0.3f }\n",
+ name, range->min, range->max, range->flat, range->fuzz);
+ }
+}
+
+#define DUMP_MOTION_RANGE(range) \
+ dumpMotionRange(dump, #range, deviceInfo.getMotionRange(AINPUT_MOTION_RANGE_##range));
+
+void NativeInputManager::dumpDeviceInfo(String8& dump) {
+ Vector<int32_t> deviceIds;
+ mInputManager->getInputDeviceIds(deviceIds);
+
+ InputDeviceInfo deviceInfo;
+ for (size_t i = 0; i < deviceIds.size(); i++) {
+ int32_t deviceId = deviceIds[i];
+
+ status_t result = mInputManager->getInputDeviceInfo(deviceId, & deviceInfo);
+ if (result == NAME_NOT_FOUND) {
+ continue;
+ } else if (result != OK) {
+ dump.appendFormat(" ** Unexpected error %d getting information about input devices.\n",
+ result);
+ continue;
+ }
+
+ dump.appendFormat(" Device %d: '%s'\n",
+ deviceInfo.getId(), deviceInfo.getName().string());
+ dump.appendFormat(" sources = 0x%08x\n",
+ deviceInfo.getSources());
+ dump.appendFormat(" keyboardType = %d\n",
+ deviceInfo.getKeyboardType());
+
+ dump.append(" motion ranges:\n");
+ DUMP_MOTION_RANGE(X);
+ DUMP_MOTION_RANGE(Y);
+ DUMP_MOTION_RANGE(PRESSURE);
+ DUMP_MOTION_RANGE(SIZE);
+ DUMP_MOTION_RANGE(TOUCH_MAJOR);
+ DUMP_MOTION_RANGE(TOUCH_MINOR);
+ DUMP_MOTION_RANGE(TOOL_MAJOR);
+ DUMP_MOTION_RANGE(TOOL_MINOR);
+ DUMP_MOTION_RANGE(ORIENTATION);
+ }
+}
+
+#undef DUMP_MOTION_RANGE
+
void NativeInputManager::logDispatchStateLd() {
String8 dump;
dumpDispatchStateLd(dump);
@@ -1899,36 +1937,37 @@ static void android_server_InputManager_nativeSetDisplayOrientation(JNIEnv* env,
}
static jint android_server_InputManager_nativeGetScanCodeState(JNIEnv* env, jclass clazz,
- jint deviceId, jint deviceClasses, jint scanCode) {
+ jint deviceId, jint sourceMask, jint scanCode) {
if (checkInputManagerUnitialized(env)) {
return AKEY_STATE_UNKNOWN;
}
return gNativeInputManager->getInputManager()->getScanCodeState(
- deviceId, deviceClasses, scanCode);
+ deviceId, uint32_t(sourceMask), scanCode);
}
static jint android_server_InputManager_nativeGetKeyCodeState(JNIEnv* env, jclass clazz,
- jint deviceId, jint deviceClasses, jint keyCode) {
+ jint deviceId, jint sourceMask, jint keyCode) {
if (checkInputManagerUnitialized(env)) {
return AKEY_STATE_UNKNOWN;
}
return gNativeInputManager->getInputManager()->getKeyCodeState(
- deviceId, deviceClasses, keyCode);
+ deviceId, uint32_t(sourceMask), keyCode);
}
static jint android_server_InputManager_nativeGetSwitchState(JNIEnv* env, jclass clazz,
- jint deviceId, jint deviceClasses, jint sw) {
+ jint deviceId, jint sourceMask, jint sw) {
if (checkInputManagerUnitialized(env)) {
return AKEY_STATE_UNKNOWN;
}
- return gNativeInputManager->getInputManager()->getSwitchState(deviceId, deviceClasses, sw);
+ return gNativeInputManager->getInputManager()->getSwitchState(
+ deviceId, uint32_t(sourceMask), sw);
}
static jboolean android_server_InputManager_nativeHasKeys(JNIEnv* env, jclass clazz,
- jintArray keyCodes, jbooleanArray outFlags) {
+ jint deviceId, jint sourceMask, jintArray keyCodes, jbooleanArray outFlags) {
if (checkInputManagerUnitialized(env)) {
return JNI_FALSE;
}
@@ -1937,8 +1976,9 @@ static jboolean android_server_InputManager_nativeHasKeys(JNIEnv* env, jclass cl
uint8_t* flags = env->GetBooleanArrayElements(outFlags, NULL);
jsize numCodes = env->GetArrayLength(keyCodes);
jboolean result;
- if (numCodes == env->GetArrayLength(outFlags)) {
- result = gNativeInputManager->getInputManager()->hasKeys(numCodes, codes, flags);
+ if (numCodes == env->GetArrayLength(keyCodes)) {
+ result = gNativeInputManager->getInputManager()->hasKeys(
+ deviceId, uint32_t(sourceMask), numCodes, codes, flags);
} else {
result = JNI_FALSE;
}
@@ -2102,7 +2142,7 @@ static JNINativeMethod gInputManagerMethods[] = {
(void*) android_server_InputManager_nativeGetKeyCodeState },
{ "nativeGetSwitchState", "(III)I",
(void*) android_server_InputManager_nativeGetSwitchState },
- { "nativeHasKeys", "([I[Z)Z",
+ { "nativeHasKeys", "(II[I[Z)Z",
(void*) android_server_InputManager_nativeHasKeys },
{ "nativeRegisterInputChannel", "(Landroid/view/InputChannel;)V",
(void*) android_server_InputManager_nativeRegisterInputChannel },