SDL  2.0
SDL_syshaptic.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2020 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_internal.h"
22 
23 #ifdef SDL_HAPTIC_LINUX
24 
25 #include "SDL_assert.h"
26 #include "SDL_haptic.h"
27 #include "../SDL_syshaptic.h"
28 #include "SDL_joystick.h"
29 #include "../../joystick/SDL_sysjoystick.h" /* For the real SDL_Joystick */
30 #include "../../joystick/linux/SDL_sysjoystick_c.h" /* For joystick hwdata */
31 #include "../../core/linux/SDL_udev.h"
32 
33 #include <unistd.h> /* close */
34 #include <linux/input.h> /* Force feedback linux stuff. */
35 #include <fcntl.h> /* O_RDWR */
36 #include <limits.h> /* INT_MAX */
37 #include <errno.h> /* errno, strerror */
38 #include <math.h> /* atan2 */
39 #include <sys/stat.h> /* stat */
40 
41 /* Just in case. */
42 #ifndef M_PI
43 # define M_PI 3.14159265358979323846
44 #endif
45 
46 
47 #define MAX_HAPTICS 32 /* It's doubtful someone has more then 32 evdev */
48 
49 static int MaybeAddDevice(const char *path);
50 #if SDL_USE_LIBUDEV
51 static int MaybeRemoveDevice(const char *path);
52 static void haptic_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath);
53 #endif /* SDL_USE_LIBUDEV */
54 
55 /*
56  * List of available haptic devices.
57  */
58 typedef struct SDL_hapticlist_item
59 {
60  char *fname; /* Dev path name (like /dev/input/event1) */
61  SDL_Haptic *haptic; /* Associated haptic. */
62  dev_t dev_num;
63  struct SDL_hapticlist_item *next;
65 
66 
67 /*
68  * Haptic system hardware data.
69  */
70 struct haptic_hwdata
71 {
72  int fd; /* File descriptor of the device. */
73  char *fname; /* Points to the name in SDL_hapticlist. */
74 };
75 
76 
77 /*
78  * Haptic system effect data.
79  */
80 struct haptic_hweffect
81 {
82  struct ff_effect effect; /* The linux kernel effect structure. */
83 };
84 
86 static SDL_hapticlist_item *SDL_hapticlist_tail = NULL;
87 static int numhaptics = 0;
88 
89 #define test_bit(nr, addr) \
90  (((1UL << ((nr) & 31)) & (((const unsigned int *) addr)[(nr) >> 5])) != 0)
91 #define EV_TEST(ev,f) \
92  if (test_bit((ev), features)) ret |= (f);
93 /*
94  * Test whether a device has haptic properties.
95  * Returns available properties or 0 if there are none.
96  */
97 static int
98 EV_IsHaptic(int fd)
99 {
100  unsigned int ret;
101  unsigned long features[1 + FF_MAX / sizeof(unsigned long)];
102 
103  /* Ask device for what it has. */
104  ret = 0;
105  if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(features)), features) < 0) {
106  return SDL_SetError("Haptic: Unable to get device's features: %s",
107  strerror(errno));
108  }
109 
110  /* Convert supported features to SDL_HAPTIC platform-neutral features. */
111  EV_TEST(FF_CONSTANT, SDL_HAPTIC_CONSTANT);
112  EV_TEST(FF_SINE, SDL_HAPTIC_SINE);
113  /* !!! FIXME: put this back when we have more bits in 2.1 */
114  /* EV_TEST(FF_SQUARE, SDL_HAPTIC_SQUARE); */
115  EV_TEST(FF_TRIANGLE, SDL_HAPTIC_TRIANGLE);
116  EV_TEST(FF_SAW_UP, SDL_HAPTIC_SAWTOOTHUP);
117  EV_TEST(FF_SAW_DOWN, SDL_HAPTIC_SAWTOOTHDOWN);
118  EV_TEST(FF_RAMP, SDL_HAPTIC_RAMP);
119  EV_TEST(FF_SPRING, SDL_HAPTIC_SPRING);
120  EV_TEST(FF_FRICTION, SDL_HAPTIC_FRICTION);
121  EV_TEST(FF_DAMPER, SDL_HAPTIC_DAMPER);
122  EV_TEST(FF_INERTIA, SDL_HAPTIC_INERTIA);
123  EV_TEST(FF_CUSTOM, SDL_HAPTIC_CUSTOM);
124  EV_TEST(FF_GAIN, SDL_HAPTIC_GAIN);
125  EV_TEST(FF_AUTOCENTER, SDL_HAPTIC_AUTOCENTER);
126  EV_TEST(FF_RUMBLE, SDL_HAPTIC_LEFTRIGHT);
127 
128  /* Return what it supports. */
129  return ret;
130 }
131 
132 
133 /*
134  * Tests whether a device is a mouse or not.
135  */
136 static int
137 EV_IsMouse(int fd)
138 {
139  unsigned long argp[40];
140 
141  /* Ask for supported features. */
142  if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(argp)), argp) < 0) {
143  return -1;
144  }
145 
146  /* Currently we only test for BTN_MOUSE which can give fake positives. */
147  if (test_bit(BTN_MOUSE, argp) != 0) {
148  return 1;
149  }
150 
151  return 0;
152 }
153 
154 /*
155  * Initializes the haptic subsystem by finding available devices.
156  */
157 int
158 SDL_SYS_HapticInit(void)
159 {
160  const char joydev_pattern[] = "/dev/input/event%d";
161  char path[PATH_MAX];
162  int i, j;
163 
164  /*
165  * Limit amount of checks to MAX_HAPTICS since we may or may not have
166  * permission to some or all devices.
167  */
168  i = 0;
169  for (j = 0; j < MAX_HAPTICS; ++j) {
170 
171  snprintf(path, PATH_MAX, joydev_pattern, i++);
172  MaybeAddDevice(path);
173  }
174 
175 #if SDL_USE_LIBUDEV
176  if (SDL_UDEV_Init() < 0) {
177  return SDL_SetError("Could not initialize UDEV");
178  }
179 
180  if ( SDL_UDEV_AddCallback(haptic_udev_callback) < 0) {
181  SDL_UDEV_Quit();
182  return SDL_SetError("Could not setup haptic <-> udev callback");
183  }
184 
185  /* Force a scan to build the initial device list */
186  SDL_UDEV_Scan();
187 #endif /* SDL_USE_LIBUDEV */
188 
189  return numhaptics;
190 }
191 
192 int
193 SDL_SYS_NumHaptics(void)
194 {
195  return numhaptics;
196 }
197 
198 static SDL_hapticlist_item *
199 HapticByDevIndex(int device_index)
200 {
202 
203  if ((device_index < 0) || (device_index >= numhaptics)) {
204  return NULL;
205  }
206 
207  while (device_index > 0) {
208  SDL_assert(item != NULL);
209  --device_index;
210  item = item->next;
211  }
212 
213  return item;
214 }
215 
216 #if SDL_USE_LIBUDEV
217 static void haptic_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath)
218 {
219  if (devpath == NULL || !(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) {
220  return;
221  }
222 
223  switch( udev_type )
224  {
225  case SDL_UDEV_DEVICEADDED:
226  MaybeAddDevice(devpath);
227  break;
228 
229  case SDL_UDEV_DEVICEREMOVED:
230  MaybeRemoveDevice(devpath);
231  break;
232 
233  default:
234  break;
235  }
236 
237 }
238 #endif /* SDL_USE_LIBUDEV */
239 
240 static int
241 MaybeAddDevice(const char *path)
242 {
243  struct stat sb;
244  int fd;
245  int success;
246  SDL_hapticlist_item *item;
247 
248  if (path == NULL) {
249  return -1;
250  }
251 
252  /* check to see if file exists */
253  if (stat(path, &sb) != 0) {
254  return -1;
255  }
256 
257  /* check for duplicates */
258  for (item = SDL_hapticlist; item != NULL; item = item->next) {
259  if (item->dev_num == sb.st_rdev) {
260  return -1; /* duplicate. */
261  }
262  }
263 
264  /* try to open */
265  fd = open(path, O_RDWR, 0);
266  if (fd < 0) {
267  return -1;
268  }
269 
270 #ifdef DEBUG_INPUT_EVENTS
271  printf("Checking %s\n", path);
272 #endif
273 
274  /* see if it works */
275  success = EV_IsHaptic(fd);
276  close(fd);
277  if (success <= 0) {
278  return -1;
279  }
280 
281  item = (SDL_hapticlist_item *) SDL_calloc(1, sizeof (SDL_hapticlist_item));
282  if (item == NULL) {
283  return -1;
284  }
285 
286  item->fname = SDL_strdup(path);
287  if (item->fname == NULL) {
288  SDL_free(item);
289  return -1;
290  }
291 
292  item->dev_num = sb.st_rdev;
293 
294  /* TODO: should we add instance IDs? */
295  if (SDL_hapticlist_tail == NULL) {
296  SDL_hapticlist = SDL_hapticlist_tail = item;
297  } else {
298  SDL_hapticlist_tail->next = item;
299  SDL_hapticlist_tail = item;
300  }
301 
302  ++numhaptics;
303 
304  /* !!! TODO: Send a haptic add event? */
305 
306  return numhaptics;
307 }
308 
309 #if SDL_USE_LIBUDEV
310 static int
311 MaybeRemoveDevice(const char* path)
312 {
313  SDL_hapticlist_item *item;
314  SDL_hapticlist_item *prev = NULL;
315 
316  if (path == NULL) {
317  return -1;
318  }
319 
320  for (item = SDL_hapticlist; item != NULL; item = item->next) {
321  /* found it, remove it. */
322  if (SDL_strcmp(path, item->fname) == 0) {
323  const int retval = item->haptic ? item->haptic->index : -1;
324 
325  if (prev != NULL) {
326  prev->next = item->next;
327  } else {
328  SDL_assert(SDL_hapticlist == item);
329  SDL_hapticlist = item->next;
330  }
331  if (item == SDL_hapticlist_tail) {
332  SDL_hapticlist_tail = prev;
333  }
334 
335  /* Need to decrement the haptic count */
336  --numhaptics;
337  /* !!! TODO: Send a haptic remove event? */
338 
339  SDL_free(item->fname);
340  SDL_free(item);
341  return retval;
342  }
343  prev = item;
344  }
345 
346  return -1;
347 }
348 #endif /* SDL_USE_LIBUDEV */
349 
350 /*
351  * Gets the name from a file descriptor.
352  */
353 static const char *
354 SDL_SYS_HapticNameFromFD(int fd)
355 {
356  static char namebuf[128];
357 
358  /* We use the evdev name ioctl. */
359  if (ioctl(fd, EVIOCGNAME(sizeof(namebuf)), namebuf) <= 0) {
360  return NULL;
361  }
362 
363  return namebuf;
364 }
365 
366 
367 /*
368  * Return the name of a haptic device, does not need to be opened.
369  */
370 const char *
372 {
373  SDL_hapticlist_item *item;
374  int fd;
375  const char *name;
376 
377  item = HapticByDevIndex(index);
378  /* Open the haptic device. */
379  name = NULL;
380  fd = open(item->fname, O_RDONLY, 0);
381 
382  if (fd >= 0) {
383 
384  name = SDL_SYS_HapticNameFromFD(fd);
385  if (name == NULL) {
386  /* No name found, return device character device */
387  name = item->fname;
388  }
389  close(fd);
390  }
391 
392  return name;
393 }
394 
395 
396 /*
397  * Opens the haptic device from the file descriptor.
398  */
399 static int
400 SDL_SYS_HapticOpenFromFD(SDL_Haptic * haptic, int fd)
401 {
402  /* Allocate the hwdata */
403  haptic->hwdata = (struct haptic_hwdata *)
404  SDL_malloc(sizeof(*haptic->hwdata));
405  if (haptic->hwdata == NULL) {
406  SDL_OutOfMemory();
407  goto open_err;
408  }
409  SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata));
410 
411  /* Set the data. */
412  haptic->hwdata->fd = fd;
413  haptic->supported = EV_IsHaptic(fd);
414  haptic->naxes = 2; /* Hardcoded for now, not sure if it's possible to find out. */
415 
416  /* Set the effects */
417  if (ioctl(fd, EVIOCGEFFECTS, &haptic->neffects) < 0) {
418  SDL_SetError("Haptic: Unable to query device memory: %s",
419  strerror(errno));
420  goto open_err;
421  }
422  haptic->nplaying = haptic->neffects; /* Linux makes no distinction. */
423  haptic->effects = (struct haptic_effect *)
424  SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects);
425  if (haptic->effects == NULL) {
426  SDL_OutOfMemory();
427  goto open_err;
428  }
429  /* Clear the memory */
430  SDL_memset(haptic->effects, 0,
431  sizeof(struct haptic_effect) * haptic->neffects);
432 
433  return 0;
434 
435  /* Error handling */
436  open_err:
437  close(fd);
438  if (haptic->hwdata != NULL) {
439  SDL_free(haptic->hwdata);
440  haptic->hwdata = NULL;
441  }
442  return -1;
443 }
444 
445 
446 /*
447  * Opens a haptic device for usage.
448  */
449 int
450 SDL_SYS_HapticOpen(SDL_Haptic * haptic)
451 {
452  int fd;
453  int ret;
454  SDL_hapticlist_item *item;
455 
456  item = HapticByDevIndex(haptic->index);
457  /* Open the character device */
458  fd = open(item->fname, O_RDWR, 0);
459  if (fd < 0) {
460  return SDL_SetError("Haptic: Unable to open %s: %s",
461  item->fname, strerror(errno));
462  }
463 
464  /* Try to create the haptic. */
465  ret = SDL_SYS_HapticOpenFromFD(haptic, fd); /* Already closes on error. */
466  if (ret < 0) {
467  return -1;
468  }
469 
470  /* Set the fname. */
471  haptic->hwdata->fname = SDL_strdup( item->fname );
472  return 0;
473 }
474 
475 
476 /*
477  * Opens a haptic device from first mouse it finds for usage.
478  */
479 int
481 {
482  int fd;
483  int device_index = 0;
484  SDL_hapticlist_item *item;
485 
486  for (item = SDL_hapticlist; item; item = item->next) {
487  /* Open the device. */
488  fd = open(item->fname, O_RDWR, 0);
489  if (fd < 0) {
490  return SDL_SetError("Haptic: Unable to open %s: %s",
491  item->fname, strerror(errno));
492  }
493 
494  /* Is it a mouse? */
495  if (EV_IsMouse(fd)) {
496  close(fd);
497  return device_index;
498  }
499 
500  close(fd);
501 
502  ++device_index;
503  }
504 
505  return -1;
506 }
507 
508 
509 /*
510  * Checks to see if a joystick has haptic features.
511  */
512 int
513 SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick)
514 {
515  if (joystick->driver != &SDL_LINUX_JoystickDriver) {
516  return 0;
517  }
518  return EV_IsHaptic(joystick->hwdata->fd);
519 }
520 
521 
522 /*
523  * Checks to see if the haptic device and joystick are in reality the same.
524  */
525 int
526 SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
527 {
528  if (joystick->driver != &SDL_LINUX_JoystickDriver) {
529  return 0;
530  }
531  /* We are assuming Linux is using evdev which should trump the old
532  * joystick methods. */
533  if (SDL_strcmp(joystick->hwdata->fname, haptic->hwdata->fname) == 0) {
534  return 1;
535  }
536  return 0;
537 }
538 
539 
540 /*
541  * Opens a SDL_Haptic from a SDL_Joystick.
542  */
543 int
544 SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
545 {
546  int device_index = 0;
547  int fd;
548  int ret;
549  SDL_hapticlist_item *item;
550 
551  if (joystick->driver != &SDL_LINUX_JoystickDriver) {
552  return -1;
553  }
554  /* Find the joystick in the haptic list. */
555  for (item = SDL_hapticlist; item; item = item->next) {
556  if (SDL_strcmp(item->fname, joystick->hwdata->fname) == 0) {
557  break;
558  }
559  ++device_index;
560  }
561  haptic->index = device_index;
562 
563  if (device_index >= MAX_HAPTICS) {
564  return SDL_SetError("Haptic: Joystick doesn't have Haptic capabilities");
565  }
566 
567  fd = open(joystick->hwdata->fname, O_RDWR, 0);
568  if (fd < 0) {
569  return SDL_SetError("Haptic: Unable to open %s: %s",
570  joystick->hwdata->fname, strerror(errno));
571  }
572  ret = SDL_SYS_HapticOpenFromFD(haptic, fd); /* Already closes on error. */
573  if (ret < 0) {
574  return -1;
575  }
576 
577  haptic->hwdata->fname = SDL_strdup( joystick->hwdata->fname );
578 
579  return 0;
580 }
581 
582 
583 /*
584  * Closes the haptic device.
585  */
586 void
587 SDL_SYS_HapticClose(SDL_Haptic * haptic)
588 {
589  if (haptic->hwdata) {
590 
591  /* Free effects. */
592  SDL_free(haptic->effects);
593  haptic->effects = NULL;
594  haptic->neffects = 0;
595 
596  /* Clean up */
597  close(haptic->hwdata->fd);
598 
599  /* Free */
600  SDL_free(haptic->hwdata->fname);
601  SDL_free(haptic->hwdata);
602  haptic->hwdata = NULL;
603  }
604 
605  /* Clear the rest. */
606  SDL_memset(haptic, 0, sizeof(SDL_Haptic));
607 }
608 
609 
610 /*
611  * Clean up after system specific haptic stuff
612  */
613 void
614 SDL_SYS_HapticQuit(void)
615 {
616  SDL_hapticlist_item *item = NULL;
617  SDL_hapticlist_item *next = NULL;
618 
619  for (item = SDL_hapticlist; item; item = next) {
620  next = item->next;
621  /* Opened and not closed haptics are leaked, this is on purpose.
622  * Close your haptic devices after usage. */
623  SDL_free(item->fname);
624  SDL_free(item);
625  }
626 
627 #if SDL_USE_LIBUDEV
628  SDL_UDEV_DelCallback(haptic_udev_callback);
629  SDL_UDEV_Quit();
630 #endif /* SDL_USE_LIBUDEV */
631 
632  numhaptics = 0;
634  SDL_hapticlist_tail = NULL;
635 }
636 
637 
638 /*
639  * Converts an SDL button to a ff_trigger button.
640  */
641 static Uint16
642 SDL_SYS_ToButton(Uint16 button)
643 {
644  Uint16 ff_button;
645 
646  ff_button = 0;
647 
648  /*
649  * Not sure what the proper syntax is because this actually isn't implemented
650  * in the current kernel from what I've seen (2.6.26).
651  */
652  if (button != 0) {
653  ff_button = BTN_GAMEPAD + button - 1;
654  }
655 
656  return ff_button;
657 }
658 
659 
660 /*
661  * Initializes the ff_effect usable direction from a SDL_HapticDirection.
662  */
663 static int
664 SDL_SYS_ToDirection(Uint16 *dest, SDL_HapticDirection * src)
665 {
666  Uint32 tmp;
667 
668  switch (src->type) {
669  case SDL_HAPTIC_POLAR:
670  /* Linux directions start from south.
671  (and range from 0 to 0xFFFF)
672  Quoting include/linux/input.h, line 926:
673  Direction of the effect is encoded as follows:
674  0 deg -> 0x0000 (down)
675  90 deg -> 0x4000 (left)
676  180 deg -> 0x8000 (up)
677  270 deg -> 0xC000 (right)
678  The force pulls into the direction specified by Linux directions,
679  i.e. the opposite convention of SDL directions.
680  */
681  tmp = ((src->dir[0] % 36000) * 0x8000) / 18000; /* convert to range [0,0xFFFF] */
682  *dest = (Uint16) tmp;
683  break;
684 
686  /*
687  We convert to polar, because that's the only supported direction on Linux.
688  The first value of a spherical direction is practically the same as a
689  Polar direction, except that we have to add 90 degrees. It is the angle
690  from EAST {1,0} towards SOUTH {0,1}.
691  --> add 9000
692  --> finally convert to [0,0xFFFF] as in case SDL_HAPTIC_POLAR.
693  */
694  tmp = ((src->dir[0]) + 9000) % 36000; /* Convert to polars */
695  tmp = (tmp * 0x8000) / 18000; /* convert to range [0,0xFFFF] */
696  *dest = (Uint16) tmp;
697  break;
698 
700  if (!src->dir[1])
701  *dest = (src->dir[0] >= 0 ? 0x4000 : 0xC000);
702  else if (!src->dir[0])
703  *dest = (src->dir[1] >= 0 ? 0x8000 : 0);
704  else {
705  float f = SDL_atan2(src->dir[1], src->dir[0]); /* Ideally we'd use fixed point math instead of floats... */
706  /*
707  atan2 takes the parameters: Y-axis-value and X-axis-value (in that order)
708  - Y-axis-value is the second coordinate (from center to SOUTH)
709  - X-axis-value is the first coordinate (from center to EAST)
710  We add 36000, because atan2 also returns negative values. Then we practically
711  have the first spherical value. Therefore we proceed as in case
712  SDL_HAPTIC_SPHERICAL and add another 9000 to get the polar value.
713  --> add 45000 in total
714  --> finally convert to [0,0xFFFF] as in case SDL_HAPTIC_POLAR.
715  */
716  tmp = (((Sint32) (f * 18000. / M_PI)) + 45000) % 36000;
717  tmp = (tmp * 0x8000) / 18000; /* convert to range [0,0xFFFF] */
718  *dest = (Uint16) tmp;
719  }
720  break;
721 
722  default:
723  return SDL_SetError("Haptic: Unsupported direction type.");
724  }
725 
726  return 0;
727 }
728 
729 
730 #define CLAMP(x) (((x) > 32767) ? 32767 : x)
731 /*
732  * Initializes the Linux effect struct from a haptic_effect.
733  * Values above 32767 (for unsigned) are unspecified so we must clamp.
734  */
735 static int
736 SDL_SYS_ToFFEffect(struct ff_effect *dest, SDL_HapticEffect * src)
737 {
738  SDL_HapticConstant *constant;
739  SDL_HapticPeriodic *periodic;
741  SDL_HapticRamp *ramp;
742  SDL_HapticLeftRight *leftright;
743 
744  /* Clear up */
745  SDL_memset(dest, 0, sizeof(struct ff_effect));
746 
747  switch (src->type) {
748  case SDL_HAPTIC_CONSTANT:
749  constant = &src->constant;
750 
751  /* Header */
752  dest->type = FF_CONSTANT;
753  if (SDL_SYS_ToDirection(&dest->direction, &constant->direction) == -1)
754  return -1;
755 
756  /* Replay */
757  dest->replay.length = (constant->length == SDL_HAPTIC_INFINITY) ?
758  0 : CLAMP(constant->length);
759  dest->replay.delay = CLAMP(constant->delay);
760 
761  /* Trigger */
762  dest->trigger.button = SDL_SYS_ToButton(constant->button);
763  dest->trigger.interval = CLAMP(constant->interval);
764 
765  /* Constant */
766  dest->u.constant.level = constant->level;
767 
768  /* Envelope */
769  dest->u.constant.envelope.attack_length =
770  CLAMP(constant->attack_length);
771  dest->u.constant.envelope.attack_level =
772  CLAMP(constant->attack_level);
773  dest->u.constant.envelope.fade_length = CLAMP(constant->fade_length);
774  dest->u.constant.envelope.fade_level = CLAMP(constant->fade_level);
775 
776  break;
777 
778  case SDL_HAPTIC_SINE:
779  /* !!! FIXME: put this back when we have more bits in 2.1 */
780  /* case SDL_HAPTIC_SQUARE: */
781  case SDL_HAPTIC_TRIANGLE:
784  periodic = &src->periodic;
785 
786  /* Header */
787  dest->type = FF_PERIODIC;
788  if (SDL_SYS_ToDirection(&dest->direction, &periodic->direction) == -1)
789  return -1;
790 
791  /* Replay */
792  dest->replay.length = (periodic->length == SDL_HAPTIC_INFINITY) ?
793  0 : CLAMP(periodic->length);
794  dest->replay.delay = CLAMP(periodic->delay);
795 
796  /* Trigger */
797  dest->trigger.button = SDL_SYS_ToButton(periodic->button);
798  dest->trigger.interval = CLAMP(periodic->interval);
799 
800  /* Periodic */
801  if (periodic->type == SDL_HAPTIC_SINE)
802  dest->u.periodic.waveform = FF_SINE;
803  /* !!! FIXME: put this back when we have more bits in 2.1 */
804  /* else if (periodic->type == SDL_HAPTIC_SQUARE)
805  dest->u.periodic.waveform = FF_SQUARE; */
806  else if (periodic->type == SDL_HAPTIC_TRIANGLE)
807  dest->u.periodic.waveform = FF_TRIANGLE;
808  else if (periodic->type == SDL_HAPTIC_SAWTOOTHUP)
809  dest->u.periodic.waveform = FF_SAW_UP;
810  else if (periodic->type == SDL_HAPTIC_SAWTOOTHDOWN)
811  dest->u.periodic.waveform = FF_SAW_DOWN;
812  dest->u.periodic.period = CLAMP(periodic->period);
813  dest->u.periodic.magnitude = periodic->magnitude;
814  dest->u.periodic.offset = periodic->offset;
815  /* Linux phase is defined in interval "[0x0000, 0x10000[", corresponds with "[0deg, 360deg[" phase shift. */
816  dest->u.periodic.phase = ((Uint32)periodic->phase * 0x10000U) / 36000;
817 
818  /* Envelope */
819  dest->u.periodic.envelope.attack_length =
820  CLAMP(periodic->attack_length);
821  dest->u.periodic.envelope.attack_level =
822  CLAMP(periodic->attack_level);
823  dest->u.periodic.envelope.fade_length = CLAMP(periodic->fade_length);
824  dest->u.periodic.envelope.fade_level = CLAMP(periodic->fade_level);
825 
826  break;
827 
828  case SDL_HAPTIC_SPRING:
829  case SDL_HAPTIC_DAMPER:
830  case SDL_HAPTIC_INERTIA:
831  case SDL_HAPTIC_FRICTION:
832  condition = &src->condition;
833 
834  /* Header */
835  if (condition->type == SDL_HAPTIC_SPRING)
836  dest->type = FF_SPRING;
837  else if (condition->type == SDL_HAPTIC_DAMPER)
838  dest->type = FF_DAMPER;
839  else if (condition->type == SDL_HAPTIC_INERTIA)
840  dest->type = FF_INERTIA;
841  else if (condition->type == SDL_HAPTIC_FRICTION)
842  dest->type = FF_FRICTION;
843  dest->direction = 0; /* Handled by the condition-specifics. */
844 
845  /* Replay */
846  dest->replay.length = (condition->length == SDL_HAPTIC_INFINITY) ?
847  0 : CLAMP(condition->length);
848  dest->replay.delay = CLAMP(condition->delay);
849 
850  /* Trigger */
851  dest->trigger.button = SDL_SYS_ToButton(condition->button);
852  dest->trigger.interval = CLAMP(condition->interval);
853 
854  /* Condition */
855  /* X axis */
856  dest->u.condition[0].right_saturation = condition->right_sat[0];
857  dest->u.condition[0].left_saturation = condition->left_sat[0];
858  dest->u.condition[0].right_coeff = condition->right_coeff[0];
859  dest->u.condition[0].left_coeff = condition->left_coeff[0];
860  dest->u.condition[0].deadband = condition->deadband[0];
861  dest->u.condition[0].center = condition->center[0];
862  /* Y axis */
863  dest->u.condition[1].right_saturation = condition->right_sat[1];
864  dest->u.condition[1].left_saturation = condition->left_sat[1];
865  dest->u.condition[1].right_coeff = condition->right_coeff[1];
866  dest->u.condition[1].left_coeff = condition->left_coeff[1];
867  dest->u.condition[1].deadband = condition->deadband[1];
868  dest->u.condition[1].center = condition->center[1];
869 
870  /*
871  * There is no envelope in the linux force feedback api for conditions.
872  */
873 
874  break;
875 
876  case SDL_HAPTIC_RAMP:
877  ramp = &src->ramp;
878 
879  /* Header */
880  dest->type = FF_RAMP;
881  if (SDL_SYS_ToDirection(&dest->direction, &ramp->direction) == -1)
882  return -1;
883 
884  /* Replay */
885  dest->replay.length = (ramp->length == SDL_HAPTIC_INFINITY) ?
886  0 : CLAMP(ramp->length);
887  dest->replay.delay = CLAMP(ramp->delay);
888 
889  /* Trigger */
890  dest->trigger.button = SDL_SYS_ToButton(ramp->button);
891  dest->trigger.interval = CLAMP(ramp->interval);
892 
893  /* Ramp */
894  dest->u.ramp.start_level = ramp->start;
895  dest->u.ramp.end_level = ramp->end;
896 
897  /* Envelope */
898  dest->u.ramp.envelope.attack_length = CLAMP(ramp->attack_length);
899  dest->u.ramp.envelope.attack_level = CLAMP(ramp->attack_level);
900  dest->u.ramp.envelope.fade_length = CLAMP(ramp->fade_length);
901  dest->u.ramp.envelope.fade_level = CLAMP(ramp->fade_level);
902 
903  break;
904 
906  leftright = &src->leftright;
907 
908  /* Header */
909  dest->type = FF_RUMBLE;
910  dest->direction = 0;
911 
912  /* Replay */
913  dest->replay.length = (leftright->length == SDL_HAPTIC_INFINITY) ?
914  0 : CLAMP(leftright->length);
915 
916  /* Trigger */
917  dest->trigger.button = 0;
918  dest->trigger.interval = 0;
919 
920  /* Rumble (Linux expects 0-65535, so multiply by 2) */
921  dest->u.rumble.strong_magnitude = CLAMP(leftright->large_magnitude) * 2;
922  dest->u.rumble.weak_magnitude = CLAMP(leftright->small_magnitude) * 2;
923 
924  break;
925 
926 
927  default:
928  return SDL_SetError("Haptic: Unknown effect type.");
929  }
930 
931  return 0;
932 }
933 
934 
935 /*
936  * Creates a new haptic effect.
937  */
938 int
939 SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
941 {
942  struct ff_effect *linux_effect;
943 
944  /* Allocate the hardware effect */
945  effect->hweffect = (struct haptic_hweffect *)
946  SDL_malloc(sizeof(struct haptic_hweffect));
947  if (effect->hweffect == NULL) {
948  return SDL_OutOfMemory();
949  }
950 
951  /* Prepare the ff_effect */
952  linux_effect = &effect->hweffect->effect;
953  if (SDL_SYS_ToFFEffect(linux_effect, base) != 0) {
954  goto new_effect_err;
955  }
956  linux_effect->id = -1; /* Have the kernel give it an id */
957 
958  /* Upload the effect */
959  if (ioctl(haptic->hwdata->fd, EVIOCSFF, linux_effect) < 0) {
960  SDL_SetError("Haptic: Error uploading effect to the device: %s",
961  strerror(errno));
962  goto new_effect_err;
963  }
964 
965  return 0;
966 
967  new_effect_err:
968  SDL_free(effect->hweffect);
969  effect->hweffect = NULL;
970  return -1;
971 }
972 
973 
974 /*
975  * Updates an effect.
976  *
977  * Note: Dynamically updating the direction can in some cases force
978  * the effect to restart and run once.
979  */
980 int
982  struct haptic_effect *effect,
984 {
985  struct ff_effect linux_effect;
986 
987  /* Create the new effect */
988  if (SDL_SYS_ToFFEffect(&linux_effect, data) != 0) {
989  return -1;
990  }
991  linux_effect.id = effect->hweffect->effect.id;
992 
993  /* See if it can be uploaded. */
994  if (ioctl(haptic->hwdata->fd, EVIOCSFF, &linux_effect) < 0) {
995  return SDL_SetError("Haptic: Error updating the effect: %s",
996  strerror(errno));
997  }
998 
999  /* Copy the new effect into memory. */
1000  SDL_memcpy(&effect->hweffect->effect, &linux_effect,
1001  sizeof(struct ff_effect));
1002 
1003  return effect->hweffect->effect.id;
1004 }
1005 
1006 
1007 /*
1008  * Runs an effect.
1009  */
1010 int
1011 SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
1013 {
1014  struct input_event run;
1015 
1016  /* Prepare to run the effect */
1017  run.type = EV_FF;
1018  run.code = effect->hweffect->effect.id;
1019  /* We don't actually have infinity here, so we just do INT_MAX which is pretty damn close. */
1020  run.value = (iterations > INT_MAX) ? INT_MAX : iterations;
1021 
1022  if (write(haptic->hwdata->fd, (const void *) &run, sizeof(run)) < 0) {
1023  return SDL_SetError("Haptic: Unable to run the effect: %s", strerror(errno));
1024  }
1025 
1026  return 0;
1027 }
1028 
1029 
1030 /*
1031  * Stops an effect.
1032  */
1033 int
1034 SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
1035 {
1036  struct input_event stop;
1037 
1038  stop.type = EV_FF;
1039  stop.code = effect->hweffect->effect.id;
1040  stop.value = 0;
1041 
1042  if (write(haptic->hwdata->fd, (const void *) &stop, sizeof(stop)) < 0) {
1043  return SDL_SetError("Haptic: Unable to stop the effect: %s",
1044  strerror(errno));
1045  }
1046 
1047  return 0;
1048 }
1049 
1050 
1051 /*
1052  * Frees the effect.
1053  */
1054 void
1055 SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
1056 {
1057  if (ioctl(haptic->hwdata->fd, EVIOCRMFF, effect->hweffect->effect.id) < 0) {
1058  SDL_SetError("Haptic: Error removing the effect from the device: %s",
1059  strerror(errno));
1060  }
1061  SDL_free(effect->hweffect);
1062  effect->hweffect = NULL;
1063 }
1064 
1065 
1066 /*
1067  * Gets the status of a haptic effect.
1068  */
1069 int
1071  struct haptic_effect *effect)
1072 {
1073 #if 0 /* Not supported atm. */
1074  struct input_event ie;
1075 
1076  ie.type = EV_FF;
1077  ie.type = EV_FF_STATUS;
1078  ie.code = effect->hweffect->effect.id;
1079 
1080  if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) {
1081  return SDL_SetError("Haptic: Error getting device status.");
1082  }
1083 
1084  return 0;
1085 #endif
1086 
1087  return -1;
1088 }
1089 
1090 
1091 /*
1092  * Sets the gain.
1093  */
1094 int
1095 SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain)
1096 {
1097  struct input_event ie;
1098 
1099  ie.type = EV_FF;
1100  ie.code = FF_GAIN;
1101  ie.value = (0xFFFFUL * gain) / 100;
1102 
1103  if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) {
1104  return SDL_SetError("Haptic: Error setting gain: %s", strerror(errno));
1105  }
1106 
1107  return 0;
1108 }
1109 
1110 
1111 /*
1112  * Sets the autocentering.
1113  */
1114 int
1115 SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
1116 {
1117  struct input_event ie;
1118 
1119  ie.type = EV_FF;
1120  ie.code = FF_AUTOCENTER;
1121  ie.value = (0xFFFFUL * autocenter) / 100;
1122 
1123  if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) {
1124  return SDL_SetError("Haptic: Error setting autocenter: %s", strerror(errno));
1125  }
1126 
1127  return 0;
1128 }
1129 
1130 
1131 /*
1132  * Pausing is not supported atm by linux.
1133  */
1134 int
1135 SDL_SYS_HapticPause(SDL_Haptic * haptic)
1136 {
1137  return -1;
1138 }
1139 
1140 
1141 /*
1142  * Unpausing is not supported atm by linux.
1143  */
1144 int
1145 SDL_SYS_HapticUnpause(SDL_Haptic * haptic)
1146 {
1147  return -1;
1148 }
1149 
1150 
1151 /*
1152  * Stops all the currently playing effects.
1153  */
1154 int
1155 SDL_SYS_HapticStopAll(SDL_Haptic * haptic)
1156 {
1157  int i, ret;
1158 
1159  /* Linux does not support this natively so we have to loop. */
1160  for (i = 0; i < haptic->neffects; i++) {
1161  if (haptic->effects[i].hweffect != NULL) {
1162  ret = SDL_SYS_HapticStopEffect(haptic, &haptic->effects[i]);
1163  if (ret < 0) {
1164  return SDL_SetError
1165  ("Haptic: Error while trying to stop all playing effects.");
1166  }
1167  }
1168  }
1169  return 0;
1170 }
1171 
1172 #endif /* SDL_HAPTIC_LINUX */
1173 
1174 /* vi: set ts=4 sw=4 expandtab: */
SDL_HAPTIC_LEFTRIGHT
#define SDL_HAPTIC_LEFTRIGHT
Left/Right effect supported.
Definition: SDL_haptic.h:183
SDL_memset
#define SDL_memset
Definition: SDL_dynapi_overrides.h:386
SDL_HAPTIC_CARTESIAN
#define SDL_HAPTIC_CARTESIAN
Uses cartesian coordinates for the direction.
Definition: SDL_haptic.h:330
SDL_SYS_HapticPause
int SDL_SYS_HapticPause(SDL_Haptic *haptic)
Uint32
uint32_t Uint32
Definition: SDL_stdinc.h:203
SDL_HAPTIC_CUSTOM
#define SDL_HAPTIC_CUSTOM
Custom effect is supported.
Definition: SDL_haptic.h:269
Sint32
int32_t Sint32
Definition: SDL_stdinc.h:197
SDL_HAPTIC_SPHERICAL
#define SDL_HAPTIC_SPHERICAL
Uses spherical coordinates for the direction.
Definition: SDL_haptic.h:337
SDL_HapticRamp::interval
Uint16 interval
Definition: SDL_haptic.h:651
SDL_HapticPeriodic::period
Uint16 period
Definition: SDL_haptic.h:566
fname
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro pixld1_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl else error unsupported endif endm macro pixld2_s mem_operand if mov asr add asl add asl mov asr sub UNIT_X add asl mov asr add asl add asl mov asr add UNIT_X add asl else pixld1_s mem_operand pixld1_s mem_operand endif endm macro pixld0_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl endif endm macro pixld_s_internal mem_operand if mem_operand pixld2_s mem_operand pixdeinterleave basereg elseif mem_operand elseif mem_operand elseif mem_operand elseif mem_operand pixld0_s mem_operand else pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else error unsupported mem_operand if bpp mem_operand endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld fname[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro fetch_mask_pixblock pixld mask_basereg pixblock_size MASK endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1 beq endif SRC MASK if dst_r_bpp DST_R else add endif PF add sub src_basereg pixdeinterleave mask_basereg pixdeinterleave dst_r_basereg process_pixblock_head pixblock_size cache_preload_simple process_pixblock_tail pixinterleave dst_w_basereg irp beq endif process_pixblock_tail_head tst beq irp if pixblock_size chunk_size tst beq pixld_src SRC pixld MASK if DST_R else pixld DST_R endif if src_basereg pixdeinterleave mask_basereg pixdeinterleave dst_r_basereg process_pixblock_head if pixblock_size cache_preload_simple endif process_pixblock_tail pixinterleave dst_w_basereg irp if pixblock_size chunk_size tst beq if DST_W else pixst DST_W else mov ORIG_W endif add lsl if lsl endif if lsl endif lsl endif lsl endif lsl endif subs mov DST_W if regs_shortage str endif bge start_of_loop_label endm macro generate_composite_function
Definition: pixman-arm-neon-asm.h:617
NULL
#define NULL
Definition: begin_code.h:167
SDL_HapticLeftRight::large_magnitude
Uint16 large_magnitude
Definition: SDL_haptic.h:685
SDL_HapticCondition
A structure containing a template for a Condition effect.
Definition: SDL_haptic.h:602
SDL_SYS_HapticName
const char * SDL_SYS_HapticName(int index)
SDL_HapticConstant::attack_length
Uint16 attack_length
Definition: SDL_haptic.h:486
SDL_joystick.h
SDL_atan2
#define SDL_atan2
Definition: SDL_dynapi_overrides.h:425
base
set set set set set set set set set set set set set set set set set set set set *set set set macro pixldst base
Definition: pixman-arm-simd-asm.h:108
SDL_HapticRamp::end
Sint16 end
Definition: SDL_haptic.h:655
SDL_HapticRamp::length
Uint32 length
Definition: SDL_haptic.h:646
SDL_SYS_HapticUnpause
int SDL_SYS_HapticUnpause(SDL_Haptic *haptic)
SDL_HapticPeriodic::phase
Uint16 phase
Definition: SDL_haptic.h:569
SDL_hapticlist_item
Definition: SDL_windowshaptic_c.h:67
iterations
static int iterations
Definition: testsprite2.c:45
SDL_HapticConstant::interval
Uint16 interval
Definition: SDL_haptic.h:480
SDL_SYS_HapticInit
int SDL_SYS_HapticInit(void)
SDL_HapticConstant::direction
SDL_HapticDirection direction
Definition: SDL_haptic.h:472
SDL_HAPTIC_DAMPER
#define SDL_HAPTIC_DAMPER
Damper effect supported - uses axes velocity.
Definition: SDL_haptic.h:242
path
GLsizei const GLchar *const * path
Definition: SDL_opengl_glext.h:3733
SDL_SYS_HapticUpdateEffect
int SDL_SYS_HapticUpdateEffect(SDL_Haptic *haptic, struct haptic_effect *effect, SDL_HapticEffect *data)
index
GLuint index
Definition: SDL_opengl_glext.h:663
SDL_HAPTIC_AUTOCENTER
#define SDL_HAPTIC_AUTOCENTER
Device can set autocenter.
Definition: SDL_haptic.h:291
haptic_effect::effect
SDL_HapticEffect effect
Definition: SDL_syshaptic.h:32
SDL_HAPTIC_INFINITY
#define SDL_HAPTIC_INFINITY
Used to play a device an infinite number of times.
Definition: SDL_haptic.h:352
SDL_HapticPeriodic::type
Uint16 type
Definition: SDL_haptic.h:552
data
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
SDL_SYS_HapticDestroyEffect
void SDL_SYS_HapticDestroyEffect(SDL_Haptic *haptic, struct haptic_effect *effect)
haptic_hwdata
Definition: SDL_windowshaptic_c.h:34
SDL_HapticLeftRight::length
Uint32 length
Definition: SDL_haptic.h:682
SDL_SYS_HapticRunEffect
int SDL_SYS_HapticRunEffect(SDL_Haptic *haptic, struct haptic_effect *effect, Uint32 iterations)
haptic_hweffect
Definition: SDL_windowshaptic_c.h:53
SDL_HapticPeriodic::delay
Uint16 delay
Definition: SDL_haptic.h:559
SDL_HapticConstant::attack_level
Uint16 attack_level
Definition: SDL_haptic.h:487
SDL_HapticPeriodic::attack_length
Uint16 attack_length
Definition: SDL_haptic.h:572
SDL_haptic.h
The SDL haptic subsystem allows you to control haptic (force feedback) devices.
SDL_HapticPeriodic::magnitude
Sint16 magnitude
Definition: SDL_haptic.h:567
SDL_HapticRamp::start
Sint16 start
Definition: SDL_haptic.h:654
condition
GLenum condition
Definition: SDL_opengl_glext.h:8673
SDL_HapticConstant::delay
Uint16 delay
Definition: SDL_haptic.h:476
SDL_SYS_HapticQuit
void SDL_SYS_HapticQuit(void)
SDL_HapticConstant::fade_level
Uint16 fade_level
Definition: SDL_haptic.h:489
SDL_memcpy
#define SDL_memcpy
Definition: SDL_dynapi_overrides.h:387
SDL_SYS_HapticSetGain
int SDL_SYS_HapticSetGain(SDL_Haptic *haptic, int gain)
retval
SDL_bool retval
Definition: testgamecontroller.c:65
SDL_SYS_HapticGetEffectStatus
int SDL_SYS_HapticGetEffectStatus(SDL_Haptic *haptic, struct haptic_effect *effect)
SDL_HapticPeriodic::fade_level
Uint16 fade_level
Definition: SDL_haptic.h:575
SDL_HapticRamp::delay
Uint16 delay
Definition: SDL_haptic.h:647
SDL_free
#define SDL_free
Definition: SDL_dynapi_overrides.h:377
SDL_HapticEffect
The generic template for any haptic effect.
Definition: SDL_haptic.h:800
f
GLfloat f
Definition: SDL_opengl_glext.h:1873
SDL_HapticPeriodic::offset
Sint16 offset
Definition: SDL_haptic.h:568
name
GLuint const GLchar * name
Definition: SDL_opengl_glext.h:663
SDL_HAPTIC_SINE
#define SDL_HAPTIC_SINE
Sine wave effect supported.
Definition: SDL_haptic.h:172
SDL_SYS_HapticStopEffect
int SDL_SYS_HapticStopEffect(SDL_Haptic *haptic, struct haptic_effect *effect)
SDL_HapticRamp::button
Uint16 button
Definition: SDL_haptic.h:650
Uint16
uint16_t Uint16
Definition: SDL_stdinc.h:191
SDL_assert.h
haptic_effect
Definition: SDL_syshaptic.h:30
SDL_HapticPeriodic::length
Uint32 length
Definition: SDL_haptic.h:558
SDL_HapticLeftRight
A structure containing a template for a Left/Right effect.
Definition: SDL_haptic.h:676
SDL_HapticConstant::button
Uint16 button
Definition: SDL_haptic.h:479
SDL_SYS_HapticStopAll
int SDL_SYS_HapticStopAll(SDL_Haptic *haptic)
SDL_HapticPeriodic::fade_length
Uint16 fade_length
Definition: SDL_haptic.h:574
SDL_HAPTIC_SAWTOOTHDOWN
#define SDL_HAPTIC_SAWTOOTHDOWN
Sawtoothdown wave effect supported.
Definition: SDL_haptic.h:213
SDL_HapticLeftRight::small_magnitude
Uint16 small_magnitude
Definition: SDL_haptic.h:686
SDL_SYS_HapticClose
void SDL_SYS_HapticClose(SDL_Haptic *haptic)
SDL_assert
#define SDL_assert(condition)
Definition: SDL_assert.h:169
SDL_HapticRamp::fade_length
Uint16 fade_length
Definition: SDL_haptic.h:660
SDL_OutOfMemory
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_HAPTIC_INERTIA
#define SDL_HAPTIC_INERTIA
Inertia effect supported - uses axes acceleration.
Definition: SDL_haptic.h:252
SDL_hapticlist_item::next
struct SDL_hapticlist_item * next
Definition: SDL_windowshaptic_c.h:77
SDL_HAPTIC_GAIN
#define SDL_HAPTIC_GAIN
Device can set global gain.
Definition: SDL_haptic.h:282
SDL_HapticPeriodic
A structure containing a template for a Periodic effect.
Definition: SDL_haptic.h:549
SDL_SYS_HapticOpen
int SDL_SYS_HapticOpen(SDL_Haptic *haptic)
SDL_SYS_HapticMouse
int SDL_SYS_HapticMouse(void)
SDL_calloc
#define SDL_calloc
Definition: SDL_dynapi_overrides.h:375
SDL_SYS_HapticNewEffect
int SDL_SYS_HapticNewEffect(SDL_Haptic *haptic, struct haptic_effect *effect, SDL_HapticEffect *base)
haptic
static SDL_Haptic * haptic
Definition: testhaptic.c:25
SDL_HapticPeriodic::interval
Uint16 interval
Definition: SDL_haptic.h:563
SDL_HapticRamp::attack_length
Uint16 attack_length
Definition: SDL_haptic.h:658
SDL_HapticConstant::length
Uint32 length
Definition: SDL_haptic.h:475
src
GLenum src
Definition: SDL_opengl_glext.h:1740
SDL_HapticConstant::level
Sint16 level
Definition: SDL_haptic.h:483
SDL_hapticlist_item::haptic
SDL_Haptic * haptic
Definition: SDL_windowshaptic_c.h:70
INT_MAX
#define INT_MAX
Definition: SDL_wave.c:31
SDL_SetError
#define SDL_SetError
Definition: SDL_dynapi_overrides.h:30
SDL_HapticRamp
A structure containing a template for a Ramp effect.
Definition: SDL_haptic.h:639
SDL_HAPTIC_SPRING
#define SDL_HAPTIC_SPRING
Spring effect supported - uses axes position.
Definition: SDL_haptic.h:232
SDL_SYS_HapticSetAutocenter
int SDL_SYS_HapticSetAutocenter(SDL_Haptic *haptic, int autocenter)
SDL_HapticConstant::fade_length
Uint16 fade_length
Definition: SDL_haptic.h:488
SDL_HapticRamp::direction
SDL_HapticDirection direction
Definition: SDL_haptic.h:643
SDL_HAPTIC_POLAR
#define SDL_HAPTIC_POLAR
Uses polar coordinates for the direction.
Definition: SDL_haptic.h:323
SDL_SYS_NumHaptics
int SDL_SYS_NumHaptics(void)
SDL_HapticLeftRight::type
Uint16 type
Definition: SDL_haptic.h:679
SDL_strdup
#define SDL_strdup
Definition: SDL_dynapi_overrides.h:397
SDL_LINUX_JoystickDriver
SDL_JoystickDriver SDL_LINUX_JoystickDriver
SDL_hapticlist
SDL_hapticlist_item * SDL_hapticlist
j
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int int in j)
Definition: SDL_x11sym.h:50
SDL_SYS_JoystickIsHaptic
int SDL_SYS_JoystickIsHaptic(SDL_Joystick *joystick)
SDL_HapticConstant::type
Uint16 type
Definition: SDL_haptic.h:471
haptic_effect::hweffect
struct haptic_hweffect * hweffect
Definition: SDL_syshaptic.h:33
SDL_SYS_JoystickSameHaptic
int SDL_SYS_JoystickSameHaptic(SDL_Haptic *haptic, SDL_Joystick *joystick)
SDL_HapticRamp::attack_level
Uint16 attack_level
Definition: SDL_haptic.h:659
SDL_malloc
#define SDL_malloc
Definition: SDL_dynapi_overrides.h:374
SDL_SYS_HapticOpenFromJoystick
int SDL_SYS_HapticOpenFromJoystick(SDL_Haptic *haptic, SDL_Joystick *joystick)
SDL_strcmp
#define SDL_strcmp
Definition: SDL_dynapi_overrides.h:417
SDL_HAPTIC_SAWTOOTHUP
#define SDL_HAPTIC_SAWTOOTHUP
Sawtoothup wave effect supported.
Definition: SDL_haptic.h:204
fd
GLuint64 GLenum GLint fd
Definition: gl2ext.h:1508
SDL_HapticRamp::type
Uint16 type
Definition: SDL_haptic.h:642
SDL_HAPTIC_CONSTANT
#define SDL_HAPTIC_CONSTANT
Constant effect supported.
Definition: SDL_haptic.h:163
SDL_HapticPeriodic::button
Uint16 button
Definition: SDL_haptic.h:562
SDL_HapticPeriodic::direction
SDL_HapticDirection direction
Definition: SDL_haptic.h:555
SDL_HAPTIC_TRIANGLE
#define SDL_HAPTIC_TRIANGLE
Triangle wave effect supported.
Definition: SDL_haptic.h:195
SDL_HAPTIC_FRICTION
#define SDL_HAPTIC_FRICTION
Friction effect supported - uses axes movement.
Definition: SDL_haptic.h:262
SDL_HapticConstant
A structure containing a template for a Constant effect.
Definition: SDL_haptic.h:468
SDL_HapticPeriodic::attack_level
Uint16 attack_level
Definition: SDL_haptic.h:573
button
SDL_Texture * button
Definition: testgamecontroller.c:67
i
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
SDL_HAPTIC_RAMP
#define SDL_HAPTIC_RAMP
Ramp effect supported.
Definition: SDL_haptic.h:222
SDL_HapticRamp::fade_level
Uint16 fade_level
Definition: SDL_haptic.h:661
SDL_HapticDirection
Structure that represents a haptic direction.
Definition: SDL_haptic.h:450