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