blob: 69a75bae2f687838efb8ed756474826a293ae002 [file] [log] [blame]
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "Macros.h"
18
19#include "CursorInputMapper.h"
20
21#include "CursorButtonAccumulator.h"
22#include "CursorScrollAccumulator.h"
23#include "TouchCursorInputMapperCommon.h"
24
25namespace android {
26
27// --- CursorMotionAccumulator ---
28
29CursorMotionAccumulator::CursorMotionAccumulator() {
30 clearRelativeAxes();
31}
32
33void CursorMotionAccumulator::reset(InputDevice* device) {
34 clearRelativeAxes();
35}
36
37void CursorMotionAccumulator::clearRelativeAxes() {
38 mRelX = 0;
39 mRelY = 0;
40}
41
42void CursorMotionAccumulator::process(const RawEvent* rawEvent) {
43 if (rawEvent->type == EV_REL) {
44 switch (rawEvent->code) {
45 case REL_X:
46 mRelX = rawEvent->value;
47 break;
48 case REL_Y:
49 mRelY = rawEvent->value;
50 break;
51 }
52 }
53}
54
55void CursorMotionAccumulator::finishSync() {
56 clearRelativeAxes();
57}
58
59// --- CursorInputMapper ---
60
61CursorInputMapper::CursorInputMapper(InputDevice* device) : InputMapper(device) {}
62
63CursorInputMapper::~CursorInputMapper() {}
64
65uint32_t CursorInputMapper::getSources() {
66 return mSource;
67}
68
69void CursorInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
70 InputMapper::populateDeviceInfo(info);
71
72 if (mParameters.mode == Parameters::MODE_POINTER) {
73 float minX, minY, maxX, maxY;
74 if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) {
75 info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, minX, maxX, 0.0f, 0.0f, 0.0f);
76 info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, minY, maxY, 0.0f, 0.0f, 0.0f);
77 }
78 } else {
79 info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, -1.0f, 1.0f, 0.0f, mXScale, 0.0f);
80 info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale, 0.0f);
81 }
82 info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mSource, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f);
83
84 if (mCursorScrollAccumulator.haveRelativeVWheel()) {
85 info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
86 }
87 if (mCursorScrollAccumulator.haveRelativeHWheel()) {
88 info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
89 }
90}
91
92void CursorInputMapper::dump(std::string& dump) {
93 dump += INDENT2 "Cursor Input Mapper:\n";
94 dumpParameters(dump);
95 dump += StringPrintf(INDENT3 "XScale: %0.3f\n", mXScale);
96 dump += StringPrintf(INDENT3 "YScale: %0.3f\n", mYScale);
97 dump += StringPrintf(INDENT3 "XPrecision: %0.3f\n", mXPrecision);
98 dump += StringPrintf(INDENT3 "YPrecision: %0.3f\n", mYPrecision);
99 dump += StringPrintf(INDENT3 "HaveVWheel: %s\n",
100 toString(mCursorScrollAccumulator.haveRelativeVWheel()));
101 dump += StringPrintf(INDENT3 "HaveHWheel: %s\n",
102 toString(mCursorScrollAccumulator.haveRelativeHWheel()));
103 dump += StringPrintf(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale);
104 dump += StringPrintf(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale);
105 dump += StringPrintf(INDENT3 "Orientation: %d\n", mOrientation);
106 dump += StringPrintf(INDENT3 "ButtonState: 0x%08x\n", mButtonState);
107 dump += StringPrintf(INDENT3 "Down: %s\n", toString(isPointerDown(mButtonState)));
108 dump += StringPrintf(INDENT3 "DownTime: %" PRId64 "\n", mDownTime);
109}
110
111void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config,
112 uint32_t changes) {
113 InputMapper::configure(when, config, changes);
114
115 if (!changes) { // first time only
116 mCursorScrollAccumulator.configure(getDevice());
117
118 // Configure basic parameters.
119 configureParameters();
120
121 // Configure device mode.
122 switch (mParameters.mode) {
123 case Parameters::MODE_POINTER_RELATIVE:
124 // Should not happen during first time configuration.
125 ALOGE("Cannot start a device in MODE_POINTER_RELATIVE, starting in MODE_POINTER");
126 mParameters.mode = Parameters::MODE_POINTER;
127 [[fallthrough]];
128 case Parameters::MODE_POINTER:
129 mSource = AINPUT_SOURCE_MOUSE;
130 mXPrecision = 1.0f;
131 mYPrecision = 1.0f;
132 mXScale = 1.0f;
133 mYScale = 1.0f;
134 mPointerController = getPolicy()->obtainPointerController(getDeviceId());
135 break;
136 case Parameters::MODE_NAVIGATION:
137 mSource = AINPUT_SOURCE_TRACKBALL;
138 mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
139 mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
140 mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
141 mYScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
142 break;
143 }
144
145 mVWheelScale = 1.0f;
146 mHWheelScale = 1.0f;
147 }
148
149 if ((!changes && config->pointerCapture) ||
150 (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE)) {
151 if (config->pointerCapture) {
152 if (mParameters.mode == Parameters::MODE_POINTER) {
153 mParameters.mode = Parameters::MODE_POINTER_RELATIVE;
154 mSource = AINPUT_SOURCE_MOUSE_RELATIVE;
155 // Keep PointerController around in order to preserve the pointer position.
156 mPointerController->fade(PointerControllerInterface::TRANSITION_IMMEDIATE);
157 } else {
158 ALOGE("Cannot request pointer capture, device is not in MODE_POINTER");
159 }
160 } else {
161 if (mParameters.mode == Parameters::MODE_POINTER_RELATIVE) {
162 mParameters.mode = Parameters::MODE_POINTER;
163 mSource = AINPUT_SOURCE_MOUSE;
164 } else {
165 ALOGE("Cannot release pointer capture, device is not in MODE_POINTER_RELATIVE");
166 }
167 }
168 bumpGeneration();
169 if (changes) {
170 getDevice()->notifyReset(when);
171 }
172 }
173
174 if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) {
175 mPointerVelocityControl.setParameters(config->pointerVelocityControlParameters);
176 mWheelXVelocityControl.setParameters(config->wheelVelocityControlParameters);
177 mWheelYVelocityControl.setParameters(config->wheelVelocityControlParameters);
178 }
179
180 if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
181 mOrientation = DISPLAY_ORIENTATION_0;
182 if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
183 std::optional<DisplayViewport> internalViewport =
184 config->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL);
185 if (internalViewport) {
186 mOrientation = internalViewport->orientation;
187 }
188 }
189
190 // Update the PointerController if viewports changed.
191 if (mParameters.mode == Parameters::MODE_POINTER) {
Garfield Tan888a6a42020-01-09 11:39:16 -0800192 updatePointerControllerDisplayViewport(*config);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700193 }
194 bumpGeneration();
195 }
196}
197
Garfield Tan888a6a42020-01-09 11:39:16 -0800198void CursorInputMapper::updatePointerControllerDisplayViewport(
199 const InputReaderConfiguration& config) {
200 std::optional<DisplayViewport> viewport =
201 config.getDisplayViewportById(config.defaultPointerDisplayId);
202 if (!viewport) {
203 ALOGW("Can't find the designated viewport with ID %" PRId32 " to update cursor input "
204 "mapper. Fall back to default display",
205 config.defaultPointerDisplayId);
206 viewport = config.getDisplayViewportById(ADISPLAY_ID_DEFAULT);
207 }
208
209 if (!viewport) {
210 ALOGE("Still can't find a viable viewport to update cursor input mapper. Skip setting it to"
211 " PointerController.");
212 return;
213 }
214
215 mPointerController->setDisplayViewport(*viewport);
216}
217
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700218void CursorInputMapper::configureParameters() {
219 mParameters.mode = Parameters::MODE_POINTER;
220 String8 cursorModeString;
221 if (getDevice()->getConfiguration().tryGetProperty(String8("cursor.mode"), cursorModeString)) {
222 if (cursorModeString == "navigation") {
223 mParameters.mode = Parameters::MODE_NAVIGATION;
224 } else if (cursorModeString != "pointer" && cursorModeString != "default") {
225 ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.string());
226 }
227 }
228
229 mParameters.orientationAware = false;
230 getDevice()->getConfiguration().tryGetProperty(String8("cursor.orientationAware"),
231 mParameters.orientationAware);
232
233 mParameters.hasAssociatedDisplay = false;
234 if (mParameters.mode == Parameters::MODE_POINTER || mParameters.orientationAware) {
235 mParameters.hasAssociatedDisplay = true;
236 }
237}
238
239void CursorInputMapper::dumpParameters(std::string& dump) {
240 dump += INDENT3 "Parameters:\n";
241 dump += StringPrintf(INDENT4 "HasAssociatedDisplay: %s\n",
242 toString(mParameters.hasAssociatedDisplay));
243
244 switch (mParameters.mode) {
245 case Parameters::MODE_POINTER:
246 dump += INDENT4 "Mode: pointer\n";
247 break;
248 case Parameters::MODE_POINTER_RELATIVE:
249 dump += INDENT4 "Mode: relative pointer\n";
250 break;
251 case Parameters::MODE_NAVIGATION:
252 dump += INDENT4 "Mode: navigation\n";
253 break;
254 default:
255 ALOG_ASSERT(false);
256 }
257
258 dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware));
259}
260
261void CursorInputMapper::reset(nsecs_t when) {
262 mButtonState = 0;
263 mDownTime = 0;
264
265 mPointerVelocityControl.reset();
266 mWheelXVelocityControl.reset();
267 mWheelYVelocityControl.reset();
268
269 mCursorButtonAccumulator.reset(getDevice());
270 mCursorMotionAccumulator.reset(getDevice());
271 mCursorScrollAccumulator.reset(getDevice());
272
273 InputMapper::reset(when);
274}
275
276void CursorInputMapper::process(const RawEvent* rawEvent) {
277 mCursorButtonAccumulator.process(rawEvent);
278 mCursorMotionAccumulator.process(rawEvent);
279 mCursorScrollAccumulator.process(rawEvent);
280
281 if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
282 sync(rawEvent->when);
283 }
284}
285
286void CursorInputMapper::sync(nsecs_t when) {
287 int32_t lastButtonState = mButtonState;
288 int32_t currentButtonState = mCursorButtonAccumulator.getButtonState();
289 mButtonState = currentButtonState;
290
291 bool wasDown = isPointerDown(lastButtonState);
292 bool down = isPointerDown(currentButtonState);
293 bool downChanged;
294 if (!wasDown && down) {
295 mDownTime = when;
296 downChanged = true;
297 } else if (wasDown && !down) {
298 downChanged = true;
299 } else {
300 downChanged = false;
301 }
302 nsecs_t downTime = mDownTime;
303 bool buttonsChanged = currentButtonState != lastButtonState;
304 int32_t buttonsPressed = currentButtonState & ~lastButtonState;
305 int32_t buttonsReleased = lastButtonState & ~currentButtonState;
306
307 float deltaX = mCursorMotionAccumulator.getRelativeX() * mXScale;
308 float deltaY = mCursorMotionAccumulator.getRelativeY() * mYScale;
309 bool moved = deltaX != 0 || deltaY != 0;
310
311 // Rotate delta according to orientation if needed.
312 if (mParameters.orientationAware && mParameters.hasAssociatedDisplay &&
313 (deltaX != 0.0f || deltaY != 0.0f)) {
314 rotateDelta(mOrientation, &deltaX, &deltaY);
315 }
316
317 // Move the pointer.
318 PointerProperties pointerProperties;
319 pointerProperties.clear();
320 pointerProperties.id = 0;
321 pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_MOUSE;
322
323 PointerCoords pointerCoords;
324 pointerCoords.clear();
325
326 float vscroll = mCursorScrollAccumulator.getRelativeVWheel();
327 float hscroll = mCursorScrollAccumulator.getRelativeHWheel();
328 bool scrolled = vscroll != 0 || hscroll != 0;
329
330 mWheelYVelocityControl.move(when, nullptr, &vscroll);
331 mWheelXVelocityControl.move(when, &hscroll, nullptr);
332
333 mPointerVelocityControl.move(when, &deltaX, &deltaY);
334
335 int32_t displayId;
336 float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
337 float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
338 if (mSource == AINPUT_SOURCE_MOUSE) {
339 if (moved || scrolled || buttonsChanged) {
340 mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);
341
342 if (moved) {
343 mPointerController->move(deltaX, deltaY);
344 }
345
346 if (buttonsChanged) {
347 mPointerController->setButtonState(currentButtonState);
348 }
349
350 mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
351 }
352
353 mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
354 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition);
355 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition);
356 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
357 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
358 displayId = mPointerController->getDisplayId();
359 } else {
360 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX);
361 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY);
362 displayId = ADISPLAY_ID_NONE;
363 }
364
365 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f);
366
367 // Moving an external trackball or mouse should wake the device.
368 // We don't do this for internal cursor devices to prevent them from waking up
369 // the device in your pocket.
370 // TODO: Use the input device configuration to control this behavior more finely.
371 uint32_t policyFlags = 0;
372 if ((buttonsPressed || moved || scrolled) && getDevice()->isExternal()) {
373 policyFlags |= POLICY_FLAG_WAKE;
374 }
375
376 // Synthesize key down from buttons if needed.
377 synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource,
378 displayId, policyFlags, lastButtonState, currentButtonState);
379
380 // Send motion event.
381 if (downChanged || moved || scrolled || buttonsChanged) {
382 int32_t metaState = mContext->getGlobalMetaState();
383 int32_t buttonState = lastButtonState;
384 int32_t motionEventAction;
385 if (downChanged) {
386 motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
387 } else if (down || (mSource != AINPUT_SOURCE_MOUSE)) {
388 motionEventAction = AMOTION_EVENT_ACTION_MOVE;
389 } else {
390 motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE;
391 }
392
393 if (buttonsReleased) {
394 BitSet32 released(buttonsReleased);
395 while (!released.isEmpty()) {
396 int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit());
397 buttonState &= ~actionButton;
398 NotifyMotionArgs releaseArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
399 mSource, displayId, policyFlags,
400 AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
401 metaState, buttonState, MotionClassification::NONE,
402 AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
403 &pointerCoords, mXPrecision, mYPrecision,
404 xCursorPosition, yCursorPosition, downTime,
405 /* videoFrames */ {});
406 getListener()->notifyMotion(&releaseArgs);
407 }
408 }
409
410 NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
411 displayId, policyFlags, motionEventAction, 0, 0, metaState,
412 currentButtonState, MotionClassification::NONE,
413 AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords,
414 mXPrecision, mYPrecision, xCursorPosition, yCursorPosition, downTime,
415 /* videoFrames */ {});
416 getListener()->notifyMotion(&args);
417
418 if (buttonsPressed) {
419 BitSet32 pressed(buttonsPressed);
420 while (!pressed.isEmpty()) {
421 int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit());
422 buttonState |= actionButton;
423 NotifyMotionArgs pressArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
424 mSource, displayId, policyFlags,
425 AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0,
426 metaState, buttonState, MotionClassification::NONE,
427 AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
428 &pointerCoords, mXPrecision, mYPrecision,
429 xCursorPosition, yCursorPosition, downTime,
430 /* videoFrames */ {});
431 getListener()->notifyMotion(&pressArgs);
432 }
433 }
434
435 ALOG_ASSERT(buttonState == currentButtonState);
436
437 // Send hover move after UP to tell the application that the mouse is hovering now.
438 if (motionEventAction == AMOTION_EVENT_ACTION_UP && (mSource == AINPUT_SOURCE_MOUSE)) {
439 NotifyMotionArgs hoverArgs(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
440 displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0,
441 0, metaState, currentButtonState, MotionClassification::NONE,
442 AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
443 &pointerCoords, mXPrecision, mYPrecision, xCursorPosition,
444 yCursorPosition, downTime, /* videoFrames */ {});
445 getListener()->notifyMotion(&hoverArgs);
446 }
447
448 // Send scroll events.
449 if (scrolled) {
450 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
451 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
452
453 NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
454 mSource, displayId, policyFlags,
455 AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
456 currentButtonState, MotionClassification::NONE,
457 AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
458 &pointerCoords, mXPrecision, mYPrecision, xCursorPosition,
459 yCursorPosition, downTime, /* videoFrames */ {});
460 getListener()->notifyMotion(&scrollArgs);
461 }
462 }
463
464 // Synthesize key up from buttons if needed.
465 synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,
466 displayId, policyFlags, lastButtonState, currentButtonState);
467
468 mCursorMotionAccumulator.finishSync();
469 mCursorScrollAccumulator.finishSync();
470}
471
472int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
473 if (scanCode >= BTN_MOUSE && scanCode < BTN_JOYSTICK) {
474 return getEventHub()->getScanCodeState(getDeviceId(), scanCode);
475 } else {
476 return AKEY_STATE_UNKNOWN;
477 }
478}
479
480void CursorInputMapper::fadePointer() {
481 if (mPointerController != nullptr) {
482 mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
483 }
484}
485
486std::optional<int32_t> CursorInputMapper::getAssociatedDisplayId() {
487 if (mParameters.hasAssociatedDisplay) {
488 if (mParameters.mode == Parameters::MODE_POINTER) {
489 return std::make_optional(mPointerController->getDisplayId());
490 } else {
491 // If the device is orientationAware and not a mouse,
492 // it expects to dispatch events to any display
493 return std::make_optional(ADISPLAY_ID_NONE);
494 }
495 }
496 return std::nullopt;
497}
498
499} // namespace android