Some work on force feedback
This commit is contained in:
parent
6e2672e49a
commit
9256649810
6 changed files with 398 additions and 126 deletions
55
SConstruct
55
SConstruct
|
@ -1,36 +1,37 @@
|
|||
# -*- python -*-
|
||||
|
||||
env = Environment(CPPFLAGS=["-g", "-O2", "-Wall", "-ansi", "-pedantic"], LIBS=["usb", "X11"])
|
||||
# env = Environment(CPPFLAGS=["-g", "-O2"], LIBS=["usb", "X11"])
|
||||
env.Program("xboxdrv", ["src/xboxdrv.cpp",
|
||||
"src/xboxmsg.cpp",
|
||||
"src/uinput.cpp",
|
||||
"src/helper.cpp",
|
||||
"src/modifier.cpp",
|
||||
"src/command_line_options.cpp",
|
||||
"src/xbox_controller.cpp",
|
||||
"src/xbox360_controller.cpp",
|
||||
"src/xbox360_wireless_controller.cpp",
|
||||
env = Environment(CPPFLAGS=['-g', '-O2', '-Wall', '-ansi', '-pedantic'], LIBS=['usb', 'X11'])
|
||||
# env = Environment(CPPFLAGS=['-g', '-O2'], LIBS=['usb', 'X11'])
|
||||
env.Program('xboxdrv', ['src/xboxdrv.cpp',
|
||||
'src/xboxmsg.cpp',
|
||||
'src/uinput.cpp',
|
||||
'src/helper.cpp',
|
||||
'src/modifier.cpp',
|
||||
'src/command_line_options.cpp',
|
||||
'src/xbox_controller.cpp',
|
||||
'src/xbox360_controller.cpp',
|
||||
'src/xbox360_wireless_controller.cpp',
|
||||
'src/firestorm_dual_controller.cpp',
|
||||
"src/evdev_helper.cpp",
|
||||
"src/linux_uinput.cpp"
|
||||
'src/evdev_helper.cpp',
|
||||
'src/linux_uinput.cpp',
|
||||
'src/force_feedback_handler.cpp'
|
||||
])
|
||||
|
||||
if False:
|
||||
env.Program("inputdrv",
|
||||
["src/inputdrv/inputdrv.cpp",
|
||||
"src/inputdrv/xbox360_driver.cpp",
|
||||
"src/inputdrv/evdev_driver.cpp",
|
||||
"src/inputdrv/xbox360_usb_thread.cpp",
|
||||
"src/inputdrv/control.cpp",
|
||||
"src/inputdrv/abs_to_rel.cpp",
|
||||
"src/inputdrv/abs_to_btn.cpp",
|
||||
"src/inputdrv/btn_to_abs.cpp",
|
||||
"src/inputdrv/autofire_button.cpp",
|
||||
"src/inputdrv/uinput_driver.cpp",
|
||||
"src/inputdrv/join_axis.cpp",
|
||||
"src/inputdrv/throttle.cpp",
|
||||
"src/inputdrv/toggle_button.cpp"],
|
||||
env.Program('inputdrv',
|
||||
['src/inputdrv/inputdrv.cpp',
|
||||
'src/inputdrv/xbox360_driver.cpp',
|
||||
'src/inputdrv/evdev_driver.cpp',
|
||||
'src/inputdrv/xbox360_usb_thread.cpp',
|
||||
'src/inputdrv/control.cpp',
|
||||
'src/inputdrv/abs_to_rel.cpp',
|
||||
'src/inputdrv/abs_to_btn.cpp',
|
||||
'src/inputdrv/btn_to_abs.cpp',
|
||||
'src/inputdrv/autofire_button.cpp',
|
||||
'src/inputdrv/uinput_driver.cpp',
|
||||
'src/inputdrv/join_axis.cpp',
|
||||
'src/inputdrv/throttle.cpp',
|
||||
'src/inputdrv/toggle_button.cpp'],
|
||||
LIBS=['boost_signals', 'usb', 'pthread'])
|
||||
|
||||
# EOF #
|
||||
|
|
2
TODO
2
TODO
|
@ -36,7 +36,7 @@ Stuff to do before 0.5 release:
|
|||
fixme:dinput:joy_polldev joystick cannot handle type 21 event (code 0) <- 21 == EV_FF (status report?)
|
||||
|
||||
http://www.immersion.com/developer/downloads/ImmFundamentals/HTML/
|
||||
|
||||
http://msdn.microsoft.com/en-us/library/bb219655(VS.85).aspx
|
||||
|
||||
Later versions:
|
||||
===============
|
||||
|
|
250
src/force_feedback_handler.cpp
Normal file
250
src/force_feedback_handler.cpp
Normal file
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
** Xbox360 USB Gamepad Userspace Driver
|
||||
** Copyright (C) 2008 Ingo Ruhnke <grumbel@gmx.de>
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <assert.h>
|
||||
#include "force_feedback_handler.hpp"
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const struct ff_envelope& envelope)
|
||||
{
|
||||
out << "Envelope(attack_length:" << envelope.attack_length
|
||||
<< ", attack_level:" << envelope.attack_level
|
||||
<< ", fade_length:" << envelope.fade_length
|
||||
<< ", fade_level:" << envelope.fade_level << ")";
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const struct ff_replay& replay)
|
||||
{
|
||||
out << "Replay(length:" << replay.length << ", delay:" << replay.delay << ")";
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const struct ff_trigger& trigger)
|
||||
{
|
||||
out << "Trigger(button:" << trigger.button << ", interval:" << trigger.interval << ")";
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const struct ff_effect& effect)
|
||||
{
|
||||
std::cout << "Effect(";
|
||||
switch (effect.type)
|
||||
{
|
||||
case FF_CONSTANT:
|
||||
out << "FF_CONSTANT("
|
||||
<< "level:" << effect.u.constant.level
|
||||
<< ", envelope:" << effect.u.constant.envelope << ")";
|
||||
break;
|
||||
|
||||
case FF_PERIODIC:
|
||||
out << "FF_PERIODIC("
|
||||
<< ", waveform:" << effect.u.periodic.waveform
|
||||
<< ", period:" << effect.u.periodic.period
|
||||
<< ", magnitude:" << effect.u.periodic.magnitude
|
||||
<< ", offset:" << effect.u.periodic.offset
|
||||
<< ", phase:" << effect.u.periodic.phase
|
||||
<< ", envelope:" << effect.u.periodic.envelope << ")";
|
||||
break;
|
||||
|
||||
case FF_RAMP:
|
||||
out << "FF_RAMP("
|
||||
<< "start_level:" << effect.u.ramp.start_level
|
||||
<< ", end_level:" << effect.u.ramp.end_level
|
||||
<< ", envelope:" << effect.u.ramp.envelope << ")";
|
||||
break;
|
||||
|
||||
case FF_SPRING:
|
||||
out << "FF_SPRING()";
|
||||
break;
|
||||
|
||||
case FF_FRICTION:
|
||||
out << "FF_FRICTION()";
|
||||
break;
|
||||
|
||||
case FF_DAMPER:
|
||||
out << "FF_DAMPER()";
|
||||
break;
|
||||
|
||||
case FF_RUMBLE:
|
||||
out << "FF_RUMBLE("
|
||||
<< "strong_magnitude:" << effect.u.rumble.strong_magnitude
|
||||
<< ", weak_magnitude:" << effect.u.rumble.weak_magnitude << ")";
|
||||
break;
|
||||
|
||||
case FF_INERTIA:
|
||||
out << "FF_INERTIA()";
|
||||
break;
|
||||
|
||||
case FF_CUSTOM:
|
||||
out << "FF_CUSTOM()";
|
||||
break;
|
||||
|
||||
default:
|
||||
out << "FF_<unknown>()";
|
||||
break;
|
||||
}
|
||||
|
||||
out << ", direction:" << effect.direction
|
||||
<< ", replay:" << effect.replay
|
||||
<< ", trigger:" << effect.trigger << ")";
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
ForceFeedbackEffect::ForceFeedbackEffect(const struct ff_effect& effect)
|
||||
{
|
||||
delay = effect.replay.delay;
|
||||
length = effect.replay.length;
|
||||
|
||||
switch(effect.type)
|
||||
{
|
||||
case FF_CONSTANT:
|
||||
start_weak_magnitude = effect.u.constant.level;
|
||||
start_strong_magnitude = effect.u.constant.level;
|
||||
end_weak_magnitude = effect.u.constant.level;
|
||||
end_strong_magnitude = effect.u.constant.level;
|
||||
|
||||
envelope = effect.u.constant.envelope;
|
||||
break;
|
||||
|
||||
case FF_PERIODIC:
|
||||
start_weak_magnitude = effect.u.periodic.magnitude;
|
||||
start_strong_magnitude = effect.u.periodic.magnitude;
|
||||
end_weak_magnitude = effect.u.periodic.magnitude;
|
||||
end_strong_magnitude = effect.u.periodic.magnitude;
|
||||
|
||||
envelope = effect.u.periodic.envelope;
|
||||
break;
|
||||
|
||||
case FF_RAMP:
|
||||
start_weak_magnitude = effect.u.ramp.start_level;
|
||||
start_strong_magnitude = effect.u.ramp.start_level;
|
||||
end_weak_magnitude = effect.u.ramp.end_level;
|
||||
end_strong_magnitude = effect.u.ramp.end_level;
|
||||
|
||||
envelope = effect.u.ramp.envelope;
|
||||
break;
|
||||
|
||||
case FF_RUMBLE:
|
||||
start_weak_magnitude = effect.u.rumble.weak_magnitude;
|
||||
start_strong_magnitude = effect.u.rumble.strong_magnitude;
|
||||
end_weak_magnitude = effect.u.rumble.weak_magnitude;
|
||||
end_strong_magnitude = effect.u.rumble.strong_magnitude;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Unsupported effects
|
||||
// case FF_SPRING:
|
||||
// case FF_FRICTION:
|
||||
// case FF_DAMPER
|
||||
// case FF_INERTIA:
|
||||
// case FF_CUSTOM:
|
||||
assert(!"Unsupported effect");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ForceFeedbackHandler::ForceFeedbackHandler()
|
||||
: max_effects(16),
|
||||
weak_magnitude(0),
|
||||
strong_magnitude(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ForceFeedbackHandler::~ForceFeedbackHandler()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
ForceFeedbackHandler::get_max_effects()
|
||||
{
|
||||
return max_effects;
|
||||
}
|
||||
|
||||
void
|
||||
ForceFeedbackHandler::upload(const struct ff_effect& effect)
|
||||
{
|
||||
std::cout << "FF_UPLOAD("
|
||||
<< "effect_id:" << effect.id
|
||||
<< ", effect_type:" << effect.type
|
||||
<< ",\n " << effect
|
||||
<< ")" << std::endl;
|
||||
effects[effect.id] = ForceFeedbackEffect(effect);
|
||||
}
|
||||
|
||||
void
|
||||
ForceFeedbackHandler::erase(int id)
|
||||
{
|
||||
std::cout << "FF_ERASE(effect_id:" << id << ")" << std::endl;
|
||||
|
||||
std::map<int, ForceFeedbackEffect>::iterator i = effects.find(id);
|
||||
if (i != effects.end())
|
||||
effects.erase(i);
|
||||
else
|
||||
std::cout << "ForceFeedbackHandler::erase: Unknown id " << id << std::endl;
|
||||
}
|
||||
|
||||
void
|
||||
ForceFeedbackHandler::play(int id)
|
||||
{
|
||||
std::cout << "FFPlay(effect_id:" << id << ")" << std::endl;
|
||||
|
||||
std::map<int, ForceFeedbackEffect>::iterator i = effects.find(id);
|
||||
if (i != effects.end())
|
||||
; // play
|
||||
else
|
||||
std::cout << "ForceFeedbackHandler::play: Unknown id " << id << std::endl;
|
||||
}
|
||||
|
||||
void
|
||||
ForceFeedbackHandler::stop(int id)
|
||||
{
|
||||
std::cout << "FFStop(effect_id:" << id << ")" << std::endl;
|
||||
|
||||
std::map<int, ForceFeedbackEffect>::iterator i = effects.find(id);
|
||||
if (i != effects.end())
|
||||
; // stop
|
||||
else
|
||||
std::cout << "ForceFeedbackHandler::play: Unknown id " << id << std::endl;
|
||||
}
|
||||
|
||||
void
|
||||
ForceFeedbackHandler::update(int msec_delta)
|
||||
{
|
||||
for(Effects::iterator i = effects.begin(); i != effects.end(); ++i)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
ForceFeedbackHandler::get_weak_magnitude() const
|
||||
{
|
||||
return weak_magnitude;
|
||||
}
|
||||
|
||||
int
|
||||
ForceFeedbackHandler::get_strong_magnitude() const
|
||||
{
|
||||
return strong_magnitude;
|
||||
}
|
||||
|
||||
/* EOF */
|
102
src/force_feedback_handler.hpp
Normal file
102
src/force_feedback_handler.hpp
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
** Xbox360 USB Gamepad Userspace Driver
|
||||
** Copyright (C) 2008 Ingo Ruhnke <grumbel@gmx.de>
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef HEADER_FF_HANDLER_HPP
|
||||
#define HEADER_FF_HANDLER_HPP
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <map>
|
||||
|
||||
class ForceFeedbackEffect
|
||||
{
|
||||
public:
|
||||
ForceFeedbackEffect() {}
|
||||
ForceFeedbackEffect(const struct ff_effect& e);
|
||||
|
||||
// Delay before the effect start
|
||||
int delay;
|
||||
|
||||
// Length of the effect
|
||||
int length;
|
||||
|
||||
// Rumble motor strength
|
||||
int start_strong_magnitude;
|
||||
int start_weak_magnitude;
|
||||
|
||||
// Rumble motor strength
|
||||
int end_strong_magnitude;
|
||||
int end_weak_magnitude;
|
||||
|
||||
// Envelope
|
||||
struct Envelope
|
||||
{
|
||||
Envelope()
|
||||
: attack_length(0),
|
||||
attack_level(0),
|
||||
fade_length(0),
|
||||
fade_level(0)
|
||||
{}
|
||||
|
||||
Envelope(const struct ff_envelope& e)
|
||||
: attack_length(e.attack_length),
|
||||
attack_level(e.attack_level),
|
||||
fade_length(e.fade_length),
|
||||
fade_level(e.fade_level)
|
||||
{
|
||||
}
|
||||
|
||||
int attack_length;
|
||||
int attack_level;
|
||||
|
||||
int fade_length;
|
||||
int fade_level;
|
||||
} envelope;
|
||||
};
|
||||
|
||||
/** */
|
||||
class ForceFeedbackHandler
|
||||
{
|
||||
private:
|
||||
int max_effects;
|
||||
typedef std::map<int, ForceFeedbackEffect> Effects;
|
||||
Effects effects;
|
||||
|
||||
int weak_magnitude;
|
||||
int strong_magnitude;
|
||||
|
||||
public:
|
||||
ForceFeedbackHandler();
|
||||
~ForceFeedbackHandler();
|
||||
|
||||
int get_max_effects();
|
||||
|
||||
void upload(const struct ff_effect& effect);
|
||||
void erase(int id);
|
||||
|
||||
void play(int id);
|
||||
void stop(int id);
|
||||
|
||||
void update(int msec_delta);
|
||||
|
||||
int get_weak_magnitude() const;
|
||||
int get_strong_magnitude() const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/* EOF */
|
|
@ -16,6 +16,7 @@
|
|||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
@ -27,95 +28,9 @@
|
|||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include "evdev_helper.hpp"
|
||||
#include "force_feedback_handler.hpp"
|
||||
#include "linux_uinput.hpp"
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const struct ff_envelope& envelope)
|
||||
{
|
||||
out << "Envelope(attack_length:" << envelope.attack_length
|
||||
<< ", attack_level:" << envelope.attack_level
|
||||
<< ", fade_length:" << envelope.fade_length
|
||||
<< ", fade_level:" << envelope.fade_level << ")";
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const struct ff_replay& replay)
|
||||
{
|
||||
out << "Replay(length:" << replay.length << ", delay:" << replay.delay << ")";
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const struct ff_trigger& trigger)
|
||||
{
|
||||
out << "Trigger(button:" << trigger.button << ", interval:" << trigger.interval << ")";
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const struct ff_effect& effect)
|
||||
{
|
||||
std::cout << "Effect(";
|
||||
switch (effect.type)
|
||||
{
|
||||
case FF_CONSTANT:
|
||||
out << "FF_CONSTANT("
|
||||
<< "level:" << effect.u.constant.level
|
||||
<< ", envelope:" << effect.u.constant.envelope << ")";
|
||||
break;
|
||||
|
||||
case FF_PERIODIC:
|
||||
out << "FF_PERIODIC("
|
||||
<< ", waveform:" << effect.u.periodic.waveform
|
||||
<< ", period:" << effect.u.periodic.period
|
||||
<< ", magnitude:" << effect.u.periodic.magnitude
|
||||
<< ", offset:" << effect.u.periodic.offset
|
||||
<< ", phase:" << effect.u.periodic.phase
|
||||
<< ", envelope:" << effect.u.periodic.envelope << ")";
|
||||
break;
|
||||
|
||||
case FF_RAMP:
|
||||
out << "FF_RAMP("
|
||||
<< "start_level:" << effect.u.ramp.start_level
|
||||
<< ", end_level:" << effect.u.ramp.end_level
|
||||
<< ", envelope:" << effect.u.ramp.envelope << ")";
|
||||
break;
|
||||
|
||||
case FF_SPRING:
|
||||
out << "FF_SPRING()";
|
||||
break;
|
||||
|
||||
case FF_FRICTION:
|
||||
out << "FF_FRICTION()";
|
||||
break;
|
||||
|
||||
case FF_DAMPER:
|
||||
out << "FF_DAMPER()";
|
||||
break;
|
||||
|
||||
case FF_RUMBLE:
|
||||
out << "FF_RUMBLE("
|
||||
<< "strong_magnitude:" << effect.u.rumble.strong_magnitude
|
||||
<< ", weak_magnitude:" << effect.u.rumble.weak_magnitude << ")";
|
||||
break;
|
||||
|
||||
case FF_INERTIA:
|
||||
out << "FF_INERTIA()";
|
||||
break;
|
||||
|
||||
case FF_CUSTOM:
|
||||
out << "FF_CUSTOM()";
|
||||
break;
|
||||
|
||||
default:
|
||||
out << "FF_<unknown>()";
|
||||
break;
|
||||
}
|
||||
|
||||
out << ", direction:" << effect.direction
|
||||
<< ", replay:" << effect.replay
|
||||
<< ", trigger:" << effect.trigger << ")";
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
LinuxUinput::LinuxUinput(const std::string& name, uint16_t vendor, uint16_t product)
|
||||
: name(name),
|
||||
vendor(vendor),
|
||||
|
@ -125,7 +40,8 @@ LinuxUinput::LinuxUinput(const std::string& name, uint16_t vendor, uint16_t prod
|
|||
rel_bit(false),
|
||||
abs_bit(false),
|
||||
led_bit(false),
|
||||
ff_bit(false)
|
||||
ff_bit(false),
|
||||
ff_handler(0)
|
||||
{
|
||||
std::fill_n(abs_lst, ABS_CNT, false);
|
||||
std::fill_n(rel_lst, REL_CNT, false);
|
||||
|
@ -241,6 +157,8 @@ LinuxUinput::add_ff(uint16_t code)
|
|||
{
|
||||
ioctl(fd, UI_SET_EVBIT, EV_FF);
|
||||
ff_bit = true;
|
||||
assert(ff_handler == 0);
|
||||
ff_handler = new ForceFeedbackHandler();
|
||||
}
|
||||
|
||||
ioctl(fd, UI_SET_FFBIT, code);
|
||||
|
@ -295,6 +213,7 @@ LinuxUinput::update(int msec_delta)
|
|||
{
|
||||
if (ff_bit)
|
||||
{
|
||||
assert(ff_handler);
|
||||
struct input_event ev;
|
||||
|
||||
int ret = read(fd, &ev, sizeof(ev));
|
||||
|
@ -318,7 +237,10 @@ LinuxUinput::update(int msec_delta)
|
|||
break;
|
||||
|
||||
case EV_FF:
|
||||
std::cout << "FFPlay(effect_id:" << ev.code << ", value:" << ev.value << ")" << std::endl;
|
||||
if (ev.value)
|
||||
ff_handler->play(ev.code);
|
||||
else
|
||||
ff_handler->stop(ev.code);
|
||||
break;
|
||||
|
||||
case EV_UINPUT:
|
||||
|
@ -335,12 +257,7 @@ LinuxUinput::update(int msec_delta)
|
|||
upload.request_id = ev.value;
|
||||
|
||||
ioctl(fd, UI_BEGIN_FF_UPLOAD, &upload);
|
||||
|
||||
std::cout << "FF_UPLOAD("
|
||||
<< "effect_id:" << upload.effect.id
|
||||
<< ", effect_type:" << upload.effect.type
|
||||
<< ",\n " << upload.effect
|
||||
<< ")" << std::endl;
|
||||
ff_handler->upload(upload.effect);
|
||||
upload.retval = 0;
|
||||
|
||||
ioctl(fd, UI_END_FF_UPLOAD, &upload);
|
||||
|
@ -358,8 +275,7 @@ LinuxUinput::update(int msec_delta)
|
|||
erase.request_id = ev.value;
|
||||
|
||||
ioctl(fd, UI_BEGIN_FF_ERASE, &erase);
|
||||
|
||||
std::cout << "FF_ERASE(effect_id:" << erase.effect_id << ")" << std::endl;
|
||||
ff_handler->erase(erase.effect_id);
|
||||
erase.retval = 0;
|
||||
|
||||
ioctl(fd, UI_END_FF_ERASE, &erase);
|
||||
|
|
|
@ -23,7 +23,8 @@
|
|||
#include <string>
|
||||
#include <stdint.h>
|
||||
|
||||
/** */
|
||||
class ForceFeedbackHandler;
|
||||
|
||||
class LinuxUinput
|
||||
{
|
||||
private:
|
||||
|
@ -44,6 +45,8 @@ private:
|
|||
bool key_lst[KEY_CNT];
|
||||
bool ff_lst[FF_CNT];
|
||||
|
||||
ForceFeedbackHandler* ff_handler;
|
||||
|
||||
public:
|
||||
LinuxUinput(const std::string& name, uint16_t vendor, uint16_t product);
|
||||
~LinuxUinput();
|
||||
|
|
Loading…
Reference in a new issue