blob: 74c0c03cd006389323741d6d3b205aa127dc2790 [file] [log] [blame]
// Copyright (c) 2012 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 <gtest/gtest.h> // for FRIEND_TEST
#include "gestures/include/filter_interpreter.h"
#include "gestures/include/finger_metrics.h"
#include "gestures/include/gestures.h"
#include "gestures/include/prop_registry.h"
#include "gestures/include/set.h"
#include "gestures/include/tracer.h"
#ifndef GESTURES_SPLIT_CORRECTING_FILTER_INTERPRETER_H_
#define GESTURES_SPLIT_CORRECTING_FILTER_INTERPRETER_H_
namespace gestures {
// This interepreter corrects problems that can occur with some touchpads.
// Currently, it corrects for the case where a large finger can erroneously
// "split" into two contacts. It works around this by looking for a contact
// to seemingly split into two, and fakes that the split didn't occur.
// This struct tracks an unmerged contact. By default the output and input
// IDs will be the same value, however after merge cycles, that may no longer
// be the case.
struct UnmergedContact {
UnmergedContact() : input_id(-1) {}
bool Valid() const { return input_id != -1; }
void Invalidate() { input_id = -1; }
short input_id;
short output_id;
float position_x;
float position_y;
};
// Tracks two input contacts that are being combined into one output contact
// because we believe they are actually two parts of the same real contact.
struct MergedContact {
MergedContact() : output_id(-1) {}
bool Valid() const { return output_id != -1; }
void Invalidate() { output_id = -1; }
FingerState input_fingers[2]; // initial state
short output_id;
};
class SplitCorrectingFilterInterpreter : public FilterInterpreter {
FRIEND_TEST(SplitCorrectingFilterInterpreterTest, DistFromPointToLineTest);
public:
// Takes ownership of |next|:
SplitCorrectingFilterInterpreter(PropRegistry* prop_reg, Interpreter* next,
Tracer* tracer);
virtual ~SplitCorrectingFilterInterpreter() {}
void Enable() { enabled_.val_ = 1; }
protected:
virtual void SyncInterpretImpl(HardwareState* hwstate, stime_t* timeout);
private:
void RemoveMissingUnmergedContacts(const HardwareState& hwstate);
void MergeFingers(const HardwareState& hwstate);
void UnmergeFingers(const HardwareState& hwstate);
void UpdateUnmergedLocations(const HardwareState& hwstate);
// Given a line that goes through (x0, y0) and (x1, y1), and a separate
// point, compute the square of the smallest distance from the point to the
// line.
static float DistSqFromPointToLine(float line_x_0, float line_y_0,
float line_x_1, float line_y_1,
float point_x, float point_y);
// Based on merged_ and unmeged_, updates the current hwstate.
void UpdateHwState(HardwareState* hwstate) const;
// Tests to see if new_contact, when paired w/ existing_contact
// are a good match for the unmerged contact, merge_recipient.
// new_contact is the current state of the finger in merge_recipient.
// Returns < 0 if this is not a good match, or an error value if it's good.
// The smaller the error, the better.
float AreMergePair(const FingerState& existing_contact,
const FingerState& new_contact,
const UnmergedContact& merge_recipient) const;
void AppendMergedContact(const FingerState& input_a,
const FingerState& input_b,
short output_id);
void AppendUnmergedContact(const FingerState& fs, short output_id);
const UnmergedContact* FindUnmerged(short input_id) const;
const MergedContact* FindMerged(short input_id) const;
static void JoinFingerState(FingerState* in_out,
const FingerState& newfinger);
static void RemoveFingerStateFromHardwareState(HardwareState* hs,
FingerState* fs);
// Sets last_tracking_ids_ to the ids in the passed hwstate.
void SetLastTrackingIds(const HardwareState& hwstate);
// Dumps internal state and hwstate.
void Dump(const HardwareState& hwstate) const;
// We only enable on non-T5R2 pads
BoolProperty enabled_;
set<short, kMaxFingers> last_tracking_ids_;
UnmergedContact unmerged_[kMaxFingers];
MergedContact merged_[kMaxFingers / 2 + 1];
// Contacts must be separated by less than this amount to be considered for
// merging.
DoubleProperty merge_max_separation_;
// The most [mm] that a finger in a merged contact can move before we break
// out and unmerge.
DoubleProperty merge_max_movement_;
// When merging, we expect that the two fingers that appear are on either
// side of the old merged contact from last frame, and that the angle from
// the old merged contact, to the new finger with the same id, to the new
// finger with a new ID has a max angle. This angle then computes the max
// ratio of: (distance from new ID point to line defined by old and new
// contacts that have the same ID) / (length from new ID point to old ID point
// in newer frame).
DoubleProperty merge_max_ratio_;
};
} // namespace gestures
#endif // GESTURES_SPLIT_CORRECTING_FILTER_INTERPRETER_H_