| // 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 |