blob: 21f0ce9a21c24870e4239580b59b1bdc1d28fb53 [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 <string.h>
#include <base/macros.h>
namespace touch_noise_filter {
InputEventFilter::InputEventFilter(NoiseFilter* filter)
: current_touching_(0), prev_touching_(0), filter_(filter),
current_slot_(0) {
for (size_t i = 0; i < arraysize(frames_[0].fingers_); i++) {
PrevFrame()->fingers_[i].tracking_id_ = -1;
CurrentFrame()->fingers_[i].tracking_id_ = -1;
}
}
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;
}
#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 canceled_ bit cleared
if ((current_touching_ & (1ULL << i)) &&
!(prev_touching_ & (1ULL << i)))
cur_finger->canceled_ = false;
}
CurrentFrame()->timestamp_ = TimevalToDouble(ev->time);
filter_->FilterFrame(PrevFrame(), CurrentFrame(), TOUCH_NOISE_MAX_SLOTS);
memcpy(PrevFrame(), CurrentFrame(), sizeof(Frame));
prev_touching_ = current_touching_;
break;
}
}
}
void InputEventFilter::GetCanceledTouches(uint64_t* slots_mask) {
for (size_t i = 0; i < arraysize(frames_[0].fingers_); i++) {
if (CurrentFrame()->fingers_[i].canceled_) {
__s32 tracking_id = CurrentFrame()->fingers_[i].tracking_id_;
if (tracking_id == -1)
tracking_id = PrevFrame()->fingers_[i].tracking_id_;
if (tracking_id != -1)
Log("TrackingID %d cancelled", tracking_id);
(*slots_mask) |= 1 << i;
// If the finger was released, we can lose the cancel bit
if (!(prev_touching_ & (1ULL << i)))
CurrentFrame()->fingers_[i].canceled_ = 0;
}
}
}
} // namespace touch_noise_filter