Add initial gamepad support.
Change-Id: I0439648f6eb5405f200e4223c915eb3a418b32b9
This commit is contained in:
165
api/current.xml
165
api/current.xml
@ -174296,6 +174296,171 @@
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="KEYCODE_BUTTON_A"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="96"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="KEYCODE_BUTTON_B"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="97"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="KEYCODE_BUTTON_C"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="98"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="KEYCODE_BUTTON_L1"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="102"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="KEYCODE_BUTTON_L2"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="104"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="KEYCODE_BUTTON_MODE"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="110"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="KEYCODE_BUTTON_R1"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="103"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="KEYCODE_BUTTON_R2"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="105"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="KEYCODE_BUTTON_SELECT"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="109"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="KEYCODE_BUTTON_START"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="108"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="KEYCODE_BUTTON_THUMBL"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="106"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="KEYCODE_BUTTON_THUMBR"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="107"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="KEYCODE_BUTTON_X"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="99"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="KEYCODE_BUTTON_Y"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="100"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="KEYCODE_BUTTON_Z"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="101"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="KEYCODE_C"
|
||||
type="int"
|
||||
transient="false"
|
||||
|
@ -124,11 +124,27 @@ public class KeyEvent implements Parcelable {
|
||||
public static final int KEYCODE_PAGE_DOWN = 93;
|
||||
public static final int KEYCODE_PICTSYMBOLS = 94; // switch symbol-sets (Emoji,Kao-moji)
|
||||
public static final int KEYCODE_SWITCH_CHARSET = 95; // switch char-sets (Kanji,Katakana)
|
||||
public static final int KEYCODE_BUTTON_A = 96;
|
||||
public static final int KEYCODE_BUTTON_B = 97;
|
||||
public static final int KEYCODE_BUTTON_C = 98;
|
||||
public static final int KEYCODE_BUTTON_X = 99;
|
||||
public static final int KEYCODE_BUTTON_Y = 100;
|
||||
public static final int KEYCODE_BUTTON_Z = 101;
|
||||
public static final int KEYCODE_BUTTON_L1 = 102;
|
||||
public static final int KEYCODE_BUTTON_R1 = 103;
|
||||
public static final int KEYCODE_BUTTON_L2 = 104;
|
||||
public static final int KEYCODE_BUTTON_R2 = 105;
|
||||
public static final int KEYCODE_BUTTON_THUMBL = 106;
|
||||
public static final int KEYCODE_BUTTON_THUMBR = 107;
|
||||
public static final int KEYCODE_BUTTON_START = 108;
|
||||
public static final int KEYCODE_BUTTON_SELECT = 109;
|
||||
public static final int KEYCODE_BUTTON_MODE = 110;
|
||||
|
||||
// NOTE: If you add a new keycode here you must also add it to:
|
||||
// isSystem()
|
||||
// native/include/android/keycodes.h
|
||||
// frameworks/base/include/ui/KeycodeLabels.h
|
||||
// external/webkit/WebKit/android/plugins/ANPKeyCodes.h
|
||||
// tools/puppet_master/PuppetMaster/nav_keys.py
|
||||
// frameworks/base/core/res/res/values/attrs.xml
|
||||
// commands/monkey/Monkey.java
|
||||
|
@ -920,6 +920,21 @@
|
||||
<enum name="KEYCODE_PAGE_DOWN" value="93" />
|
||||
<enum name="KEYCODE_PICTSYMBOLS" value="94" />
|
||||
<enum name="KEYCODE_SWITCH_CHARSET" value="95" />
|
||||
<enum name="KEYCODE_BUTTON_A" value="96" />
|
||||
<enum name="KEYCODE_BUTTON_B" value="97" />
|
||||
<enum name="KEYCODE_BUTTON_C" value="98" />
|
||||
<enum name="KEYCODE_BUTTON_X" value="99" />
|
||||
<enum name="KEYCODE_BUTTON_Y" value="100" />
|
||||
<enum name="KEYCODE_BUTTON_Z" value="101" />
|
||||
<enum name="KEYCODE_BUTTON_L1" value="102" />
|
||||
<enum name="KEYCODE_BUTTON_R1" value="103" />
|
||||
<enum name="KEYCODE_BUTTON_L2" value="104" />
|
||||
<enum name="KEYCODE_BUTTON_R2" value="105" />
|
||||
<enum name="KEYCODE_BUTTON_THUMBL" value="106" />
|
||||
<enum name="KEYCODE_BUTTON_THUMBR" value="107" />
|
||||
<enum name="KEYCODE_BUTTON_START" value="108" />
|
||||
<enum name="KEYCODE_BUTTON_SELECT" value="109" />
|
||||
<enum name="KEYCODE_BUTTON_MODE" value="110" />
|
||||
</attr>
|
||||
|
||||
<!-- ***************************************************************** -->
|
||||
|
338
include/ui/InputDevice.h
Normal file
338
include/ui/InputDevice.h
Normal file
@ -0,0 +1,338 @@
|
||||
/*
|
||||
* 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_WIDTH_MAJOR = 8,
|
||||
FIELD_ABS_MT_TRACKING_ID = 16
|
||||
};
|
||||
|
||||
uint32_t pointerCount;
|
||||
struct Pointer {
|
||||
uint32_t fields;
|
||||
|
||||
int32_t absMTPositionX;
|
||||
int32_t absMTPositionY;
|
||||
int32_t absMTTouchMajor;
|
||||
int32_t absMTWidthMajor;
|
||||
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;
|
||||
};
|
||||
|
||||
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;
|
||||
} 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;
|
||||
} 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
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include <ui/EventHub.h>
|
||||
#include <ui/Input.h>
|
||||
#include <ui/InputDevice.h>
|
||||
#include <ui/InputDispatcher.h>
|
||||
#include <utils/KeyedVector.h>
|
||||
#include <utils/threads.h>
|
||||
@ -30,311 +31,8 @@
|
||||
#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 32
|
||||
|
||||
/* 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_WIDTH_MAJOR = 8,
|
||||
FIELD_ABS_MT_TRACKING_ID = 16
|
||||
};
|
||||
|
||||
uint32_t pointerCount;
|
||||
struct Pointer {
|
||||
uint32_t fields;
|
||||
|
||||
int32_t absMTPositionX;
|
||||
int32_t absMTPositionY;
|
||||
int32_t absMTTouchMajor;
|
||||
int32_t absMTWidthMajor;
|
||||
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;
|
||||
};
|
||||
|
||||
struct TouchData {
|
||||
uint32_t pointerCount;
|
||||
PointerData pointers[MAX_POINTERS];
|
||||
BitSet32 idBits;
|
||||
uint32_t idToIndex[MAX_POINTER_ID];
|
||||
|
||||
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;
|
||||
} 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;
|
||||
} 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); }
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Input reader policy interface.
|
||||
*
|
||||
|
@ -17,6 +17,8 @@
|
||||
#ifndef _UI_KEYCODE_LABELS_H
|
||||
#define _UI_KEYCODE_LABELS_H
|
||||
|
||||
#include <android/keycodes.h>
|
||||
|
||||
struct KeycodeLabel {
|
||||
const char *literal;
|
||||
int value;
|
||||
@ -118,117 +120,28 @@ static const KeycodeLabel KEYCODES[] = {
|
||||
{ "PAGE_DOWN", 93 },
|
||||
{ "PICTSYMBOLS", 94 },
|
||||
{ "SWITCH_CHARSET", 95 },
|
||||
{ "BUTTON_A", 96 },
|
||||
{ "BUTTON_B", 97 },
|
||||
{ "BUTTON_C", 98 },
|
||||
{ "BUTTON_X", 99 },
|
||||
{ "BUTTON_Y", 100 },
|
||||
{ "BUTTON_Z", 101 },
|
||||
{ "BUTTON_L1", 102 },
|
||||
{ "BUTTON_R1", 103 },
|
||||
{ "BUTTON_L2", 104 },
|
||||
{ "BUTTON_R2", 105 },
|
||||
{ "BUTTON_THUMBL", 106 },
|
||||
{ "BUTTON_THUMBR", 107 },
|
||||
{ "BUTTON_START", 108 },
|
||||
{ "BUTTON_SELECT", 109 },
|
||||
{ "BUTTON_MODE", 110 },
|
||||
|
||||
// NOTE: If you add a new keycode here you must also add it to:
|
||||
// (enum KeyCode, in this file)
|
||||
// frameworks/base/core/java/android/view/KeyEvent.java
|
||||
// tools/puppet_master/PuppetMaster.nav_keys.py
|
||||
// frameworks/base/core/res/res/values/attrs.xml
|
||||
// NOTE: If you add a new keycode here you must also add it to several other files.
|
||||
// Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
|
||||
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
// These constants need to match the above mappings.
|
||||
typedef enum KeyCode {
|
||||
kKeyCodeUnknown = 0,
|
||||
|
||||
kKeyCodeSoftLeft = 1,
|
||||
kKeyCodeSoftRight = 2,
|
||||
kKeyCodeHome = 3,
|
||||
kKeyCodeBack = 4,
|
||||
kKeyCodeCall = 5,
|
||||
kKeyCodeEndCall = 6,
|
||||
kKeyCode0 = 7,
|
||||
kKeyCode1 = 8,
|
||||
kKeyCode2 = 9,
|
||||
kKeyCode3 = 10,
|
||||
kKeyCode4 = 11,
|
||||
kKeyCode5 = 12,
|
||||
kKeyCode6 = 13,
|
||||
kKeyCode7 = 14,
|
||||
kKeyCode8 = 15,
|
||||
kKeyCode9 = 16,
|
||||
kKeyCodeStar = 17,
|
||||
kKeyCodePound = 18,
|
||||
kKeyCodeDpadUp = 19,
|
||||
kKeyCodeDpadDown = 20,
|
||||
kKeyCodeDpadLeft = 21,
|
||||
kKeyCodeDpadRight = 22,
|
||||
kKeyCodeDpadCenter = 23,
|
||||
kKeyCodeVolumeUp = 24,
|
||||
kKeyCodeVolumeDown = 25,
|
||||
kKeyCodePower = 26,
|
||||
kKeyCodeCamera = 27,
|
||||
kKeyCodeClear = 28,
|
||||
kKeyCodeA = 29,
|
||||
kKeyCodeB = 30,
|
||||
kKeyCodeC = 31,
|
||||
kKeyCodeD = 32,
|
||||
kKeyCodeE = 33,
|
||||
kKeyCodeF = 34,
|
||||
kKeyCodeG = 35,
|
||||
kKeyCodeH = 36,
|
||||
kKeyCodeI = 37,
|
||||
kKeyCodeJ = 38,
|
||||
kKeyCodeK = 39,
|
||||
kKeyCodeL = 40,
|
||||
kKeyCodeM = 41,
|
||||
kKeyCodeN = 42,
|
||||
kKeyCodeO = 43,
|
||||
kKeyCodeP = 44,
|
||||
kKeyCodeQ = 45,
|
||||
kKeyCodeR = 46,
|
||||
kKeyCodeS = 47,
|
||||
kKeyCodeT = 48,
|
||||
kKeyCodeU = 49,
|
||||
kKeyCodeV = 50,
|
||||
kKeyCodeW = 51,
|
||||
kKeyCodeX = 52,
|
||||
kKeyCodeY = 53,
|
||||
kKeyCodeZ = 54,
|
||||
kKeyCodeComma = 55,
|
||||
kKeyCodePeriod = 56,
|
||||
kKeyCodeAltLeft = 57,
|
||||
kKeyCodeAltRight = 58,
|
||||
kKeyCodeShiftLeft = 59,
|
||||
kKeyCodeShiftRight = 60,
|
||||
kKeyCodeTab = 61,
|
||||
kKeyCodeSpace = 62,
|
||||
kKeyCodeSym = 63,
|
||||
kKeyCodeExplorer = 64,
|
||||
kKeyCodeEnvelope = 65,
|
||||
kKeyCodeNewline = 66,
|
||||
kKeyCodeDel = 67,
|
||||
kKeyCodeGrave = 68,
|
||||
kKeyCodeMinus = 69,
|
||||
kKeyCodeEquals = 70,
|
||||
kKeyCodeLeftBracket = 71,
|
||||
kKeyCodeRightBracket = 72,
|
||||
kKeyCodeBackslash = 73,
|
||||
kKeyCodeSemicolon = 74,
|
||||
kKeyCodeApostrophe = 75,
|
||||
kKeyCodeSlash = 76,
|
||||
kKeyCodeAt = 77,
|
||||
kKeyCodeNum = 78,
|
||||
kKeyCodeHeadSetHook = 79,
|
||||
kKeyCodeFocus = 80,
|
||||
kKeyCodePlus = 81,
|
||||
kKeyCodeMenu = 82,
|
||||
kKeyCodeNotification = 83,
|
||||
kKeyCodeSearch = 84,
|
||||
kKeyCodePlayPause = 85,
|
||||
kKeyCodeStop = 86,
|
||||
kKeyCodeNextSong = 87,
|
||||
kKeyCodePreviousSong = 88,
|
||||
kKeyCodeRewind = 89,
|
||||
kKeyCodeForward = 90,
|
||||
kKeyCodeMute = 91,
|
||||
kKeyCodePageUp = 92,
|
||||
kKeyCodePageDown = 93,
|
||||
kKeyCodePictSymbols = 94,
|
||||
kKeyCodeSwitchCharset = 95
|
||||
} KeyCode;
|
||||
|
||||
static const KeycodeLabel FLAGS[] = {
|
||||
{ "WAKE", 0x00000001 },
|
||||
{ "WAKE_DROPPED", 0x00000002 },
|
||||
|
@ -12,6 +12,7 @@ LOCAL_SRC_FILES:= \
|
||||
KeyLayoutMap.cpp \
|
||||
KeyCharacterMap.cpp \
|
||||
Input.cpp \
|
||||
InputDevice.cpp \
|
||||
InputDispatcher.cpp \
|
||||
InputManager.cpp \
|
||||
InputReader.cpp \
|
||||
@ -38,3 +39,13 @@ ifeq ($(TARGET_SIMULATOR),true)
|
||||
endif
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
|
||||
# Include subdirectory makefiles
|
||||
# ============================================================
|
||||
|
||||
# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
|
||||
# team really wants is to build the stuff defined by this makefile.
|
||||
ifeq (,$(ONE_SHOT_MAKEFILE))
|
||||
include $(call first-makefiles-under,$(LOCAL_PATH))
|
||||
endif
|
||||
|
@ -54,6 +54,9 @@
|
||||
*/
|
||||
#define test_bit(bit, array) (array[bit/8] & (1<<(bit%8)))
|
||||
|
||||
/* this macro computes the number of bytes needed to represent a bit array of the specified size */
|
||||
#define sizeof_bit_array(bits) ((bits + 7) / 8)
|
||||
|
||||
#define ID_MASK 0x0000ffff
|
||||
#define SEQ_MASK 0x7fff0000
|
||||
#define SEQ_SHIFT 16
|
||||
@ -182,7 +185,7 @@ int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t deviceClasses,
|
||||
}
|
||||
|
||||
int32_t EventHub::getScanCodeStateLocked(device_t* device, int32_t scanCode) const {
|
||||
uint8_t key_bitmask[(KEY_MAX + 7) / 8];
|
||||
uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
|
||||
memset(key_bitmask, 0, sizeof(key_bitmask));
|
||||
if (ioctl(mFDs[id_to_index(device->id)].fd,
|
||||
EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) {
|
||||
@ -218,7 +221,7 @@ int32_t EventHub::getKeyCodeStateLocked(device_t* device, int32_t keyCode) const
|
||||
Vector<int32_t> scanCodes;
|
||||
device->layoutMap->findScancodes(keyCode, &scanCodes);
|
||||
|
||||
uint8_t key_bitmask[(KEY_MAX + 7) / 8];
|
||||
uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
|
||||
memset(key_bitmask, 0, sizeof(key_bitmask));
|
||||
if (ioctl(mFDs[id_to_index(device->id)].fd,
|
||||
EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) {
|
||||
@ -264,7 +267,7 @@ int32_t EventHub::getSwitchState(int32_t deviceId, int32_t deviceClasses, int32_
|
||||
}
|
||||
|
||||
int32_t EventHub::getSwitchStateLocked(device_t* device, int32_t sw) const {
|
||||
uint8_t sw_bitmask[(SW_MAX + 7) / 8];
|
||||
uint8_t sw_bitmask[sizeof_bit_array(SW_MAX + 1)];
|
||||
memset(sw_bitmask, 0, sizeof(sw_bitmask));
|
||||
if (ioctl(mFDs[id_to_index(device->id)].fd,
|
||||
EVIOCGSW(sizeof(sw_bitmask)), sw_bitmask) >= 0) {
|
||||
@ -409,7 +412,7 @@ bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType,
|
||||
LOGV("iev.code=%d outKeycode=%d outFlags=0x%08x err=%d\n",
|
||||
iev.code, *outKeycode, *outFlags, err);
|
||||
if (err != 0) {
|
||||
*outKeycode = 0;
|
||||
*outKeycode = AKEYCODE_UNKNOWN;
|
||||
*outFlags = 0;
|
||||
}
|
||||
} else {
|
||||
@ -509,6 +512,26 @@ bool EventHub::hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFla
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static bool containsNonZeroByte(const uint8_t* array, uint32_t startIndex, uint32_t endIndex) {
|
||||
const uint8_t* end = array + endIndex;
|
||||
array += startIndex;
|
||||
while (array != end) {
|
||||
if (*(array++) != 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static const int32_t GAMEPAD_KEYCODES[] = {
|
||||
AKEYCODE_BUTTON_A, AKEYCODE_BUTTON_B, AKEYCODE_BUTTON_C,
|
||||
AKEYCODE_BUTTON_X, AKEYCODE_BUTTON_Y, AKEYCODE_BUTTON_Z,
|
||||
AKEYCODE_BUTTON_L1, AKEYCODE_BUTTON_R1,
|
||||
AKEYCODE_BUTTON_L2, AKEYCODE_BUTTON_R2,
|
||||
AKEYCODE_BUTTON_THUMBL, AKEYCODE_BUTTON_THUMBR,
|
||||
AKEYCODE_BUTTON_START, AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE
|
||||
};
|
||||
|
||||
int EventHub::open_device(const char *deviceName)
|
||||
{
|
||||
int version;
|
||||
@ -626,27 +649,27 @@ int EventHub::open_device(const char *deviceName)
|
||||
mFDs[mFDCount].fd = fd;
|
||||
mFDs[mFDCount].events = POLLIN;
|
||||
|
||||
// figure out the kinds of events the device reports
|
||||
// Figure out the kinds of events the device reports.
|
||||
|
||||
// See if this is a keyboard, and classify it. Note that we only
|
||||
// consider up through the function keys; we don't want to include
|
||||
// ones after that (play cd etc) so we don't mistakenly consider a
|
||||
// controller to be a keyboard.
|
||||
uint8_t key_bitmask[(KEY_MAX+7)/8];
|
||||
uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
|
||||
memset(key_bitmask, 0, sizeof(key_bitmask));
|
||||
|
||||
LOGV("Getting keys...");
|
||||
if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >= 0) {
|
||||
//LOGI("MAP\n");
|
||||
//for (int i=0; i<((KEY_MAX+7)/8); i++) {
|
||||
//for (int i = 0; i < sizeof(key_bitmask); i++) {
|
||||
// LOGI("%d: 0x%02x\n", i, key_bitmask[i]);
|
||||
//}
|
||||
for (int i=0; i<((BTN_MISC+7)/8); i++) {
|
||||
if (key_bitmask[i] != 0) {
|
||||
|
||||
// See if this is a keyboard. Ignore everything in the button range except for
|
||||
// gamepads which are also considered keyboards.
|
||||
if (containsNonZeroByte(key_bitmask, 0, sizeof_bit_array(BTN_MISC))
|
||||
|| containsNonZeroByte(key_bitmask, sizeof_bit_array(BTN_GAMEPAD),
|
||||
sizeof_bit_array(BTN_DIGI))
|
||||
|| containsNonZeroByte(key_bitmask, sizeof_bit_array(KEY_OK),
|
||||
sizeof_bit_array(KEY_MAX + 1))) {
|
||||
device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((device->classes & INPUT_DEVICE_CLASS_KEYBOARD) != 0) {
|
||||
|
||||
device->keyBitmask = new uint8_t[sizeof(key_bitmask)];
|
||||
if (device->keyBitmask != NULL) {
|
||||
memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask));
|
||||
@ -658,24 +681,23 @@ int EventHub::open_device(const char *deviceName)
|
||||
}
|
||||
}
|
||||
|
||||
// See if this is a trackball.
|
||||
// See if this is a trackball (or mouse).
|
||||
if (test_bit(BTN_MOUSE, key_bitmask)) {
|
||||
uint8_t rel_bitmask[(REL_MAX+7)/8];
|
||||
uint8_t rel_bitmask[sizeof_bit_array(REL_MAX + 1)];
|
||||
memset(rel_bitmask, 0, sizeof(rel_bitmask));
|
||||
LOGV("Getting relative controllers...");
|
||||
if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) >= 0)
|
||||
{
|
||||
if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) >= 0) {
|
||||
if (test_bit(REL_X, rel_bitmask) && test_bit(REL_Y, rel_bitmask)) {
|
||||
device->classes |= INPUT_DEVICE_CLASS_TRACKBALL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t abs_bitmask[(ABS_MAX+7)/8];
|
||||
// See if this is a touch pad.
|
||||
uint8_t abs_bitmask[sizeof_bit_array(ABS_MAX + 1)];
|
||||
memset(abs_bitmask, 0, sizeof(abs_bitmask));
|
||||
LOGV("Getting absolute controllers...");
|
||||
ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask);
|
||||
|
||||
if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) >= 0) {
|
||||
// Is this a new modern multi-touch driver?
|
||||
if (test_bit(ABS_MT_TOUCH_MAJOR, abs_bitmask)
|
||||
&& test_bit(ABS_MT_POSITION_X, abs_bitmask)
|
||||
@ -687,10 +709,11 @@ int EventHub::open_device(const char *deviceName)
|
||||
&& test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) {
|
||||
device->classes |= INPUT_DEVICE_CLASS_TOUCHSCREEN;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef EV_SW
|
||||
// figure out the switches this device reports
|
||||
uint8_t sw_bitmask[(SW_MAX+7)/8];
|
||||
uint8_t sw_bitmask[sizeof_bit_array(SW_MAX + 1)];
|
||||
memset(sw_bitmask, 0, sizeof(sw_bitmask));
|
||||
if (ioctl(fd, EVIOCGBIT(EV_SW, sizeof(sw_bitmask)), sw_bitmask) >= 0) {
|
||||
for (int i=0; i<EV_SW; i++) {
|
||||
@ -726,7 +749,10 @@ int EventHub::open_device(const char *deviceName)
|
||||
"%s/usr/keylayout/%s", root, "qwerty.kl");
|
||||
defaultKeymap = true;
|
||||
}
|
||||
device->layoutMap->load(keylayoutFilename);
|
||||
status_t status = device->layoutMap->load(keylayoutFilename);
|
||||
if (status) {
|
||||
LOGE("Error %d loading key layout.", status);
|
||||
}
|
||||
|
||||
// tell the world about the devname (the descriptive name)
|
||||
if (!mHaveFirstKeyboard && !defaultKeymap && strstr(name, "-keypad")) {
|
||||
@ -746,19 +772,27 @@ int EventHub::open_device(const char *deviceName)
|
||||
property_set(propName, name);
|
||||
|
||||
// 'Q' key support = cheap test of whether this is an alpha-capable kbd
|
||||
if (hasKeycode(device, kKeyCodeQ)) {
|
||||
if (hasKeycode(device, AKEYCODE_Q)) {
|
||||
device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY;
|
||||
}
|
||||
|
||||
// See if this has a DPAD.
|
||||
if (hasKeycode(device, kKeyCodeDpadUp) &&
|
||||
hasKeycode(device, kKeyCodeDpadDown) &&
|
||||
hasKeycode(device, kKeyCodeDpadLeft) &&
|
||||
hasKeycode(device, kKeyCodeDpadRight) &&
|
||||
hasKeycode(device, kKeyCodeDpadCenter)) {
|
||||
// See if this device has a DPAD.
|
||||
if (hasKeycode(device, AKEYCODE_DPAD_UP) &&
|
||||
hasKeycode(device, AKEYCODE_DPAD_DOWN) &&
|
||||
hasKeycode(device, AKEYCODE_DPAD_LEFT) &&
|
||||
hasKeycode(device, AKEYCODE_DPAD_RIGHT) &&
|
||||
hasKeycode(device, AKEYCODE_DPAD_CENTER)) {
|
||||
device->classes |= INPUT_DEVICE_CLASS_DPAD;
|
||||
}
|
||||
|
||||
// See if this device has a gamepad.
|
||||
for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES); i++) {
|
||||
if (hasKeycode(device, GAMEPAD_KEYCODES[i])) {
|
||||
device->classes |= INPUT_DEVICE_CLASS_GAMEPAD;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LOGI("New keyboard: device->id=0x%x devname='%s' propName='%s' keylayout='%s'\n",
|
||||
device->id, name, propName, keylayoutFilename);
|
||||
}
|
||||
|
@ -22,26 +22,26 @@ void InputEvent::initialize(int32_t deviceId, int32_t nature) {
|
||||
|
||||
bool KeyEvent::hasDefaultAction(int32_t keyCode) {
|
||||
switch (keyCode) {
|
||||
case KEYCODE_HOME:
|
||||
case KEYCODE_BACK:
|
||||
case KEYCODE_CALL:
|
||||
case KEYCODE_ENDCALL:
|
||||
case KEYCODE_VOLUME_UP:
|
||||
case KEYCODE_VOLUME_DOWN:
|
||||
case KEYCODE_POWER:
|
||||
case KEYCODE_CAMERA:
|
||||
case KEYCODE_HEADSETHOOK:
|
||||
case KEYCODE_MENU:
|
||||
case KEYCODE_NOTIFICATION:
|
||||
case KEYCODE_FOCUS:
|
||||
case KEYCODE_SEARCH:
|
||||
case KEYCODE_MEDIA_PLAY_PAUSE:
|
||||
case KEYCODE_MEDIA_STOP:
|
||||
case KEYCODE_MEDIA_NEXT:
|
||||
case KEYCODE_MEDIA_PREVIOUS:
|
||||
case KEYCODE_MEDIA_REWIND:
|
||||
case KEYCODE_MEDIA_FAST_FORWARD:
|
||||
case KEYCODE_MUTE:
|
||||
case AKEYCODE_HOME:
|
||||
case AKEYCODE_BACK:
|
||||
case AKEYCODE_CALL:
|
||||
case AKEYCODE_ENDCALL:
|
||||
case AKEYCODE_VOLUME_UP:
|
||||
case AKEYCODE_VOLUME_DOWN:
|
||||
case AKEYCODE_POWER:
|
||||
case AKEYCODE_CAMERA:
|
||||
case AKEYCODE_HEADSETHOOK:
|
||||
case AKEYCODE_MENU:
|
||||
case AKEYCODE_NOTIFICATION:
|
||||
case AKEYCODE_FOCUS:
|
||||
case AKEYCODE_SEARCH:
|
||||
case AKEYCODE_MEDIA_PLAY_PAUSE:
|
||||
case AKEYCODE_MEDIA_STOP:
|
||||
case AKEYCODE_MEDIA_NEXT:
|
||||
case AKEYCODE_MEDIA_PREVIOUS:
|
||||
case AKEYCODE_MEDIA_REWIND:
|
||||
case AKEYCODE_MEDIA_FAST_FORWARD:
|
||||
case AKEYCODE_MUTE:
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -54,26 +54,26 @@ bool KeyEvent::hasDefaultAction() const {
|
||||
|
||||
bool KeyEvent::isSystemKey(int32_t keyCode) {
|
||||
switch (keyCode) {
|
||||
case KEYCODE_MENU:
|
||||
case KEYCODE_SOFT_RIGHT:
|
||||
case KEYCODE_HOME:
|
||||
case KEYCODE_BACK:
|
||||
case KEYCODE_CALL:
|
||||
case KEYCODE_ENDCALL:
|
||||
case KEYCODE_VOLUME_UP:
|
||||
case KEYCODE_VOLUME_DOWN:
|
||||
case KEYCODE_MUTE:
|
||||
case KEYCODE_POWER:
|
||||
case KEYCODE_HEADSETHOOK:
|
||||
case KEYCODE_MEDIA_PLAY_PAUSE:
|
||||
case KEYCODE_MEDIA_STOP:
|
||||
case KEYCODE_MEDIA_NEXT:
|
||||
case KEYCODE_MEDIA_PREVIOUS:
|
||||
case KEYCODE_MEDIA_REWIND:
|
||||
case KEYCODE_MEDIA_FAST_FORWARD:
|
||||
case KEYCODE_CAMERA:
|
||||
case KEYCODE_FOCUS:
|
||||
case KEYCODE_SEARCH:
|
||||
case AKEYCODE_MENU:
|
||||
case AKEYCODE_SOFT_RIGHT:
|
||||
case AKEYCODE_HOME:
|
||||
case AKEYCODE_BACK:
|
||||
case AKEYCODE_CALL:
|
||||
case AKEYCODE_ENDCALL:
|
||||
case AKEYCODE_VOLUME_UP:
|
||||
case AKEYCODE_VOLUME_DOWN:
|
||||
case AKEYCODE_MUTE:
|
||||
case AKEYCODE_POWER:
|
||||
case AKEYCODE_HEADSETHOOK:
|
||||
case AKEYCODE_MEDIA_PLAY_PAUSE:
|
||||
case AKEYCODE_MEDIA_STOP:
|
||||
case AKEYCODE_MEDIA_NEXT:
|
||||
case AKEYCODE_MEDIA_PREVIOUS:
|
||||
case AKEYCODE_MEDIA_REWIND:
|
||||
case AKEYCODE_MEDIA_FAST_FORWARD:
|
||||
case AKEYCODE_CAMERA:
|
||||
case AKEYCODE_FOCUS:
|
||||
case AKEYCODE_SEARCH:
|
||||
return true;
|
||||
}
|
||||
|
||||
|
729
libs/ui/InputDevice.cpp
Normal file
729
libs/ui/InputDevice.cpp
Normal file
@ -0,0 +1,729 @@
|
||||
//
|
||||
// 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 = META_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
|
@ -40,10 +40,10 @@ namespace android {
|
||||
|
||||
// TODO, this needs to be somewhere else, perhaps in the policy
|
||||
static inline bool isMovementKey(int32_t keyCode) {
|
||||
return keyCode == KEYCODE_DPAD_UP
|
||||
|| keyCode == KEYCODE_DPAD_DOWN
|
||||
|| keyCode == KEYCODE_DPAD_LEFT
|
||||
|| keyCode == KEYCODE_DPAD_RIGHT;
|
||||
return keyCode == AKEYCODE_DPAD_UP
|
||||
|| keyCode == AKEYCODE_DPAD_DOWN
|
||||
|| keyCode == AKEYCODE_DPAD_LEFT
|
||||
|| keyCode == AKEYCODE_DPAD_RIGHT;
|
||||
}
|
||||
|
||||
static inline nsecs_t now() {
|
||||
|
@ -33,18 +33,6 @@
|
||||
/** Amount that trackball needs to move in order to generate a key event. */
|
||||
#define TRACKBALL_MOVEMENT_THRESHOLD 6
|
||||
|
||||
/* 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 {
|
||||
|
||||
@ -71,19 +59,19 @@ inline static void swap(T& a, T& b) {
|
||||
int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) {
|
||||
int32_t mask;
|
||||
switch (keyCode) {
|
||||
case KEYCODE_ALT_LEFT:
|
||||
case AKEYCODE_ALT_LEFT:
|
||||
mask = META_ALT_LEFT_ON;
|
||||
break;
|
||||
case KEYCODE_ALT_RIGHT:
|
||||
case AKEYCODE_ALT_RIGHT:
|
||||
mask = META_ALT_RIGHT_ON;
|
||||
break;
|
||||
case KEYCODE_SHIFT_LEFT:
|
||||
case AKEYCODE_SHIFT_LEFT:
|
||||
mask = META_SHIFT_LEFT_ON;
|
||||
break;
|
||||
case KEYCODE_SHIFT_RIGHT:
|
||||
case AKEYCODE_SHIFT_RIGHT:
|
||||
mask = META_SHIFT_RIGHT_ON;
|
||||
break;
|
||||
case KEYCODE_SYM:
|
||||
case AKEYCODE_SYM:
|
||||
mask = META_SYM_ON;
|
||||
break;
|
||||
default:
|
||||
@ -107,10 +95,10 @@ int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) {
|
||||
static const int32_t keyCodeRotationMap[][4] = {
|
||||
// key codes enumerated counter-clockwise with the original (unrotated) key first
|
||||
// no rotation, 90 degree rotation, 180 degree rotation, 270 degree rotation
|
||||
{ KEYCODE_DPAD_DOWN, KEYCODE_DPAD_RIGHT, KEYCODE_DPAD_UP, KEYCODE_DPAD_LEFT },
|
||||
{ KEYCODE_DPAD_RIGHT, KEYCODE_DPAD_UP, KEYCODE_DPAD_LEFT, KEYCODE_DPAD_DOWN },
|
||||
{ KEYCODE_DPAD_UP, KEYCODE_DPAD_LEFT, KEYCODE_DPAD_DOWN, KEYCODE_DPAD_RIGHT },
|
||||
{ KEYCODE_DPAD_LEFT, KEYCODE_DPAD_DOWN, KEYCODE_DPAD_RIGHT, KEYCODE_DPAD_UP },
|
||||
{ AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT },
|
||||
{ AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN },
|
||||
{ AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT },
|
||||
{ AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP },
|
||||
};
|
||||
static const int keyCodeRotationMapSize =
|
||||
sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]);
|
||||
@ -127,668 +115,6 @@ int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) {
|
||||
}
|
||||
|
||||
|
||||
// --- 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 = META_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();
|
||||
}
|
||||
|
||||
|
||||
// --- InputReader ---
|
||||
|
||||
InputReader::InputReader(const sp<EventHubInterface>& eventHub,
|
||||
@ -927,32 +253,30 @@ void InputReader::handleKey(const RawEvent* rawEvent) {
|
||||
bool down = rawEvent->value != 0;
|
||||
int32_t scanCode = rawEvent->scanCode;
|
||||
|
||||
if (device->isKeyboard() && (scanCode < BTN_FIRST || scanCode > BTN_LAST)) {
|
||||
int32_t keyCode = rawEvent->keyCode;
|
||||
onKey(rawEvent->when, device, down, keyCode, scanCode, rawEvent->flags);
|
||||
} else if (device->isSingleTouchScreen()) {
|
||||
if (device->isSingleTouchScreen()) {
|
||||
switch (rawEvent->scanCode) {
|
||||
case BTN_TOUCH:
|
||||
device->singleTouchScreen.accumulator.fields |=
|
||||
InputDevice::SingleTouchScreenState::Accumulator::FIELD_BTN_TOUCH;
|
||||
device->singleTouchScreen.accumulator.btnTouch = down;
|
||||
break;
|
||||
return;
|
||||
}
|
||||
} else if (device->isTrackball()) {
|
||||
}
|
||||
|
||||
if (device->isTrackball()) {
|
||||
switch (rawEvent->scanCode) {
|
||||
case BTN_MOUSE:
|
||||
device->trackball.accumulator.fields |=
|
||||
InputDevice::TrackballState::Accumulator::FIELD_BTN_MOUSE;
|
||||
device->trackball.accumulator.btnMouse = down;
|
||||
|
||||
// send the down immediately
|
||||
// XXX this emulates the old behavior of KeyInputQueue, unclear whether it is
|
||||
// necessary or if we can wait until the next sync
|
||||
onTrackballStateChanged(rawEvent->when, device);
|
||||
device->trackball.accumulator.clear();
|
||||
break;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (device->isKeyboard()) {
|
||||
int32_t keyCode = rawEvent->keyCode;
|
||||
onKey(rawEvent->when, device, down, keyCode, scanCode, rawEvent->flags);
|
||||
}
|
||||
}
|
||||
|
||||
void InputReader::handleRelativeMotion(const RawEvent* rawEvent) {
|
||||
|
@ -76,7 +76,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() {
|
||||
const int32_t nature = INPUT_EVENT_NATURE_KEY;
|
||||
const int32_t action = KEY_EVENT_ACTION_DOWN;
|
||||
const int32_t flags = KEY_EVENT_FLAG_FROM_SYSTEM;
|
||||
const int32_t keyCode = KEYCODE_ENTER;
|
||||
const int32_t keyCode = AKEYCODE_ENTER;
|
||||
const int32_t scanCode = 13;
|
||||
const int32_t metaState = META_ALT_LEFT_ON | META_ALT_ON;
|
||||
const int32_t repeatCount = 1;
|
||||
|
@ -122,3 +122,13 @@ LOCAL_SRC_FILES := $(commonSources) BackupData.cpp BackupHelpers.cpp
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
# Include subdirectory makefiles
|
||||
# ============================================================
|
||||
|
||||
# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
|
||||
# team really wants is to build the stuff defined by this makefile.
|
||||
ifeq (,$(ONE_SHOT_MAKEFILE))
|
||||
include $(call first-makefiles-under,$(LOCAL_PATH))
|
||||
endif
|
@ -68,7 +68,10 @@ enum {
|
||||
INPUT_DEVICE_CLASS_TOUCHSCREEN_MT= 0x00000010,
|
||||
|
||||
/* The input device is a directional pad. */
|
||||
INPUT_DEVICE_CLASS_DPAD = 0x00000020
|
||||
INPUT_DEVICE_CLASS_DPAD = 0x00000020,
|
||||
|
||||
/* The input device is a gamepad (implies keyboard). */
|
||||
INPUT_DEVICE_CLASS_GAMEPAD = 0x00000040
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -41,114 +41,122 @@ extern "C" {
|
||||
|
||||
/*
|
||||
* Key codes.
|
||||
*
|
||||
* XXX: The declarations in <ui/KeycodeLabel.h> should be updated to use these instead.
|
||||
* We should probably move this into android/keycodes.h and add some new API for
|
||||
* getting labels so that we can remove the other tables also in KeycodeLabel.h.
|
||||
*/
|
||||
enum {
|
||||
KEYCODE_UNKNOWN = 0,
|
||||
KEYCODE_SOFT_LEFT = 1,
|
||||
KEYCODE_SOFT_RIGHT = 2,
|
||||
KEYCODE_HOME = 3,
|
||||
KEYCODE_BACK = 4,
|
||||
KEYCODE_CALL = 5,
|
||||
KEYCODE_ENDCALL = 6,
|
||||
KEYCODE_0 = 7,
|
||||
KEYCODE_1 = 8,
|
||||
KEYCODE_2 = 9,
|
||||
KEYCODE_3 = 10,
|
||||
KEYCODE_4 = 11,
|
||||
KEYCODE_5 = 12,
|
||||
KEYCODE_6 = 13,
|
||||
KEYCODE_7 = 14,
|
||||
KEYCODE_8 = 15,
|
||||
KEYCODE_9 = 16,
|
||||
KEYCODE_STAR = 17,
|
||||
KEYCODE_POUND = 18,
|
||||
KEYCODE_DPAD_UP = 19,
|
||||
KEYCODE_DPAD_DOWN = 20,
|
||||
KEYCODE_DPAD_LEFT = 21,
|
||||
KEYCODE_DPAD_RIGHT = 22,
|
||||
KEYCODE_DPAD_CENTER = 23,
|
||||
KEYCODE_VOLUME_UP = 24,
|
||||
KEYCODE_VOLUME_DOWN = 25,
|
||||
KEYCODE_POWER = 26,
|
||||
KEYCODE_CAMERA = 27,
|
||||
KEYCODE_CLEAR = 28,
|
||||
KEYCODE_A = 29,
|
||||
KEYCODE_B = 30,
|
||||
KEYCODE_C = 31,
|
||||
KEYCODE_D = 32,
|
||||
KEYCODE_E = 33,
|
||||
KEYCODE_F = 34,
|
||||
KEYCODE_G = 35,
|
||||
KEYCODE_H = 36,
|
||||
KEYCODE_I = 37,
|
||||
KEYCODE_J = 38,
|
||||
KEYCODE_K = 39,
|
||||
KEYCODE_L = 40,
|
||||
KEYCODE_M = 41,
|
||||
KEYCODE_N = 42,
|
||||
KEYCODE_O = 43,
|
||||
KEYCODE_P = 44,
|
||||
KEYCODE_Q = 45,
|
||||
KEYCODE_R = 46,
|
||||
KEYCODE_S = 47,
|
||||
KEYCODE_T = 48,
|
||||
KEYCODE_U = 49,
|
||||
KEYCODE_V = 50,
|
||||
KEYCODE_W = 51,
|
||||
KEYCODE_X = 52,
|
||||
KEYCODE_Y = 53,
|
||||
KEYCODE_Z = 54,
|
||||
KEYCODE_COMMA = 55,
|
||||
KEYCODE_PERIOD = 56,
|
||||
KEYCODE_ALT_LEFT = 57,
|
||||
KEYCODE_ALT_RIGHT = 58,
|
||||
KEYCODE_SHIFT_LEFT = 59,
|
||||
KEYCODE_SHIFT_RIGHT = 60,
|
||||
KEYCODE_TAB = 61,
|
||||
KEYCODE_SPACE = 62,
|
||||
KEYCODE_SYM = 63,
|
||||
KEYCODE_EXPLORER = 64,
|
||||
KEYCODE_ENVELOPE = 65,
|
||||
KEYCODE_ENTER = 66,
|
||||
KEYCODE_DEL = 67,
|
||||
KEYCODE_GRAVE = 68,
|
||||
KEYCODE_MINUS = 69,
|
||||
KEYCODE_EQUALS = 70,
|
||||
KEYCODE_LEFT_BRACKET = 71,
|
||||
KEYCODE_RIGHT_BRACKET = 72,
|
||||
KEYCODE_BACKSLASH = 73,
|
||||
KEYCODE_SEMICOLON = 74,
|
||||
KEYCODE_APOSTROPHE = 75,
|
||||
KEYCODE_SLASH = 76,
|
||||
KEYCODE_AT = 77,
|
||||
KEYCODE_NUM = 78,
|
||||
KEYCODE_HEADSETHOOK = 79,
|
||||
KEYCODE_FOCUS = 80, // *Camera* focus
|
||||
KEYCODE_PLUS = 81,
|
||||
KEYCODE_MENU = 82,
|
||||
KEYCODE_NOTIFICATION = 83,
|
||||
KEYCODE_SEARCH = 84,
|
||||
KEYCODE_MEDIA_PLAY_PAUSE= 85,
|
||||
KEYCODE_MEDIA_STOP = 86,
|
||||
KEYCODE_MEDIA_NEXT = 87,
|
||||
KEYCODE_MEDIA_PREVIOUS = 88,
|
||||
KEYCODE_MEDIA_REWIND = 89,
|
||||
KEYCODE_MEDIA_FAST_FORWARD = 90,
|
||||
KEYCODE_MUTE = 91,
|
||||
KEYCODE_PAGE_UP = 92,
|
||||
KEYCODE_PAGE_DOWN = 93
|
||||
AKEYCODE_UNKNOWN = 0,
|
||||
AKEYCODE_SOFT_LEFT = 1,
|
||||
AKEYCODE_SOFT_RIGHT = 2,
|
||||
AKEYCODE_HOME = 3,
|
||||
AKEYCODE_BACK = 4,
|
||||
AKEYCODE_CALL = 5,
|
||||
AKEYCODE_ENDCALL = 6,
|
||||
AKEYCODE_0 = 7,
|
||||
AKEYCODE_1 = 8,
|
||||
AKEYCODE_2 = 9,
|
||||
AKEYCODE_3 = 10,
|
||||
AKEYCODE_4 = 11,
|
||||
AKEYCODE_5 = 12,
|
||||
AKEYCODE_6 = 13,
|
||||
AKEYCODE_7 = 14,
|
||||
AKEYCODE_8 = 15,
|
||||
AKEYCODE_9 = 16,
|
||||
AKEYCODE_STAR = 17,
|
||||
AKEYCODE_POUND = 18,
|
||||
AKEYCODE_DPAD_UP = 19,
|
||||
AKEYCODE_DPAD_DOWN = 20,
|
||||
AKEYCODE_DPAD_LEFT = 21,
|
||||
AKEYCODE_DPAD_RIGHT = 22,
|
||||
AKEYCODE_DPAD_CENTER = 23,
|
||||
AKEYCODE_VOLUME_UP = 24,
|
||||
AKEYCODE_VOLUME_DOWN = 25,
|
||||
AKEYCODE_POWER = 26,
|
||||
AKEYCODE_CAMERA = 27,
|
||||
AKEYCODE_CLEAR = 28,
|
||||
AKEYCODE_A = 29,
|
||||
AKEYCODE_B = 30,
|
||||
AKEYCODE_C = 31,
|
||||
AKEYCODE_D = 32,
|
||||
AKEYCODE_E = 33,
|
||||
AKEYCODE_F = 34,
|
||||
AKEYCODE_G = 35,
|
||||
AKEYCODE_H = 36,
|
||||
AKEYCODE_I = 37,
|
||||
AKEYCODE_J = 38,
|
||||
AKEYCODE_K = 39,
|
||||
AKEYCODE_L = 40,
|
||||
AKEYCODE_M = 41,
|
||||
AKEYCODE_N = 42,
|
||||
AKEYCODE_O = 43,
|
||||
AKEYCODE_P = 44,
|
||||
AKEYCODE_Q = 45,
|
||||
AKEYCODE_R = 46,
|
||||
AKEYCODE_S = 47,
|
||||
AKEYCODE_T = 48,
|
||||
AKEYCODE_U = 49,
|
||||
AKEYCODE_V = 50,
|
||||
AKEYCODE_W = 51,
|
||||
AKEYCODE_X = 52,
|
||||
AKEYCODE_Y = 53,
|
||||
AKEYCODE_Z = 54,
|
||||
AKEYCODE_COMMA = 55,
|
||||
AKEYCODE_PERIOD = 56,
|
||||
AKEYCODE_ALT_LEFT = 57,
|
||||
AKEYCODE_ALT_RIGHT = 58,
|
||||
AKEYCODE_SHIFT_LEFT = 59,
|
||||
AKEYCODE_SHIFT_RIGHT = 60,
|
||||
AKEYCODE_TAB = 61,
|
||||
AKEYCODE_SPACE = 62,
|
||||
AKEYCODE_SYM = 63,
|
||||
AKEYCODE_EXPLORER = 64,
|
||||
AKEYCODE_ENVELOPE = 65,
|
||||
AKEYCODE_ENTER = 66,
|
||||
AKEYCODE_DEL = 67,
|
||||
AKEYCODE_GRAVE = 68,
|
||||
AKEYCODE_MINUS = 69,
|
||||
AKEYCODE_EQUALS = 70,
|
||||
AKEYCODE_LEFT_BRACKET = 71,
|
||||
AKEYCODE_RIGHT_BRACKET = 72,
|
||||
AKEYCODE_BACKSLASH = 73,
|
||||
AKEYCODE_SEMICOLON = 74,
|
||||
AKEYCODE_APOSTROPHE = 75,
|
||||
AKEYCODE_SLASH = 76,
|
||||
AKEYCODE_AT = 77,
|
||||
AKEYCODE_NUM = 78,
|
||||
AKEYCODE_HEADSETHOOK = 79,
|
||||
AKEYCODE_FOCUS = 80, // *Camera* focus
|
||||
AKEYCODE_PLUS = 81,
|
||||
AKEYCODE_MENU = 82,
|
||||
AKEYCODE_NOTIFICATION = 83,
|
||||
AKEYCODE_SEARCH = 84,
|
||||
AKEYCODE_MEDIA_PLAY_PAUSE= 85,
|
||||
AKEYCODE_MEDIA_STOP = 86,
|
||||
AKEYCODE_MEDIA_NEXT = 87,
|
||||
AKEYCODE_MEDIA_PREVIOUS = 88,
|
||||
AKEYCODE_MEDIA_REWIND = 89,
|
||||
AKEYCODE_MEDIA_FAST_FORWARD = 90,
|
||||
AKEYCODE_MUTE = 91,
|
||||
AKEYCODE_PAGE_UP = 92,
|
||||
AKEYCODE_PAGE_DOWN = 93,
|
||||
AKEYCODE_PICTSYMBOLS = 94,
|
||||
AKEYCODE_SWITCH_CHARSET = 95,
|
||||
AKEYCODE_BUTTON_A = 96,
|
||||
AKEYCODE_BUTTON_B = 97,
|
||||
AKEYCODE_BUTTON_C = 98,
|
||||
AKEYCODE_BUTTON_X = 99,
|
||||
AKEYCODE_BUTTON_Y = 100,
|
||||
AKEYCODE_BUTTON_Z = 101,
|
||||
AKEYCODE_BUTTON_L1 = 102,
|
||||
AKEYCODE_BUTTON_R1 = 103,
|
||||
AKEYCODE_BUTTON_L2 = 104,
|
||||
AKEYCODE_BUTTON_R2 = 105,
|
||||
AKEYCODE_BUTTON_THUMBL = 106,
|
||||
AKEYCODE_BUTTON_THUMBR = 107,
|
||||
AKEYCODE_BUTTON_START = 108,
|
||||
AKEYCODE_BUTTON_SELECT = 109,
|
||||
AKEYCODE_BUTTON_MODE = 110,
|
||||
|
||||
/* NOTE: If you add a new keycode here you must also add it to:
|
||||
* native/include/android/keycodes.h
|
||||
* frameworks/base/include/ui/KeycodeLabels.h
|
||||
* frameworks/base/core/java/android/view/KeyEvent.java
|
||||
* tools/puppet_master/PuppetMaster.nav_keys.py
|
||||
* frameworks/base/core/res/res/values/attrs.xml
|
||||
*/
|
||||
// NOTE: If you add a new keycode here you must also add it to several other files.
|
||||
// Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -405,28 +405,28 @@ NativeInputManager::~NativeInputManager() {
|
||||
}
|
||||
|
||||
bool NativeInputManager::isAppSwitchKey(int32_t keyCode) {
|
||||
return keyCode == KEYCODE_HOME || keyCode == KEYCODE_ENDCALL;
|
||||
return keyCode == AKEYCODE_HOME || keyCode == AKEYCODE_ENDCALL;
|
||||
}
|
||||
|
||||
bool NativeInputManager::isPolicyKey(int32_t keyCode, bool isScreenOn) {
|
||||
// Special keys that the WindowManagerPolicy might care about.
|
||||
switch (keyCode) {
|
||||
case KEYCODE_VOLUME_UP:
|
||||
case KEYCODE_VOLUME_DOWN:
|
||||
case KEYCODE_ENDCALL:
|
||||
case KEYCODE_POWER:
|
||||
case KEYCODE_CALL:
|
||||
case KEYCODE_HOME:
|
||||
case KEYCODE_MENU:
|
||||
case KEYCODE_SEARCH:
|
||||
case AKEYCODE_VOLUME_UP:
|
||||
case AKEYCODE_VOLUME_DOWN:
|
||||
case AKEYCODE_ENDCALL:
|
||||
case AKEYCODE_POWER:
|
||||
case AKEYCODE_CALL:
|
||||
case AKEYCODE_HOME:
|
||||
case AKEYCODE_MENU:
|
||||
case AKEYCODE_SEARCH:
|
||||
// media keys
|
||||
case KEYCODE_HEADSETHOOK:
|
||||
case KEYCODE_MEDIA_PLAY_PAUSE:
|
||||
case KEYCODE_MEDIA_STOP:
|
||||
case KEYCODE_MEDIA_NEXT:
|
||||
case KEYCODE_MEDIA_PREVIOUS:
|
||||
case KEYCODE_MEDIA_REWIND:
|
||||
case KEYCODE_MEDIA_FAST_FORWARD:
|
||||
case AKEYCODE_HEADSETHOOK:
|
||||
case AKEYCODE_MEDIA_PLAY_PAUSE:
|
||||
case AKEYCODE_MEDIA_STOP:
|
||||
case AKEYCODE_MEDIA_NEXT:
|
||||
case AKEYCODE_MEDIA_PREVIOUS:
|
||||
case AKEYCODE_MEDIA_REWIND:
|
||||
case AKEYCODE_MEDIA_FAST_FORWARD:
|
||||
return true;
|
||||
default:
|
||||
// We need to pass all keys to the policy in the following cases:
|
||||
|
Reference in New Issue
Block a user