1 /*  RetroArch - A frontend for libretro.
2  *  Copyright (C) 2010-2014 - Hans-Kristian Arntzen
3  *  Copyright (C) 2011-2020 - Daniel De Matteis
4  *
5  *  RetroArch is free software: you can redistribute it and/or modify it under the terms
6  *  of the GNU General Public License as published by the Free Software Found-
7  *  ation, either version 3 of the License, or (at your option) any later version.
8  *
9  *  RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
10  *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11  *  PURPOSE.  See the GNU General Public License for more details.
12  *
13  *  You should have received a copy of the GNU General Public License along with RetroArch.
14  *  If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 #ifndef __XINPUT_JOYPAD_INL_H
18 #define __XINPUT_JOYPAD_INL_H
19 
20 #include <stdint.h>
21 #include <boolean.h>
22 #include <retro_common_api.h>
23 
24 #if defined(HAVE_DYNAMIC) && !defined(__WINRT__)
load_xinput_dll(void)25 static bool load_xinput_dll(void)
26 {
27    const char *version = "1.4";
28    /* Find the correct path to load the DLL from.
29     * Usually this will be from the system directory,
30     * but occasionally a user may wish to use a third-party
31     * wrapper DLL (such as x360ce); support these by checking
32     * the working directory first.
33     *
34     * No need to check for existance as we will be checking dylib_load's
35     * success anyway.
36     */
37 
38    g_xinput_dll = dylib_load("xinput1_4.dll");
39    if (!g_xinput_dll)
40    {
41       g_xinput_dll = dylib_load("xinput1_3.dll");
42       version = "1.3";
43    }
44 
45    if (!g_xinput_dll)
46    {
47       RARCH_ERR("[XInput]: Failed to load XInput, ensure DirectX and controller drivers are up to date.\n");
48       return false;
49    }
50 
51    RARCH_LOG("[XInput]: Found XInput v%s.\n", version);
52    return true;
53 }
54 #endif
55 
xinput_joypad_button_state(unsigned xuser,uint16_t btn_word,unsigned port,uint16_t joykey)56 static int16_t xinput_joypad_button_state(
57       unsigned xuser, uint16_t btn_word,
58       unsigned port, uint16_t joykey)
59 {
60    unsigned hat_dir  = GET_HAT_DIR(joykey);
61 
62    if (hat_dir)
63    {
64       switch (hat_dir)
65       {
66          case HAT_UP_MASK:
67             return (btn_word & XINPUT_GAMEPAD_DPAD_UP);
68          case HAT_DOWN_MASK:
69             return (btn_word & XINPUT_GAMEPAD_DPAD_DOWN);
70          case HAT_LEFT_MASK:
71             return (btn_word & XINPUT_GAMEPAD_DPAD_LEFT);
72          case HAT_RIGHT_MASK:
73             return (btn_word & XINPUT_GAMEPAD_DPAD_RIGHT);
74          default:
75             break;
76       }
77       /* hat requested and no hat button down */
78    }
79    else if (joykey < g_xinput_num_buttons)
80       return (btn_word & button_index_to_bitmap_code[joykey]);
81    return 0;
82 }
83 
xinput_joypad_axis_state(XINPUT_GAMEPAD * pad,unsigned port,uint32_t joyaxis)84 static int16_t xinput_joypad_axis_state(
85       XINPUT_GAMEPAD *pad,
86       unsigned port, uint32_t joyaxis)
87 {
88    int16_t val         = 0;
89    int     axis        = -1;
90    bool is_neg         = false;
91    bool is_pos         = false;
92    /* triggers (axes 4,5) cannot be negative */
93    if (AXIS_NEG_GET(joyaxis) <= 3)
94    {
95       axis             = AXIS_NEG_GET(joyaxis);
96       is_neg           = true;
97    }
98    else if (AXIS_POS_GET(joyaxis) <= 5)
99    {
100       axis             = AXIS_POS_GET(joyaxis);
101       is_pos           = true;
102    }
103    else
104       return 0;
105 
106    switch (axis)
107    {
108       case 0:
109          val = pad->sThumbLX;
110          break;
111       case 1:
112          val = pad->sThumbLY;
113          break;
114       case 2:
115          val = pad->sThumbRX;
116          break;
117       case 3:
118          val = pad->sThumbRY;
119          break;
120       case 4:
121          val = pad->bLeftTrigger  * 32767 / 255;
122          break; /* map 0..255 to 0..32767 */
123       case 5:
124          val = pad->bRightTrigger * 32767 / 255;
125          break;
126    }
127 
128    if (is_neg && val > 0)
129       return 0;
130    else if (is_pos && val < 0)
131       return 0;
132    /* Clamp to avoid overflow error. */
133    else if (val == -32768)
134       return -32767;
135    return val;
136 }
137 
138 #endif
139