src/sysdep/windows/input.c
static void scan_xinput_joysticks(void)
{
    PRECOND(xinput_module, return);

    XINPUT_CAPABILITIES caps;
    for (int device = 0; device < 4; device++) {
        if ((*p_XInputGetCapabilities)(device, XINPUT_FLAG_GAMEPAD,
                                       &caps) != ERROR_SUCCESS) {
            continue;
        }
        JoystickInfo info;
        mem_clear(&info, sizeof(info));
        for (int i = 0; i < lenof(info.button_map); i++) {
            info.button_map[i] = -1;
        }
        info.is_xinput = 1;
        info.xinput_device = device;
        info.xinput_caps = caps;
        const WORD dpad_buttons = (XINPUT_GAMEPAD_DPAD_UP
                                 | XINPUT_GAMEPAD_DPAD_DOWN
                                 | XINPUT_GAMEPAD_DPAD_LEFT
                                 | XINPUT_GAMEPAD_DPAD_RIGHT);
        info.has_dpad = (caps.Gamepad.wButtons & dpad_buttons) == dpad_buttons;

        for (int i = 0; i < lenof(xinput_button_map); i++) {
            if (caps.Gamepad.wButtons & xinput_button_map[i].flag) {
                const int index = info.num_buttons++;
                info.button_map[xinput_button_map[i].name] = index;
            }
        }
        if (caps.Gamepad.bLeftTrigger) {
            const int index = info.num_buttons++;
            info.button_map[INPUT_JOYBUTTON_L2] = index;
        }
        if (caps.Gamepad.bRightTrigger) {
            const int index = info.num_buttons++;
            info.button_map[INPUT_JOYBUTTON_R2] = index;
        }
        if (caps.Gamepad.sThumbLX && caps.Gamepad.sThumbLY) {
            info.num_sticks = 1;
        }
        if (caps.Gamepad.sThumbRX && caps.Gamepad.sThumbRY) {
            info.num_sticks = 2;
        }

        sys_mutex_lock(joystick_mutex, -1);
        int i;
        for (i = 0; i < num_joysticks; i++) {
            if (joysticks[i].is_xinput
             && joysticks[i].xinput_device == device) {
                break;
            }
        }
        if (i == num_joysticks) {
            for (i = 0; i < num_joysticks; i++) {
                if (!joystick_info[i].connected) {
                    if (!joysticks[i].is_xinput) {
                        mem_free(joysticks[i].preparsed_data);
                        mem_free(joysticks[i].input_state);
                        hidjoy_destroy(joysticks[i].hid_handle);
                    }
                    break;
                }
            }
        }
        const int is_new = (i == num_joysticks);
        if (is_new) {
            JoystickInfo *new_joysticks = mem_realloc(
                joysticks, sizeof(*joysticks) * (num_joysticks + 1), 0);
            if (UNLIKELY(!new_joysticks)) {
                DLOG("No memory to expand joysticks array to %d entries",
                     num_joysticks + 1);
                sys_mutex_unlock(joystick_mutex);
                return;
            }
            joysticks = new_joysticks;
            SysInputJoystick *new_joystick_info = mem_realloc(
                joystick_info, sizeof(*joystick_info) * (num_joysticks + 1), 0);
            if (UNLIKELY(!new_joystick_info)) {
                DLOG("No memory to expand joystick_info array to %d entries",
                     num_joysticks + 1);
                sys_mutex_unlock(joystick_mutex);
                return;
            }
            joystick_info = new_joystick_info;
            num_joysticks++;
            joystick_info[i].connected = 0;
        }
        if (!joystick_info[i].connected) {
            joysticks[i] = info;
            joystick_info[i].connected = 1;
            joystick_info[i].can_rumble = (caps.Vibration.wLeftMotorSpeed
                                        || caps.Vibration.wRightMotorSpeed);
            joystick_info[i].num_buttons = info.num_buttons;
            joystick_info[i].num_sticks = info.num_sticks;
            if (is_new) {
                DLOG("New joystick %d: XInput %d, %d buttons, %d sticks",
                     i, device, info.num_buttons, info.num_sticks);
            } else {
                DLOG("Joystick %d (XInput %d) reconnected", i, device);
            }
            send_joystick_connect_event(i, INPUT_JOYSTICK_CONNECTED);
        }
        sys_mutex_unlock(joystick_mutex);
    }
}
/*************************************************************************/
/*************** Local routines: XInput joystick handling ****************/
/*************************************************************************/
Local routines: XInput joystick handling
Local routines : XInput joystick handling
static void scan_xinput_joysticks(void)
{
    PRECOND(xinput_module, return);
    XINPUT_CAPABILITIES caps;
    for (int device = 0; device < 4; device++) {
        if ((*p_XInputGetCapabilities)(device, XINPUT_FLAG_GAMEPAD,
                                       &caps) != ERROR_SUCCESS) {
            continue;
        }
        JoystickInfo info;
        mem_clear(&info, sizeof(info));
        for (int i = 0; i < lenof(info.button_map); i++) {
            info.button_map[i] = -1;
        }
        info.is_xinput = 1;
        info.xinput_device = device;
        info.xinput_caps = caps;
        const WORD dpad_buttons = (XINPUT_GAMEPAD_DPAD_UP
                                 | XINPUT_GAMEPAD_DPAD_DOWN
                                 | XINPUT_GAMEPAD_DPAD_LEFT
                                 | XINPUT_GAMEPAD_DPAD_RIGHT);
        info.has_dpad = (caps.Gamepad.wButtons & dpad_buttons) == dpad_buttons;
        for (int i = 0; i < lenof(xinput_button_map); i++) {
            if (caps.Gamepad.wButtons & xinput_button_map[i].flag) {
                const int index = info.num_buttons++;
                info.button_map[xinput_button_map[i].name] = index;
            }
        }
        if (caps.Gamepad.bLeftTrigger) {
            const int index = info.num_buttons++;
            info.button_map[INPUT_JOYBUTTON_L2] = index;
        }
        if (caps.Gamepad.bRightTrigger) {
            const int index = info.num_buttons++;
            info.button_map[INPUT_JOYBUTTON_R2] = index;
        }
        if (caps.Gamepad.sThumbLX && caps.Gamepad.sThumbLY) {
            info.num_sticks = 1;
        }
        if (caps.Gamepad.sThumbRX && caps.Gamepad.sThumbRY) {
            info.num_sticks = 2;
        }
        sys_mutex_lock(joystick_mutex, -1);
        int i;
        for (i = 0; i < num_joysticks; i++) {
            if (joysticks[i].is_xinput
             && joysticks[i].xinput_device == device) {
                break;
            }
        }
        if (i == num_joysticks) {
            for (i = 0; i < num_joysticks; i++) {
                if (!joystick_info[i].connected) {
                    if (!joysticks[i].is_xinput) {
                        mem_free(joysticks[i].preparsed_data);
                        mem_free(joysticks[i].input_state);
                        hidjoy_destroy(joysticks[i].hid_handle);
                    }
                    break;
                }
            }
        }
        const int is_new = (i == num_joysticks);
        if (is_new) {
            JoystickInfo *new_joysticks = mem_realloc(
                joysticks, sizeof(*joysticks) * (num_joysticks + 1), 0);
            if (UNLIKELY(!new_joysticks)) {
                DLOG("No memory to expand joysticks array to %d entries",
                     num_joysticks + 1);
                sys_mutex_unlock(joystick_mutex);
                return;
            }
            joysticks = new_joysticks;
            SysInputJoystick *new_joystick_info = mem_realloc(
                joystick_info, sizeof(*joystick_info) * (num_joysticks + 1), 0);
            if (UNLIKELY(!new_joystick_info)) {
                DLOG("No memory to expand joystick_info array to %d entries",
                     num_joysticks + 1);
                sys_mutex_unlock(joystick_mutex);
                return;
            }
            joystick_info = new_joystick_info;
            num_joysticks++;
            joystick_info[i].connected = 0;
        }
        if (!joystick_info[i].connected) {
            joysticks[i] = info;
            joystick_info[i].connected = 1;
            joystick_info[i].can_rumble = (caps.Vibration.wLeftMotorSpeed
                                        || caps.Vibration.wRightMotorSpeed);
            joystick_info[i].num_buttons = info.num_buttons;
            joystick_info[i].num_sticks = info.num_sticks;
            if (is_new) {
                DLOG("New joystick %d: XInput %d, %d buttons, %d sticks",
                     i, device, info.num_buttons, info.num_sticks);
            } else {
                DLOG("Joystick %d (XInput %d) reconnected", i, device);
            }
            send_joystick_connect_event(i, INPUT_JOYSTICK_CONNECTED);
        }
        sys_mutex_unlock(joystick_mutex);
    }
}
static void scan_xinput_joysticks ( void ) { PRECOND ( xinput_module , return ) ; XINPUT_CAPABILITIES caps ; for ( int device = 0 ; device < 4 ; device ++ ) { if ( ( * p_XInputGetCapabilities ) ( device , XINPUT_FLAG_GAMEPAD , & caps ) != ERROR_SUCCESS ) { continue ; } JoystickInfo info ; mem_clear ( & info , sizeof ( info ) ) ; for ( int i = 0 ; i < lenof ( info . button_map ) ; i ++ ) { info . button_map [ i ] = -1 ; } info . is_xinput = 1 ; info . xinput_device = device ; info . xinput_caps = caps ; const WORD dpad_buttons = ( XINPUT_GAMEPAD_DPAD_UP | XINPUT_GAMEPAD_DPAD_DOWN | XINPUT_GAMEPAD_DPAD_LEFT | XINPUT_GAMEPAD_DPAD_RIGHT ) ; info . has_dpad = ( caps . Gamepad . wButtons & dpad_buttons ) == dpad_buttons ; for ( int i = 0 ; i < lenof ( xinput_button_map ) ; i ++ ) { if ( caps . Gamepad . wButtons & xinput_button_map [ i ] . flag ) { const int index = info . num_buttons ++ ; info . button_map [ xinput_button_map [ i ] . name ] = index ; } } if ( caps . Gamepad . bLeftTrigger ) { const int index = info . num_buttons ++ ; info . button_map [ INPUT_JOYBUTTON_L2 ] = index ; } if ( caps . Gamepad . bRightTrigger ) { const int index = info . num_buttons ++ ; info . button_map [ INPUT_JOYBUTTON_R2 ] = index ; } if ( caps . Gamepad . sThumbLX && caps . Gamepad . sThumbLY ) { info . num_sticks = 1 ; } if ( caps . Gamepad . sThumbRX && caps . Gamepad . sThumbRY ) { info . num_sticks = 2 ; } sys_mutex_lock ( joystick_mutex , -1 ) ; int i ; for ( i = 0 ; i < num_joysticks ; i ++ ) { if ( joysticks [ i ] . is_xinput && joysticks [ i ] . xinput_device == device ) { break ; } } if ( i == num_joysticks ) { for ( i = 0 ; i < num_joysticks ; i ++ ) { if ( ! joystick_info [ i ] . connected ) { if ( ! joysticks [ i ] . is_xinput ) { mem_free ( joysticks [ i ] . preparsed_data ) ; mem_free ( joysticks [ i ] . input_state ) ; hidjoy_destroy ( joysticks [ i ] . hid_handle ) ; } break ; } } } const int is_new = ( i == num_joysticks ) ; if ( is_new ) { JoystickInfo * new_joysticks = mem_realloc ( joysticks , sizeof ( * joysticks ) * ( num_joysticks + 1 ) , 0 ) ; if ( UNLIKELY ( ! new_joysticks ) ) { DLOG ( " " , num_joysticks + 1 ) ; sys_mutex_unlock ( joystick_mutex ) ; return ; } joysticks = new_joysticks ; SysInputJoystick * new_joystick_info = mem_realloc ( joystick_info , sizeof ( * joystick_info ) * ( num_joysticks + 1 ) , 0 ) ; if ( UNLIKELY ( ! new_joystick_info ) ) { DLOG ( " " , num_joysticks + 1 ) ; sys_mutex_unlock ( joystick_mutex ) ; return ; } joystick_info = new_joystick_info ; num_joysticks ++ ; joystick_info [ i ] . connected = 0 ; } if ( ! joystick_info [ i ] . connected ) { joysticks [ i ] = info ; joystick_info [ i ] . connected = 1 ; joystick_info [ i ] . can_rumble = ( caps . Vibration . wLeftMotorSpeed || caps . Vibration . wRightMotorSpeed ) ; joystick_info [ i ] . num_buttons = info . num_buttons ; joystick_info [ i ] . num_sticks = info . num_sticks ; if ( is_new ) { DLOG ( " " , i , device , info . num_buttons , info . num_sticks ) ; } else { DLOG ( " " , i , device ) ; } send_joystick_connect_event ( i , INPUT_JOYSTICK_CONNECTED ) ; } sys_mutex_unlock ( joystick_mutex ) ; } }
Local routines: XInput joystick handling
Local routines : XInput joystick handling