1 //////////////////////////////////////////////////////////////////////////////////////// 2 // 3 // Nestopia - NES/Famicom emulator written in C++ 4 // 5 // Copyright (C) 2003-2008 Martin Freij 6 // 7 // This file is part of Nestopia. 8 // 9 // Nestopia is free software; you can redistribute it and/or modify 10 // it under the terms of the GNU General Public License as published by 11 // the Free Software Foundation; either version 2 of the License, or 12 // (at your option) any later version. 13 // 14 // Nestopia is distributed in the hope that it will be useful, 15 // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 // GNU General Public License for more details. 18 // 19 // You should have received a copy of the GNU General Public License 20 // along with Nestopia; if not, write to the Free Software 21 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 // 23 //////////////////////////////////////////////////////////////////////////////////////// 24 25 #ifndef NST_DIRECTX_DIRECTINPUT_H 26 #define NST_DIRECTX_DIRECTINPUT_H 27 28 #pragma once 29 30 #define DIRECTINPUT_VERSION 0x0800 31 32 #include "NstDirectX.hpp" 33 #include "NstObjectPod.hpp" 34 #include "NstObjectHeap.hpp" 35 #include "NstCollectionVector.hpp" 36 #include <dinput.h> 37 38 namespace Nestopia 39 { 40 namespace DirectX 41 { 42 class DirectInput 43 { 44 class Keyboard; 45 class Joystick; 46 47 public: 48 49 explicit DirectInput(HWND); 50 ~DirectInput(); 51 52 enum 53 { 54 MAX_JOYSTICKS = 32, 55 NUM_KEYBOARD_KEYS = 256, 56 AXIS_X = 0x001, 57 AXIS_Y = 0x002, 58 AXIS_Z = 0x004, 59 AXIS_RX = 0x008, 60 AXIS_RY = 0x010, 61 AXIS_RZ = 0x020, 62 AXIS_SLIDER_0 = 0x040, 63 AXIS_SLIDER_1 = 0x080, 64 AXIS_POV_0 = 0x100, 65 AXIS_POV_1 = 0x200, 66 AXIS_POV_2 = 0x400, 67 AXIS_POV_3 = 0x800, 68 AXIS_ALL = 0xFFF, 69 DEADZONE_MAX = 100, 70 DEFAULT_AXES = AXIS_X|AXIS_Y|AXIS_Z|AXIS_RX|AXIS_RY|AXIS_RZ|AXIS_POV_0|AXIS_POV_1|AXIS_POV_2|AXIS_POV_3, 71 DEFAULT_DEADZONE = 50 72 }; 73 74 enum ScanMode 75 { 76 SCAN_MODE_ALL, 77 SCAN_MODE_JOY 78 }; 79 80 enum ScanResult 81 { 82 SCAN_INVALID_KEY = -1, 83 SCAN_NO_KEY, 84 SCAN_GOOD_KEY 85 }; 86 87 class Key; 88 89 void Acquire(); 90 void Unacquire(); 91 void Calibrate(); 92 void Poll(); 93 void Build(const Key*,uint); 94 bool MapKey(Key&,wcstring,const System::Guid* = NULL,uint=0) const; 95 const HeapString GetKeyName(const Key&) const; 96 97 void BeginScanMode(HWND) const; 98 ScanResult ScanKey(Key&,ScanMode=SCAN_MODE_ALL); 99 void EndScanMode() const; 100 101 class Key 102 { 103 friend class DirectInput; 104 friend class Keyboard; 105 friend class Joystick; 106 107 public: 108 109 bool MapVirtualKey(uint,uint,uint,uint); 110 bool MapVirtualKey(GenericString); 111 bool GetVirtualKey(ACCEL&) const; 112 bool IsVirtualKey() const; 113 bool GetToggle(bool&) const; 114 115 private: 116 117 union 118 { 119 const BYTE* data; 120 DWORD vKey; 121 }; 122 123 uint (*code)(const void* const); 124 125 public: 126 Key()127 Key() 128 : data(NULL), code(KeyNone) {} 129 operator ==(const Key & key) const130 bool operator == (const Key& key) const 131 { 132 return data == key.data && code == key.code; 133 } 134 Unmap()135 void Unmap() 136 { 137 data = NULL; 138 code = KeyNone; 139 } 140 Assigned() const141 bool Assigned() const 142 { 143 return data; 144 } 145 GetState() const146 uint GetState() const 147 { 148 return code( data ); 149 } 150 151 template<typename Value> GetState(Value & value,uint mask) const152 void GetState(Value& value,uint mask) const 153 { 154 value |= code( data ) & mask; 155 } 156 }; 157 158 private: 159 160 class Base 161 { 162 static IDirectInput8& Create(); 163 164 public: 165 166 explicit Base(HWND); 167 ~Base(); 168 169 IDirectInput8& com; 170 HWND const hWnd; 171 }; 172 173 class Device 174 { 175 public: 176 177 void Enable(bool); 178 179 protected: 180 181 explicit Device(IDirectInputDevice8&); 182 ~Device(); 183 184 bool Acquire(void*,uint); 185 void Unacquire(); 186 187 IDirectInputDevice8& com; 188 bool enabled; 189 }; 190 191 class Keyboard : public Device 192 { 193 public: 194 195 explicit Keyboard(Base&); 196 197 enum 198 { 199 MAX_KEYS = NUM_KEYBOARD_KEYS 200 }; 201 202 void Acquire(); 203 void Unacquire(); 204 205 NST_FORCE_INLINE void Poll(); 206 207 bool Map(Key&,wcstring) const; 208 bool Map(Key&,uint) const; 209 210 void BeginScanMode(HWND) const; 211 bool Scan(uchar (&)[MAX_KEYS]) const; 212 ScanResult Scan(Key&) const; 213 void EndScanMode() const; 214 215 bool Assigned(const Key&) const; 216 wcstring GetName(const Key&) const; 217 218 private: 219 220 enum 221 { 222 COOPERATIVE_FLAGS = DISCL_FOREGROUND|DISCL_NONEXCLUSIVE|DISCL_NOWINKEY, 223 SCAN_COOPERATIVE_FLAGS = DISCL_BACKGROUND|DISCL_NONEXCLUSIVE 224 }; 225 226 static BOOL CALLBACK EnumObjects(LPCDIDEVICEOBJECTINSTANCE,LPVOID); 227 static IDirectInputDevice8& Create(IDirectInput8&); 228 229 void SetCooperativeLevel(HWND,DWORD) const; 230 void Clear(); 231 232 NST_NO_INLINE void OnError(HRESULT); 233 234 typedef Object::Heap<BYTE,MAX_KEYS> Buffer; 235 236 Buffer buffer; 237 HWND const hWnd; 238 239 static HeapString keyNames[MAX_KEYS]; 240 241 public: 242 GetBuffer() const243 const uchar* GetBuffer() const 244 { 245 return buffer; 246 } 247 }; 248 249 class Joystick : public Device 250 { 251 public: 252 253 Joystick(Base&,const DIDEVICEINSTANCE&); 254 255 enum 256 { 257 POV_CENTER = 0xFFFF, 258 POV_UPRIGHT = 45 * DI_DEGREES, 259 POV_DOWNRIGHT = 135 * DI_DEGREES, 260 POV_DOWNLEFT = 225 * DI_DEGREES, 261 POV_UPLEFT = 315 * DI_DEGREES 262 }; 263 264 enum Exception 265 { 266 ERR_API 267 }; 268 269 void Acquire(); 270 void Unacquire(); 271 void Calibrate(); 272 273 NST_FORCE_INLINE void Poll(); 274 275 bool Map(Key&,wcstring) const; 276 277 void BeginScanMode() const; 278 bool Scan(Key&); 279 void EndScanMode() const; 280 281 bool Assigned(const Key&) const; 282 bool SetAxisDeadZone(uint); 283 wcstring GetName(const Key&) const; 284 285 private: 286 287 static IDirectInputDevice8& Create(Base&,const GUID&); 288 289 void Clear(); 290 291 NST_NO_INLINE void OnError(HRESULT); 292 293 class Caps 294 { 295 struct Context 296 { 297 Context(Caps&,IDirectInputDevice8&); 298 299 Caps& caps; 300 IDirectInputDevice8& com; 301 uint numButtons; 302 }; 303 304 enum 305 { 306 AXIS_MIN_RANGE = -1000, 307 AXIS_MAX_RANGE = +1000 308 }; 309 310 static BOOL CALLBACK EnumObjectsProc(LPCDIDEVICEOBJECTINSTANCE,LPVOID); 311 312 public: 313 314 Caps(IDirectInputDevice8&,const DIDEVICEINSTANCE&); 315 316 enum 317 { 318 NUM_POVS = 4, 319 NUM_BUTTONS = 32 320 }; 321 322 uint axes; 323 const System::Guid guid; 324 const HeapString name; 325 }; 326 327 class Calibrator 328 { 329 long lX; 330 long lY; 331 long lZ; 332 long lRx; 333 long lRy; 334 long lRz; 335 336 public: 337 338 Calibrator(); 339 340 inline void Reset(DIJOYSTATE&,bool); 341 inline void Fix(DIJOYSTATE&) const; 342 }; 343 344 const Caps caps; 345 Object::Pod<DIJOYSTATE> state; 346 Calibrator calibrator; 347 bool calibrated; 348 bool scanEnabled; 349 uint deadZone; 350 uint axes; 351 352 enum 353 { 354 TABLE_KEYS = 32 355 }; 356 357 struct Lookup; 358 static const Lookup table[TABLE_KEYS]; 359 360 public: 361 GetGuid() const362 const System::Guid& GetGuid() const 363 { 364 return caps.guid; 365 } 366 GetName() const367 const HeapString& GetName() const 368 { 369 return caps.name; 370 } 371 GetAxisDeadZone() const372 uint GetAxisDeadZone() const 373 { 374 return deadZone; 375 } 376 GetAvailableAxes() const377 uint GetAvailableAxes() const 378 { 379 return caps.axes; 380 } 381 GetScannerAxes() const382 uint GetScannerAxes() const 383 { 384 return axes; 385 } 386 ScanEnable(bool enable)387 void ScanEnable(bool enable) 388 { 389 scanEnabled = enable; 390 } 391 ScanEnabled() const392 bool ScanEnabled() const 393 { 394 return scanEnabled; 395 } 396 SetScannerAxes(uint flags)397 void SetScannerAxes(uint flags) 398 { 399 NST_ASSERT( flags <= AXIS_ALL ); 400 axes = flags; 401 } 402 SetScannerAxes(uint flags,bool on)403 void SetScannerAxes(uint flags,bool on) 404 { 405 NST_ASSERT( flags <= AXIS_ALL ); 406 axes = (on ? axes | flags : axes & ~flags); 407 } 408 }; 409 410 typedef Collection::Vector<Joystick> Joysticks; 411 412 static BOOL CALLBACK EnumJoysticks(LPCDIDEVICEINSTANCE,LPVOID); 413 414 static uint KeyDown (const void* const); 415 static uint KeyNegDir (const void* const); 416 static uint KeyPosDir (const void* const); 417 static uint KeyPovUp (const void* const); 418 static uint KeyPovRight (const void* const); 419 static uint KeyPovDown (const void* const); 420 static uint KeyPovLeft (const void* const); 421 static uint KeyNone (const void* const); 422 423 Base base; 424 Keyboard keyboard; 425 Joysticks joysticks; 426 427 public: 428 MapKeyboard(Key & key,uint code) const429 bool MapKeyboard(Key& key,uint code) const 430 { 431 key.Unmap(); 432 return keyboard.Map( key, code ); 433 } 434 NumJoysticks() const435 uint NumJoysticks() const 436 { 437 return joysticks.Size(); 438 } 439 JoystickScanEnabled(uint index) const440 bool JoystickScanEnabled(uint index) const 441 { 442 NST_ASSERT( index < joysticks.Size() ); 443 return joysticks[index].ScanEnabled(); 444 } 445 ScanEnableJoystick(uint index,bool enable)446 void ScanEnableJoystick(uint index,bool enable) 447 { 448 NST_ASSERT( index < joysticks.Size() ); 449 joysticks[index].ScanEnable( enable ); 450 } 451 GetJoystickGuid(uint index) const452 const System::Guid& GetJoystickGuid(uint index) const 453 { 454 NST_ASSERT( index < joysticks.Size() ); 455 return joysticks[index].GetGuid(); 456 } 457 GetJoystickName(uint index) const458 const HeapString& GetJoystickName(uint index) const 459 { 460 NST_ASSERT( index < joysticks.Size() ); 461 return joysticks[index].GetName(); 462 } 463 Calibrate(uint index)464 void Calibrate(uint index) 465 { 466 NST_ASSERT( index < joysticks.Size() ); 467 joysticks[index].Calibrate(); 468 } 469 SetAxisDeadZone(uint index,uint deadZone)470 bool SetAxisDeadZone(uint index,uint deadZone) 471 { 472 NST_ASSERT( index < joysticks.Size() ); 473 return joysticks[index].SetAxisDeadZone( deadZone ); 474 } 475 GetAxisDeadZone(uint index) const476 uint GetAxisDeadZone(uint index) const 477 { 478 NST_ASSERT( index < joysticks.Size() ); 479 return joysticks[index].GetAxisDeadZone(); 480 } 481 GetAvailableAxes(uint index) const482 uint GetAvailableAxes(uint index) const 483 { 484 NST_ASSERT( index < joysticks.Size() ); 485 return joysticks[index].GetAvailableAxes(); 486 } 487 SetScannerAxes(uint index,uint axes)488 void SetScannerAxes(uint index,uint axes) 489 { 490 NST_ASSERT( index < joysticks.Size() ); 491 return joysticks[index].SetScannerAxes( axes ); 492 } 493 SetScannerAxes(uint index,uint axes,bool state)494 void SetScannerAxes(uint index,uint axes,bool state) 495 { 496 NST_ASSERT( index < joysticks.Size() ); 497 return joysticks[index].SetScannerAxes( axes, state ); 498 } 499 GetScannerAxes(uint index) const500 uint GetScannerAxes(uint index) const 501 { 502 NST_ASSERT( index < joysticks.Size() ); 503 return joysticks[index].GetScannerAxes(); 504 } 505 GetKeyboardBuffer() const506 const uchar* GetKeyboardBuffer() const 507 { 508 return keyboard.GetBuffer(); 509 } 510 AnyPressed()511 bool AnyPressed() 512 { 513 Key key; 514 return ScanKey( key ) != SCAN_NO_KEY; 515 } 516 }; 517 } 518 } 519 520 #endif 521