Andrew Eikum : xinput: Implement XInputGetKeystroke.

Alexandre Julliard julliard at winehq.org
Fri Jan 24 16:14:09 CST 2020


Module: wine
Branch: master
Commit: c1d51031ef2c8926777e45f596a49eae4a3ff328
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=c1d51031ef2c8926777e45f596a49eae4a3ff328

Author: Andrew Eikum <aeikum at codeweavers.com>
Date:   Thu Jan 23 14:28:56 2020 -0600

xinput: Implement XInputGetKeystroke.

Signed-off-by: Andrew Eikum <aeikum at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/xinput1_3/xinput_main.c    | 216 ++++++++++++++++++++++++++++++++++++++--
 dlls/xinput1_3/xinput_private.h |   1 +
 2 files changed, 209 insertions(+), 8 deletions(-)

diff --git a/dlls/xinput1_3/xinput_main.c b/dlls/xinput1_3/xinput_main.c
index 5485ae8d2d..63b7dd7f0b 100644
--- a/dlls/xinput1_3/xinput_main.c
+++ b/dlls/xinput1_3/xinput_main.c
@@ -202,19 +202,219 @@ DWORD WINAPI DECLSPEC_HOTPATCH XInputGetStateEx(DWORD index, XINPUT_STATE* state
     return xinput_get_state(index, state);
 }
 
-DWORD WINAPI DECLSPEC_HOTPATCH XInputGetKeystroke(DWORD index, DWORD reserved, PXINPUT_KEYSTROKE keystroke)
+static const int JS_STATE_OFF = 0;
+static const int JS_STATE_LOW = 1;
+static const int JS_STATE_HIGH = 2;
+
+static int joystick_state(const SHORT value)
 {
-    static int warn_once;
+    if (value > 20000)
+        return JS_STATE_HIGH;
+    if (value < -20000)
+        return JS_STATE_LOW;
+    return JS_STATE_OFF;
+}
 
-    if (!warn_once++)
-        FIXME("(index %u, reserved %u, keystroke %p) Stub!\n", index, reserved, keystroke);
+static WORD js_vk_offs(const int x, const int y)
+{
+    if (y == JS_STATE_OFF)
+    {
+      /*if (x == JS_STATE_OFF) shouldn't get here */
+        if (x == JS_STATE_LOW) return 3; /* LEFT */
+      /*if (x == JS_STATE_HIGH)*/ return 2; /* RIGHT */
+    }
+    if (y == JS_STATE_HIGH)
+    {
+        if (x == JS_STATE_OFF) return 0; /* UP */
+        if (x == JS_STATE_LOW) return 4; /* UPLEFT */
+      /*if (x == JS_STATE_HIGH)*/ return 5; /* UPRIGHT */
+    }
+  /*if (y == JS_STATE_LOW)*/
+    {
+        if (x == JS_STATE_OFF) return 1; /* DOWN */
+        if (x == JS_STATE_LOW) return 7; /* DOWNLEFT */
+      /*if (x == JS_STATE_HIGH)*/ return 6; /* DOWNRIGHT */
+    }
+}
 
