// Configure device mode.
switch (mParameters.mode) {
+ case Parameters::MODE_POINTER_RELATIVE:
+ // Should not happen during first time configuration.
+ ALOGE("Cannot start a device in MODE_POINTER_RELATIVE, starting in MODE_POINTER");
+ mParameters.mode = Parameters::MODE_POINTER;
+ // fall through.
case Parameters::MODE_POINTER:
mSource = AINPUT_SOURCE_MOUSE;
mXPrecision = 1.0f;
mHWheelScale = 1.0f;
}
+ if ((!changes && config->pointerCapture)
+ || (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE)) {
+ if (config->pointerCapture) {
+ if (mParameters.mode == Parameters::MODE_POINTER) {
+ mParameters.mode = Parameters::MODE_POINTER_RELATIVE;
+ mSource = AINPUT_SOURCE_MOUSE_RELATIVE;
+ // Keep PointerController around in order to preserve the pointer position.
+ mPointerController->fade(PointerControllerInterface::TRANSITION_IMMEDIATE);
+ } else {
+ ALOGE("Cannot request pointer capture, device is not in MODE_POINTER");
+ }
+ } else {
+ if (mParameters.mode == Parameters::MODE_POINTER_RELATIVE) {
+ mParameters.mode = Parameters::MODE_POINTER;
+ mSource = AINPUT_SOURCE_MOUSE;
+ } else {
+ ALOGE("Cannot release pointer capture, device is not in MODE_POINTER_RELATIVE");
+ }
+ }
+ bumpGeneration();
+ if (changes) {
+ getDevice()->notifyReset(when);
+ }
+ }
+
if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) {
mPointerVelocityControl.setParameters(config->pointerVelocityControlParameters);
mWheelXVelocityControl.setParameters(config->wheelVelocityControlParameters);
case Parameters::MODE_POINTER:
dump.append(INDENT4 "Mode: pointer\n");
break;
+ case Parameters::MODE_POINTER_RELATIVE:
+ dump.append(INDENT4 "Mode: relative pointer\n");
+ break;
case Parameters::MODE_NAVIGATION:
dump.append(INDENT4 "Mode: navigation\n");
break;
mPointerVelocityControl.move(when, &deltaX, &deltaY);
int32_t displayId;
- if (mPointerController != NULL) {
+ if (mSource == AINPUT_SOURCE_MOUSE) {
if (moved || scrolled || buttonsChanged) {
mPointerController->setPresentation(
PointerControllerInterface::PRESENTATION_POINTER);
int32_t motionEventAction;
if (downChanged) {
motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
- } else if (down || mPointerController == NULL) {
+ } else if (down || (mSource != AINPUT_SOURCE_MOUSE)) {
motionEventAction = AMOTION_EVENT_ACTION_MOVE;
} else {
motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE;
// Send hover move after UP to tell the application that the mouse is hovering now.
if (motionEventAction == AMOTION_EVENT_ACTION_UP
- && mPointerController != NULL) {
+ && (mSource == AINPUT_SOURCE_MOUSE)) {
NotifyMotionArgs hoverArgs(when, getDeviceId(), mSource, policyFlags,
AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE,
mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
- mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
- mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
} else if (currentFingerCount == 0) {
// Case 3. No fingers down and button is not pressed. (NEUTRAL)
if (mPointerGesture.lastGestureMode != PointerGesture::NEUTRAL) {
mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE,
down ? 1.0f : 0.0f);
- mPointerGesture.currentGestureCoords[0].setAxisValue(
- AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
- mPointerGesture.currentGestureCoords[0].setAxisValue(
- AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
if (lastFingerCount == 0 && currentFingerCount != 0) {
mPointerGesture.resetTap();
mPointerGesture.referenceGestureX);
mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y,
mPointerGesture.referenceGestureY);
- mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X,
- commonDeltaX);
- mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y,
- commonDeltaY);
mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
} else if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) {
// FREEFORM mode.
AMOTION_EVENT_AXIS_Y, mPointerGesture.referenceGestureY + deltaY);
mPointerGesture.currentGestureCoords[i].setAxisValue(
AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
- mPointerGesture.currentGestureCoords[i].setAxisValue(
- AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
- mPointerGesture.currentGestureCoords[i].setAxisValue(
- AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
}
if (mPointerGesture.activeGestureId < 0) {
mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE,
hovering ? 0.0f : 1.0f);
- mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, x);
- mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, y);
mPointerSimple.currentProperties.id = 0;
mPointerSimple.currentProperties.toolType =
mCurrentCookedState.cookedPointerData.pointerProperties[currentIndex].toolType;
transform = t;
}
+ void setPointerCapture(bool enabled) {
+ mConfig.pointerCapture = enabled;
+ }
+
private:
virtual void getReaderConfiguration(InputReaderConfiguration* outConfig) {
*outConfig = mConfig;
mGlobalMetaState = state;
}
+ uint32_t getGeneration() {
+ return mGeneration;
+ }
+
private:
virtual void updateGlobalMetaState() {
mUpdateGlobalMetaStateWasCalled = true;
mFakeEventHub->addConfigurationProperty(DEVICE_ID, String8(key), String8(value));
}
+ void configureDevice(uint32_t changes) {
+ mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), changes);
+ }
+
void addMapperAndConfigure(InputMapper* mapper) {
mDevice->addMapper(mapper);
- mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0);
+ configureDevice(0);
mDevice->reset(ARBITRARY_TIME);
}
void setDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height,
int32_t orientation) {
mFakePolicy->setDisplayInfo(displayId, width, height, orientation);
- mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
- InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+ configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
}
static void process(InputMapper* mapper, nsecs_t when, int32_t deviceId, int32_t type,
process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, 20);
process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AINPUT_SOURCE_MOUSE, args.source);
+ ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, args.action);
+ ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
+ 110.0f, 220.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
+ ASSERT_NO_FATAL_FAILURE(assertPosition(mFakePointerController, 110.0f, 220.0f));
+}
+
+TEST_F(CursorInputMapperTest, Process_PointerCapture) {
+ CursorInputMapper* mapper = new CursorInputMapper(mDevice);
+ addConfigurationProperty("cursor.mode", "pointer");
+ mFakePolicy->setPointerCapture(true);
+ addMapperAndConfigure(mapper);
+
+ NotifyDeviceResetArgs resetArgs;
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
+ ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime);
+ ASSERT_EQ(DEVICE_ID, resetArgs.deviceId);
+
+ mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1);
+ mFakePointerController->setPosition(100, 200);
+ mFakePointerController->setButtonState(0);
+
+ NotifyMotionArgs args;
+
+ // Move.
+ process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, 10);
+ process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, 20);
+ process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AINPUT_SOURCE_MOUSE_RELATIVE, args.source);
+ ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
+ ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
+ 10.0f, 20.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
+ ASSERT_NO_FATAL_FAILURE(assertPosition(mFakePointerController, 100.0f, 200.0f));
+
+ // Button press.
+ process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 1);
+ process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AINPUT_SOURCE_MOUSE_RELATIVE, args.source);
+ ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action);
+ ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
+ 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AINPUT_SOURCE_MOUSE_RELATIVE, args.source);
+ ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_PRESS, args.action);
+ ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
+ 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
+
+ // Button release.
+ process(mapper, ARBITRARY_TIME + 2, DEVICE_ID, EV_KEY, BTN_MOUSE, 0);
+ process(mapper, ARBITRARY_TIME + 2, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AINPUT_SOURCE_MOUSE_RELATIVE, args.source);
+ ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_RELEASE, args.action);
+ ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AINPUT_SOURCE_MOUSE_RELATIVE, args.source);
+ ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action);
+ ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
+
+ // Another move.
+ process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, 30);
+ process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, 40);
+ process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AINPUT_SOURCE_MOUSE_RELATIVE, args.source);
+ ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
+ ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
+ 30.0f, 40.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
+ ASSERT_NO_FATAL_FAILURE(assertPosition(mFakePointerController, 100.0f, 200.0f));
+
+ // Disable pointer capture and check that the device generation got bumped
+ // and events are generated the usual way.
+ const uint32_t generation = mFakeContext->getGeneration();
+ mFakePolicy->setPointerCapture(false);
+ configureDevice(InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+ ASSERT_TRUE(mFakeContext->getGeneration() != generation);
+
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
+ ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime);
+ ASSERT_EQ(DEVICE_ID, resetArgs.deviceId);
+
+ process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, 10);
+ process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, 20);
+ process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AINPUT_SOURCE_MOUSE, args.source);
ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, args.action);
ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
110.0f, 220.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));