blob: 0fd152c20a6b6f459b6055a0a78349f7acbfa0eb [file] [log] [blame]
// Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "touch_noise_filter/input_event_filter.h"
#include <linux/input.h>
#include <stdio.h>
#include <base/basictypes.h>
namespace touch_noise_filter {
InputEventFilter::InputEventFilter(NoiseFilter* next)
: current_frame_(0), current_touching_(0), prev_touching_(0),
next_(next), current_slot_(0) {
for (size_t i = 0; i < arraysize(frames_); i++) {
for (size_t j = 0; j < arraysize(frames_[i].fingers_); j++) {
frames_[i].fingers_[j].slot_ = j;
}
}
}
namespace {
#define SETSTR(type_num, code_num) \
do { \
if ((ev)->type == type_num) { \
type_str = #type_num; \
if ((ev)->code == code_num) { \
code_str = #code_num; \
} \
} \
} while (0)
double TimevalToDouble(const struct timeval& tv) {
// printf("%ld usec\n", tv.tv_usec);
return static_cast<double>(tv.tv_sec) + static_cast<double>(tv.tv_usec) /
1000000.0;
}
void LogInputEvent(const struct input_event* ev) {
const char* type_str = "(unknown)";
const char* code_str = "(unknown)";
SETSTR(EV_KEY, BTN_TOUCH);
SETSTR(EV_ABS, ABS_X);
SETSTR(EV_ABS, ABS_Y);
SETSTR(EV_ABS, ABS_Z);
SETSTR(EV_ABS, ABS_RX);
SETSTR(EV_ABS, ABS_RY);
SETSTR(EV_ABS, ABS_RZ);
SETSTR(EV_ABS, ABS_THROTTLE);
SETSTR(EV_ABS, ABS_RUDDER);
SETSTR(EV_ABS, ABS_WHEEL);
SETSTR(EV_ABS, ABS_GAS);
SETSTR(EV_ABS, ABS_BRAKE);
SETSTR(EV_ABS, ABS_HAT0X);
SETSTR(EV_ABS, ABS_HAT0Y);
SETSTR(EV_ABS, ABS_HAT1X);
SETSTR(EV_ABS, ABS_HAT1Y);
SETSTR(EV_ABS, ABS_HAT2X);
SETSTR(EV_ABS, ABS_HAT2Y);
SETSTR(EV_ABS, ABS_HAT3X);
SETSTR(EV_ABS, ABS_HAT3Y);
SETSTR(EV_ABS, ABS_PRESSURE);
SETSTR(EV_ABS, ABS_DISTANCE);
SETSTR(EV_ABS, ABS_TILT_X);
SETSTR(EV_ABS, ABS_TILT_Y);
SETSTR(EV_ABS, ABS_TOOL_WIDTH);
SETSTR(EV_ABS, ABS_MT_SLOT);
SETSTR(EV_ABS, ABS_MT_TOUCH_MAJOR);
SETSTR(EV_ABS, ABS_MT_TOUCH_MINOR);
SETSTR(EV_ABS, ABS_MT_WIDTH_MAJOR);
SETSTR(EV_ABS, ABS_MT_WIDTH_MINOR);
SETSTR(EV_ABS, ABS_MT_ORIENTATION);
SETSTR(EV_ABS, ABS_MT_POSITION_X);
SETSTR(EV_ABS, ABS_MT_POSITION_Y);
SETSTR(EV_ABS, ABS_MT_TOOL_TYPE);
SETSTR(EV_ABS, ABS_MT_BLOB_ID);
SETSTR(EV_ABS, ABS_MT_TRACKING_ID);
SETSTR(EV_ABS, ABS_MT_PRESSURE);
SETSTR(EV_ABS, ABS_MT_DISTANCE);
if (ev->type == 0 && ev->code == 0) {
TouchNoiseFilterLog("INPUT: %f ---------- SYN_REPORT ----------\n",
TimevalToDouble(ev->time));
} else {
TouchNoiseFilterLog("INPUT: %f %s %s %d\n",
TimevalToDouble(ev->time), type_str, code_str, ev->value);
}
}
#undef SETSTR
} // namespace {}
void InputEventFilter::HandleInputEvent(const struct input_event* ev) {
static const __u16 kMinKey = ABS_MT_TOUCH_MAJOR;
static __s32 Finger::* const member_map[] = {
// The first one must correspond w/ kMinKey above, and they must be in
// numerical order.
NULL, // ABS_MT_TOUCH_MAJOR
NULL, // ABS_MT_TOUCH_MINOR
NULL, // ABS_MT_WIDTH_MAJOR
NULL, // ABS_MT_WIDTH_MINOR
NULL, // ABS_MT_ORIENTATION
&Finger::x_pos_, // ABS_MT_POSITION_X
&Finger::y_pos_, // ABS_MT_POSITION_Y
NULL, // ABS_MT_TOOL_TYPE
NULL, // ABS_MT_BLOB_ID
&Finger::tracking_id_, // ABS_MT_TRACKING_ID
NULL, // ABS_MT_PRESSURE
};
switch (ev->type) {
case EV_ABS: {
switch (ev->code) {
case ABS_MT_SLOT:
current_slot_ = ev->value;
break;
case ABS_MT_TRACKING_ID:
if (ev->value >= 0)
current_touching_ |= (1ULL << current_slot_);
else
current_touching_ &= ~(1ULL << current_slot_);
// fallthrough
default:
if (ev->code < kMinKey ||
ev->code >= kMinKey + arraysize(member_map) ||
member_map[ev->code - kMinKey] == NULL)
break;
CurrentFrame()->fingers_[
current_slot_].*member_map[ev->code - kMinKey] = ev->value;
break;
}
break;
}
case EV_SYN: {
for (size_t i = 0; i < arraysize(frames_[0].fingers_); i++) {
Finger* cur_finger = &CurrentFrame()->fingers_[i];
// New fingers should have their cancelled_ bit cleared
if ((current_touching_ & (1ULL << i)) &&
!(prev_touching_ & (1ULL << i)))
cur_finger->cancelled_ = false;
cur_finger->timestamp_ = TimevalToDouble(ev->time);
next_->FilterFinger(cur_finger);
}
prev_touching_ = current_touching_;
break;
}
}
}
void InputEventFilter::GetCancelledTouches(uint64_t* slots_mask) {
for (size_t i = 0; i < arraysize(frames_[0].fingers_); i++) {
if (CurrentFrame()->fingers_[i].cancelled_) {
(*slots_mask) |= 1 << i;
// If the finger was released, we can lose the cancel bit
if (!(prev_touching_ & (1ULL << i)))
CurrentFrame()->fingers_[i].cancelled_ = 0;
}
}
}
} // namespace touch_noise_filter