21 #include "../SDL_internal.h"
32 #if !SDL_EVENTS_DISABLED
33 #include "../events/SDL_events_c.h"
36 #define SDL_CONTROLLER_PLATFORM_FIELD "platform:"
84 typedef struct _ControllerMapping_t
90 struct _ControllerMapping_t *
next;
134 if (hint && *hint ==
'@') {
156 if (entries ==
NULL) {
197 if (num_events <= 0) {
207 for (i = 0; i < num_events; ++
i) {
243 for (i = 0; i < gamecontroller->num_bindings; ++
i) {
248 if (value >= binding->
input.
axis.axis_min &&
254 if (value >= binding->
input.
axis.axis_max &&
263 if (last_match && (!match || !
HasSameOutput(last_match, match))) {
286 gamecontroller->last_match_axis[
axis] = match;
293 for (i = 0; i < gamecontroller->num_bindings; ++
i) {
311 Uint8 last_mask = gamecontroller->last_hat_mask[hat];
314 for (i = 0; i < gamecontroller->num_bindings; ++
i) {
317 if ((changed_mask & binding->
input.
hat.hat_mask) != 0) {
318 if (value & binding->
input.
hat.hat_mask) {
330 gamecontroller->last_hat_mask[hat] =
value;
338 switch(event->
type) {
342 while (controllerlist) {
343 if (controllerlist->joystick->instance_id == event->
jaxis.
which) {
347 controllerlist = controllerlist->next;
355 while (controllerlist) {
356 if (controllerlist->joystick->instance_id == event->
jbutton.
which) {
360 controllerlist = controllerlist->next;
367 while (controllerlist) {
368 if (controllerlist->joystick->instance_id == event->
jhat.
which) {
372 controllerlist = controllerlist->next;
389 while (controllerlist) {
390 if (controllerlist->joystick->instance_id == event->
jdevice.
which) {
400 controllerlist = controllerlist->next;
417 while (pSupportedController) {
418 if (
SDL_memcmp(guid, &pSupportedController->
guid,
sizeof(*guid)) == 0) {
419 return pSupportedController;
421 pSupportedController = pSupportedController->
next;
443 if (pchString && (*pchString ==
'+' || *pchString ==
'-')) {
447 if (!pchString || !pchString[0]) {
494 if (!pchString || !pchString[0])
524 char half_axis_input = 0;
525 char half_axis_output = 0;
527 if (*szGameButton ==
'+' || *szGameButton ==
'-') {
528 half_axis_output = *szGameButton++;
540 if (half_axis_output ==
'+') {
543 }
else if (half_axis_output ==
'-') {
555 SDL_SetError(
"Unexpected controller element %s", szGameButton);
559 if (*szJoystickButton ==
'+' || *szJoystickButton ==
'-') {
560 half_axis_input = *szJoystickButton++;
562 if (szJoystickButton[
SDL_strlen(szJoystickButton) - 1] ==
'~') {
566 if (szJoystickButton[0] ==
'a' &&
SDL_isdigit(szJoystickButton[1])) {
569 if (half_axis_input ==
'+') {
572 }
else if (half_axis_input ==
'-') {
584 }
else if (szJoystickButton[0] ==
'b' &&
SDL_isdigit(szJoystickButton[1])) {
587 }
else if (szJoystickButton[0] ==
'h' &&
SDL_isdigit(szJoystickButton[1]) &&
588 szJoystickButton[2] ==
'.' &&
SDL_isdigit(szJoystickButton[3])) {
589 int hat =
SDL_atoi(&szJoystickButton[1]);
595 SDL_SetError(
"Unexpected joystick element: %s", szJoystickButton);
599 ++gamecontroller->num_bindings;
601 if (!gamecontroller->bindings) {
602 gamecontroller->num_bindings = 0;
606 gamecontroller->bindings[gamecontroller->num_bindings - 1] = bind;
616 char szGameButton[20];
617 char szJoystickButton[20];
620 const char *pchPos = pchString;
625 while (pchPos && *pchPos) {
626 if (*pchPos ==
':') {
629 }
else if (*pchPos ==
' ') {
631 }
else if (*pchPos ==
',') {
638 }
else if (bGameButton) {
639 if (i >=
sizeof(szGameButton)) {
640 SDL_SetError(
"Button name too large: %s", szGameButton);
643 szGameButton[
i] = *pchPos;
646 if (i >=
sizeof(szJoystickButton)) {
647 SDL_SetError(
"Joystick button name too large: %s", szJoystickButton);
650 szJoystickButton[
i] = *pchPos;
667 gamecontroller->guid =
guid;
668 gamecontroller->name = pchName;
669 gamecontroller->num_bindings = 0;
670 SDL_memset(gamecontroller->last_match_axis, 0, gamecontroller->joystick->naxes *
sizeof(*gamecontroller->last_match_axis));
675 for (i = 0; i < gamecontroller->num_bindings; ++
i) {
681 if (binding->
input.
axis.axis < gamecontroller->joystick->naxes) {
682 gamecontroller->joystick->axes[binding->
input.
axis.axis].value =
695 const char *pFirstComma =
SDL_strchr(pMapping,
',');
697 char *pchGUID =
SDL_malloc(pFirstComma - pMapping + 1);
702 SDL_memcpy(pchGUID, pMapping, pFirstComma - pMapping);
703 pchGUID[pFirstComma - pMapping] =
'\0';
708 SDL_memcmp(&pchGUID[20],
"504944564944", 12) == 0) {
716 SDL_memcmp(&pchGUID[4],
"000000000000", 12) == 0 &&
717 SDL_memcmp(&pchGUID[20],
"000000000000", 12) == 0) {
734 const char *pFirstComma, *pSecondComma;
741 pSecondComma =
SDL_strchr(pFirstComma + 1,
',');
745 pchName =
SDL_malloc(pSecondComma - pFirstComma);
750 SDL_memcpy(pchName, pFirstComma + 1, pSecondComma - pFirstComma);
751 pchName[pSecondComma - pFirstComma - 1] = 0;
761 const char *pFirstComma, *pSecondComma;
767 pSecondComma =
SDL_strchr(pFirstComma + 1,
',');
780 while (gamecontrollerlist) {
781 if (!
SDL_memcmp(&gamecontrollerlist->guid, &pControllerMapping->
guid,
sizeof(pControllerMapping->
guid))) {
784 event.cdevice.which = gamecontrollerlist->joystick->instance_id;
791 gamecontrollerlist = gamecontrollerlist->next;
807 SDL_SetError(
"Couldn't parse name from %s", mappingString);
819 if (pControllerMapping) {
821 if (pControllerMapping->
priority <= priority) {
824 pControllerMapping->
name = pchName;
826 pControllerMapping->
mapping = pchMapping;
827 pControllerMapping->
priority = priority;
836 pControllerMapping =
SDL_malloc(
sizeof(*pControllerMapping));
837 if (!pControllerMapping) {
843 pControllerMapping->
guid = jGUID;
844 pControllerMapping->
name = pchName;
845 pControllerMapping->
mapping = pchMapping;
847 pControllerMapping->
priority = priority;
849 if (s_pSupportedControllers) {
853 for ( pPrevMapping = s_pSupportedControllers, pCurrMapping = pPrevMapping->
next;
855 pPrevMapping = pCurrMapping, pCurrMapping = pCurrMapping->
next ) {
858 pPrevMapping->
next = pControllerMapping;
860 s_pSupportedControllers = pControllerMapping;
864 return pControllerMapping;
875 #if defined(SDL_JOYSTICK_EMSCRIPTEN)
876 if (!mapping && s_pEmscriptenMapping) {
880 (
void) s_pEmscriptenMapping;
883 if (!mapping && name) {
884 if (
SDL_strstr(name,
"Xbox 360 Wireless Receiver")) {
888 "none,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
894 if (!mapping && name) {
907 #if SDL_JOYSTICK_XINPUT
908 if (!mapping && SDL_SYS_IsXInputGamepad_DeviceIndex(device_index)) {
923 char *
buf, *line, *line_end, *tmp, *comma, line_platform[64];
924 size_t db_size, platform_len;
936 return SDL_SetError(
"Could not allocate space to read DB into memory");
954 while (line < buf + db_size) {
956 if (line_end !=
NULL) {
959 line_end = buf + db_size;
968 platform_len = comma - tmp + 1;
999 if (!mappingString) {
1005 return SDL_SetError(
"Couldn't parse GUID from %s", mappingString);
1017 if (!pControllerMapping) {
1024 if (is_xinput_mapping) {
1025 s_pXInputMapping = pControllerMapping;
1027 if (is_emscripten_mapping) {
1028 s_pEmscriptenMapping = pControllerMapping;
1049 int num_mappings = 0;
1052 for (mapping = s_pSupportedControllers;
mapping; mapping = mapping->
next) {
1058 return num_mappings;
1069 for (mapping = s_pSupportedControllers;
mapping; mapping = mapping->
next) {
1073 if (mapping_index == 0) {
1074 char *pMappingString;
1082 if (!pMappingString) {
1087 return pMappingString;
1100 char *pMappingString =
NULL;
1109 if (!pMappingString) {
1115 return pMappingString;
1124 if (!gamecontroller) {
1135 if (hint && hint[0]) {
1137 char *pUserMappings =
SDL_malloc(nchHints + 1);
1138 char *pTempMappings = pUserMappings;
1140 pUserMappings[nchHints] =
'\0';
1141 while (pUserMappings) {
1142 char *pchNewLine =
NULL;
1144 pchNewLine =
SDL_strchr(pUserMappings,
'\n');
1151 pUserMappings = pchNewLine + 1;
1153 pUserMappings =
NULL;
1167 const char *pMappingString =
NULL;
1169 while (pMappingString) {
1216 if (pSupportedController) {
1217 return pSupportedController->
name;
1230 if (pSupportedController) {
1243 if (pSupportedController) {
1270 #if defined(__LINUX__)
1271 bSteamVirtualGamepad = (vendor == 0x28DE && product == 0x11FF);
1272 #elif defined(__MACOSX__)
1273 bSteamVirtualGamepad = (
SDL_strncmp(name,
"GamePad-", 8) == 0);
1274 #elif defined(__WIN32__)
1278 if (bSteamVirtualGamepad) {
1284 for (i = 0; i < SDL_allowed_controllers.
num_entries; ++
i) {
1285 if (vidpid == SDL_allowed_controllers.
entries[i]) {
1291 for (i = 0; i < SDL_ignored_controllers.
num_entries; ++
i) {
1292 if (vidpid == SDL_ignored_controllers.
entries[i]) {
1307 SDL_GameController *
1310 SDL_GameController *gamecontroller;
1311 SDL_GameController *gamecontrollerlist;
1323 while (gamecontrollerlist) {
1325 gamecontroller = gamecontrollerlist;
1326 ++gamecontroller->ref_count;
1328 return (gamecontroller);
1330 gamecontrollerlist = gamecontrollerlist->next;
1335 if (!pSupportedController) {
1336 SDL_SetError(
"Couldn't find mapping for device (%d)", device_index);
1342 gamecontroller = (SDL_GameController *)
SDL_calloc(1,
sizeof(*gamecontroller));
1343 if (gamecontroller ==
NULL) {
1350 if (!gamecontroller->joystick) {
1356 if (gamecontroller->joystick->naxes) {
1358 if (!gamecontroller->last_match_axis) {
1366 if (gamecontroller->joystick->nhats) {
1367 gamecontroller->last_hat_mask = (
Uint8 *)
SDL_calloc(gamecontroller->joystick->nhats,
sizeof(*gamecontroller->last_hat_mask));
1368 if (!gamecontroller->last_hat_mask) {
1371 SDL_free(gamecontroller->last_match_axis);
1381 ++gamecontroller->ref_count;
1388 return (gamecontroller);
1409 if (!gamecontroller)
1412 for (i = 0; i < gamecontroller->num_bindings; ++
i) {
1422 valid_input_range = (value >= binding->
input.
axis.axis_min && value <= binding->
input.
axis.axis_max);
1424 valid_input_range = (value >= binding->
input.
axis.axis_max && value <= binding->
input.
axis.axis_min);
1426 if (valid_input_range) {
1428 float normalized_value = (float)(value - binding->
input.
axis.axis_min) / (binding->
input.
axis.axis_max - binding->
input.
axis.axis_min);
1439 if (hat_mask & binding->
input.
hat.hat_mask) {
1445 valid_output_range = (value >= binding->
output.
axis.axis_min && value <= binding->
output.
axis.axis_max);
1447 valid_output_range = (value >= binding->
output.
axis.axis_max && value <= binding->
output.
axis.axis_min);
1450 if (value != 0 && valid_output_range) {
1466 if (!gamecontroller)
1469 for (i = 0; i < gamecontroller->num_bindings; ++
i) {
1478 valid_input_range = (value >= binding->
input.
axis.axis_min && value <= binding->
input.
axis.axis_max);
1479 if (valid_input_range) {
1483 valid_input_range = (value >= binding->
input.
axis.axis_max && value <= binding->
input.
axis.axis_min);
1484 if (valid_input_range) {
1502 if (!gamecontroller)
1505 return gamecontroller->name;
1533 if (!gamecontroller)
1544 if (!gamecontroller)
1547 return gamecontroller->joystick;
1554 SDL_GameController *
1557 SDL_GameController *gamecontroller;
1561 while (gamecontroller) {
1562 if (gamecontroller->joystick->instance_id == joyid) {
1564 return gamecontroller;
1566 gamecontroller = gamecontroller->next;
1585 for (i = 0; i < gamecontroller->num_bindings; ++
i) {
1617 for (i = 0; i < gamecontroller->num_bindings; ++
i) {
1639 SDL_GameController *gamecontrollerlist, *gamecontrollerlistprev;
1641 if (!gamecontroller)
1647 if (--gamecontroller->ref_count > 0) {
1655 gamecontrollerlistprev =
NULL;
1656 while (gamecontrollerlist) {
1657 if (gamecontroller == gamecontrollerlist) {
1658 if (gamecontrollerlistprev) {
1660 gamecontrollerlistprev->next = gamecontrollerlist->next;
1666 gamecontrollerlistprev = gamecontrollerlist;
1667 gamecontrollerlist = gamecontrollerlist->next;
1670 SDL_free(gamecontroller->bindings);
1671 SDL_free(gamecontroller->last_match_axis);
1672 SDL_free(gamecontroller->last_hat_mask);
1698 while (s_pSupportedControllers) {
1700 s_pSupportedControllers = s_pSupportedControllers->
next;
1713 if (SDL_allowed_controllers.
entries) {
1717 if (SDL_ignored_controllers.
entries) {
1733 #if !SDL_EVENTS_DISABLED
1737 event.caxis.which = gamecontroller->joystick->instance_id;
1738 event.caxis.axis =
axis;
1739 event.caxis.value =
value;
1754 #if !SDL_EVENTS_DISABLED
1775 #if !SDL_EVENTS_DISABLED
1777 event.cbutton.which = gamecontroller->joystick->instance_id;
1778 event.cbutton.button =
button;
1779 event.cbutton.state =
state;
1792 #if SDL_EVENTS_DISABLED
1795 const Uint32 event_list[] = {
static const char * map_StringForControllerAxis[]
void SDL_UnlockJoystickList(void)
char * SDL_GameControllerMapping(SDL_GameController *gamecontroller)
#define SDL_DelEventWatch
Uint16 SDL_GameControllerGetProduct(SDL_GameController *gamecontroller)
SDL_GameControllerBindType
#define SDL_CONTROLLER_PLATFORM_FIELD
#define SDL_JoystickGetButton
SDL_GameControllerButton SDL_GameControllerGetButtonFromString(const char *pchString)
SDL_JoyDeviceEvent jdevice
#define SDL_JoystickClose
#define MAKE_VIDPID(VID, PID)
static int SDL_GameControllerEventWatcher(void *userdata, SDL_Event *event)
static void HandleJoystickHat(SDL_GameController *gamecontroller, int hat, Uint8 value)
#define SDL_JoystickGetVendor
void SDL_GameControllerQuitMappings(void)
SDL_ControllerDeviceEvent cdevice
int SDL_GameControllerInitMappings(void)
SDL_GameControllerButtonBind SDL_GameControllerGetBindForButton(SDL_GameController *gamecontroller, SDL_GameControllerButton button)
SDL_ControllerMappingPriority priority
SDL_JoyButtonEvent jbutton
struct _ControllerMapping_t * next
static void ResetOutput(SDL_GameController *gamecontroller, SDL_ExtendedGameControllerBind *bind)
static void UpdateEventsForDeviceRemoval()
char * SDL_GameControllerMappingForIndex(int mapping_index)
Uint16 SDL_GameControllerGetVendor(SDL_GameController *gamecontroller)
Sint16 SDL_GameControllerGetAxis(SDL_GameController *gamecontroller, SDL_GameControllerAxis axis)
SDL_GameControllerAxis SDL_GameControllerGetAxisFromString(const char *pchString)
#define SDL_JoystickNameForIndex
static SDL_vidpid_list SDL_ignored_controllers
static SDL_Event events[EVENT_BUF_SIZE]
SDL_GameControllerBindType inputType
static ControllerMapping_t * SDL_PrivateGetControllerMappingForNameAndGUID(const char *name, SDL_JoystickGUID guid)
#define SDL_RWread(ctx, ptr, size, n)
void SDL_LockJoystickList(void)
#define SDL_InvalidParamError(param)
static void SDL_GameControllerLoadHints()
static ControllerMapping_t * s_pEmscriptenMapping
SDL_ExtendedGameControllerBind * bindings
#define SDL_JoystickGetGUIDString
#define SDL_JoystickGetProduct
#define SDL_JoystickGetHat
GLuint const GLchar * name
SDL_GameControllerAxis axis
struct _SDL_GameController * next
#define SDL_JoystickGetDeviceGUID
SDL_GameController * SDL_GameControllerFromInstanceID(SDL_JoystickID joyid)
#define SDL_GetHintBoolean
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)
static ControllerMapping_t * SDL_PrivateGetControllerMappingForGUID(SDL_JoystickGUID *guid)
static int SDL_PrivateGameControllerAddMapping(const char *mappingString, SDL_ControllerMappingPriority priority)
#define SDL_JOYSTICK_AXIS_MIN
void SDL_GameControllerClose(SDL_GameController *gamecontroller)
void * SDL_calloc(size_t nmemb, size_t size)
#define SDL_JOYSTICK_AXIS_MAX
GLenum GLenum GLenum input
#define SDL_GetEventState(type)
static SDL_GameController * SDL_gamecontrollers
static ControllerMapping_t * s_pSupportedControllers
int SDL_GameControllerEventState(int state)
void SDL_GameControllerQuit(void)
int SDL_GameControllerAddMapping(const char *mappingString)
#define SDL_stack_alloc(type, count)
const char * SDL_GameControllerGetStringForAxis(SDL_GameControllerAxis axis)
const char * SDL_GameControllerName(SDL_GameController *gamecontroller)
static void SDL_PrivateGameControllerParseControllerConfigString(SDL_GameController *gamecontroller, const char *pchString)
SDL_GameControllerBindType outputType
SDL_ExtendedGameControllerBind ** last_match_axis
static SDL_bool HasSameOutput(SDL_ExtendedGameControllerBind *a, SDL_ExtendedGameControllerBind *b)
Uint16 SDL_GameControllerGetProductVersion(SDL_GameController *gamecontroller)
SDL_bool SDL_ShouldIgnoreGameController(const char *name, SDL_JoystickGUID guid)
GLsizei const GLfloat * value
#define SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT
SDL_ControllerMappingPriority
static int SDL_PrivateGameControllerButton(SDL_GameController *gamecontroller, SDL_GameControllerButton button, Uint8 state)
#define SDL_JoystickGetAttached
static const char * map_StringForControllerButton[]
union SDL_ExtendedGameControllerBind::@21 input
void SDL_GameControllerUpdate(void)
GLenum GLuint GLenum GLsizei const GLchar * buf
static ControllerMapping_t * SDL_PrivateGetControllerMapping(int device_index)
static char * SDL_PrivateGetControllerMappingFromMappingString(const char *pMapping)
SDL_bool SDL_IsGameControllerNameAndGUID(const char *name, SDL_JoystickGUID guid)
static void SDL_PrivateGameControllerParseElement(SDL_GameController *gamecontroller, const char *szGameButton, const char *szJoystickButton)
SDL_GameController * SDL_GameControllerOpen(int device_index)
static char * SDL_PrivateGetControllerGUIDFromMappingString(const char *pMapping)
static void HandleJoystickButton(SDL_GameController *gamecontroller, int button, Uint8 state)
static void SDL_PrivateGameControllerRefreshMapping(ControllerMapping_t *pControllerMapping)
SDL_bool SDL_IsGameController(int device_index)
#define SDL_OutOfMemory()
static char * SDL_PrivateGetControllerNameFromMappingString(const char *pMapping)
static void SDL_GameControllerIgnoreDevicesExceptChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
static const char * s_ControllerMappings[]
#define SDL_JoystickUpdate
static SDL_JoystickGUID s_zeroGUID
SDL_GameControllerButtonBind SDL_GameControllerGetBindForAxis(SDL_GameController *gamecontroller, SDL_GameControllerAxis axis)
static SDL_vidpid_list SDL_allowed_controllers
#define SDL_JoystickGetAxis
void SDL_GetJoystickGUIDInfo(SDL_JoystickGUID guid, Uint16 *vendor, Uint16 *product, Uint16 *version)
#define SDL_AddEventWatch
SDL_Joystick * SDL_GameControllerGetJoystick(SDL_GameController *gamecontroller)
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 void
#define SDL_AddHintCallback
static ControllerMapping_t * s_pXInputMapping
#define SDL_DelHintCallback
SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
int SDL_GameControllerNumMappings(void)
#define SDL_arraysize(array)
GLenum GLenum GLenum GLenum mapping
#define SDL_HINT_GAMECONTROLLERCONFIG
A variable that lets you manually hint extra gamecontroller db entries.
SDL_GameControllerButton button
static void SDL_PrivateLoadButtonMapping(SDL_GameController *gamecontroller, SDL_JoystickGUID guid, const char *pchName, const char *pchMapping)
#define SDL_JoystickGetProductVersion
#define SDL_stack_free(data)
GLboolean GLboolean GLboolean GLboolean a
static void SDL_LoadVIDPIDListFromHint(const char *hint, SDL_vidpid_list *list)
int SDL_GameControllerAddMappingsFromRW(SDL_RWops *rw, int freerw)
int SDL_GameControllerInit(void)
const char * SDL_GameControllerGetStringForButton(SDL_GameControllerButton axis)
char * SDL_GameControllerMappingForGUID(SDL_JoystickGUID guid)
static ControllerMapping_t * SDL_PrivateAddMappingForGUID(SDL_JoystickGUID jGUID, const char *mappingString, SDL_bool *existing, SDL_ControllerMappingPriority priority)
Uint8 SDL_GameControllerGetButton(SDL_GameController *gamecontroller, SDL_GameControllerButton button)
GLboolean GLboolean GLboolean b
#define SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES
static int SDL_PrivateGameControllerAxis(SDL_GameController *gamecontroller, SDL_GameControllerAxis axis, Sint16 value)
#define SDL_LoadFile(file, datasize)
static void HandleJoystickAxis(SDL_GameController *gamecontroller, int axis, int value)
SDL_bool SDL_GameControllerGetAttached(SDL_GameController *gamecontroller)
#define SDL_JoystickGetGUIDFromString
static void SDL_GameControllerIgnoreDevicesChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
union SDL_ExtendedGameControllerBind::@22 output
const char * SDL_GameControllerNameForIndex(int device_index)