zenilib: zenilib/jni/external/sdl/src/haptic/linux/SDL_syshaptic.c Source File

zenilib 0.5.3.0

- Main Page
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
SDL_syshaptic.c
Go to the documentation of this file.
1 /*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "SDL_config.h"
22
23 #ifdef SDL_HAPTIC_LINUX
24
25 #include "SDL_haptic.h"
26 #include "../SDL_syshaptic.h"
27 #include "SDL_joystick.h"
28 #include "../../joystick/SDL_sysjoystick.h" /* For the real SDL_Joystick */
29 #include "../../joystick/linux/SDL_sysjoystick_c.h" /* For joystick hwdata */
30
31 #include <unistd.h> /* close */
32 #include <linux/input.h> /* Force feedback linux stuff. */
33 #include <fcntl.h> /* O_RDWR */
34 #include <limits.h> /* INT_MAX */
35 #include <errno.h> /* errno, strerror */
36 #include <math.h> /* atan2 */
37 #include <sys/stat.h> /* stat */
38
39 /* Just in case. */
40 #ifndef M_PI
41 # define M_PI 3.14159265358979323846
42 #endif
43
44
45 #define MAX_HAPTICS 32 /* It's doubtful someone has more then 32 evdev */
46
47
48 /*
49 * List of available haptic devices.
50 */
51 static struct
52 {
53 char *fname; /* Dev path name (like /dev/input/event1) */
54 SDL_Haptic *haptic; /* Assosciated haptic. */
55 } SDL_hapticlist[MAX_HAPTICS];
56
57
58 /*
59 * Haptic system hardware data.
60 */
61 struct haptic_hwdata
62 {
63 int fd; /* File descriptor of the device. */
64 char *fname; /* Points to the name in SDL_hapticlist. */
65 };
66
67
68 /*
69 * Haptic system effect data.
70 */
71 struct haptic_hweffect
72 {
73 struct ff_effect effect; /* The linux kernel effect structure. */
74 };
75
76
77
78 #define test_bit(nr, addr) \
79 (((1UL << ((nr) & 31)) & (((const unsigned int *) addr)[(nr) >> 5])) != 0)
80 #define EV_TEST(ev,f) \
81 if (test_bit((ev), features)) ret |= (f);
82 /*
83 * Test whether a device has haptic properties.
84 * Returns available properties or 0 if there are none.
85 */
86 static int
87 EV_IsHaptic(int fd)
88 {
89 unsigned int ret;
90 unsigned long features[1 + FF_MAX / sizeof(unsigned long)];
91
92 /* Ask device for what it has. */
93 ret = 0;
94 if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(features)), features) < 0) {
95 return SDL_SetError("Haptic: Unable to get device's features: %s",
96 strerror(errno));
97 }
98
99 /* Convert supported features to SDL_HAPTIC platform-neutral features. */
100 EV_TEST(FF_CONSTANT, SDL_HAPTIC_CONSTANT);
101 EV_TEST(FF_SINE, SDL_HAPTIC_SINE);
102 /* !!! FIXME: put this back when we have more bits in 2.1 */
103 /* EV_TEST(FF_SQUARE, SDL_HAPTIC_SQUARE); */
104 EV_TEST(FF_TRIANGLE, SDL_HAPTIC_TRIANGLE);
105 EV_TEST(FF_SAW_UP, SDL_HAPTIC_SAWTOOTHUP);
106 EV_TEST(FF_SAW_DOWN, SDL_HAPTIC_SAWTOOTHDOWN);
107 EV_TEST(FF_RAMP, SDL_HAPTIC_RAMP);
108 EV_TEST(FF_SPRING, SDL_HAPTIC_SPRING);
109 EV_TEST(FF_FRICTION, SDL_HAPTIC_FRICTION);
110 EV_TEST(FF_DAMPER, SDL_HAPTIC_DAMPER);
111 EV_TEST(FF_INERTIA, SDL_HAPTIC_INERTIA);
112 EV_TEST(FF_CUSTOM, SDL_HAPTIC_CUSTOM);
113 EV_TEST(FF_GAIN, SDL_HAPTIC_GAIN);
114 EV_TEST(FF_AUTOCENTER, SDL_HAPTIC_AUTOCENTER);
115 EV_TEST(FF_RUMBLE, SDL_HAPTIC_LEFTRIGHT);
116
117 /* Return what it supports. */
118 return ret;
119 }
120
121
122 /*
123 * Tests whether a device is a mouse or not.
124 */
125 static int
126 EV_IsMouse(int fd)
127 {
128 unsigned long argp[40];
129
130 /* Ask for supported features. */
131 if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(argp)), argp) < 0) {
132 return -1;
133 }
134
135 /* Currently we only test for BTN_MOUSE which can give fake positives. */
136 if (test_bit(BTN_MOUSE, argp) != 0) {
137 return 1;
138 }
139
140 return 0;
141 }
142
143 /*
144 * Initializes the haptic subsystem by finding available devices.
145 */
146 int
147 SDL_SYS_HapticInit(void)
148 {
149 const char joydev_pattern[] = "/dev/input/event%d";
150 dev_t dev_nums[MAX_HAPTICS];
151 char path[PATH_MAX];
152 struct stat sb;
153 int fd;
154 int i, j, k;
155 int duplicate;
156 int numhaptics;
157
158 numhaptics = 0;
159
160 /*
161 * Limit amount of checks to MAX_HAPTICS since we may or may not have
162 * permission to some or all devices.
163 */
164 i = 0;
165 for (j = 0; j < MAX_HAPTICS; ++j) {
166
167 snprintf(path, PATH_MAX, joydev_pattern, i++);
168
169 /* check to see if file exists */
170 if (stat(path, &sb) != 0)
171 break;
172
173 /* check for duplicates */
174 duplicate = 0;
175 for (k = 0; (k < numhaptics) && !duplicate; ++k) {
176 if (sb.st_rdev == dev_nums[k]) {
177 duplicate = 1;
178 }
179 }
180 if (duplicate) {
181 continue;
182 }
183
184 /* try to open */
185 fd = open(path, O_RDWR, 0);
186 if (fd < 0)
187 continue;
188
189 #ifdef DEBUG_INPUT_EVENTS
190 printf("Checking %s\n", path);
191 #endif
192
193 /* see if it works */
194 if (EV_IsHaptic(fd) > 0) {
195 SDL_hapticlist[numhaptics].fname = SDL_strdup(path);
196 SDL_hapticlist[numhaptics].haptic = NULL;
197 dev_nums[numhaptics] = sb.st_rdev;
198 ++numhaptics;
199 }
200 close(fd);
201 }
202
203 return numhaptics;
204 }
205
206
207 /*
208 * Gets the name from a file descriptor.
209 */
210 static const char *
211 SDL_SYS_HapticNameFromFD(int fd)
212 {
213 static char namebuf[128];
214
215 /* We use the evdev name ioctl. */
216 if (ioctl(fd, EVIOCGNAME(sizeof(namebuf)), namebuf) <= 0) {
217 return NULL;
218 }
219
220 return namebuf;
221 }
222
223
224 /*
225 * Return the name of a haptic device, does not need to be opened.
226 */
227 const char *
228 SDL_SYS_HapticName(int index)
229 {
230 int fd;
231 const char *name;
232
233 /* Open the haptic device. */
234 name = NULL;
235 fd = open(SDL_hapticlist[index].fname, O_RDONLY, 0);
236
237 if (fd >= 0) {
238
239 name = SDL_SYS_HapticNameFromFD(fd);
240 if (name == NULL) {
241 /* No name found, return device character device */
242 name = SDL_hapticlist[index].fname;
243 }
244 }
245 close(fd);
246
247 return name;
248 }
249
250
251 /*
252 * Opens the haptic device from the file descriptor.
253 */
254 static int
255 SDL_SYS_HapticOpenFromFD(SDL_Haptic * haptic, int fd)
256 {
257 /* Allocate the hwdata */
258 haptic->hwdata = (struct haptic_hwdata *)
259 SDL_malloc(sizeof(*haptic->hwdata));
260 if (haptic->hwdata == NULL) {
261 SDL_OutOfMemory();
262 goto open_err;
263 }
264 SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata));
265
266 /* Set the data. */
267 haptic->hwdata->fd = fd;
268 haptic->supported = EV_IsHaptic(fd);
269 haptic->naxes = 2; /* Hardcoded for now, not sure if it's possible to find out. */
270
271 /* Set the effects */
272 if (ioctl(fd, EVIOCGEFFECTS, &haptic->neffects) < 0) {
273 SDL_SetError("Haptic: Unable to query device memory: %s",
274 strerror(errno));
275 goto open_err;
276 }
277 haptic->nplaying = haptic->neffects; /* Linux makes no distinction. */
278 haptic->effects = (struct haptic_effect *)
279 SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects);
280 if (haptic->effects == NULL) {
281 SDL_OutOfMemory();
282 goto open_err;
283 }
284 /* Clear the memory */
285 SDL_memset(haptic->effects, 0,
286 sizeof(struct haptic_effect) * haptic->neffects);
287
288 return 0;
289
290 /* Error handling */
291 open_err:
292 close(fd);
293 if (haptic->hwdata != NULL) {
294 free(haptic->hwdata);
295 haptic->hwdata = NULL;
296 }
297 return -1;
298 }
299
300
301 /*
302 * Opens a haptic device for usage.
303 */
304 int
305 SDL_SYS_HapticOpen(SDL_Haptic * haptic)
306 {
307 int fd;
308 int ret;
309
310 /* Open the character device */
311 fd = open(SDL_hapticlist[haptic->index].fname, O_RDWR, 0);
312 if (fd < 0) {
313 return SDL_SetError("Haptic: Unable to open %s: %s",
314 SDL_hapticlist[haptic->index], strerror(errno));
315 }
316
317 /* Try to create the haptic. */
318 ret = SDL_SYS_HapticOpenFromFD(haptic, fd); /* Already closes on error. */
319 if (ret < 0) {
320 return -1;
321 }
322
323 /* Set the fname. */
324 haptic->hwdata->fname = SDL_hapticlist[haptic->index].fname;
325 return 0;
326 }
327
328
329 /*
330 * Opens a haptic device from first mouse it finds for usage.
331 */
332 int
333 SDL_SYS_HapticMouse(void)
334 {
335 int fd;
336 int i;
337
338 for (i = 0; i < SDL_numhaptics; i++) {
339
340 /* Open the device. */
341 fd = open(SDL_hapticlist[i].fname, O_RDWR, 0);
342 if (fd < 0) {
343 return SDL_SetError("Haptic: Unable to open %s: %s",
344 SDL_hapticlist[i], strerror(errno));
345 }
346
347 /* Is it a mouse? */
348 if (EV_IsMouse(fd)) {
349 close(fd);
350 return i;
351 }
352
353 close(fd);
354 }
355
356 return -1;
357 }
358
359
360 /*
361 * Checks to see if a joystick has haptic features.
362 */
363 int
364 SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick)
365 {
366 return EV_IsHaptic(joystick->hwdata->fd);
367 }
368
369
370 /*
371 * Checks to see if the haptic device and joystick are in reality the same.
372 */
373 int
374 SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
375 {
376 /* We are assuming Linux is using evdev which should trump the old
377 * joystick methods. */
378 if (SDL_strcmp(joystick->hwdata->fname, haptic->hwdata->fname) == 0) {
379 return 1;
380 }
381 return 0;
382 }
383
384
385 /*
386 * Opens a SDL_Haptic from a SDL_Joystick.
387 */
388 int
389 SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
390 {
391 int i;
392 int fd;
393 int ret;
394
395
396 /* Find the joystick in the haptic list. */
397 for (i = 0; i < MAX_HAPTICS; i++) {
398 if (SDL_hapticlist[i].fname != NULL) {
399 if (SDL_strcmp(SDL_hapticlist[i].fname, joystick->hwdata->fname)
400 == 0) {
401 haptic->index = i;
402 break;
403 }
404 }
405 }
406 if (i >= MAX_HAPTICS) {
407 return SDL_SetError("Haptic: Joystick doesn't have Haptic capabilities");
408 }
409
410 fd = open(joystick->hwdata->fname, O_RDWR, 0);
411 if (fd < 0) {
412 return SDL_SetError("Haptic: Unable to open %s: %s",
413 joystick->hwdata->fname, strerror(errno));
414 }
415 ret = SDL_SYS_HapticOpenFromFD(haptic, fd); /* Already closes on error. */
416 if (ret < 0) {
417 return -1;
418 }
419
420 haptic->hwdata->fname = SDL_hapticlist[haptic->index].fname;
421 return 0;
422 }
423
424
425 /*
426 * Closes the haptic device.
427 */
428 void
429 SDL_SYS_HapticClose(SDL_Haptic * haptic)
430 {
431 if (haptic->hwdata) {
432
433 /* Free effects. */
434 SDL_free(haptic->effects);
435 haptic->effects = NULL;
436 haptic->neffects = 0;
437
438 /* Clean up */
439 close(haptic->hwdata->fd);
440
441 /* Free */
442 SDL_free(haptic->hwdata);
443 haptic->hwdata = NULL;
444 }
445
446 /* Clear the rest. */
447 SDL_memset(haptic, 0, sizeof(SDL_Haptic));
448 }
449
450
451 /*
452 * Clean up after system specific haptic stuff
453 */
454 void
455 SDL_SYS_HapticQuit(void)
456 {
457 int i;
458
459 for (i = 0; SDL_hapticlist[i].fname != NULL; i++) {
460 /* Opened and not closed haptics are leaked, this is on purpose.
461 * Close your haptic devices after usage. */
462
463 SDL_free(SDL_hapticlist[i].fname);
464 }
465 SDL_hapticlist[0].fname = NULL;
466 }
467
468
469 /*
470 * Converts an SDL button to a ff_trigger button.
471 */
472 static Uint16
473 SDL_SYS_ToButton(Uint16 button)
474 {
475 Uint16 ff_button;
476
477 ff_button = 0;
478
479 /*
480 * Not sure what the proper syntax is because this actually isn't implemented
481 * in the current kernel from what I've seen (2.6.26).
482 */
483 if (button != 0) {
484 ff_button = BTN_GAMEPAD + button - 1;
485 }
486
487 return ff_button;
488 }
489
490
491 /*
492 * Returns the ff_effect usable direction from a SDL_HapticDirection.
493 */
494 static Uint16
495 SDL_SYS_ToDirection(SDL_HapticDirection * dir)
496 {
497 Uint32 tmp;
498 float f; /* Ideally we'd use fixed point math instead of floats... */
499
500 switch (dir->type) {
501 case SDL_HAPTIC_POLAR:
502 /* Linux directions start from south.
503 (and range from 0 to 0xFFFF)
504 Quoting include/linux/input.h, line 926:
505 Direction of the effect is encoded as follows:
506 0 deg -> 0x0000 (down)
507 90 deg -> 0x4000 (left)
508 180 deg -> 0x8000 (up)
509 270 deg -> 0xC000 (right)
510 */
511 tmp = (((18000 + dir->dir[0]) % 36000) * 0xFFFF) / 36000; /* convert to range [0,0xFFFF] */
512 return (Uint16) tmp;
513
514 case SDL_HAPTIC_SPHERICAL:
515 /*
516 We convert to polar, because that's the only supported direction on Linux.
517 The first value of a spherical direction is practically the same as a
518 Polar direction, except that we have to add 90 degrees. It is the angle
519 from EAST {1,0} towards SOUTH {0,1}.
520 --> add 9000
521 --> finally add 18000 and convert to [0,0xFFFF] as in case SDL_HAPTIC_POLAR.
522 */
523 tmp = ((dir->dir[0]) + 9000) % 36000; /* Convert to polars */
524 tmp = (((18000 + tmp) % 36000) * 0xFFFF) / 36000; /* convert to range [0,0xFFFF] */
525 return (Uint16) tmp;
526
527 case SDL_HAPTIC_CARTESIAN:
528 f = atan2(dir->dir[1], dir->dir[0]);
529 /*
530 atan2 takes the parameters: Y-axis-value and X-axis-value (in that order)
531 - Y-axis-value is the second coordinate (from center to SOUTH)
532 - X-axis-value is the first coordinate (from center to EAST)
533 We add 36000, because atan2 also returns negative values. Then we practically
534 have the first spherical value. Therefore we proceed as in case
535 SDL_HAPTIC_SPHERICAL and add another 9000 to get the polar value.
536 --> add 45000 in total
537 --> finally add 18000 and convert to [0,0xFFFF] as in case SDL_HAPTIC_POLAR.
538 */
539 tmp = (((int) (f * 18000. / M_PI)) + 45000) % 36000;
540 tmp = (((18000 + tmp) % 36000) * 0xFFFF) / 36000; /* convert to range [0,0xFFFF] */
541 return (Uint16) tmp;
542
543 default:
544 return (Uint16) SDL_SetError("Haptic: Unsupported direction type.");
545 }
546
547 return 0;
548 }
549
550
551 #define CLAMP(x) (((x) > 32767) ? 32767 : x)
552 /*
553 * Initializes the Linux effect struct from a haptic_effect.
554 * Values above 32767 (for unsigned) are unspecified so we must clamp.
555 */
556 static int
557 SDL_SYS_ToFFEffect(struct ff_effect *dest, SDL_HapticEffect * src)
558 {
559 Uint32 tmp;
560 SDL_HapticConstant *constant;
561 SDL_HapticPeriodic *periodic;
562 SDL_HapticCondition *condition;
563 SDL_HapticRamp *ramp;
564 SDL_HapticLeftRight *leftright;
565
566 /* Clear up */
567 SDL_memset(dest, 0, sizeof(struct ff_effect));
568
569 switch (src->type) {
570 case SDL_HAPTIC_CONSTANT:
571 constant = &src->constant;
572
573 /* Header */
574 dest->type = FF_CONSTANT;
575 dest->direction = SDL_SYS_ToDirection(&constant->direction);
576 if (dest->direction == (Uint16) - 1)
577 return -1;
578
579 /* Replay */
580 dest->replay.length = (constant->length == SDL_HAPTIC_INFINITY) ?
581 0 : CLAMP(constant->length);
582 dest->replay.delay = CLAMP(constant->delay);
583
584 /* Trigger */
585 dest->trigger.button = SDL_SYS_ToButton(constant->button);
586 dest->trigger.interval = CLAMP(constant->interval);
587
588 /* Constant */
589 dest->u.constant.level = constant->level;
590
591 /* Envelope */
592 dest->u.constant.envelope.attack_length =
593 CLAMP(constant->attack_length);
594 dest->u.constant.envelope.attack_level =
595 CLAMP(constant->attack_level);
596 dest->u.constant.envelope.fade_length = CLAMP(constant->fade_length);
597 dest->u.constant.envelope.fade_level = CLAMP(constant->fade_level);
598
599 break;
600
601 case SDL_HAPTIC_SINE:
602 /* !!! FIXME: put this back when we have more bits in 2.1 */
603 /* case SDL_HAPTIC_SQUARE: */
604 case SDL_HAPTIC_TRIANGLE:
605 case SDL_HAPTIC_SAWTOOTHUP:
606 case SDL_HAPTIC_SAWTOOTHDOWN:
607 periodic = &src->periodic;
608
609 /* Header */
610 dest->type = FF_PERIODIC;
611 dest->direction = SDL_SYS_ToDirection(&periodic->direction);
612 if (dest->direction == (Uint16) - 1)
613 return -1;
614
615 /* Replay */
616 dest->replay.length = (periodic->length == SDL_HAPTIC_INFINITY) ?
617 0 : CLAMP(periodic->length);
618 dest->replay.delay = CLAMP(periodic->delay);
619
620 /* Trigger */
621 dest->trigger.button = SDL_SYS_ToButton(periodic->button);
622 dest->trigger.interval = CLAMP(periodic->interval);
623
624 /* Periodic */
625 if (periodic->type == SDL_HAPTIC_SINE)
626 dest->u.periodic.waveform = FF_SINE;
627 /* !!! FIXME: put this back when we have more bits in 2.1 */
628 /* else if (periodic->type == SDL_HAPTIC_SQUARE)
629 dest->u.periodic.waveform = FF_SQUARE; */
630 else if (periodic->type == SDL_HAPTIC_TRIANGLE)
631 dest->u.periodic.waveform = FF_TRIANGLE;
632 else if (periodic->type == SDL_HAPTIC_SAWTOOTHUP)
633 dest->u.periodic.waveform = FF_SAW_UP;
634 else if (periodic->type == SDL_HAPTIC_SAWTOOTHDOWN)
635 dest->u.periodic.waveform = FF_SAW_DOWN;
636 dest->u.periodic.period = CLAMP(periodic->period);
637 dest->u.periodic.magnitude = periodic->magnitude;
638 dest->u.periodic.offset = periodic->offset;
639 /* Phase is calculated based of offset from period and then clamped. */
640 tmp = ((periodic->phase % 36000) * dest->u.periodic.period) / 36000;
641 dest->u.periodic.phase = CLAMP(tmp);
642
643 /* Envelope */
644 dest->u.periodic.envelope.attack_length =
645 CLAMP(periodic->attack_length);
646 dest->u.periodic.envelope.attack_level =
647 CLAMP(periodic->attack_level);
648 dest->u.periodic.envelope.fade_length = CLAMP(periodic->fade_length);
649 dest->u.periodic.envelope.fade_level = CLAMP(periodic->fade_level);
650
651 break;
652
653 case SDL_HAPTIC_SPRING:
654 case SDL_HAPTIC_DAMPER:
655 case SDL_HAPTIC_INERTIA:
656 case SDL_HAPTIC_FRICTION:
657 condition = &src->condition;
658
659 /* Header */
660 if (condition->type == SDL_HAPTIC_SPRING)
661 dest->type = FF_SPRING;
662 else if (condition->type == SDL_HAPTIC_DAMPER)
663 dest->type = FF_DAMPER;
664 else if (condition->type == SDL_HAPTIC_INERTIA)
665 dest->type = FF_INERTIA;
666 else if (condition->type == SDL_HAPTIC_FRICTION)
667 dest->type = FF_FRICTION;
668 dest->direction = 0; /* Handled by the condition-specifics. */
669
670 /* Replay */
671 dest->replay.length = (condition->length == SDL_HAPTIC_INFINITY) ?
672 0 : CLAMP(condition->length);
673 dest->replay.delay = CLAMP(condition->delay);
674
675 /* Trigger */
676 dest->trigger.button = SDL_SYS_ToButton(condition->button);
677 dest->trigger.interval = CLAMP(condition->interval);
678
679 /* Condition */
680 /* X axis */
681 dest->u.condition[0].right_saturation =
682 CLAMP(condition->right_sat[0]);
683 dest->u.condition[0].left_saturation = CLAMP(condition->left_sat[0]);
684 dest->u.condition[0].right_coeff = condition->right_coeff[0];
685 dest->u.condition[0].left_coeff = condition->left_coeff[0];
686 dest->u.condition[0].deadband = CLAMP(condition->deadband[0]);
687 dest->u.condition[0].center = condition->center[0];
688 /* Y axis */
689 dest->u.condition[1].right_saturation =
690 CLAMP(condition->right_sat[1]);
691 dest->u.condition[1].left_saturation = CLAMP(condition->left_sat[1]);
692 dest->u.condition[1].right_coeff = condition->right_coeff[1];
693 dest->u.condition[1].left_coeff = condition->left_coeff[1];
694 dest->u.condition[1].deadband = CLAMP(condition->deadband[1]);
695 dest->u.condition[1].center = condition->center[1];
696
697 /*
698 * There is no envelope in the linux force feedback api for conditions.
699 */
700
701 break;
702
703 case SDL_HAPTIC_RAMP:
704 ramp = &src->ramp;
705
706 /* Header */
707 dest->type = FF_RAMP;
708 dest->direction = SDL_SYS_ToDirection(&ramp->direction);
709 if (dest->direction == (Uint16) - 1)
710 return -1;
711
712 /* Replay */
713 dest->replay.length = (ramp->length == SDL_HAPTIC_INFINITY) ?
714 0 : CLAMP(ramp->length);
715 dest->replay.delay = CLAMP(ramp->delay);
716
717 /* Trigger */
718 dest->trigger.button = SDL_SYS_ToButton(ramp->button);
719 dest->trigger.interval = CLAMP(ramp->interval);
720
721 /* Ramp */
722 dest->u.ramp.start_level = ramp->start;
723 dest->u.ramp.end_level = ramp->end;
724
725 /* Envelope */
726 dest->u.ramp.envelope.attack_length = CLAMP(ramp->attack_length);
727 dest->u.ramp.envelope.attack_level = CLAMP(ramp->attack_level);
728 dest->u.ramp.envelope.fade_length = CLAMP(ramp->fade_length);
729 dest->u.ramp.envelope.fade_level = CLAMP(ramp->fade_level);
730
731 break;
732
733 case SDL_HAPTIC_LEFTRIGHT:
734 leftright = &src->leftright;
735
736 /* Header */
737 dest->type = FF_RUMBLE;
738 dest->direction = 0;
739
740 /* Replay */
741 dest->replay.length = (leftright->length == SDL_HAPTIC_INFINITY) ?
742 0 : CLAMP(leftright->length);
743
744 /* Trigger */
745 dest->trigger.button = 0;
746 dest->trigger.interval = 0;
747
748 /* Rumble */
749 dest->u.rumble.strong_magnitude = leftright->large_magnitude;
750 dest->u.rumble.weak_magnitude = leftright->small_magnitude;
751
752 break;
753
754
755 default:
756 return SDL_SetError("Haptic: Unknown effect type.");
757 }
758
759 return 0;
760 }
761
762
763 /*
764 * Creates a new haptic effect.
765 */
766 int
767 SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
768 SDL_HapticEffect * base)
769 {
770 struct ff_effect *linux_effect;
771
772 /* Allocate the hardware effect */
773 effect->hweffect = (struct haptic_hweffect *)
774 SDL_malloc(sizeof(struct haptic_hweffect));
775 if (effect->hweffect == NULL) {
776 return SDL_OutOfMemory();
777 }
778
779 /* Prepare the ff_effect */
780 linux_effect = &effect->hweffect->effect;
781 if (SDL_SYS_ToFFEffect(linux_effect, base) != 0) {
782 goto new_effect_err;
783 }
784 linux_effect->id = -1; /* Have the kernel give it an id */
785
786 /* Upload the effect */
787 if (ioctl(haptic->hwdata->fd, EVIOCSFF, linux_effect) < 0) {
788 SDL_SetError("Haptic: Error uploading effect to the device: %s",
789 strerror(errno));
790 goto new_effect_err;
791 }
792
793 return 0;
794
795 new_effect_err:
796 free(effect->hweffect);
797 effect->hweffect = NULL;
798 return -1;
799 }
800
801
802 /*
803 * Updates an effect.
804 *
805 * Note: Dynamically updating the direction can in some cases force
806 * the effect to restart and run once.
807 */
808 int
809 SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic,
810 struct haptic_effect *effect,
811 SDL_HapticEffect * data)
812 {
813 struct ff_effect linux_effect;
814
815 /* Create the new effect */
816 if (SDL_SYS_ToFFEffect(&linux_effect, data) != 0) {
817 return -1;
818 }
819 linux_effect.id = effect->hweffect->effect.id;
820
821 /* See if it can be uploaded. */
822 if (ioctl(haptic->hwdata->fd, EVIOCSFF, &linux_effect) < 0) {
823 return SDL_SetError("Haptic: Error updating the effect: %s",
824 strerror(errno));
825 }
826
827 /* Copy the new effect into memory. */
828 SDL_memcpy(&effect->hweffect->effect, &linux_effect,
829 sizeof(struct ff_effect));
830
831 return effect->hweffect->effect.id;
832 }
833
834
835 /*
836 * Runs an effect.
837 */
838 int
839 SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
840 Uint32 iterations)
841 {
842 struct input_event run;
843
844 /* Prepare to run the effect */
845 run.type = EV_FF;
846 run.code = effect->hweffect->effect.id;
847 /* We don't actually have infinity here, so we just do INT_MAX which is pretty damn close. */
848 run.value = (iterations > INT_MAX) ? INT_MAX : iterations;
849
850 if (write(haptic->hwdata->fd, (const void *) &run, sizeof(run)) < 0) {
851 return SDL_SetError("Haptic: Unable to run the effect: %s", strerror(errno));
852 }
853
854 return 0;
855 }
856
857
858 /*
859 * Stops an effect.
860 */
861 int
862 SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
863 {
864 struct input_event stop;
865
866 stop.type = EV_FF;
867 stop.code = effect->hweffect->effect.id;
868 stop.value = 0;
869
870 if (write(haptic->hwdata->fd, (const void *) &stop, sizeof(stop)) < 0) {
871 return SDL_SetError("Haptic: Unable to stop the effect: %s",
872 strerror(errno));
873 }
874
875 return 0;
876 }
877
878
879 /*
880 * Frees the effect.
881 */
882 void
883 SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
884 {
885 if (ioctl(haptic->hwdata->fd, EVIOCRMFF, effect->hweffect->effect.id) < 0) {
886 SDL_SetError("Haptic: Error removing the effect from the device: %s",
887 strerror(errno));
888 }
889 SDL_free(effect->hweffect);
890 effect->hweffect = NULL;
891 }
892
893
894 /*
895 * Gets the status of a haptic effect.
896 */
897 int
898 SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic,
899 struct haptic_effect *effect)
900 {
901 #if 0 /* Not supported atm. */
902 struct input_event ie;
903
904 ie.type = EV_FF;
905 ie.type = EV_FF_STATUS;
906 ie.code = effect->hweffect->effect.id;
907
908 if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) {
909 return SDL_SetError("Haptic: Error getting device status.");
910 }
911
912 return 0;
913 #endif
914
915 return -1;
916 }
917
918
919 /*
920 * Sets the gain.
921 */
922 int
923 SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain)
924 {
925 struct input_event ie;
926
927 ie.type = EV_FF;
928 ie.code = FF_GAIN;
929 ie.value = (0xFFFFUL * gain) / 100;
930
931 if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) {
932 return SDL_SetError("Haptic: Error setting gain: %s", strerror(errno));
933 }
934
935 return 0;
936 }
937
938
939 /*
940 * Sets the autocentering.
941 */
942 int
943 SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
944 {
945 struct input_event ie;
946
947 ie.type = EV_FF;
948 ie.code = FF_AUTOCENTER;
949 ie.value = (0xFFFFUL * autocenter) / 100;
950
951 if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) {
952 return SDL_SetError("Haptic: Error setting autocenter: %s", strerror(errno));
953 }
954
955 return 0;
956 }
957
958
959 /*
960 * Pausing is not supported atm by linux.
961 */
962 int
963 SDL_SYS_HapticPause(SDL_Haptic * haptic)
964 {
965 return -1;
966 }
967
968
969 /*
970 * Unpausing is not supported atm by linux.
971 */
972 int
973 SDL_SYS_HapticUnpause(SDL_Haptic * haptic)
974 {
975 return -1;
976 }
977
978
979 /*
980 * Stops all the currently playing effects.
981 */
982 int
983 SDL_SYS_HapticStopAll(SDL_Haptic * haptic)
984 {
985 int i, ret;
986
987 /* Linux does not support this natively so we have to loop. */
988 for (i = 0; i < haptic->neffects; i++) {
989 if (haptic->effects[i].hweffect != NULL) {
990 ret = SDL_SYS_HapticStopEffect(haptic, &haptic->effects[i]);
991 if (ret < 0) {
992 return SDL_SetError
993 ("Haptic: Error while trying to stop all playing effects.");
994 }
995 }
996 }
997 return 0;
998 }
999
1000
1001 #endif /* SDL_HAPTIC_LINUX */
SDL_HapticConstant::type
Uint16 type
Definition: SDL_haptic.h:460
SDL_SYS_HapticOpenFromJoystick
int SDL_SYS_HapticOpenFromJoystick(SDL_Haptic *haptic, SDL_Joystick *joystick)
_SDL_Haptic::hwdata
struct haptic_hwdata * hwdata
Definition: SDL_syshaptic.h:52
SDL_HapticPeriodic::period
Uint16 period
Definition: SDL_haptic.h:555
SDL_HapticCondition::deadband
Uint16 deadband[3]
Definition: SDL_haptic.h:611
SDL_HapticDirection
Structure that represents a haptic direction.
Definition: SDL_haptic.h:439
SDL_HapticCondition::type
Uint16 type
Definition: SDL_haptic.h:594
condition
GLenum condition
Definition: gl2ext.h:1403
SDL_HapticCondition::delay
Uint16 delay
Definition: SDL_haptic.h:600
SDL_HapticConstant::interval
Uint16 interval
Definition: SDL_haptic.h:469
SDL_HapticPeriodic::type
Uint16 type
Definition: SDL_haptic.h:541
_SDL_Haptic::effects
struct haptic_effect * effects
Definition: SDL_syshaptic.h:46
SDL_HAPTIC_SPHERICAL
#define SDL_HAPTIC_SPHERICAL
Uses spherical coordinates for the direction.
Definition: SDL_haptic.h:329
SDL_HapticConstant::fade_level
Uint16 fade_level
Definition: SDL_haptic.h:478
SDL_joystick.h
SDL_HAPTIC_AUTOCENTER
#define SDL_HAPTIC_AUTOCENTER
Device can set autocenter.
Definition: SDL_haptic.h:285
_SDL_Haptic::index
Uint8 index
Definition: SDL_syshaptic.h:44
SDL_HapticPeriodic
A structure containing a template for a Periodic effect.
Definition: SDL_haptic.h:538
NULL
#define NULL
Definition: ftobjs.h:61
f
GLclampf f
Definition: glew.h:3390
SDL_HAPTIC_GAIN
#define SDL_HAPTIC_GAIN
Device can set global gain.
Definition: SDL_haptic.h:276
SDL_HAPTIC_CUSTOM
#define SDL_HAPTIC_CUSTOM
Custom effect is supported.
Definition: SDL_haptic.h:263
SDL_HAPTIC_TRIANGLE
#define SDL_HAPTIC_TRIANGLE
Triangle wave effect supported.
Definition: SDL_haptic.h:189
k
int32_t k
Definition: e_log.c:102
SDL_SYS_HapticOpen
int SDL_SYS_HapticOpen(SDL_Haptic *haptic)
SDL_HapticPeriodic::length
Uint32 length
Definition: SDL_haptic.h:547
SDL_SYS_HapticMouse
int SDL_SYS_HapticMouse(void)
SDL_SYS_JoystickSameHaptic
int SDL_SYS_JoystickSameHaptic(SDL_Haptic *haptic, SDL_Joystick *joystick)
_SDL_Haptic
Definition: SDL_syshaptic.h:42
SDL_HapticRamp::end
Sint16 end
Definition: SDL_haptic.h:644
SDL_HapticCondition::button
Uint16 button
Definition: SDL_haptic.h:603
SDL_HAPTIC_INERTIA
#define SDL_HAPTIC_INERTIA
Inertia effect supported - uses axes acceleration.
Definition: SDL_haptic.h:246
free
SDL_EventEntry * free
Definition: SDL_events.c:80
_SDL_Haptic::naxes
int naxes
Definition: SDL_syshaptic.h:50
SDL_free
DECLSPEC void SDLCALL SDL_free(void *mem)
SDL_HapticRamp::fade_level
Uint16 fade_level
Definition: SDL_haptic.h:650
j
int32_t j
Definition: e_log.c:102
SDL_HapticRamp::type
Uint16 type
Definition: SDL_haptic.h:631
SDL_HapticEffect::ramp
SDL_HapticRamp ramp
Definition: SDL_haptic.h:794
SDL_HapticCondition::interval
Uint16 interval
Definition: SDL_haptic.h:604
SDL_SYS_HapticStopEffect
int SDL_SYS_HapticStopEffect(SDL_Haptic *haptic, struct haptic_effect *effect)
SDL_SYS_HapticName
const char * SDL_SYS_HapticName(int index)
SDL_HapticCondition
A structure containing a template for a Condition effect.
Definition: SDL_haptic.h:591
name
EGLImageKHR EGLint * name
Definition: eglext.h:284
SDL_HapticLeftRight::type
Uint16 type
Definition: SDL_haptic.h:668
SDL_HapticPeriodic::fade_level
Uint16 fade_level
Definition: SDL_haptic.h:564
SDL_haptic.h
The SDL Haptic subsystem allows you to control haptic (force feedback) devices.
SDL_SYS_HapticUnpause
int SDL_SYS_HapticUnpause(SDL_Haptic *haptic)
SDL_HapticConstant::attack_length
Uint16 attack_length
Definition: SDL_haptic.h:475
SDL_HapticCondition::left_coeff
Sint16 left_coeff[3]
Definition: SDL_haptic.h:610
SDL_HapticLeftRight::small_magnitude
Uint16 small_magnitude
Definition: SDL_haptic.h:675
SDL_HapticCondition::right_sat
Uint16 right_sat[3]
Definition: SDL_haptic.h:607
SDL_HapticPeriodic::button
Uint16 button
Definition: SDL_haptic.h:551
SDL_HapticCondition::right_coeff
Sint16 right_coeff[3]
Definition: SDL_haptic.h:609
SDL_HapticDirection::type
Uint8 type
Definition: SDL_haptic.h:441
SDL_HAPTIC_SINE
#define SDL_HAPTIC_SINE
Sine wave effect supported.
Definition: SDL_haptic.h:166
SDL_HapticPeriodic::attack_level
Uint16 attack_level
Definition: SDL_haptic.h:562
path
GLsizei const GLchar *const * path
Definition: glew.h:5828
SDL_SYS_HapticGetEffectStatus
int SDL_SYS_HapticGetEffectStatus(SDL_Haptic *haptic, struct haptic_effect *effect)
SDL_config.h
_SDL_Joystick::hwdata
struct joystick_hwdata * hwdata
Definition: SDL_sysjoystick.h:49
ret
ret
Definition: glew_str_glx.c:2
SDL_HapticRamp::length
Uint32 length
Definition: SDL_haptic.h:635
SDL_HapticConstant
A structure containing a template for a Constant effect.
Definition: SDL_haptic.h:457
SDL_numhaptics
Uint8 SDL_numhaptics
Definition: SDL_haptic.c:28
_SDL_Haptic::neffects
int neffects
Definition: SDL_syshaptic.h:47
SDL_HAPTIC_INFINITY
#define SDL_HAPTIC_INFINITY
Used to play a device an infinite number of times.
Definition: SDL_haptic.h:344
SDL_HapticRamp::interval
Uint16 interval
Definition: SDL_haptic.h:640
SDL_HAPTIC_CARTESIAN
#define SDL_HAPTIC_CARTESIAN
Uses cartesian coordinates for the direction.
Definition: SDL_haptic.h:322
Uint32
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:145
SDL_HapticPeriodic::fade_length
Uint16 fade_length
Definition: SDL_haptic.h:563
_SDL_Haptic::supported
unsigned int supported
Definition: SDL_syshaptic.h:49
SDL_HapticEffect::condition
SDL_HapticCondition condition
Definition: SDL_haptic.h:793
SDL_HapticLeftRight
A structure containing a template for a Left/Right effect.
Definition: SDL_haptic.h:665
SDL_HapticConstant::level
Sint16 level
Definition: SDL_haptic.h:472
SDL_HapticEffect
The generic template for any haptic effect.
Definition: SDL_haptic.h:787
SDL_HapticConstant::delay
Uint16 delay
Definition: SDL_haptic.h:465
SDL_HAPTIC_CONSTANT
#define SDL_HAPTIC_CONSTANT
Constant effect supported.
Definition: SDL_haptic.h:157
SDL_SYS_HapticSetAutocenter
int SDL_SYS_HapticSetAutocenter(SDL_Haptic *haptic, int autocenter)
SDL_HapticConstant::attack_level
Uint16 attack_level
Definition: SDL_haptic.h:476
int
int
Definition: SDL_systhread.c:37
SDL_HapticCondition::length
Uint32 length
Definition: SDL_haptic.h:599
SDL_HapticPeriodic::offset
Sint16 offset
Definition: SDL_haptic.h:557
data
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl2ext.h:848
SDL_strdup
DECLSPEC char *SDLCALL SDL_strdup(const char *str)
Definition: SDL_string.c:511
haptic_effect
Definition: SDL_syshaptic.h:33
SDL_HAPTIC_POLAR
#define SDL_HAPTIC_POLAR
Uses polar coordinates for the direction.
Definition: SDL_haptic.h:315
SDL_memset
DECLSPEC void *SDLCALL SDL_memset(void *dst, int c, size_t len)
Definition: SDL_string.c:261
SDL_HapticEffect::constant
SDL_HapticConstant constant
Definition: SDL_haptic.h:791
SDL_SetError
DECLSPEC int SDLCALL SDL_SetError(const char *fmt,...)
Definition: SDL_error.c:53
SDL_malloc
DECLSPEC void *SDLCALL SDL_malloc(size_t size)
index
GLuint index
Definition: glew.h:1800
SDL_SYS_HapticUpdateEffect
int SDL_SYS_HapticUpdateEffect(SDL_Haptic *haptic, struct haptic_effect *effect, SDL_HapticEffect *data)
SDL_strcmp
DECLSPEC int SDLCALL SDL_strcmp(const char *str1, const char *str2)
Definition: SDL_string.c:910
SDL_HapticDirection::dir
Sint32 dir[3]
Definition: SDL_haptic.h:442
SDL_SYS_JoystickIsHaptic
int SDL_SYS_JoystickIsHaptic(SDL_Joystick *joystick)
SDL_HapticConstant::length
Uint32 length
Definition: SDL_haptic.h:464
SDL_HapticRamp::direction
SDL_HapticDirection direction
Definition: SDL_haptic.h:632
SDL_HapticConstant::button
Uint16 button
Definition: SDL_haptic.h:468
SDL_HapticEffect::type
Uint16 type
Definition: SDL_haptic.h:790
SDL_HapticRamp
A structure containing a template for a Ramp effect.
Definition: SDL_haptic.h:628
M_PI
#define M_PI
Definition: os.h:45
SDL_SYS_HapticDestroyEffect
void SDL_SYS_HapticDestroyEffect(SDL_Haptic *haptic, struct haptic_effect *effect)
SDL_HapticRamp::attack_length
Uint16 attack_length
Definition: SDL_haptic.h:647
EVIOCRMFF
#define EVIOCRMFF
Definition: SDL_config_linux.h:368
PATH_MAX
#define PATH_MAX
Definition: hrtf.c:34
SDL_HapticRamp::fade_length
Uint16 fade_length
Definition: SDL_haptic.h:649
SDL_OutOfMemory
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_HapticRamp::delay
Uint16 delay
Definition: SDL_haptic.h:636
haptic_effect::effect
SDL_HapticEffect effect
Definition: SDL_syshaptic.h:35
SDL_SYS_HapticInit
int SDL_SYS_HapticInit(void)
SDL_SYS_HapticQuit
void SDL_SYS_HapticQuit(void)
haptic_effect::hweffect
struct haptic_hweffect * hweffect
Definition: SDL_syshaptic.h:36
SDL_SYS_HapticClose
void SDL_SYS_HapticClose(SDL_Haptic *haptic)
SDL_SYS_HapticPause
int SDL_SYS_HapticPause(SDL_Haptic *haptic)
SDL_memcpy
DECLSPEC void *SDLCALL SDL_memcpy(void *dst, const void *src, size_t len)
Definition: SDL_string.c:293
SDL_HapticPeriodic::direction
SDL_HapticDirection direction
Definition: SDL_haptic.h:544
SDL_HapticEffect::leftright
SDL_HapticLeftRight leftright
Definition: SDL_haptic.h:795
SDL_HapticPeriodic::magnitude
Sint16 magnitude
Definition: SDL_haptic.h:556
SDL_HAPTIC_RAMP
#define SDL_HAPTIC_RAMP
Ramp effect supported.
Definition: SDL_haptic.h:216
SDL_HAPTIC_SPRING
#define SDL_HAPTIC_SPRING
Spring effect supported - uses axes position.
Definition: SDL_haptic.h:226
_SDL_Haptic::nplaying
int nplaying
Definition: SDL_syshaptic.h:48
SDL_HapticPeriodic::attack_length
Uint16 attack_length
Definition: SDL_haptic.h:561
SDL_HapticRamp::start
Sint16 start
Definition: SDL_haptic.h:643
_SDL_Joystick
Definition: SDL_sysjoystick.h:29
SDL_HapticPeriodic::delay
Uint16 delay
Definition: SDL_haptic.h:548
SDL_HapticPeriodic::interval
Uint16 interval
Definition: SDL_haptic.h:552
SDL_SYS_HapticStopAll
int SDL_SYS_HapticStopAll(SDL_Haptic *haptic)
SDL_HapticCondition::center
Sint16 center[3]
Definition: SDL_haptic.h:612
Uint16
uint16_t Uint16
An unsigned 16-bit integer type.
Definition: SDL_stdinc.h:137
SDL_HAPTIC_SAWTOOTHUP
#define SDL_HAPTIC_SAWTOOTHUP
Sawtoothup wave effect supported.
Definition: SDL_haptic.h:198
joystick_hwdata::fd
int fd
Definition: SDL_sysjoystick_c.h:29
SDL_SYS_HapticSetGain
int SDL_SYS_HapticSetGain(SDL_Haptic *haptic, int gain)
src
GLenum src
Definition: glew.h:2396
i
int i
Definition: pngrutil.c:1377
joystick_hwdata::fname
char * fname
Definition: SDL_sysjoystick_c.h:32
SDL_HapticLeftRight::large_magnitude
Uint16 large_magnitude
Definition: SDL_haptic.h:674
SDL_HAPTIC_LEFTRIGHT
#define SDL_HAPTIC_LEFTRIGHT
Left/Right effect supported.
Definition: SDL_haptic.h:177
SDL_SYS_HapticRunEffect
int SDL_SYS_HapticRunEffect(SDL_Haptic *haptic, struct haptic_effect *effect, Uint32 iterations)
SDL_HapticEffect::periodic
SDL_HapticPeriodic periodic
Definition: SDL_haptic.h:792
SDL_HapticRamp::attack_level
Uint16 attack_level
Definition: SDL_haptic.h:648
SDL_HapticLeftRight::length
Uint32 length
Definition: SDL_haptic.h:671
SDL_HapticRamp::button
Uint16 button
Definition: SDL_haptic.h:639
SDL_HAPTIC_FRICTION
#define SDL_HAPTIC_FRICTION
Friction effect supported - uses axes movement.
Definition: SDL_haptic.h:256
SDL_HAPTIC_SAWTOOTHDOWN
#define SDL_HAPTIC_SAWTOOTHDOWN
Sawtoothdown wave effect supported.
Definition: SDL_haptic.h:207
SDL_HapticPeriodic::phase
Uint16 phase
Definition: SDL_haptic.h:558
SDL_HapticConstant::fade_length
Uint16 fade_length
Definition: SDL_haptic.h:477
SDL_HapticConstant::direction
SDL_HapticDirection direction
Definition: SDL_haptic.h:461
SDL_SYS_HapticNewEffect
int SDL_SYS_HapticNewEffect(SDL_Haptic *haptic, struct haptic_effect *effect, SDL_HapticEffect *base)
SDL_HAPTIC_DAMPER
#define SDL_HAPTIC_DAMPER
Damper effect supported - uses axes velocity.
Definition: SDL_haptic.h:236
SDL_HapticCondition::left_sat
Uint16 left_sat[3]
Definition: SDL_haptic.h:608