1 /*
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 "PointerControllerInterface.h"
24 #include "TouchCursorInputMapperCommon.h"
25
26 namespace android {
27
28 // --- CursorMotionAccumulator ---
29
CursorMotionAccumulator()30 CursorMotionAccumulator::CursorMotionAccumulator() {
31 clearRelativeAxes();
32 }
33
reset(InputDevice * device)34 void CursorMotionAccumulator::reset(InputDevice* device) {
35 clearRelativeAxes();
36 }
37
clearRelativeAxes()38 void CursorMotionAccumulator::clearRelativeAxes() {
39 mRelX = 0;
40 mRelY = 0;
41 }
42
process(const RawEvent * rawEvent)43 void CursorMotionAccumulator::process(const RawEvent* rawEvent) {
44 if (rawEvent->type == EV_REL) {
45 switch (rawEvent->code) {
46 case REL_X:
47 mRelX = rawEvent->value;
48 break;
49 case REL_Y:
50 mRelY = rawEvent->value;
51 break;
52 }
53 }
54 }
55
finishSync()56 void CursorMotionAccumulator::finishSync() {
57 clearRelativeAxes();
58 }
59
60 // --- CursorInputMapper ---
61
CursorInputMapper(InputDevice * device)62 CursorInputMapper::CursorInputMapper(InputDevice* device) : InputMapper(device) {}
63
~CursorInputMapper()64 CursorInputMapper::~CursorInputMapper() {}
65
getSources()66 uint32_t CursorInputMapper::getSources() {
67 return mSource;
68 }
69
populateDeviceInfo(InputDeviceInfo * info)70 void CursorInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
71 InputMapper::populateDeviceInfo(info);
72
73 if (mParameters.mode == Parameters::MODE_POINTER) {
74 float minX, minY, maxX, maxY;
75 if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) {
76 info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, minX, maxX, 0.0f, 0.0f, 0.0f);
77 info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, minY, maxY, 0.0f, 0.0f, 0.0f);
78 }
79 } else {
80 info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, -1.0f, 1.0f, 0.0f, mXScale, 0.0f);
81 info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale, 0.0f);
82 }
83 info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mSource, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f);
84
85 if (mCursorScrollAccumulator.haveRelativeVWheel()) {
86 info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
87 }
88 if (mCursorScrollAccumulator.haveRelativeHWheel()) {
89 info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
90 }
91 }
92
dump(std::string & dump)93 void CursorInputMapper::dump(std::string& dump) {
94 dump += INDENT2 "Cursor Input Mapper:\n";
95 dumpParameters(dump);
96 dump += StringPrintf(INDENT3 "XScale: %0.3f\n", mXScale);
97 dump += StringPrintf(INDENT3 "YScale: %0.3f\n", mYScale);
98 dump += StringPrintf(INDENT3 "XPrecision: %0.3f\n", mXPrecision);
99 dump += StringPrintf(INDENT3 "YPrecision: %0.3f\n", mYPrecision);
100 dump += StringPrintf(INDENT3 "HaveVWheel: %s\n",
101 toString(mCursorScrollAccumulator.haveRelativeVWheel()));
102 dump += StringPrintf(INDENT3 "HaveHWheel: %s\n",
103 toString(mCursorScrollAccumulator.haveRelativeHWheel()));
104 dump += StringPrintf(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale);
105 dump += StringPrintf(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale);
106 dump += StringPrintf(INDENT3 "Orientation: %d\n", mOrientation);
107 dump += StringPrintf(INDENT3 "ButtonState: 0x%08x\n", mButtonState);
108 dump += StringPrintf(INDENT3 "Down: %s\n", toString(isPointerDown(mButtonState)));
109 dump += StringPrintf(INDENT3 "DownTime: %" PRId64 "\n", mDownTime);
110 }
111
configure(nsecs_t when,const InputReaderConfiguration * config,uint32_t changes)112 void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config,
113 uint32_t changes) {
114 InputMapper::configure(when, config, changes);
115
116 if (!changes) { // first time only
117 mCursorScrollAccumulator.configure(getDevice());
118
119 // Configure basic parameters.
120 configureParameters();
121
122 // Configure device mode.
123 switch (mParameters.mode) {
124 case Parameters::MODE_POINTER_RELATIVE:
125 // Should not happen during first time configuration.
126 ALOGE("Cannot start a device in MODE_POINTER_RELATIVE, starting in MODE_POINTER");
127 mParameters.mode = Parameters::MODE_POINTER;
128 [[fallthrough]];
129 case Parameters::MODE_POINTER:
130 mSource = AINPUT_SOURCE_MOUSE;
131 mXPrecision = 1.0f;
132 mYPrecision = 1.0f;
133 mXScale = 1.0f;
134 mYScale = 1.0f;
135 mPointerController = getPolicy()->obtainPointerController(getDeviceId());
136 break;
137 case Parameters::MODE_NAVIGATION:
138 mSource = AINPUT_SOURCE_TRACKBALL;
139 mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
140 mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
141 mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
142 mYScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
143 break;
144 }
145
146 mVWheelScale = 1.0f;
147 mHWheelScale = 1.0f;
148 }
149
150 if ((!changes && config->pointerCapture) ||
151 (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE)) {
152 if (config->pointerCapture) {
153 if (mParameters.mode == Parameters::MODE_POINTER) {
154 mParameters.mode = Parameters::MODE_POINTER_RELATIVE;
155 mSource = AINPUT_SOURCE_MOUSE_RELATIVE;
156 // Keep PointerController around in order to preserve the pointer position.
157 mPointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
158 } else {
159 ALOGE("Cannot request pointer capture, device is not in MODE_POINTER");
160 }
161 } else {
162 if (mParameters.mode == Parameters::MODE_POINTER_RELATIVE) {
163 mParameters.mode = Parameters::MODE_POINTER;
164 mSource = AINPUT_SOURCE_MOUSE;
165 } else {
166 ALOGE("Cannot release pointer capture, device is not in MODE_POINTER_RELATIVE");
167 }
168 }
169 bumpGeneration();
170 if (changes) {
171 getDevice()->notifyReset(when);
172 }
173 }
174
175 if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) {
176 mPointerVelocityControl.setParameters(config->pointerVelocityControlParameters);
177 mWheelXVelocityControl.setParameters(config->wheelVelocityControlParameters);
178 mWheelYVelocityControl.setParameters(config->wheelVelocityControlParameters);
179 }
180
181 if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
182 mOrientation = DISPLAY_ORIENTATION_0;
183 if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
184 std::optional<DisplayViewport> internalViewport =
185 config->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL);
186 if (internalViewport) {
187 mOrientation = internalViewport->orientation;
188 }
189 }
190
191 // Update the PointerController if viewports changed.
192 if (mParameters.mode == Parameters::MODE_POINTER) {
193 updatePointerControllerDisplayViewport(*config);
194 }
195 bumpGeneration();
196 }
197 }
198
updatePointerControllerDisplayViewport(const InputReaderConfiguration & config)199 void CursorInputMapper::updatePointerControllerDisplayViewport(
200 const InputReaderConfiguration& config) {
201 std::optional<DisplayViewport> viewport =
202 config.getDisplayViewportById(config.defaultPointerDisplayId);
203 if (!viewport) {
204 ALOGW("Can't find the designated viewport with ID %" PRId32 " to update cursor input "
205 "mapper. Fall back to default display",
206 config.defaultPointerDisplayId);
207 viewport = config.getDisplayViewportById(ADISPLAY_ID_DEFAULT);
208 }
209
210 if (!viewport) {
211 ALOGE("Still can't find a viable viewport to update cursor input mapper. Skip setting it to"
212 " PointerController.");
213 return;
214 }
215
216 mPointerController->setDisplayViewport(*viewport);
217 }
218
configureParameters()219 void CursorInputMapper::configureParameters() {
220 mParameters.mode = Parameters::MODE_POINTER;
221 String8 cursorModeString;
222 if (getDevice()->getConfiguration().tryGetProperty(String8("cursor.mode"), cursorModeString)) {
223 if (cursorModeString == "navigation") {
224 mParameters.mode = Parameters::MODE_NAVIGATION;
225 } else if (cursorModeString != "pointer" && cursorModeString != "default") {
226 ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.string());
227 }
228 }
229
230 mParameters.orientationAware = false;
231 getDevice()->getConfiguration().tryGetProperty(String8("cursor.orientationAware"),
232 mParameters.orientationAware);
233
234 mParameters.hasAssociatedDisplay = false;
235 if (mParameters.mode == Parameters::MODE_POINTER || mParameters.orientationAware) {
236 mParameters.hasAssociatedDisplay = true;
237 }
238 }
239
dumpParameters(std::string & dump)240 void CursorInputMapper::dumpParameters(std::string& dump) {
241 dump += INDENT3 "Parameters:\n";
242 dump += StringPrintf(INDENT4 "HasAssociatedDisplay: %s\n",
243 toString(mParameters.hasAssociatedDisplay));
244
245 switch (mParameters.mode) {
246 case Parameters::MODE_POINTER:
247 dump += INDENT4 "Mode: pointer\n";
248 break;
249 case Parameters::MODE_POINTER_RELATIVE:
250 dump += INDENT4 "Mode: relative pointer\n";
251 break;
252 case Parameters::MODE_NAVIGATION:
253 dump += INDENT4 "Mode: navigation\n";
254 break;
255 default:
256 ALOG_ASSERT(false);
257 }
258
259 dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware));
260 }
261
reset(nsecs_t when)262 void CursorInputMapper::reset(nsecs_t when) {
263 mButtonState = 0;
264 mDownTime = 0;
265
266 mPointerVelocityControl.reset();
267 mWheelXVelocityControl.reset();
268 mWheelYVelocityControl.reset();
269
270 mCursorButtonAccumulator.reset(getDevice());
271 mCursorMotionAccumulator.reset(getDevice());
272 mCursorScrollAccumulator.reset(getDevice());
273
274 InputMapper::reset(when);
275 }
276
process(const RawEvent * rawEvent)277 void CursorInputMapper::process(const RawEvent* rawEvent) {
278 mCursorButtonAccumulator.process(rawEvent);
279 mCursorMotionAccumulator.process(rawEvent);
280 mCursorScrollAccumulator.process(rawEvent);
281
282 if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
283 sync(rawEvent->when);
284 }
285 }
286
sync(nsecs_t when)287 void CursorInputMapper::sync(nsecs_t when) {
288 int32_t lastButtonState = mButtonState;
289 int32_t currentButtonState = mCursorButtonAccumulator.getButtonState();
290 mButtonState = currentButtonState;
291
292 bool wasDown = isPointerDown(lastButtonState);
293 bool down = isPointerDown(currentButtonState);
294 bool downChanged;
295 if (!wasDown && down) {
296 mDownTime = when;
297 downChanged = true;
298 } else if (wasDown && !down) {
299 downChanged = true;
300 } else {
301 downChanged = false;
302 }
303 nsecs_t downTime = mDownTime;
304 bool buttonsChanged = currentButtonState != lastButtonState;
305 int32_t buttonsPressed = currentButtonState & ~lastButtonState;
306 int32_t buttonsReleased = lastButtonState & ~currentButtonState;
307
308 float deltaX = mCursorMotionAccumulator.getRelativeX() * mXScale;
309 float deltaY = mCursorMotionAccumulator.getRelativeY() * mYScale;
310 bool moved = deltaX != 0 || deltaY != 0;
311
312 // Rotate delta according to orientation if needed.
313 if (mParameters.orientationAware && mParameters.hasAssociatedDisplay &&
314 (deltaX != 0.0f || deltaY != 0.0f)) {
315 rotateDelta(mOrientation, &deltaX, &deltaY);
316 }
317
318 // Move the pointer.
319 PointerProperties pointerProperties;
320 pointerProperties.clear();
321 pointerProperties.id = 0;
322 pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_MOUSE;
323
324 PointerCoords pointerCoords;
325 pointerCoords.clear();
326
327 float vscroll = mCursorScrollAccumulator.getRelativeVWheel();
328 float hscroll = mCursorScrollAccumulator.getRelativeHWheel();
329 bool scrolled = vscroll != 0 || hscroll != 0;
330
331 mWheelYVelocityControl.move(when, nullptr, &vscroll);
332 mWheelXVelocityControl.move(when, &hscroll, nullptr);
333
334 mPointerVelocityControl.move(when, &deltaX, &deltaY);
335
336 int32_t displayId;
337 if (mSource == AINPUT_SOURCE_MOUSE) {
338 if (moved || scrolled || buttonsChanged) {
339 mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER);
340
341 if (moved) {
342 mPointerController->move(deltaX, deltaY);
343 }
344
345 if (buttonsChanged) {
346 mPointerController->setButtonState(currentButtonState);
347 }
348
349 mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
350 }
351
352 float x, y;
353 mPointerController->getPosition(&x, &y);
354 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
355 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
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,
403 /* deviceTimestamp */ 0, 1, &pointerProperties,
404 &pointerCoords, mXPrecision, mYPrecision, 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,
414 /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
415 mXPrecision, mYPrecision, downTime, /* 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,
428 /* deviceTimestamp */ 0, 1, &pointerProperties,
429 &pointerCoords, mXPrecision, mYPrecision, 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,
443 /* deviceTimestamp */ 0, 1, &pointerProperties,
444 &pointerCoords, mXPrecision, mYPrecision, downTime,
445 /* videoFrames */ {});
446 getListener()->notifyMotion(&hoverArgs);
447 }
448
449 // Send scroll events.
450 if (scrolled) {
451 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
452 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
453
454 NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
455 mSource, displayId, policyFlags,
456 AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
457 currentButtonState, MotionClassification::NONE,
458 AMOTION_EVENT_EDGE_FLAG_NONE,
459 /* deviceTimestamp */ 0, 1, &pointerProperties,
460 &pointerCoords, mXPrecision, mYPrecision, downTime,
461 /* videoFrames */ {});
462 getListener()->notifyMotion(&scrollArgs);
463 }
464 }
465
466 // Synthesize key up from buttons if needed.
467 synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,
468 displayId, policyFlags, lastButtonState, currentButtonState);
469
470 mCursorMotionAccumulator.finishSync();
471 mCursorScrollAccumulator.finishSync();
472 }
473
getScanCodeState(uint32_t sourceMask,int32_t scanCode)474 int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
475 if (scanCode >= BTN_MOUSE && scanCode < BTN_JOYSTICK) {
476 return getEventHub()->getScanCodeState(getDeviceId(), scanCode);
477 } else {
478 return AKEY_STATE_UNKNOWN;
479 }
480 }
481
fadePointer()482 void CursorInputMapper::fadePointer() {
483 if (mPointerController != nullptr) {
484 mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
485 }
486 }
487
getAssociatedDisplay()488 std::optional<int32_t> CursorInputMapper::getAssociatedDisplay() {
489 if (mParameters.hasAssociatedDisplay) {
490 if (mParameters.mode == Parameters::MODE_POINTER) {
491 return std::make_optional(mPointerController->getDisplayId());
492 } else {
493 // If the device is orientationAware and not a mouse,
494 // it expects to dispatch events to any display
495 return std::make_optional(ADISPLAY_ID_NONE);
496 }
497 }
498 return std::nullopt;
499 }
500
501 } // namespace android
502