blob: c74987dfec9752904fe064b9e7598ed0835f9c0d [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
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -080033void CursorMotionAccumulator::reset(InputDeviceContext& deviceContext) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -070034 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
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -080061CursorInputMapper::CursorInputMapper(InputDeviceContext& deviceContext)
62 : InputMapper(deviceContext) {}
Prabir Pradhanbaa5c822019-08-30 15:27:05 -070063
64CursorInputMapper::~CursorInputMapper() {}
65
66uint32_t CursorInputMapper::getSources() {
67 return mSource;
68}
69
70void 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
93void 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
112void 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
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800117 mCursorScrollAccumulator.configure(getDeviceContext());
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700118
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;
Prabir Pradhanc7ef27e2020-02-03 19:19:15 -0800135 mPointerController = getContext()->getPointerController(getDeviceId());
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700136 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) {
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800171 NotifyDeviceResetArgs args(getContext()->getNextSequenceNum(), when, getDeviceId());
172 getListener()->notifyDeviceReset(&args);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700173 }
174 }
175
176 if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) {
177 mPointerVelocityControl.setParameters(config->pointerVelocityControlParameters);
178 mWheelXVelocityControl.setParameters(config->wheelVelocityControlParameters);
179 mWheelYVelocityControl.setParameters(config->wheelVelocityControlParameters);
180 }
181
182 if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
183 mOrientation = DISPLAY_ORIENTATION_0;
184 if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
185 std::optional<DisplayViewport> internalViewport =
186 config->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL);
187 if (internalViewport) {
188 mOrientation = internalViewport->orientation;
189 }
190 }
191
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700192 bumpGeneration();
193 }
194}
195
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700196void CursorInputMapper::configureParameters() {
197 mParameters.mode = Parameters::MODE_POINTER;
198 String8 cursorModeString;
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800199 if (getDeviceContext().getConfiguration().tryGetProperty(String8("cursor.mode"),
200 cursorModeString)) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700201 if (cursorModeString == "navigation") {
202 mParameters.mode = Parameters::MODE_NAVIGATION;
203 } else if (cursorModeString != "pointer" && cursorModeString != "default") {
204 ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.string());
205 }
206 }
207
208 mParameters.orientationAware = false;
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800209 getDeviceContext().getConfiguration().tryGetProperty(String8("cursor.orientationAware"),
210 mParameters.orientationAware);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700211
212 mParameters.hasAssociatedDisplay = false;
213 if (mParameters.mode == Parameters::MODE_POINTER || mParameters.orientationAware) {
214 mParameters.hasAssociatedDisplay = true;
215 }
216}
217
218void CursorInputMapper::dumpParameters(std::string& dump) {
219 dump += INDENT3 "Parameters:\n";
220 dump += StringPrintf(INDENT4 "HasAssociatedDisplay: %s\n",
221 toString(mParameters.hasAssociatedDisplay));
222
223 switch (mParameters.mode) {
224 case Parameters::MODE_POINTER:
225 dump += INDENT4 "Mode: pointer\n";
226 break;
227 case Parameters::MODE_POINTER_RELATIVE:
228 dump += INDENT4 "Mode: relative pointer\n";
229 break;
230 case Parameters::MODE_NAVIGATION:
231 dump += INDENT4 "Mode: navigation\n";
232 break;
233 default:
234 ALOG_ASSERT(false);
235 }
236
237 dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware));
238}
239
240void CursorInputMapper::reset(nsecs_t when) {
241 mButtonState = 0;
242 mDownTime = 0;
243
244 mPointerVelocityControl.reset();
245 mWheelXVelocityControl.reset();
246 mWheelYVelocityControl.reset();
247
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800248 mCursorButtonAccumulator.reset(getDeviceContext());
249 mCursorMotionAccumulator.reset(getDeviceContext());
250 mCursorScrollAccumulator.reset(getDeviceContext());
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700251
252 InputMapper::reset(when);
253}
254
255void CursorInputMapper::process(const RawEvent* rawEvent) {
256 mCursorButtonAccumulator.process(rawEvent);
257 mCursorMotionAccumulator.process(rawEvent);
258 mCursorScrollAccumulator.process(rawEvent);
259
260 if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
261 sync(rawEvent->when);
262 }
263}
264
265void CursorInputMapper::sync(nsecs_t when) {
266 int32_t lastButtonState = mButtonState;
267 int32_t currentButtonState = mCursorButtonAccumulator.getButtonState();
268 mButtonState = currentButtonState;
269
270 bool wasDown = isPointerDown(lastButtonState);
271 bool down = isPointerDown(currentButtonState);
272 bool downChanged;
273 if (!wasDown && down) {
274 mDownTime = when;
275 downChanged = true;
276 } else if (wasDown && !down) {
277 downChanged = true;
278 } else {
279 downChanged = false;
280 }
281 nsecs_t downTime = mDownTime;
282 bool buttonsChanged = currentButtonState != lastButtonState;
283 int32_t buttonsPressed = currentButtonState & ~lastButtonState;
284 int32_t buttonsReleased = lastButtonState & ~currentButtonState;
285
286 float deltaX = mCursorMotionAccumulator.getRelativeX() * mXScale;
287 float deltaY = mCursorMotionAccumulator.getRelativeY() * mYScale;
288 bool moved = deltaX != 0 || deltaY != 0;
289
290 // Rotate delta according to orientation if needed.
291 if (mParameters.orientationAware && mParameters.hasAssociatedDisplay &&
292 (deltaX != 0.0f || deltaY != 0.0f)) {
293 rotateDelta(mOrientation, &deltaX, &deltaY);
294 }
295
296 // Move the pointer.
297 PointerProperties pointerProperties;
298 pointerProperties.clear();
299 pointerProperties.id = 0;
300 pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_MOUSE;
301
302 PointerCoords pointerCoords;
303 pointerCoords.clear();
304
305 float vscroll = mCursorScrollAccumulator.getRelativeVWheel();
306 float hscroll = mCursorScrollAccumulator.getRelativeHWheel();
307 bool scrolled = vscroll != 0 || hscroll != 0;
308
309 mWheelYVelocityControl.move(when, nullptr, &vscroll);
310 mWheelXVelocityControl.move(when, &hscroll, nullptr);
311
312 mPointerVelocityControl.move(when, &deltaX, &deltaY);
313
314 int32_t displayId;
315 float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
316 float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
317 if (mSource == AINPUT_SOURCE_MOUSE) {
318 if (moved || scrolled || buttonsChanged) {
319 mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);
320
321 if (moved) {
322 mPointerController->move(deltaX, deltaY);
323 }
324
325 if (buttonsChanged) {
326 mPointerController->setButtonState(currentButtonState);
327 }
328
329 mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
330 }
331
332 mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
333 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition);
334 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition);
335 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
336 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
337 displayId = mPointerController->getDisplayId();
338 } else {
339 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX);
340 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY);
341 displayId = ADISPLAY_ID_NONE;
342 }
343
344 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f);
345
346 // Moving an external trackball or mouse should wake the device.
347 // We don't do this for internal cursor devices to prevent them from waking up
348 // the device in your pocket.
349 // TODO: Use the input device configuration to control this behavior more finely.
350 uint32_t policyFlags = 0;
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800351 if ((buttonsPressed || moved || scrolled) && getDeviceContext().isExternal()) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700352 policyFlags |= POLICY_FLAG_WAKE;
353 }
354
355 // Synthesize key down from buttons if needed.
356 synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource,
357 displayId, policyFlags, lastButtonState, currentButtonState);
358
359 // Send motion event.
360 if (downChanged || moved || scrolled || buttonsChanged) {
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800361 int32_t metaState = getContext()->getGlobalMetaState();
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700362 int32_t buttonState = lastButtonState;
363 int32_t motionEventAction;
364 if (downChanged) {
365 motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
366 } else if (down || (mSource != AINPUT_SOURCE_MOUSE)) {
367 motionEventAction = AMOTION_EVENT_ACTION_MOVE;
368 } else {
369 motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE;
370 }
371
372 if (buttonsReleased) {
373 BitSet32 released(buttonsReleased);
374 while (!released.isEmpty()) {
375 int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit());
376 buttonState &= ~actionButton;
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800377 NotifyMotionArgs releaseArgs(getContext()->getNextSequenceNum(), when,
378 getDeviceId(), mSource, displayId, policyFlags,
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700379 AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
380 metaState, buttonState, MotionClassification::NONE,
381 AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
382 &pointerCoords, mXPrecision, mYPrecision,
383 xCursorPosition, yCursorPosition, downTime,
384 /* videoFrames */ {});
385 getListener()->notifyMotion(&releaseArgs);
386 }
387 }
388
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800389 NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource,
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700390 displayId, policyFlags, motionEventAction, 0, 0, metaState,
391 currentButtonState, MotionClassification::NONE,
392 AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords,
393 mXPrecision, mYPrecision, xCursorPosition, yCursorPosition, downTime,
394 /* videoFrames */ {});
395 getListener()->notifyMotion(&args);
396
397 if (buttonsPressed) {
398 BitSet32 pressed(buttonsPressed);
399 while (!pressed.isEmpty()) {
400 int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit());
401 buttonState |= actionButton;
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800402 NotifyMotionArgs pressArgs(getContext()->getNextSequenceNum(), when, getDeviceId(),
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700403 mSource, displayId, policyFlags,
404 AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0,
405 metaState, buttonState, MotionClassification::NONE,
406 AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
407 &pointerCoords, mXPrecision, mYPrecision,
408 xCursorPosition, yCursorPosition, downTime,
409 /* videoFrames */ {});
410 getListener()->notifyMotion(&pressArgs);
411 }
412 }
413
414 ALOG_ASSERT(buttonState == currentButtonState);
415
416 // Send hover move after UP to tell the application that the mouse is hovering now.
417 if (motionEventAction == AMOTION_EVENT_ACTION_UP && (mSource == AINPUT_SOURCE_MOUSE)) {
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800418 NotifyMotionArgs hoverArgs(getContext()->getNextSequenceNum(), when, getDeviceId(),
419 mSource, displayId, policyFlags,
420 AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
421 currentButtonState, MotionClassification::NONE,
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700422 AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
423 &pointerCoords, mXPrecision, mYPrecision, xCursorPosition,
424 yCursorPosition, downTime, /* videoFrames */ {});
425 getListener()->notifyMotion(&hoverArgs);
426 }
427
428 // Send scroll events.
429 if (scrolled) {
430 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
431 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
432
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800433 NotifyMotionArgs scrollArgs(getContext()->getNextSequenceNum(), when, getDeviceId(),
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700434 mSource, displayId, policyFlags,
435 AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
436 currentButtonState, MotionClassification::NONE,
437 AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
438 &pointerCoords, mXPrecision, mYPrecision, xCursorPosition,
439 yCursorPosition, downTime, /* videoFrames */ {});
440 getListener()->notifyMotion(&scrollArgs);
441 }
442 }
443
444 // Synthesize key up from buttons if needed.
445 synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,
446 displayId, policyFlags, lastButtonState, currentButtonState);
447
448 mCursorMotionAccumulator.finishSync();
449 mCursorScrollAccumulator.finishSync();
450}
451
452int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
453 if (scanCode >= BTN_MOUSE && scanCode < BTN_JOYSTICK) {
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800454 return getDeviceContext().getScanCodeState(scanCode);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700455 } else {
456 return AKEY_STATE_UNKNOWN;
457 }
458}
459
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700460std::optional<int32_t> CursorInputMapper::getAssociatedDisplayId() {
461 if (mParameters.hasAssociatedDisplay) {
462 if (mParameters.mode == Parameters::MODE_POINTER) {
463 return std::make_optional(mPointerController->getDisplayId());
464 } else {
465 // If the device is orientationAware and not a mouse,
466 // it expects to dispatch events to any display
467 return std::make_optional(ADISPLAY_ID_NONE);
468 }
469 }
470 return std::nullopt;
471}
472
473} // namespace android