Some work on forcefeedback/rumble

This commit is contained in:
Ingo Ruhnke 2008-12-30 06:43:06 +01:00
parent fbf4744a4c
commit 8639d800b5
4 changed files with 100 additions and 4 deletions

2
TODO
View file

@ -1,3 +1,5 @@
- fix http://userweb.kernel.org/~dtor/eviocgbit-bug.html in evtest
- cleanup evtest some more, add more features
- make guitar button configurable
- --mimic-xpad

View file

@ -37,7 +37,8 @@ uInputCfg::uInputCfg()
dpad_as_button = false;
trigger_as_zaxis = false;
dpad_only = false;
force_feedback = false;
// Button Mapping
btn_map[XBOX_BTN_START] = BTN_START;
btn_map[XBOX_BTN_GUIDE] = BTN_MODE;
@ -86,7 +87,7 @@ uInput::uInput(GamepadType type, uInputCfg config_)
for (int i = 0; i < uinput_filename_count; ++i)
{
if ((fd = open(uinput_filename[i], O_WRONLY | O_NDELAY)) >= 0)
if ((fd = open(uinput_filename[i], O_RDWR | O_NDELAY)) >= 0)
{
break;
}
@ -137,6 +138,13 @@ uInput::setup_xbox360_gamepad(GamepadType type)
ioctl(fd, UI_SET_EVBIT, EV_ABS);
ioctl(fd, UI_SET_EVBIT, EV_KEY);
if (cfg.force_feedback)
{
ioctl(fd, UI_SET_EVBIT, EV_FF);
ioctl(fd, UI_SET_FFBIT, FF_PERIODIC);
ioctl(fd, UI_SET_FFBIT, FF_RUMBLE);
}
ioctl(fd, UI_SET_ABSBIT, cfg.axis_map[XBOX_AXIS_X1]);
ioctl(fd, UI_SET_ABSBIT, cfg.axis_map[XBOX_AXIS_Y1]);
@ -199,6 +207,9 @@ uInput::setup_xbox360_gamepad(GamepadType type)
strncpy(uinp.name, "Xbox Gamepad (userspace driver)", UINPUT_MAX_NAME_SIZE);
if (cfg.force_feedback)
uinp.ff_effects_max = 16;
uinp.id.version = 0;
uinp.id.bustype = BUS_USB;
uinp.id.vendor = 0x045e; // FIXME: this shouldn't be hardcoded
@ -545,4 +556,73 @@ uInput::send(Xbox360GuitarMsg& msg)
send_axis(cfg.axis_map[XBOX_AXIS_Y1], msg.tilt);
}
void
uInput::update()
{
if (cfg.force_feedback)
{
struct input_event ev;
int ret;
if ((ret = read(fd, &ev, sizeof(ev))) == sizeof(ev))
{
std::cout << "type: " << ev.type << " code: " << ev.code << " value: " << ev.value << std::endl;
switch(ev.type)
{
case EV_FF:
std::cout << "EV_FF: playing effect: effect_id = " << ev.code << " value: " << ev.value << std::endl;
break;
case EV_UINPUT:
switch (ev.code)
{
case UI_FF_UPLOAD:
{
struct uinput_ff_upload upload;
memset(&upload, 0, sizeof(upload));
// *VERY* important, without this you
// break the kernel and have to reboot due
// to dead hanging process
upload.request_id = ev.value;
ioctl(fd, UI_BEGIN_FF_UPLOAD, &upload);
std::cout << "FF_UPLOAD: rumble upload: effect_id = " << upload.effect.id << std::endl;
upload.retval = 0;
ioctl(fd, UI_END_FF_UPLOAD, &upload);
}
break;
case UI_FF_ERASE:
{
struct uinput_ff_erase erase;
memset(&erase, 0, sizeof(erase));
// *VERY* important, without this you
// break the kernel and have to reboot due
// to dead hanging process
erase.request_id = ev.value;
ioctl(fd, UI_BEGIN_FF_ERASE, &erase);
std::cout << "FF_ERASE: rumble erase: effect_id = " << erase.effect_id << std::endl;
erase.retval = 0; // FIXME: is this used?
ioctl(fd, UI_END_FF_ERASE, &erase);
}
break;
}
break;
}
std::cout << "--------------------------------" << std::endl;
}
if (ret < 0)
std::cout << "Error: " << strerror(errno) << " " << ret << std::endl;
}
}
/* EOF */

View file

@ -32,6 +32,7 @@ public:
bool dpad_as_button;
bool trigger_as_zaxis;
bool dpad_only;
bool force_feedback;
int btn_map[XBOX_BTN_MAX];
int axis_map[XBOX_AXIS_MAX];
@ -59,6 +60,8 @@ public:
void send_button(uint16_t code, int32_t value);
void send_axis(uint16_t code, int32_t value);
void update();
};
#endif

View file

@ -380,6 +380,7 @@ void print_command_line_help(int argc, char** argv)
std::cout << " --square-axis Cause the diagonals to be reported as (1,1) instead of (0.7, 0.7)" << std::endl;
std::cout << " --relative-axis MAP Make an axis emulate a joystick throttle (example: y2=64000)" << std::endl;
std::cout << " --autofire MAP Cause the given buttons to act as autofire (example: A=250)" << std::endl;
std::cout << " --force-feedback Enable force feedback support" << std::endl;
std::cout << std::endl;
std::cout << "See README for more documentation and examples." << std::endl;
std::cout << "Report bugs to Ingo Ruhnke <grumbel@gmx.de>" << std::endl;
@ -531,6 +532,10 @@ void parse_command_line(int argc, char** argv, CommandLineOptions& opts)
exit(EXIT_FAILURE);
}
}
else if (strcmp(argv[i], "--force-feedback") == 0)
{
opts.uinput_config.force_feedback = true;
}
else if (strcmp(argv[i], "-b") == 0 ||
strcmp(argv[i], "--buttonmap") == 0)
{
@ -860,6 +865,8 @@ void print_info(struct usb_device* dev,
}
std::cout << std::endl;
}
std::cout << "ForceFeedback: " << ((opts.uinput_config.force_feedback) ? "enabled" : "disabled") << std::endl;
}
namespace Math {
@ -980,7 +987,8 @@ void controller_loop(uInput* uinput, XboxGenericController* controller, CommandL
relative_axis_modifier.reset(new RelativeAxisModifier(opts.relative_axis_map));
if (autofire_modifier.get() ||
relative_axis_modifier.get())
relative_axis_modifier.get() ||
opts.uinput_config.force_feedback)
timeout = 30;
memset(&oldmsg, 0, sizeof(oldmsg));
@ -1050,6 +1058,8 @@ void controller_loop(uInput* uinput, XboxGenericController* controller, CommandL
}
}
}
uinput->update();
}
}
@ -1177,8 +1187,9 @@ void run_main(CommandLineOptions& opts)
uInput* uinput = 0;
if (!opts.no_uinput)
{
std::cout << "Starting with uinput" << std::endl;
std::cout << "Starting with uinput... " << std::flush;
uinput = new uInput(opts.gamepad_type, opts.uinput_config);
std::cout << "done" << std::endl;
}
else
{