1 /* 2 * DSFML - The Simple and Fast Multimedia Library for D 3 * 4 * Copyright (c) 2013 - 2018 Jeremy DeHaan (dehaan.jeremiah@gmail.com) 5 * 6 * This software is provided 'as-is', without any express or implied warranty. 7 * In no event will the authors be held liable for any damages arising from the 8 * use of this software. 9 * 10 * Permission is granted to anyone to use this software for any purpose, 11 * including commercial applications, and to alter it and redistribute it 12 * freely, subject to the following restrictions: 13 * 14 * 1. The origin of this software must not be misrepresented; you must not claim 15 * that you wrote the original software. If you use this software in a product, 16 * an acknowledgment in the product documentation would be appreciated but is 17 * not required. 18 * 19 * 2. Altered source versions must be plainly marked as such, and must not be 20 * misrepresented as being the original software. 21 * 22 * 3. This notice may not be removed or altered from any source distribution 23 * 24 * 25 * DSFML is based on SFML (Copyright Laurent Gomila) 26 */ 27 28 /** 29 * $(U Joystick) provides an interface to the state of the joysticks. It only 30 * contains static functions, so it's not meant to be instanciated. Instead, 31 * each joystick is identified by an index that is passed to the functions of 32 * this class. 33 * 34 * This class allows users to query the state of joysticks at any time and 35 * directly, without having to deal with a window and its events. Compared to 36 * the `JoystickMoved`, `JoystickButtonPressed`, and `JoystickButtonReleased` 37 * events, $(U Joystick) can retrieve the state of axes and buttons of joysticks 38 * at any time (you don't need to store and update a boolean on your side in 39 * order to know if a button is pressed or released), and you always get the 40 * real state of joysticks, even if they are moved, pressed or released when 41 * your window is out of focus and no event is triggered. 42 * 43 * DSFML supports: 44 * $(UL 45 * $(LI 8 joysticks (Joystick.Count)) 46 * $(LI 32 buttons per joystick (Joystick.ButtonCount)) 47 * $(LI 8 axes per joystick (Joystick.AxisCount))) 48 * 49 * $(PARA 50 * Unlike the keyboard or mouse, the state of joysticks is sometimes not 51 * directly available (depending on the OS), therefore an `update()` function 52 * must be called in order to update the current state of joysticks. When you 53 * have a window with event handling, this is done automatically, you don't need 54 * to call anything. But if you have no window, or if you want to check 55 * joysticks state before creating one, you must call `Joystick.update` 56 * explicitly.) 57 * 58 * Example: 59 * --- 60 * // Is joystick #0 connected? 61 * bool connected = Joystick.isConnected(0); 62 * 63 * // How many buttons does joystick #0 support? 64 * uint buttons = Joystick.getButtonCount(0); 65 * 66 * // Does joystick #0 define a X axis? 67 * bool hasX = Joystick.hasAxis(0, Joystick.Axis.X); 68 * 69 * // Is button #2 pressed on joystick #0? 70 * bool pressed = Joystick.isButtonPressed(0, 2); 71 * 72 * // What's the current position of the Y axis on joystick #0? 73 * float position = Joystick.getAxisPosition(0, Joystick.Axis.Y); 74 * --- 75 * 76 * See_Also: 77 * $(KEYBOAD_LINK), $(MOUSE_LINK) 78 */ 79 module dsfml.window.joystick; 80 81 /** 82 * Give access to the real-time state of the joysticks. 83 */ 84 final abstract class Joystick 85 { 86 /// Structure holding a joystick's identification 87 struct Identification 88 { 89 private static dstring[immutable(uint)[2]] nameCache; 90 91 /// Index of the joystick. 92 uint index; 93 94 /// Name of the joystick. 95 @property dstring name() const 96 { 97 //In theory, each vid:pid combination should only have one name associated with it. 98 //slightly arcane syntax to make older GDC happy. 99 uint[2] tempkey; 100 tempkey[0] = vendorId; 101 tempkey[1] = productId; 102 immutable(uint)[2] key = tempkey; 103 104 dstring* cachedName = (key in nameCache); 105 if (cachedName !is null) { 106 return *cachedName; 107 } else { 108 import std.exception; 109 110 dchar[] retrievedName; 111 dstring retval; 112 113 retrievedName.length = sfJoystick_getIdentificationNameLength(index); 114 115 sfJoystick_getIdentificationName(index, retrievedName.ptr); 116 117 nameCache[key] = retval = assumeUnique(retrievedName); 118 119 return retval; 120 } 121 } 122 123 /// Manufacturer identifier. 124 uint vendorId; 125 126 /// Product identifier. 127 uint productId; 128 } 129 130 //Constants related to joysticks capabilities. 131 enum 132 { 133 /// Maximum number of supported joysticks. 134 JoystickCount = 8, 135 /// Maximum number of supported buttons. 136 JoystickButtonCount = 32, 137 /// Maximum number of supported axes. 138 JoystickAxisCount = 8 139 } 140 141 /// Axes supported by SFML joysticks. 142 enum Axis 143 { 144 /// The X axis. 145 X, 146 /// The Y axis. 147 Y, 148 /// The Z axis. 149 Z, 150 /// The R axis. 151 R, 152 /// The U axis. 153 U, 154 /// The V axis. 155 V, 156 /// The X axis of the point-of-view hat. 157 PovX, 158 /// The Y axis of the point-of-view hat. 159 PovY 160 } 161 162 /** 163 * Return the number of buttons supported by a joystick. 164 * 165 * If the joystick is not connected, this function returns 0. 166 * 167 * Params: 168 * joystick = Index of the joystick 169 * 170 * Returns: Number of buttons supported by the joystick. 171 */ 172 static uint getButtonCount(uint joystick) 173 { 174 return sfJoystick_getButtonCount(joystick); 175 } 176 177 /** 178 * Get the current position of a joystick axis. 179 * 180 * If the joystick is not connected, this function returns 0. 181 * 182 * Params: 183 * joystick = Index of the joystick 184 * axis = Axis to check 185 * 186 * Returns: Current position of the axis, in range [-100 .. 100]. 187 */ 188 static float getAxisPosition(uint joystick, Axis axis) 189 { 190 return sfJoystick_getAxisPosition(joystick, axis); 191 } 192 193 /** 194 * Get the joystick information 195 * 196 * Params: 197 * joystick = Index of the joystick 198 * 199 * Returns: Structure containing the joystick information. 200 */ 201 static Identification getIdentification(uint joystick) { 202 Identification identification; 203 204 sfJoystick_getIdentification(joystick, &identification.vendorId, &identification.productId); 205 206 return identification; 207 } 208 209 /** 210 * Check if a joystick supports a given axis. 211 * 212 * If the joystick is not connected, this function returns false. 213 * 214 * Params: 215 * joystick = Index of the joystick 216 * axis = Axis to check 217 * 218 * Returns: true if the joystick supports the axis, false otherwise. 219 */ 220 static bool hasAxis(uint joystick, Axis axis) 221 { 222 return (sfJoystick_hasAxis(joystick, axis)); 223 } 224 225 /** 226 * Check if a joystick button is pressed. 227 * 228 * If the joystick is not connected, this function returns false. 229 * 230 * Params: 231 * joystick = Index of the joystick 232 * button = Button to check 233 * 234 * Returns: true if the button is pressed, false otherwise. 235 */ 236 static bool isButtonPressed(uint joystick, uint button) 237 { 238 return sfJoystick_isButtonPressed(joystick, button); 239 } 240 241 /** 242 * Check if a joystick is connected. 243 * 244 * Params: 245 * joystick = Index of the joystick 246 * 247 * Returns: true if the joystick is connected, false otherwise. 248 */ 249 static bool isConnected(uint joystick) 250 { 251 return (sfJoystick_isConnected(joystick)); 252 } 253 254 /** 255 * Update the states of all joysticks. 256 * 257 * This function is used internally by SFML, so you normally don't have to 258 * call it explicitely. 259 * 260 * However, you may need to call it if you have no window yet (or no window 261 * at all): in this case the joysticks states are not updated automatically. 262 */ 263 static void update() 264 { 265 sfJoystick_update(); 266 } 267 268 } 269 270 unittest 271 { 272 version(DSFML_Unittest_Window) 273 { 274 import std.stdio; 275 276 Joystick.update(); 277 278 bool[] joysticks = [false,false,false,false,false,false,false,false]; 279 280 for(uint i; i < Joystick.JoystickCount; ++i) 281 { 282 if(Joystick.isConnected(i)) 283 { 284 auto id = Joystick.getIdentification(i); 285 joysticks[i] = true; 286 writeln("Joystick number ",i," is connected!"); 287 writefln("Type: %s, ID: %x:%x", id.name, id.vendorId, id.productId); 288 } 289 } 290 291 foreach(uint i,bool joystick;joysticks) 292 { 293 if(joystick) 294 { 295 //Check buttons 296 uint buttonCounts = Joystick.getButtonCount(i); 297 298 for(uint j = 0; j<buttonCounts; ++j) 299 { 300 if(Joystick.isButtonPressed(i,j)) 301 { 302 writeln("Button ", j, " was pressed on joystick ", i); 303 } 304 } 305 306 //check axis 307 for(int j = 0; j<Joystick.JoystickAxisCount;++j) 308 { 309 Joystick.Axis axis = cast(Joystick.Axis)j; 310 311 if(Joystick.hasAxis(i,axis)) 312 { 313 writeln("Axis ", axis, " has a position of ", Joystick.getAxisPosition(i,axis), "for joystick", i); 314 } 315 } 316 } 317 } 318 } 319 } 320 321 private extern(C): 322 //Check if a joystick is connected 323 bool sfJoystick_isConnected(uint joystick); 324 325 //Return the number of buttons supported by a joystick 326 uint sfJoystick_getButtonCount(uint joystick); 327 328 //Return the length of the joystick identification structure's name 329 size_t sfJoystick_getIdentificationNameLength(uint joystick); 330 331 //Write the name of the joystick into a D-allocated string buffer. 332 void sfJoystick_getIdentificationName (uint joystick, dchar* nameBuffer); 333 334 //Return the identification structure for a joystick 335 void sfJoystick_getIdentification(uint joystick, uint* vendorID, uint* productId); 336 337 //Check if a joystick supports a given axis 338 bool sfJoystick_hasAxis(uint joystick, int axis); 339 340 //Check if a joystick button is pressed 341 bool sfJoystick_isButtonPressed(uint joystick, uint button); 342 343 //Get the current position of a joystick axis 344 float sfJoystick_getAxisPosition(uint joystick, int axis); 345 346 //Update the states of all joysticks 347 void sfJoystick_update();