am 6d0fec2d: Refactor input reader to support new device types more easily.
Merge commit '6d0fec2de3601821f4f44eeb7d7deedebb2b7117' into gingerbread-plus-aosp * commit '6d0fec2de3601821f4f44eeb7d7deedebb2b7117': Refactor input reader to support new device types more easily.
This commit is contained in:
commit
7be99a70f9
@ -59,6 +59,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.
|
||||
*/
|
||||
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
/* Intercepts a trackball event.
|
||||
* The policy can use this method as an opportunity to perform power management functions
|
||||
* and early event preprocessing.
|
||||
*
|
||||
* Returns a policy action constant such as ACTION_DISPATCH.
|
||||
*/
|
||||
virtual int32_t interceptTrackball(nsecs_t when, bool buttonChanged, bool buttonDown,
|
||||
bool rolled) = 0;
|
||||
|
||||
/* Intercepts a touch event.
|
||||
* The policy can use this method as an opportunity to perform power management functions
|
||||
* and early event preprocessing.
|
||||
*
|
||||
* Returns a policy action constant such as ACTION_DISPATCH.
|
||||
*/
|
||||
virtual int32_t interceptTouch(nsecs_t when) = 0;
|
||||
bool down, int32_t keyCode, int32_t scanCode, uint32_t& policyFlags) = 0;
|
||||
|
||||
/* 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.
|
||||
*
|
||||
* 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 interceptSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue,
|
||||
uint32_t& policyFlags) = 0;
|
||||
|
||||
/* 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 such as updating policy flags.
|
||||
*
|
||||
* Returns a policy action constant such as ACTION_DISPATCH.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* This method may be called on any thread (usually by the input manager).
|
||||
*/
|
||||
virtual bool getCurrentVirtualKey(int32_t* outKeyCode, int32_t* outScanCode) const = 0;
|
||||
|
||||
/* Gets the current input device configuration.
|
||||
*
|
||||
* This method may be called on any thread (usually by the input manager).
|
||||
*/
|
||||
virtual void getCurrentInputConfiguration(InputConfiguration* outConfiguration) const = 0;
|
||||
virtual void getInputConfiguration(InputConfiguration* outConfiguration) = 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.
|
||||
/* 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 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;
|
||||
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;
|
||||
|
||||
/* 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);
|
||||
|
||||
// virtual key management
|
||||
void updateExportedVirtualKeyState();
|
||||
void handleConfigurationChanged(nsecs_t when);
|
||||
|
||||
// input configuration management
|
||||
void updateExportedInputConfiguration();
|
||||
// state management for all devices
|
||||
Mutex mStateLock;
|
||||
|
||||
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
|
||||
|
@ -12,7 +12,6 @@ LOCAL_SRC_FILES:= \
|
||||
KeyLayoutMap.cpp \
|
||||
KeyCharacterMap.cpp \
|
||||
Input.cpp \
|
||||
InputDevice.cpp \
|
||||
InputDispatcher.cpp \
|
||||
InputManager.cpp \
|
||||
InputReader.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) {
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user