diff --git a/dlls/xinput1_3/xinput1_3_main.c b/dlls/xinput1_3/xinput1_3_main.c index 2b3a5f7..41a383b 100644 --- a/dlls/xinput1_3/xinput1_3_main.c +++ b/dlls/xinput1_3/xinput1_3_main.c @@ -21,6 +21,14 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include #include "wine/debug.h" #include "windef.h" @@ -46,13 +54,198 @@ BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved) return TRUE; } +#define LINUX_JSDEV "/dev/input/js0" + +struct LinuxJoystick +{ + int enabled; + int fd; + int num_axis; + int num_button; + XINPUT_STATE state; +}; + +struct LinuxJoystick g_joystick = { + .enabled = 0, + .fd = -1, + .num_axis = 0, + .num_button = 0, + .state = { 0 } +}; + +int init_linux_joystick(struct LinuxJoystick* js) +{ + if (js->enabled) + { + puts("ignoring multiple enable calls"); + return 0; + } + else + { + FIXME("init_linux_joystick()\n"); + if ((js->fd = open(LINUX_JSDEV, O_RDONLY | O_NONBLOCK)) < 0) + { + js->enabled = FALSE; + perror(LINUX_JSDEV); + return -1; + } + else + { + js->enabled = TRUE; + ioctl(js->fd, JSIOCGAXES, &js->num_axis); + ioctl(js->fd, JSIOCGBUTTONS, &js->num_button); + return 0; + } + } +} + +#define XINPUT_SHIFT_DPAD_UP 0 +#define XINPUT_SHIFT_DPAD_DOWN 1 +#define XINPUT_SHIFT_DPAD_LEFT 2 +#define XINPUT_SHIFT_DPAD_RIGHT 3 +#define XINPUT_SHIFT_START 4 +#define XINPUT_SHIFT_BACK 5 +#define XINPUT_SHIFT_LEFT_THUMB 6 +#define XINPUT_SHIFT_RIGHT_THUMB 7 +#define XINPUT_SHIFT_LEFT_SHOULDER 8 +#define XINPUT_SHIFT_RIGHT_SHOULDER 9 + +#define XINPUT_SHIFT_A 12 +#define XINPUT_SHIFT_B 13 +#define XINPUT_SHIFT_X 14 +#define XINPUT_SHIFT_Y 15 + +#define SET_BIT(bitmask, bit) bitmask |= 1 << bit +#define UNSET_BIT(bitmask, bit) bitmask &= ~(1 << bit) +#define SET_BIT_TO(bitmask, bit, value) if (value) { SET_BIT(bitmask, bit); } else { UNSET_BIT(bitmask, bit); } + +void read_linux_joystick(struct LinuxJoystick* js, XINPUT_STATE* pState) +{ + //FIXME("read_linux_joystick"); + struct js_event event; + + int ret; + while((ret = read(js->fd, &event, sizeof(event)))) + { + //printf("XXX got some events: %d %d\n", (int)ret, (int)errno); + if (ret < 0 && errno == EAGAIN) + { + break; + } + if (ret < 0) + { + //FIXME("Read Error\n"); + perror("CONTROLLER"); + break; + } + else + { + // ok + js->state.dwPacketNumber += 1; + + if (event.type & JS_EVENT_AXIS) + { + //printf("Axis: %d %d\n", (int)event.number, (int)event.value); + switch(event.number) + { + case 0: js->state.Gamepad.sThumbLX = event.value; break; + case 1: js->state.Gamepad.sThumbLY = event.value; break; + case 2: js->state.Gamepad.sThumbRX = event.value; break; + case 3: js->state.Gamepad.sThumbRY = event.value; break; + case 4: js->state.Gamepad.bRightTrigger = (event.value + 32767) >> 8; break; + case 5: js->state.Gamepad.bLeftTrigger = (event.value + 32767) >> 8; break; + + case 6: + if (event.value > 0) + { + UNSET_BIT(js->state.Gamepad.wButtons, XINPUT_SHIFT_DPAD_LEFT); + SET_BIT(js->state.Gamepad.wButtons, XINPUT_SHIFT_DPAD_RIGHT); + } + else if (event.value < 0) + { + SET_BIT(js->state.Gamepad.wButtons, XINPUT_SHIFT_DPAD_LEFT); + UNSET_BIT(js->state.Gamepad.wButtons, XINPUT_SHIFT_DPAD_RIGHT); + } + else + { + UNSET_BIT(js->state.Gamepad.wButtons, XINPUT_SHIFT_DPAD_LEFT); + UNSET_BIT(js->state.Gamepad.wButtons, XINPUT_SHIFT_DPAD_RIGHT); + } + break; + + case 7: + if (event.value > 0) + { + UNSET_BIT(js->state.Gamepad.wButtons, XINPUT_SHIFT_DPAD_UP); + SET_BIT(js->state.Gamepad.wButtons, XINPUT_SHIFT_DPAD_DOWN); + } + else if (event.value < 0) + { + SET_BIT(js->state.Gamepad.wButtons, XINPUT_SHIFT_DPAD_UP); + UNSET_BIT(js->state.Gamepad.wButtons, XINPUT_SHIFT_DPAD_DOWN); + } + else + { + UNSET_BIT(js->state.Gamepad.wButtons, XINPUT_SHIFT_DPAD_UP); + UNSET_BIT(js->state.Gamepad.wButtons, XINPUT_SHIFT_DPAD_DOWN); + } + break; + } + } + else if (event.type & JS_EVENT_BUTTON) + { + //printf("Button: %d %d\n", (int)event.number, (int)event.value); + switch(event.number) + { + case 0: SET_BIT_TO(js->state.Gamepad.wButtons, XINPUT_SHIFT_A, event.value); break; + case 1: SET_BIT_TO(js->state.Gamepad.wButtons, XINPUT_SHIFT_B, event.value); break; + case 2: SET_BIT_TO(js->state.Gamepad.wButtons, XINPUT_SHIFT_X, event.value); break; + case 3: SET_BIT_TO(js->state.Gamepad.wButtons, XINPUT_SHIFT_Y, event.value); break; + case 4: SET_BIT_TO(js->state.Gamepad.wButtons, XINPUT_SHIFT_LEFT_SHOULDER, event.value); break; + case 5: SET_BIT_TO(js->state.Gamepad.wButtons, XINPUT_SHIFT_RIGHT_SHOULDER, event.value); break; + case 6: SET_BIT_TO(js->state.Gamepad.wButtons, XINPUT_SHIFT_BACK, event.value); break; + case 7: SET_BIT_TO(js->state.Gamepad.wButtons, XINPUT_SHIFT_START, event.value); break; + case 8: SET_BIT_TO(js->state.Gamepad.wButtons, XINPUT_SHIFT_LEFT_SHOULDER, event.value); break; + case 9: SET_BIT_TO(js->state.Gamepad.wButtons, XINPUT_SHIFT_LEFT_THUMB, event.value); break; + case 10: SET_BIT_TO(js->state.Gamepad.wButtons, XINPUT_SHIFT_RIGHT_THUMB, event.value); break; + } + } + } + } + + *pState = js->state; +} + +void deinit_linux_joystick(struct LinuxJoystick* js) +{ + if (!js->enabled) + { + puts("ignoring multiple deinit_linux_joystick() calls"); + } + else + { + close(js->fd); + js->enabled = FALSE; + } +} + void WINAPI XInputEnable(BOOL enable) { - /* Setting to false will stop messages from XInputSetState being sent - to the controllers. Setting to true will send the last vibration - value (sent to XInputSetState) to the controller and allow messages to - be sent */ - FIXME("(%d) Stub!\n", enable); + /* Setting to false will stop messages from XInputSetState being sent + to the controllers. Setting to true will send the last vibration + value (sent to XInputSetState) to the controller and allow messages to + be sent */ + if (enable) + { + if (init_linux_joystick(&g_joystick) < 0) + { + puts("init_linux_joystick() failed\n"); + } + } + else + { + deinit_linux_joystick(&g_joystick); + } } DWORD WINAPI XInputSetState(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration) @@ -69,12 +262,29 @@ DWORD WINAPI XInputSetState(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration) DWORD WINAPI XInputGetState(DWORD dwUserIndex, XINPUT_STATE* pState) { + TRACE("Test\n"); static int warn_once; if (!warn_once++) FIXME("(%u %p)\n", dwUserIndex, pState); - if (dwUserIndex < XUSER_MAX_COUNT) + if (dwUserIndex == 0 && g_joystick.enabled) + { + pState->dwPacketNumber = 0; + + pState->Gamepad.wButtons = 0; + pState->Gamepad.bLeftTrigger = 0; + pState->Gamepad.bRightTrigger = 0; + pState->Gamepad.sThumbLX = 0; + pState->Gamepad.sThumbLY = 0; + pState->Gamepad.sThumbRX = 5; + pState->Gamepad.sThumbRY = 45; + + read_linux_joystick(&g_joystick, pState); + + return ERROR_SUCCESS; + } + else if (dwUserIndex < XUSER_MAX_COUNT) { return ERROR_DEVICE_NOT_CONNECTED; /* If controller exists then return ERROR_SUCCESS */