• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // clang-format off
18 #include "../Macros.h"
19 // clang-format on
20 
21 #include "CursorInputMapper.h"
22 
23 #include "CursorButtonAccumulator.h"
24 #include "CursorScrollAccumulator.h"
25 #include "PointerControllerInterface.h"
26 #include "TouchCursorInputMapperCommon.h"
27 
28 namespace android {
29 
30 // --- CursorMotionAccumulator ---
31 
CursorMotionAccumulator()32 CursorMotionAccumulator::CursorMotionAccumulator() {
33     clearRelativeAxes();
34 }
35 
reset(InputDeviceContext & deviceContext)36 void CursorMotionAccumulator::reset(InputDeviceContext& deviceContext) {
37     clearRelativeAxes();
38 }
39 
clearRelativeAxes()40 void CursorMotionAccumulator::clearRelativeAxes() {
41     mRelX = 0;
42     mRelY = 0;
43 }
44 
process(const RawEvent * rawEvent)45 void CursorMotionAccumulator::process(const RawEvent* rawEvent) {
46     if (rawEvent->type == EV_REL) {
47         switch (rawEvent->code) {
48             case REL_X:
49                 mRelX = rawEvent->value;
50                 break;
51             case REL_Y:
52                 mRelY = rawEvent->value;
53                 break;
54         }
55     }
56 }
57 
finishSync()58 void CursorMotionAccumulator::finishSync() {
59     clearRelativeAxes();
60 }
61 
62 // --- CursorInputMapper ---
63 
CursorInputMapper(InputDeviceContext & deviceContext)64 CursorInputMapper::CursorInputMapper(InputDeviceContext& deviceContext)
65       : InputMapper(deviceContext) {}
66 
~CursorInputMapper()67 CursorInputMapper::~CursorInputMapper() {}
68 
getSources()69 uint32_t CursorInputMapper::getSources() {
70     return mSource;
71 }
72 
populateDeviceInfo(InputDeviceInfo * info)73 void CursorInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
74     InputMapper::populateDeviceInfo(info);
75 
76     if (mParameters.mode == Parameters::MODE_POINTER) {
77         float minX, minY, maxX, maxY;
78         if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) {
79             info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, minX, maxX, 0.0f, 0.0f, 0.0f);
80             info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, minY, maxY, 0.0f, 0.0f, 0.0f);
81         }
82     } else {
83         info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, -1.0f, 1.0f, 0.0f, mXScale, 0.0f);
84         info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale, 0.0f);
85         info->addMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, mSource, -1.0f, 1.0f, 0.0f, mXScale,
86                              0.0f);
87         info->addMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale,
88                              0.0f);
89     }
90     info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mSource, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f);
91 
92     if (mCursorScrollAccumulator.haveRelativeVWheel()) {
93         info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
94     }
95     if (mCursorScrollAccumulator.haveRelativeHWheel()) {
96         info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
97     }
98 }
99 
dump(std::string & dump)100 void CursorInputMapper::dump(std::string& dump) {
101     dump += INDENT2 "Cursor Input Mapper:\n";
102     dumpParameters(dump);
103     dump += StringPrintf(INDENT3 "XScale: %0.3f\n", mXScale);
104     dump += StringPrintf(INDENT3 "YScale: %0.3f\n", mYScale);
105     dump += StringPrintf(INDENT3 "XPrecision: %0.3f\n", mXPrecision);
106     dump += StringPrintf(INDENT3 "YPrecision: %0.3f\n", mYPrecision);
107     dump += StringPrintf(INDENT3 "HaveVWheel: %s\n",
108                          toString(mCursorScrollAccumulator.haveRelativeVWheel()));
109     dump += StringPrintf(INDENT3 "HaveHWheel: %s\n",
110                          toString(mCursorScrollAccumulator.haveRelativeHWheel()));
111     dump += StringPrintf(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale);
112     dump += StringPrintf(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale);
113     dump += StringPrintf(INDENT3 "Orientation: %d\n", mOrientation);
114     dump += StringPrintf(INDENT3 "ButtonState: 0x%08x\n", mButtonState);
115     dump += StringPrintf(INDENT3 "Down: %s\n", toString(isPointerDown(mButtonState)));
116     dump += StringPrintf(INDENT3 "DownTime: %" PRId64 "\n", mDownTime);
117 }
118 
configure(nsecs_t when,const InputReaderConfiguration * config,uint32_t changes)119 void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config,
120                                   uint32_t changes) {
121     InputMapper::configure(when, config, changes);
122 
123     if (!changes) { // first time only
124         mCursorScrollAccumulator.configure(getDeviceContext());
125 
126         // Configure basic parameters.
127         configureParameters();
128 
129         // Configure device mode.
130         switch (mParameters.mode) {
131             case Parameters::MODE_POINTER_RELATIVE:
132                 // Should not happen during first time configuration.
133                 ALOGE("Cannot start a device in MODE_POINTER_RELATIVE, starting in MODE_POINTER");
134                 mParameters.mode = Parameters::MODE_POINTER;
135                 [[fallthrough]];
136             case Parameters::MODE_POINTER:
137                 mSource = AINPUT_SOURCE_MOUSE;
138                 mXPrecision = 1.0f;
139                 mYPrecision = 1.0f;
140                 mXScale = 1.0f;
141                 mYScale = 1.0f;
142                 mPointerController = getContext()->getPointerController(getDeviceId());
143                 break;
144             case Parameters::MODE_NAVIGATION:
145                 mSource = AINPUT_SOURCE_TRACKBALL;
146                 mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
147                 mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
148                 mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
149                 mYScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
150                 break;
151         }
152 
153         mVWheelScale = 1.0f;
154         mHWheelScale = 1.0f;
155     }
156 
157     if ((!changes && config->pointerCapture) ||
158         (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE)) {
159         if (config->pointerCapture) {
160             if (mParameters.mode == Parameters::MODE_POINTER) {
161                 mParameters.mode = Parameters::MODE_POINTER_RELATIVE;
162                 mSource = AINPUT_SOURCE_MOUSE_RELATIVE;
163                 // Keep PointerController around in order to preserve the pointer position.
164                 mPointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
165             } else {
166                 ALOGE("Cannot request pointer capture, device is not in MODE_POINTER");
167             }
168         } else {
169             if (mParameters.mode == Parameters::MODE_POINTER_RELATIVE) {
170                 mParameters.mode = Parameters::MODE_POINTER;
171                 mSource = AINPUT_SOURCE_MOUSE;
172             } else {
173                 ALOGE("Cannot release pointer capture, device is not in MODE_POINTER_RELATIVE");
174             }
175         }
176         bumpGeneration();
177         if (changes) {
178             NotifyDeviceResetArgs args(getContext()->getNextId(), when, getDeviceId());
179             getListener()->notifyDeviceReset(&args);
180         }
181     }
182 
183     if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) {
184         mPointerVelocityControl.setParameters(config->pointerVelocityControlParameters);
185         mWheelXVelocityControl.setParameters(config->wheelVelocityControlParameters);
186         mWheelYVelocityControl.setParameters(config->wheelVelocityControlParameters);
187     }
188 
189     if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
190         mOrientation = DISPLAY_ORIENTATION_0;
191         mDisplayWidth = 0;
192         mDisplayHeight = 0;
193         const bool isOrientedDevice =
194                 (mParameters.orientationAware && mParameters.hasAssociatedDisplay);
195 
196         if (isPerWindowInputRotationEnabled()) {
197             // When per-window input rotation is enabled, InputReader works in the un-rotated
198             // coordinate space, so we don't need to do anything if the device is already
199             // orientation-aware. If the device is not orientation-aware, then we need to apply the
200             // inverse rotation of the display so that when the display rotation is applied later
201             // as a part of the per-window transform, we get the expected screen coordinates.
202             if (!isOrientedDevice) {
203                 std::optional<DisplayViewport> internalViewport =
204                         config->getDisplayViewportByType(ViewportType::INTERNAL);
205                 if (internalViewport) {
206                     mOrientation = getInverseRotation(internalViewport->orientation);
207                     mDisplayWidth = internalViewport->deviceWidth;
208                     mDisplayHeight = internalViewport->deviceHeight;
209                 }
210             }
211         } else {
212             if (isOrientedDevice) {
213                 std::optional<DisplayViewport> internalViewport =
214                         config->getDisplayViewportByType(ViewportType::INTERNAL);
215                 if (internalViewport) {
216                     mOrientation = internalViewport->orientation;
217                 }
218             }
219         }
220 
221         bumpGeneration();
222     }
223 }
224 
configureParameters()225 void CursorInputMapper::configureParameters() {
226     mParameters.mode = Parameters::MODE_POINTER;
227     String8 cursorModeString;
228     if (getDeviceContext().getConfiguration().tryGetProperty(String8("cursor.mode"),
229                                                              cursorModeString)) {
230         if (cursorModeString == "navigation") {
231             mParameters.mode = Parameters::MODE_NAVIGATION;
232         } else if (cursorModeString != "pointer" && cursorModeString != "default") {
233             ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.string());
234         }
235     }
236 
237     mParameters.orientationAware = false;
238     getDeviceContext().getConfiguration().tryGetProperty(String8("cursor.orientationAware"),
239                                                          mParameters.orientationAware);
240 
241     mParameters.hasAssociatedDisplay = false;
242     if (mParameters.mode == Parameters::MODE_POINTER || mParameters.orientationAware) {
243         mParameters.hasAssociatedDisplay = true;
244     }
245 }
246 
dumpParameters(std::string & dump)247 void CursorInputMapper::dumpParameters(std::string& dump) {
248     dump += INDENT3 "Parameters:\n";
249     dump += StringPrintf(INDENT4 "HasAssociatedDisplay: %s\n",
250                          toString(mParameters.hasAssociatedDisplay));
251 
252     switch (mParameters.mode) {
253         case Parameters::MODE_POINTER:
254             dump += INDENT4 "Mode: pointer\n";
255             break;
256         case Parameters::MODE_POINTER_RELATIVE:
257             dump += INDENT4 "Mode: relative pointer\n";
258             break;
259         case Parameters::MODE_NAVIGATION:
260             dump += INDENT4 "Mode: navigation\n";
261             break;
262         default:
263             ALOG_ASSERT(false);
264     }
265 
266     dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware));
267 }
268 
reset(nsecs_t when)269 void CursorInputMapper::reset(nsecs_t when) {
270     mButtonState = 0;
271     mDownTime = 0;
272 
273     mPointerVelocityControl.reset();
274     mWheelXVelocityControl.reset();
275     mWheelYVelocityControl.reset();
276 
277     mCursorButtonAccumulator.reset(getDeviceContext());
278     mCursorMotionAccumulator.reset(getDeviceContext());
279     mCursorScrollAccumulator.reset(getDeviceContext());
280 
281     InputMapper::reset(when);
282 }
283 
process(const RawEvent * rawEvent)284 void CursorInputMapper::process(const RawEvent* rawEvent) {
285     mCursorButtonAccumulator.process(rawEvent);
286     mCursorMotionAccumulator.process(rawEvent);
287     mCursorScrollAccumulator.process(rawEvent);
288 
289     if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
290         sync(rawEvent->when, rawEvent->readTime);
291     }
292 }
293 
sync(nsecs_t when,nsecs_t readTime)294 void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) {
295     int32_t lastButtonState = mButtonState;
296     int32_t currentButtonState = mCursorButtonAccumulator.getButtonState();
297     mButtonState = currentButtonState;
298 
299     bool wasDown = isPointerDown(lastButtonState);
300     bool down = isPointerDown(currentButtonState);
301     bool downChanged;
302     if (!wasDown && down) {
303         mDownTime = when;
304         downChanged = true;
305     } else if (wasDown && !down) {
306         downChanged = true;
307     } else {
308         downChanged = false;
309     }
310     nsecs_t downTime = mDownTime;
311     bool buttonsChanged = currentButtonState != lastButtonState;
312     int32_t buttonsPressed = currentButtonState & ~lastButtonState;
313     int32_t buttonsReleased = lastButtonState & ~currentButtonState;
314 
315     float deltaX = mCursorMotionAccumulator.getRelativeX() * mXScale;
316     float deltaY = mCursorMotionAccumulator.getRelativeY() * mYScale;
317     bool moved = deltaX != 0 || deltaY != 0;
318 
319     // Rotate delta according to orientation.
320     rotateDelta(mOrientation, &deltaX, &deltaY);
321 
322     // Move the pointer.
323     PointerProperties pointerProperties;
324     pointerProperties.clear();
325     pointerProperties.id = 0;
326     pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_MOUSE;
327 
328     PointerCoords pointerCoords;
329     pointerCoords.clear();
330 
331     float vscroll = mCursorScrollAccumulator.getRelativeVWheel();
332     float hscroll = mCursorScrollAccumulator.getRelativeHWheel();
333     bool scrolled = vscroll != 0 || hscroll != 0;
334 
335     mWheelYVelocityControl.move(when, nullptr, &vscroll);
336     mWheelXVelocityControl.move(when, &hscroll, nullptr);
337 
338     mPointerVelocityControl.move(when, &deltaX, &deltaY);
339 
340     int32_t displayId = ADISPLAY_ID_NONE;
341     float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
342     float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
343     if (mSource == AINPUT_SOURCE_MOUSE) {
344         if (moved || scrolled || buttonsChanged) {
345             mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER);
346 
347             if (moved) {
348                 float dx = deltaX;
349                 float dy = deltaY;
350                 if (isPerWindowInputRotationEnabled()) {
351                     // Rotate the delta from InputReader's un-rotated coordinate space to
352                     // PointerController's rotated coordinate space that is oriented with the
353                     // viewport.
354                     rotateDelta(getInverseRotation(mOrientation), &dx, &dy);
355                 }
356                 mPointerController->move(dx, dy);
357             }
358 
359             if (buttonsChanged) {
360                 mPointerController->setButtonState(currentButtonState);
361             }
362 
363             mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
364         }
365 
366         mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
367         if (isPerWindowInputRotationEnabled()) {
368             // Rotate the cursor position that is in PointerController's rotated coordinate space
369             // to InputReader's un-rotated coordinate space.
370             rotatePoint(mOrientation, xCursorPosition /*byRef*/, yCursorPosition /*byRef*/,
371                         mDisplayWidth, mDisplayHeight);
372         }
373         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition);
374         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition);
375         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
376         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
377         displayId = mPointerController->getDisplayId();
378     } else {
379         // Pointer capture and navigation modes
380         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX);
381         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY);
382         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
383         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
384     }
385 
386     pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f);
387 
388     // Moving an external trackball or mouse should wake the device.
389     // We don't do this for internal cursor devices to prevent them from waking up
390     // the device in your pocket.
391     // TODO: Use the input device configuration to control this behavior more finely.
392     uint32_t policyFlags = 0;
393     if ((buttonsPressed || moved || scrolled) && getDeviceContext().isExternal()) {
394         policyFlags |= POLICY_FLAG_WAKE;
395     }
396 
397     // Synthesize key down from buttons if needed.
398     synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, readTime, getDeviceId(),
399                          mSource, displayId, policyFlags, lastButtonState, currentButtonState);
400 
401     // Send motion event.
402     if (downChanged || moved || scrolled || buttonsChanged) {
403         int32_t metaState = getContext()->getGlobalMetaState();
404         int32_t buttonState = lastButtonState;
405         int32_t motionEventAction;
406         if (downChanged) {
407             motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
408         } else if (down || (mSource != AINPUT_SOURCE_MOUSE)) {
409             motionEventAction = AMOTION_EVENT_ACTION_MOVE;
410         } else {
411             motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE;
412         }
413 
414         if (buttonsReleased) {
415             BitSet32 released(buttonsReleased);
416             while (!released.isEmpty()) {
417                 int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit());
418                 buttonState &= ~actionButton;
419                 NotifyMotionArgs releaseArgs(getContext()->getNextId(), when, readTime,
420                                              getDeviceId(), mSource, displayId, policyFlags,
421                                              AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
422                                              metaState, buttonState, MotionClassification::NONE,
423                                              AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
424                                              &pointerCoords, mXPrecision, mYPrecision,
425                                              xCursorPosition, yCursorPosition, downTime,
426                                              /* videoFrames */ {});
427                 getListener()->notifyMotion(&releaseArgs);
428             }
429         }
430 
431         NotifyMotionArgs args(getContext()->getNextId(), when, readTime, getDeviceId(), mSource,
432                               displayId, policyFlags, motionEventAction, 0, 0, metaState,
433                               currentButtonState, MotionClassification::NONE,
434                               AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords,
435                               mXPrecision, mYPrecision, xCursorPosition, yCursorPosition, downTime,
436                               /* videoFrames */ {});
437         getListener()->notifyMotion(&args);
438 
439         if (buttonsPressed) {
440             BitSet32 pressed(buttonsPressed);
441             while (!pressed.isEmpty()) {
442                 int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit());
443                 buttonState |= actionButton;
444                 NotifyMotionArgs pressArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
445                                            mSource, displayId, policyFlags,
446                                            AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0,
447                                            metaState, buttonState, MotionClassification::NONE,
448                                            AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
449                                            &pointerCoords, mXPrecision, mYPrecision,
450                                            xCursorPosition, yCursorPosition, downTime,
451                                            /* videoFrames */ {});
452                 getListener()->notifyMotion(&pressArgs);
453             }
454         }
455 
456         ALOG_ASSERT(buttonState == currentButtonState);
457 
458         // Send hover move after UP to tell the application that the mouse is hovering now.
459         if (motionEventAction == AMOTION_EVENT_ACTION_UP && (mSource == AINPUT_SOURCE_MOUSE)) {
460             NotifyMotionArgs hoverArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
461                                        mSource, displayId, policyFlags,
462                                        AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
463                                        currentButtonState, MotionClassification::NONE,
464                                        AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
465                                        &pointerCoords, mXPrecision, mYPrecision, xCursorPosition,
466                                        yCursorPosition, downTime, /* videoFrames */ {});
467             getListener()->notifyMotion(&hoverArgs);
468         }
469 
470         // Send scroll events.
471         if (scrolled) {
472             pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
473             pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
474 
475             NotifyMotionArgs scrollArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
476                                         mSource, displayId, policyFlags,
477                                         AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
478                                         currentButtonState, MotionClassification::NONE,
479                                         AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
480                                         &pointerCoords, mXPrecision, mYPrecision, xCursorPosition,
481                                         yCursorPosition, downTime, /* videoFrames */ {});
482             getListener()->notifyMotion(&scrollArgs);
483         }
484     }
485 
486     // Synthesize key up from buttons if needed.
487     synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, readTime, getDeviceId(), mSource,
488                          displayId, policyFlags, lastButtonState, currentButtonState);
489 
490     mCursorMotionAccumulator.finishSync();
491     mCursorScrollAccumulator.finishSync();
492 }
493 
getScanCodeState(uint32_t sourceMask,int32_t scanCode)494 int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
495     if (scanCode >= BTN_MOUSE && scanCode < BTN_JOYSTICK) {
496         return getDeviceContext().getScanCodeState(scanCode);
497     } else {
498         return AKEY_STATE_UNKNOWN;
499     }
500 }
501 
getAssociatedDisplayId()502 std::optional<int32_t> CursorInputMapper::getAssociatedDisplayId() {
503     if (mParameters.hasAssociatedDisplay) {
504         if (mParameters.mode == Parameters::MODE_POINTER) {
505             return std::make_optional(mPointerController->getDisplayId());
506         } else {
507             // If the device is orientationAware and not a mouse,
508             // it expects to dispatch events to any display
509             return std::make_optional(ADISPLAY_ID_NONE);
510         }
511     }
512     return std::nullopt;
513 }
514 
515 } // namespace android
516