Home | History | Annotate | Download | only in evdev
      1 /*
      2  * Copyright (C) 2015 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 #define LOG_TAG "MouseInputMapper"
     18 //#define LOG_NDEBUG 0
     19 
     20 #include "MouseInputMapper.h"
     21 
     22 #include <linux/input.h>
     23 #include <hardware/input.h>
     24 #include <utils/Log.h>
     25 #include <utils/misc.h>
     26 
     27 #include "InputHost.h"
     28 #include "InputHub.h"
     29 
     30 
     31 namespace android {
     32 
     33 // Map scancodes to input HAL usages.
     34 // The order of these definitions MUST remain in sync with the order they are
     35 // defined in linux/input.h.
     36 static struct {
     37     int32_t scancode;
     38     InputUsage usage;
     39 } codeMap[] = {
     40     {BTN_LEFT, INPUT_USAGE_BUTTON_PRIMARY},
     41     {BTN_RIGHT, INPUT_USAGE_BUTTON_SECONDARY},
     42     {BTN_MIDDLE, INPUT_USAGE_BUTTON_TERTIARY},
     43     {BTN_SIDE, INPUT_USAGE_BUTTON_UNKNOWN},
     44     {BTN_EXTRA, INPUT_USAGE_BUTTON_UNKNOWN},
     45     {BTN_FORWARD, INPUT_USAGE_BUTTON_FORWARD},
     46     {BTN_BACK, INPUT_USAGE_BUTTON_BACK},
     47     {BTN_TASK, INPUT_USAGE_BUTTON_UNKNOWN},
     48 };
     49 
     50 
     51 bool MouseInputMapper::configureInputReport(InputDeviceNode* devNode,
     52         InputReportDefinition* report) {
     53     setInputReportDefinition(report);
     54     getInputReportDefinition()->addCollection(INPUT_COLLECTION_ID_MOUSE, 1);
     55 
     56     // Configure mouse axes
     57     if (!devNode->hasRelativeAxis(REL_X) || !devNode->hasRelativeAxis(REL_Y)) {
     58         ALOGE("Device %s is missing a relative x or y axis. Device cannot be configured.",
     59                 devNode->getPath().c_str());
     60         return false;
     61     }
     62     getInputReportDefinition()->declareUsage(INPUT_COLLECTION_ID_MOUSE, INPUT_USAGE_AXIS_X,
     63             INT32_MIN, INT32_MAX, 1.0f);
     64     getInputReportDefinition()->declareUsage(INPUT_COLLECTION_ID_MOUSE, INPUT_USAGE_AXIS_Y,
     65             INT32_MIN, INT32_MAX, 1.0f);
     66     if (devNode->hasRelativeAxis(REL_WHEEL)) {
     67         getInputReportDefinition()->declareUsage(INPUT_COLLECTION_ID_MOUSE,
     68                 INPUT_USAGE_AXIS_VSCROLL, -1, 1, 0.0f);
     69     }
     70     if (devNode->hasRelativeAxis(REL_HWHEEL)) {
     71         getInputReportDefinition()->declareUsage(INPUT_COLLECTION_ID_MOUSE,
     72                 INPUT_USAGE_AXIS_HSCROLL, -1, 1, 0.0f);
     73     }
     74 
     75     // Configure mouse buttons
     76     InputUsage usages[NELEM(codeMap)];
     77     int numUsages = 0;
     78     for (int32_t i = 0; i < NELEM(codeMap); ++i) {
     79         if (devNode->hasKey(codeMap[i].scancode)) {
     80             usages[numUsages++] = codeMap[i].usage;
     81         }
     82     }
     83     if (numUsages == 0) {
     84         ALOGW("MouseInputMapper found no buttons for %s", devNode->getPath().c_str());
     85     }
     86     getInputReportDefinition()->declareUsages(INPUT_COLLECTION_ID_MOUSE, usages, numUsages);
     87     return true;
     88 }
     89 
     90 void MouseInputMapper::process(const InputEvent& event) {
     91     ALOGV("processing mouse event. type=%d code=%d value=%d",
     92             event.type, event.code, event.value);
     93     switch (event.type) {
     94         case EV_KEY:
     95             processButton(event.code, event.value);
     96             break;
     97         case EV_REL:
     98             processMotion(event.code, event.value);
     99             break;
    100         case EV_SYN:
    101             if (event.code == SYN_REPORT) {
    102                 sync(event.when);
    103             }
    104             break;
    105         default:
    106             ALOGV("unknown mouse event type: %d", event.type);
    107     }
    108 }
    109 
    110 void MouseInputMapper::processMotion(int32_t code, int32_t value) {
    111     switch (code) {
    112         case REL_X:
    113             mRelX = value;
    114             break;
    115         case REL_Y:
    116             mRelY = value;
    117             break;
    118         case REL_WHEEL:
    119             mRelWheel = value;
    120             break;
    121         case REL_HWHEEL:
    122             mRelHWheel = value;
    123             break;
    124         default:
    125             // Unknown code. Ignore.
    126             break;
    127     }
    128 }
    129 
    130 // Map evdev button codes to bit indices. This function assumes code >=
    131 // BTN_MOUSE.
    132 uint32_t buttonToBit(int32_t code) {
    133     return static_cast<uint32_t>(code - BTN_MOUSE);
    134 }
    135 
    136 void MouseInputMapper::processButton(int32_t code, int32_t value) {
    137     // Mouse buttons start at BTN_MOUSE and end before BTN_JOYSTICK. There isn't
    138     // really enough room after the mouse buttons for another button class, so
    139     // the risk of a button type being inserted after mouse is low.
    140     if (code >= BTN_MOUSE && code < BTN_JOYSTICK) {
    141         if (value) {
    142             mButtonValues.markBit(buttonToBit(code));
    143         } else {
    144             mButtonValues.clearBit(buttonToBit(code));
    145         }
    146         mUpdatedButtonMask.markBit(buttonToBit(code));
    147     }
    148 }
    149 
    150 void MouseInputMapper::sync(nsecs_t when) {
    151     // Process updated button states.
    152     while (!mUpdatedButtonMask.isEmpty()) {
    153         auto bit = mUpdatedButtonMask.clearFirstMarkedBit();
    154         getInputReport()->setBoolUsage(INPUT_COLLECTION_ID_MOUSE, codeMap[bit].usage,
    155                 mButtonValues.hasBit(bit), 0);
    156     }
    157 
    158     // Process motion and scroll changes.
    159     if (mRelX != 0) {
    160         getInputReport()->setIntUsage(INPUT_COLLECTION_ID_MOUSE, INPUT_USAGE_AXIS_X, mRelX, 0);
    161     }
    162     if (mRelY != 0) {
    163         getInputReport()->setIntUsage(INPUT_COLLECTION_ID_MOUSE, INPUT_USAGE_AXIS_Y, mRelY, 0);
    164     }
    165     if (mRelWheel != 0) {
    166         getInputReport()->setIntUsage(INPUT_COLLECTION_ID_MOUSE, INPUT_USAGE_AXIS_VSCROLL,
    167                 mRelWheel, 0);
    168     }
    169     if (mRelHWheel != 0) {
    170         getInputReport()->setIntUsage(INPUT_COLLECTION_ID_MOUSE, INPUT_USAGE_AXIS_HSCROLL,
    171                 mRelHWheel, 0);
    172     }
    173 
    174     // Report and reset.
    175     getInputReport()->reportEvent(getDeviceHandle());
    176     mUpdatedButtonMask.clear();
    177     mButtonValues.clear();
    178     mRelX = 0;
    179     mRelY = 0;
    180     mRelWheel = 0;
    181     mRelHWheel = 0;
    182 }
    183 
    184 }  // namespace android
    185