summaryrefslogtreecommitdiff
path: root/services/inputflinger/reader/mapper/gestures/HardwareStateConverter.cpp
blob: b89b7f38a92bd6b26ca505f140550ab70449c38b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/*
 * Copyright 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// clang-format off
#include "../Macros.h"
// clang-format on
#include "gestures/HardwareStateConverter.h"

#include <chrono>
#include <vector>

#include <com_android_input_flags.h>
#include <linux/input-event-codes.h>

namespace input_flags = com::android::input::flags;

namespace android {

const bool REPORT_PALMS_TO_GESTURES_LIBRARY = input_flags::report_palms_to_gestures_library();

HardwareStateConverter::HardwareStateConverter(const InputDeviceContext& deviceContext,
                                               MultiTouchMotionAccumulator& motionAccumulator)
      : mDeviceContext(deviceContext),
        mMotionAccumulator(motionAccumulator),
        mTouchButtonAccumulator(deviceContext) {
    mTouchButtonAccumulator.configure();
}

std::optional<SelfContainedHardwareState> HardwareStateConverter::processRawEvent(
        const RawEvent* rawEvent) {
    std::optional<SelfContainedHardwareState> out;
    if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
        out = produceHardwareState(rawEvent->when);
        mMotionAccumulator.finishSync();
        mMscTimestamp = 0;
    }
    if (rawEvent->type == EV_MSC && rawEvent->code == MSC_TIMESTAMP) {
        mMscTimestamp = rawEvent->value;
    }
    mCursorButtonAccumulator.process(rawEvent);
    mMotionAccumulator.process(rawEvent);
    mTouchButtonAccumulator.process(rawEvent);
    return out;
}

SelfContainedHardwareState HardwareStateConverter::produceHardwareState(nsecs_t when) {
    SelfContainedHardwareState schs;
    // The gestures library uses doubles to represent timestamps in seconds.
    schs.state.timestamp = std::chrono::duration<stime_t>(std::chrono::nanoseconds(when)).count();
    schs.state.msc_timestamp =
            std::chrono::duration<stime_t>(std::chrono::microseconds(mMscTimestamp)).count();

    schs.state.buttons_down = 0;
    if (mCursorButtonAccumulator.isLeftPressed()) {
        schs.state.buttons_down |= GESTURES_BUTTON_LEFT;
    }
    if (mCursorButtonAccumulator.isMiddlePressed()) {
        schs.state.buttons_down |= GESTURES_BUTTON_MIDDLE;
    }
    if (mCursorButtonAccumulator.isRightPressed()) {
        schs.state.buttons_down |= GESTURES_BUTTON_RIGHT;
    }
    if (mCursorButtonAccumulator.isBackPressed() || mCursorButtonAccumulator.isSidePressed()) {
        schs.state.buttons_down |= GESTURES_BUTTON_BACK;
    }
    if (mCursorButtonAccumulator.isForwardPressed() || mCursorButtonAccumulator.isExtraPressed()) {
        schs.state.buttons_down |= GESTURES_BUTTON_FORWARD;
    }

    schs.fingers.clear();
    size_t numPalms = 0;
    for (size_t i = 0; i < mMotionAccumulator.getSlotCount(); i++) {
        MultiTouchMotionAccumulator::Slot slot = mMotionAccumulator.getSlot(i);
        if (!slot.isInUse()) {
            continue;
        }
        // Some touchpads continue to report contacts even after they've identified them as palms.
        // We want to exclude these contacts from the HardwareStates.
        if (!REPORT_PALMS_TO_GESTURES_LIBRARY && slot.getToolType() == ToolType::PALM) {
            numPalms++;
            continue;
        }

        FingerState& fingerState = schs.fingers.emplace_back();
        fingerState = {};
        fingerState.touch_major = slot.getTouchMajor();
        fingerState.touch_minor = slot.getTouchMinor();
        fingerState.width_major = slot.getToolMajor();
        fingerState.width_minor = slot.getToolMinor();
        fingerState.pressure = slot.getPressure();
        fingerState.orientation = slot.getOrientation();
        fingerState.position_x = slot.getX();
        fingerState.position_y = slot.getY();
        fingerState.tracking_id = slot.getTrackingId();
        if (REPORT_PALMS_TO_GESTURES_LIBRARY) {
            fingerState.tool_type = slot.getToolType() == ToolType::PALM
                    ? FingerState::ToolType::kPalm
                    : FingerState::ToolType::kFinger;
        }
    }
    schs.state.fingers = schs.fingers.data();
    schs.state.finger_cnt = schs.fingers.size();
    schs.state.touch_cnt = mTouchButtonAccumulator.getTouchCount() - numPalms;
    return schs;
}

void HardwareStateConverter::reset() {
    mCursorButtonAccumulator.reset(mDeviceContext);
    mTouchButtonAccumulator.reset();
    mMscTimestamp = 0;
}

} // namespace android