23#include "force_feedback.h"
25#include <core/exception.h>
38#define BITS_PER_LONG (sizeof(long) * 8)
39#define NBITS(x) ((((x)-1) / BITS_PER_LONG) + 1)
40#define OFF(x) ((x) % BITS_PER_LONG)
41#define BIT(x) (1UL << OFF(x))
42#define LONG(x) ((x) / BITS_PER_LONG)
43#define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
127 DIR *d = opendir(
"/dev/input");
130 throw Exception(
"Could not open directory /dev/input");
134 while ((de = readdir(d)) != NULL) {
135 if (fnmatch(
"event*", de->d_name, 0) != FNM_NOMATCH) {
137 if (asprintf(&path,
"/dev/input/%s", de->d_name) == -1) {
141 fd_ = open(path, O_RDWR);
148 char name[256] =
"Unknown";
149 if (ioctl(fd_, EVIOCGNAME(
sizeof(name)), name) < 0) {
155 if (strcmp(name, device_name) != 0) {
161 long features[NBITS(EV_MAX)];
162 memset(features, 0,
sizeof(features));
163 if (ioctl(fd_, EVIOCGBIT(0, EV_MAX), features) < 0) {
166 throw Exception(
"Cannot get feedback feature vector");
169 if (!test_bit(EV_FF, features)) {
172 throw Exception(
"Device '%s' does not support force-feedback", device_name);
175 long ff_features[NBITS(FF_MAX)];
177 memset(ff_features, 0,
sizeof(ff_features));
178 if (ioctl(fd_, EVIOCGBIT(EV_FF, FF_MAX), ff_features) < 0) {
181 throw Exception(
"Cannot get device force feedback feature vector");
184 long no_ff_features[NBITS(FF_MAX)];
185 memset(no_ff_features, 0,
sizeof(no_ff_features));
186 if (memcmp(ff_features, no_ff_features,
sizeof(no_ff_features)) == 0) {
189 throw Exception(
"Device has no force feedback features");
192 can_rumble_ = test_bit(FF_RUMBLE, ff_features);
193 can_periodic_ = test_bit(FF_PERIODIC, ff_features);
194 can_constant_ = test_bit(FF_CONSTANT, ff_features);
195 can_spring_ = test_bit(FF_SPRING, ff_features);
196 can_friction_ = test_bit(FF_FRICTION, ff_features);
197 can_damper_ = test_bit(FF_DAMPER, ff_features);
198 can_inertia_ = test_bit(FF_INERTIA, ff_features);
199 can_ramp_ = test_bit(FF_RAMP, ff_features);
200 can_square_ = test_bit(FF_SQUARE, ff_features);
201 can_triangle_ = test_bit(FF_TRIANGLE, ff_features);
202 can_sine_ = test_bit(FF_SINE, ff_features);
203 can_saw_up_ = test_bit(FF_SAW_UP, ff_features);
204 can_saw_down_ = test_bit(FF_SAW_DOWN, ff_features);
205 can_custom_ = test_bit(FF_CUSTOM, ff_features);
207 if (ioctl(fd_, EVIOCGEFFECTS, &num_effects_) < 0) {
218 throw Exception(
"Force feedback joystick '%s' not found", device_name);
221 memset(&rumble_, 0,
sizeof(rumble_));
222 rumble_.type = FF_RUMBLE;
247 uint16_t weak_magnitude,
252 if ((rumble_.id == -1) || (rumble_.u.rumble.strong_magnitude != strong_magnitude)
253 || (rumble_.u.rumble.weak_magnitude != weak_magnitude) || (rumble_.direction != direction)
254 || (rumble_.replay.length != length) || (rumble_.replay.delay != length)) {
256 rumble_.u.rumble.strong_magnitude = strong_magnitude;
257 rumble_.u.rumble.weak_magnitude = weak_magnitude;
258 rumble_.direction = direction;
259 rumble_.replay.length = length;
260 rumble_.replay.delay = delay;
262 if (ioctl(fd_, EVIOCSFF, &rumble_) < 0) {
263 throw Exception(
"Failed to upload rumble effect");
267 struct input_event play;
269 play.code = rumble_.id;
272 if (write(fd_, &play,
sizeof(play)) < 0) {
273 throw Exception(
"Failed to start rumble effect");
281 if (rumble_.id != -1) {
282 if (ioctl(fd_, EVIOCRMFF, rumble_.id) < 0) {
283 throw Exception(
"Failed to stop rumble effect");
Direction
Direction of the effect.
JoystickForceFeedback(const char *device_name)
Constructor.
void rumble(uint16_t strong_magnitude, uint16_t weak_magnitude, Direction direction=DIRECTION_DOWN, uint16_t length=0, uint16_t delay=0)
Rumble the joystick.
void stop_all()
Stop all current effects.
void stop_rumble()
Stop rumbling.
~JoystickForceFeedback()
Destructor.
Base class for exceptions in Fawkes.
Fawkes library namespace.