blob: e2ef510d0f4f2a684c265e858a1377b5f7496e6b [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 <replay_device.h>
#include <assert.h>
#include <cmath>
#include "gestures_mock.h"
#include "libevdev_mock.h"
namespace replay {
std::vector<ReplayDevice*> ReplayDevice::devices_;
ReplayDevice::ReplayDevice(ReplayDeviceConfig* config)
: config_(config), has_device_data_(false), evdev_file_(NULL),
evdev_gesture_(NULL), interpreter_(NULL), current_state_(NULL),
current_time_(0), timer_target_time_(0), timer_callback_(NULL),
timer_callback_udata_(NULL) {
id_ = devices_.size();
devices_.push_back(this);
// read device file into evemu
evdev_file_ = new EvemuDevice();
if (config_->device.Good()) {
evdev_file_->ReadDeviceFile(config_->device.GetFP());
has_device_data_ = true;
}
// load properties from properties file
if (!config->properties.empty()) {
if (!properties_.Load(config->properties)) {
std::cerr << "Failed loading properties file" << std::endl;
exit(-1);
}
}
// create libevdev mock
evdev_device_ = NewEvdevMock(id_);
interpreter_ = replay::NewGestureInterpreterMock(id_);
interpreter_->SetPropProvider(&CPropProvider, &properties_);
evdev_gesture_ = new EvdevGesture(evdev_device_, interpreter_);
interpreter_->Initialize(config_->device_class);
// init fake device hardware properties
struct HardwareProperties hwprops;
evdev_gesture_->InitHardwareProperties(&hwprops, &properties_);
// this property is unused but xorg conf file sets it
int accel_profile = 0;
properties_.GetPropValue("AccelerationProfile", &accel_profile);
if (!properties_.CheckIntegrity()) {
std::cerr << "Property Integrity Error" << std::endl;
exit(-1);
}
interpreter_->SetHardwareProperties(hwprops);
}
ReplayDevice::~ReplayDevice() {
devices_[id_] = NULL;
}
void ReplayDevice::ReplayEvents(Stream* stream) {
// Try to read device info from log file. If it exists it will
// override any device info read from the device file.
int ret = EvdevReadInfoFromFile(stream->GetFP(), &evdev_device_->info);
if (!has_device_data_ && ret <= 0) {
std::cerr << "device file or device header in log is required" << std::endl;
exit(-1);
}
struct input_event event;
while (EvdevReadEventFromFile(stream->GetFP(), &event) > 0) {
ReplayEvent(event);
}
// handle remaining timers.
RunTimer(INFINITY);
std::string activity = interpreter_->EncodeActivityLog();
Log(ReplayDeviceConfig::kLogActivity, activity.c_str());
}
void ReplayDevice::ReplayEvent(const struct input_event& event) {
// Passing to C API. Drop const qualifier.
Event_Process(evdev_device_, const_cast<struct input_event*>(&event));
}
void ReplayDevice::VLog(ReplayDeviceConfig::LogCategory category,
const char* format, va_list args) {
Stream& stream = config_->log[category];
if (stream.Good()) {
vfprintf(stream.GetFP(), format, args);
}
}
void ReplayDevice::Log(ReplayDeviceConfig::LogCategory category,
const char* format, ...) {
Stream& stream = config_->log[category];
if (stream.Good()) {
va_list args;
va_start(args, format);
VLog(category, format, args);
va_end(args);
}
}
void ReplayDevice::VLogAll(ReplayDeviceConfig::LogCategory category,
const char* format, va_list args) {
for (size_t i = 0; i < devices_.size(); ++i) {
if (devices_[i]) {
devices_[i]->VLog(category, format, args);
}
}
}
void ReplayDevice::SynCallback(EventStatePtr evstate, struct timeval* timeval) {
current_state_ = evstate;
stime_t next_event = StimeFromTimeval(timeval);
RunTimer(next_event);
current_time_ = next_event;
evdev_gesture_->PushEventState(evstate, timeval);
}
void ReplayDevice::GestureCallback(const struct Gesture* gesture) {
const char* separator = "----------------------------------------"
"----------------------------------------\n";
Stream& stream = config_->log[ReplayDeviceConfig::kLogGestures];
if (stream.Good()) {
FILE* fp = stream.GetFP();
fprintf(fp, "%s", separator);
fprintf(fp, "%f.6 - ", current_time_);
switch (gesture->type) {
case kGestureTypeContactInitiated:
fprintf(fp, "Contact Initiated");
break;
case kGestureTypeMove:
fprintf(fp, "Move (%d, %d)",
static_cast<int>(gesture->details.move.dx),
static_cast<int>(gesture->details.move.dy));
break;
case kGestureTypeScroll:
fprintf(fp, "Scroll (%d, %d)",
static_cast<int>(gesture->details.scroll.dx),
static_cast<int>(gesture->details.scroll.dy));
break;
case kGestureTypeButtonsChange:
fprintf(fp, "Buttons Change up=%d, down=%d",
gesture->details.buttons.up,
gesture->details.buttons.up);
break;
case kGestureTypeFling:
fprintf(fp, "Fling state=%d (%d, %d)",
gesture->details.fling.fling_state,
static_cast<int>(gesture->details.fling.vx),
static_cast<int>(gesture->details.fling.vy));
break;
case kGestureTypeSwipe:
fprintf(fp, "Swipe dx=%d", static_cast<int>(gesture->details.swipe.dx));
break;
case kGestureTypePinch:
fprintf(fp, "Pinch dz=%d", static_cast<int>(gesture->details.pinch.dz));
break;
case kGestureTypeSwipeLift:
fprintf(fp, "Swipe Lift");
break;
case kGestureTypeMetrics:
fprintf(fp, "Metrics type=%d (%f, %f)",
gesture->details.metrics.type,
gesture->details.metrics.data[0],
gesture->details.metrics.data[1]);
break;
}
fprintf(fp, "\n%s", separator);
}
}
void ReplayDevice::SetFakeTimer(stime_t time, GesturesTimerCallback callback,
void* callback_udata) {
timer_target_time_ = current_time_ + time;
timer_callback_ = callback;
timer_callback_udata_ = callback_udata;
}
void ReplayDevice::RunTimer(stime_t next_event) {
while (timer_callback_ && (timer_target_time_ < next_event)) {
current_time_ = timer_target_time_;
GesturesTimerCallback callback = timer_callback_;
timer_callback_ = NULL;
// the callback might re-set timer_callback
stime_t next = callback(timer_target_time_, timer_callback_udata_);
if (next >= 0.0)
SetFakeTimer(next, callback, timer_callback_udata_);
}
}
ReplayDevice* ReplayDevice::GetDevice(size_t id) {
assert(id < devices_.size());
assert(devices_[id] != NULL);
return devices_[id];
}
} // namespace replay