-    if (index >= XUSER_MAX_COUNT)
-        return ERROR_BAD_ARGUMENTS;
-    if (!controllers[index].platform_private)
+static DWORD check_joystick_keystroke(const DWORD index, XINPUT_KEYSTROKE *keystroke,
+        const SHORT *cur_x, const SHORT *cur_y, SHORT *last_x, SHORT *last_y,
+        const WORD base_vk)
+{
+    int cur_vk = 0, cur_x_st, cur_y_st;
+    int last_vk = 0, last_x_st, last_y_st;
+
+    cur_x_st = joystick_state(*cur_x);
+    cur_y_st = joystick_state(*cur_y);
+    if (cur_x_st || cur_y_st)
+        cur_vk = base_vk + js_vk_offs(cur_x_st, cur_y_st);
+
+    last_x_st = joystick_state(*last_x);
+    last_y_st = joystick_state(*last_y);
+    if (last_x_st || last_y_st)
+        last_vk = base_vk + js_vk_offs(last_x_st, last_y_st);
+
+    if (cur_vk != last_vk)
+    {
+        if (last_vk)
+        {
+            /* joystick was set, and now different. send a KEYUP event, and set
+             * last pos to centered, so the appropriate KEYDOWN event will be
+             * sent on the next call. */
+            keystroke->VirtualKey = last_vk;
+            keystroke->Unicode = 0; /* unused */
+            keystroke->Flags = XINPUT_KEYSTROKE_KEYUP;
+            keystroke->UserIndex = index;
+            keystroke->HidCode = 0;
+
+            *last_x = 0;
+            *last_y = 0;
+
+            return ERROR_SUCCESS;
+        }
+
+        /* joystick was unset, send KEYDOWN. */
+        keystroke->VirtualKey = cur_vk;
+        keystroke->Unicode = 0; /* unused */
+        keystroke->Flags = XINPUT_KEYSTROKE_KEYDOWN;
+        keystroke->UserIndex = index;
+        keystroke->HidCode = 0;
+
+        *last_x = *cur_x;
+        *last_y = *cur_y;
+
+        return ERROR_SUCCESS;
+    }
+
+    *last_x = *cur_x;
+    *last_y = *cur_y;
+
+    return ERROR_EMPTY;
+}
+
+static BOOL trigger_is_on(const BYTE value)
+{
+    return value > 30;
+}
+
+static DWORD check_for_keystroke(const DWORD index, XINPUT_KEYSTROKE *keystroke)
+{
+    xinput_controller *device = &controllers[index];
+    const XINPUT_GAMEPAD *cur;
+    DWORD ret = ERROR_EMPTY;
+    int i;
+
+    static const struct {
+        int mask;
+        WORD vk;
+    } buttons[] = {
+        { XINPUT_GAMEPAD_DPAD_UP, VK_PAD_DPAD_UP },
+        { XINPUT_GAMEPAD_DPAD_DOWN, VK_PAD_DPAD_DOWN },
+        { XINPUT_GAMEPAD_DPAD_LEFT, VK_PAD_DPAD_LEFT },
+        { XINPUT_GAMEPAD_DPAD_RIGHT, VK_PAD_DPAD_RIGHT },
+        { XINPUT_GAMEPAD_START, VK_PAD_START },
+        { XINPUT_GAMEPAD_BACK, VK_PAD_BACK },
+        { XINPUT_GAMEPAD_LEFT_THUMB, VK_PAD_LTHUMB_PRESS },
+        { XINPUT_GAMEPAD_RIGHT_THUMB, VK_PAD_RTHUMB_PRESS },
+        { XINPUT_GAMEPAD_LEFT_SHOULDER, VK_PAD_LSHOULDER },
+        { XINPUT_GAMEPAD_RIGHT_SHOULDER, VK_PAD_RSHOULDER },
+        { XINPUT_GAMEPAD_A, VK_PAD_A },
+        { XINPUT_GAMEPAD_B, VK_PAD_B },
+        { XINPUT_GAMEPAD_X, VK_PAD_X },
+        { XINPUT_GAMEPAD_Y, VK_PAD_Y },
+        /* note: guide button does not send an event */
+    };
+
+    if (!verify_and_lock_device(device))
         return ERROR_DEVICE_NOT_CONNECTED;
 
-    return ERROR_NOT_SUPPORTED;
+    cur = &device->state.Gamepad;
+
+    /*** buttons ***/
+    for (i = 0; i < ARRAY_SIZE(buttons); ++i)
+    {
+        if ((cur->wButtons & buttons[i].mask) ^ (device->last_keystroke.wButtons & buttons[i].mask))
+        {
+            keystroke->VirtualKey = buttons[i].vk;
+            keystroke->Unicode = 0; /* unused */
+            if (cur->wButtons & buttons[i].mask)
+            {
+                keystroke->Flags = XINPUT_KEYSTROKE_KEYDOWN;
+                device->last_keystroke.wButtons |= buttons[i].mask;
+            }
+            else
+            {
+                keystroke->Flags = XINPUT_KEYSTROKE_KEYUP;
+                device->last_keystroke.wButtons &= ~buttons[i].mask;
+            }
+            keystroke->UserIndex = index;
+            keystroke->HidCode = 0;
+            ret = ERROR_SUCCESS;
+            goto done;
+        }
+    }
+
+    /*** triggers ***/
+    if (trigger_is_on(cur->bLeftTrigger) ^ trigger_is_on(device->last_keystroke.bLeftTrigger))
+    {
+        keystroke->VirtualKey = VK_PAD_LTRIGGER;
+        keystroke->Unicode = 0; /* unused */
+        keystroke->Flags = trigger_is_on(cur->bLeftTrigger) ? XINPUT_KEYSTROKE_KEYDOWN : XINPUT_KEYSTROKE_KEYUP;
+        keystroke->UserIndex = index;
+        keystroke->HidCode = 0;
+        device->last_keystroke.bLeftTrigger = cur->bLeftTrigger;
+        ret = ERROR_SUCCESS;
+        goto done;
+    }
+
+    if (trigger_is_on(cur->bRightTrigger) ^ trigger_is_on(device->last_keystroke.bRightTrigger))
+    {
+        keystroke->VirtualKey = VK_PAD_RTRIGGER;
+        keystroke->Unicode = 0; /* unused */
+        keystroke->Flags = trigger_is_on(cur->bRightTrigger) ? XINPUT_KEYSTROKE_KEYDOWN : XINPUT_KEYSTROKE_KEYUP;
+        keystroke->UserIndex = index;
+        keystroke->HidCode = 0;
+        device->last_keystroke.bRightTrigger = cur->bRightTrigger;
+        ret = ERROR_SUCCESS;
+        goto done;
+    }
+
+    /*** joysticks ***/
+    ret = check_joystick_keystroke(index, keystroke, &cur->sThumbLX, &cur->sThumbLY,
+            &device->last_keystroke.sThumbLX,
+            &device->last_keystroke.sThumbLY, VK_PAD_LTHUMB_UP);
+    if (ret == ERROR_SUCCESS)
+        goto done;
+
+    ret = check_joystick_keystroke(index, keystroke, &cur->sThumbRX, &cur->sThumbRY,
+            &device->last_keystroke.sThumbRX,
+            &device->last_keystroke.sThumbRY, VK_PAD_RTHUMB_UP);
+    if (ret == ERROR_SUCCESS)
+        goto done;
+
+done:
+    unlock_device(device);
+
+    return ret;
+}
+
+DWORD WINAPI DECLSPEC_HOTPATCH XInputGetKeystroke(DWORD index, DWORD reserved, PXINPUT_KEYSTROKE keystroke)
+{
+    TRACE("(index %u, reserved %u, keystroke %p)\n", index, reserved, keystroke);
+
+    if (index >= XUSER_MAX_COUNT && index != XUSER_INDEX_ANY)
+        return ERROR_BAD_ARGUMENTS;
+
+    if (index == XUSER_INDEX_ANY)
+    {
+        int i;
+        for (i = 0; i < XUSER_MAX_COUNT; ++i)
+            if (check_for_keystroke(i, keystroke) == ERROR_SUCCESS)
+                return ERROR_SUCCESS;
+        return ERROR_EMPTY;
+    }
+
+    return check_for_keystroke(index, keystroke);
 }
 
 DWORD WINAPI DECLSPEC_HOTPATCH XInputGetCapabilities(DWORD index, DWORD flags, XINPUT_CAPABILITIES* capabilities)
diff --git a/dlls/xinput1_3/xinput_private.h b/dlls/xinput1_3/xinput_private.h
index f3456cd8e7..7de9a2a2e4 100644
--- a/dlls/xinput1_3/xinput_private.h
+++ b/dlls/xinput1_3/xinput_private.h
@@ -23,6 +23,7 @@ typedef struct _xinput_controller
     XINPUT_CAPABILITIES caps;
     void *platform_private; /* non-NULL when device is valid; validity may be read without holding crit */
     XINPUT_STATE state;
+    XINPUT_GAMEPAD last_keystroke;
     XINPUT_VIBRATION vibration;
 } xinput_controller;
 




More information about the wine-cvs mailing list