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 #include <new> 26 #include "language/resource.h" 27 #include "NstApplicationException.hpp" 28 #include "NstApplicationInstance.hpp" 29 #include "NstSystemKeyboard.hpp" 30 #include "NstDirectInput.hpp" 31 #include "NstIoScreen.hpp" 32 #include "NstIoLog.hpp" 33 34 #if NST_MSVC 35 #pragma comment(lib,"dinput8") 36 #pragma comment(lib,"dxguid") 37 #endif 38 39 namespace Nestopia 40 { 41 namespace DirectX 42 { 43 HeapString DirectInput::Keyboard::keyNames[MAX_KEYS]; 44 45 struct DirectInput::Joystick::Lookup 46 { 47 uint (*code)(const void* const); 48 ushort offset; 49 ushort axis; 50 wcstring name; 51 }; 52 53 const DirectInput::Joystick::Lookup DirectInput::Joystick::table[TABLE_KEYS] = 54 { 55 { KeyPosDir, DIJOFS_Y, AXIS_Y, L"+y" }, 56 { KeyPosDir, DIJOFS_X, AXIS_X, L"+x" }, 57 { KeyNegDir, DIJOFS_Y, AXIS_Y, L"-y" }, 58 { KeyNegDir, DIJOFS_X, AXIS_X, L"-x" }, 59 { KeyPosDir, DIJOFS_Z, AXIS_Z, L"+z" }, 60 { KeyNegDir, DIJOFS_Z, AXIS_Z, L"-z" }, 61 { KeyPosDir, DIJOFS_RY, AXIS_RY, L"+ry" }, 62 { KeyPosDir, DIJOFS_RX, AXIS_RX, L"+rx" }, 63 { KeyPosDir, DIJOFS_RY, AXIS_RY, L"-ry" }, 64 { KeyNegDir, DIJOFS_RX, AXIS_RX, L"-rx" }, 65 { KeyPosDir, DIJOFS_RZ, AXIS_RZ, L"+rz" }, 66 { KeyNegDir, DIJOFS_RZ, AXIS_RZ, L"-rz" }, 67 { KeyNegDir, DIJOFS_SLIDER(0), AXIS_SLIDER_0, L"-s0" }, 68 { KeyPosDir, DIJOFS_SLIDER(0), AXIS_SLIDER_0, L"+s0" }, 69 { KeyNegDir, DIJOFS_SLIDER(1), AXIS_SLIDER_1, L"-s1" }, 70 { KeyPosDir, DIJOFS_SLIDER(1), AXIS_SLIDER_1, L"+s1" }, 71 { KeyPovUp, DIJOFS_POV(0), AXIS_POV_0, L"-p0y" }, 72 { KeyPovRight, DIJOFS_POV(0), AXIS_POV_0, L"+p0x" }, 73 { KeyPovDown, DIJOFS_POV(0), AXIS_POV_0, L"+p0y" }, 74 { KeyPovLeft, DIJOFS_POV(0), AXIS_POV_0, L"-p0x" }, 75 { KeyPovUp, DIJOFS_POV(1), AXIS_POV_1, L"-p1y" }, 76 { KeyPovRight, DIJOFS_POV(1), AXIS_POV_1, L"+p1x" }, 77 { KeyPovDown, DIJOFS_POV(1), AXIS_POV_1, L"+p1y" }, 78 { KeyPovLeft, DIJOFS_POV(1), AXIS_POV_1, L"-p1x" }, 79 { KeyPovUp, DIJOFS_POV(2), AXIS_POV_2, L"-p2y" }, 80 { KeyPovRight, DIJOFS_POV(2), AXIS_POV_2, L"+p2x" }, 81 { KeyPovDown, DIJOFS_POV(2), AXIS_POV_2, L"+p2y" }, 82 { KeyPovLeft, DIJOFS_POV(2), AXIS_POV_2, L"-p2x" }, 83 { KeyPovUp, DIJOFS_POV(3), AXIS_POV_3, L"-p3y" }, 84 { KeyPovRight, DIJOFS_POV(3), AXIS_POV_3, L"+p3x" }, 85 { KeyPovDown, DIJOFS_POV(3), AXIS_POV_3, L"+p3y" }, 86 { KeyPovLeft, DIJOFS_POV(3), AXIS_POV_3, L"-p3x" } 87 }; 88 89 #ifdef NST_MSVC_OPTIMIZE 90 #pragma optimize("t", on) 91 #endif 92 Fix(DIJOYSTATE & state) const93 inline void DirectInput::Joystick::Calibrator::Fix(DIJOYSTATE& state) const 94 { 95 state.lX -= lX; 96 state.lY -= lY; 97 state.lZ -= lZ; 98 state.lRx -= lRx; 99 state.lRy -= lRy; 100 state.lRz -= lRz; 101 } 102 Poll()103 NST_FORCE_INLINE void DirectInput::Keyboard::Poll() 104 { 105 if (enabled) 106 { 107 HRESULT hResult; 108 109 if (FAILED(hResult=com.Poll()) || FAILED(hResult=com.GetDeviceState( Buffer::SIZE, buffer ))) 110 OnError( hResult ); 111 } 112 } 113 Poll()114 NST_FORCE_INLINE void DirectInput::Joystick::Poll() 115 { 116 if (enabled) 117 { 118 HRESULT hResult; 119 120 if (SUCCEEDED(hResult=com.Poll()) && SUCCEEDED(hResult=com.GetDeviceState( sizeof(state), &state ))) 121 calibrator.Fix( state ); 122 else 123 OnError( hResult ); 124 } 125 } 126 Poll()127 void DirectInput::Poll() 128 { 129 keyboard.Poll(); 130 131 for (Joysticks::Iterator it(joysticks.Begin()), end(joysticks.End()); it != end; ++it) 132 it->Poll(); 133 } 134 135 #ifdef NST_MSVC_OPTIMIZE 136 #pragma optimize("", on) 137 #endif 138 Base(HWND const h)139 DirectInput::Base::Base(HWND const h) 140 : com(Create()), hWnd(h) {} 141 ~Base()142 DirectInput::Base::~Base() 143 { 144 com.Release(); 145 } 146 Create()147 IDirectInput8& DirectInput::Base::Create() 148 { 149 Io::Log() << "DirectInput: initializing..\r\n"; 150 151 IDirectInput8* com; 152 153 if (FAILED(::DirectInput8Create( ::GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, reinterpret_cast<void**>(&com), NULL ))) 154 throw Application::Exception( IDS_ERR_FAILED, L"DirectInput8Create()" ); 155 156 return *com; 157 } 158 DirectInput(HWND const hWnd)159 DirectInput::DirectInput(HWND const hWnd) 160 : base(hWnd), keyboard(base) 161 { 162 if (SUCCEEDED(base.com.EnumDevices( DI8DEVCLASS_GAMECTRL, EnumJoysticks, this, DIEDFL_ATTACHEDONLY ))) 163 Io::Log() << "DirectInput: found " << joysticks.Size() << " attached joystick(s)\r\n"; 164 else 165 Io::Log() << "DirectInput: IDirectInput8::EnumDevices() failed! No joysticks can be used!\r\n"; 166 } 167 ~DirectInput()168 DirectInput::~DirectInput() 169 { 170 for (uint i=joysticks.Size(); i; ) 171 joysticks[--i].Joystick::~Joystick(); 172 } 173 EnumJoysticks(LPCDIDEVICEINSTANCE const instance,LPVOID const context)174 BOOL CALLBACK DirectInput::EnumJoysticks(LPCDIDEVICEINSTANCE const instance,LPVOID const context) 175 { 176 if (instance) 177 { 178 DirectInput& directInput = *static_cast<DirectInput*>(context); 179 180 if (directInput.joysticks.Size() == MAX_JOYSTICKS) 181 { 182 Io::Log() << "DirectInput: warning, device count limit reached, stopping enumeration..\r\n"; 183 return DIENUM_STOP; 184 } 185 186 Io::Log() << "DirectInput: enumerating device - name: " 187 << (*instance->tszProductName ? instance->tszProductName : L"unknown") 188 << ", GUID: " 189 << System::Guid( instance->guidInstance ).GetString() 190 << "\r\n"; 191 192 directInput.joysticks.Grow(); 193 194 try 195 { 196 new (&directInput.joysticks.Back()) Joystick( directInput.base, *instance ); 197 } 198 catch (Joystick::Exception) 199 { 200 directInput.joysticks.Shrink(); 201 Io::Log() << "DirectInput: warning, bogus device, continuing enumeration..\r\n"; 202 } 203 } 204 205 return DIENUM_CONTINUE; 206 } 207 Acquire()208 void DirectInput::Acquire() 209 { 210 keyboard.Acquire(); 211 212 for (Joysticks::Iterator it(joysticks.Begin()), end(joysticks.End()); it != end; ++it) 213 it->Acquire(); 214 } 215 Unacquire()216 void DirectInput::Unacquire() 217 { 218 keyboard.Unacquire(); 219 220 for (Joysticks::Iterator it(joysticks.Begin()), end(joysticks.End()); it != end; ++it) 221 it->Unacquire(); 222 } 223 Calibrate()224 void DirectInput::Calibrate() 225 { 226 for (Joysticks::Iterator it(joysticks.Begin()), end(joysticks.End()); it != end; ++it) 227 it->Calibrate(); 228 } 229 BeginScanMode(HWND hWnd) const230 void DirectInput::BeginScanMode(HWND hWnd) const 231 { 232 keyboard.BeginScanMode( hWnd ); 233 234 for (Joysticks::ConstIterator it(joysticks.Begin()), end(joysticks.End()); it != end; ++it) 235 it->BeginScanMode(); 236 } 237 EndScanMode() const238 void DirectInput::EndScanMode() const 239 { 240 keyboard.EndScanMode(); 241 242 for (Joysticks::ConstIterator it(joysticks.Begin()), end(joysticks.End()); it != end; ++it) 243 it->EndScanMode(); 244 } 245 Build(const Key * const keys,const uint count)246 void DirectInput::Build(const Key* const keys,const uint count) 247 { 248 keyboard.Enable( false ); 249 250 for (const Key *it=keys, *const end=keys+count; it != end; ++it) 251 { 252 if (keyboard.Assigned( *it )) 253 { 254 keyboard.Enable( true ); 255 break; 256 } 257 } 258 259 for (Joysticks::Iterator it(joysticks.Begin()), end(joysticks.End()); it != end; ++it) 260 { 261 it->Enable( false ); 262 263 for (const Key *jt=keys, *const jend=keys+count; jt != jend; ++jt) 264 { 265 if (it->Assigned( *jt )) 266 { 267 it->Enable( true ); 268 break; 269 } 270 } 271 } 272 } 273 ScanKey(Key & key,const ScanMode scanMode)274 DirectInput::ScanResult DirectInput::ScanKey(Key& key,const ScanMode scanMode) 275 { 276 const ScanResult scan = (scanMode == SCAN_MODE_ALL ? keyboard.Scan( key ) : SCAN_NO_KEY); 277 278 if (scan != SCAN_GOOD_KEY) 279 { 280 if (scan == SCAN_NO_KEY) 281 { 282 for (Joysticks::Iterator it(joysticks.Begin()), end(joysticks.End()); it != end; ++it) 283 { 284 if (it->Scan( key )) 285 return SCAN_GOOD_KEY; 286 } 287 } 288 289 key.Unmap(); 290 } 291 292 return scan; 293 } 294 MapKey(Key & key,wcstring const name,const System::Guid * const guids,const uint numGuids) const295 bool DirectInput::MapKey(Key& key,wcstring const name,const System::Guid* const guids,const uint numGuids) const 296 { 297 key.Unmap(); 298 299 if 300 ( 301 name && *name && 302 (name[0] != '.' || name[1] != '.' || name[2] != '.' || name[3] != '\0') 303 ) 304 { 305 if 306 ( 307 (name[0] == '(') && 308 (name[1] == 'j' || name[1] == 'J') && 309 (name[2] == 'o' || name[2] == 'O') && 310 (name[3] == 'y' || name[3] == 'Y') && 311 (name[4] == ' ') && 312 (name[5] >= '0' && name[5] <= '9') && 313 ( 314 (name[6] == ')' && name[7] == ' ') || 315 (name[6] >= '0' && name[6] <= '9' && name[7] == ')' && name[8] == ' ') 316 ) 317 ) 318 { 319 uint index = name[5] - '0'; 320 321 if (name[6] != ')') 322 index = (index * 10) + (name[6] - '0'); 323 324 if (index < NST_MIN(MAX_JOYSTICKS,numGuids)) 325 { 326 const System::Guid& guid = guids[index]; 327 328 for (Joysticks::ConstIterator it(joysticks.Begin()), end(joysticks.End()); it != end; ++it) 329 { 330 if (it->GetGuid() == guid) 331 return it->Map( key, name + (name[7] == ' ' ? 8 : 9) ); 332 } 333 } 334 } 335 else 336 { 337 return keyboard.Map( key, name ); 338 } 339 } 340 341 return false; 342 } 343 GetKeyName(const Key & key) const344 const HeapString DirectInput::GetKeyName(const Key& key) const 345 { 346 if (key.Assigned()) 347 { 348 if (keyboard.Assigned( key )) 349 { 350 return keyboard.GetName( key ); 351 } 352 else 353 { 354 for (uint i=0, n=joysticks.Size(); i < n; ++i) 355 { 356 if (joysticks[i].Assigned( key )) 357 return HeapString("(joy ") << i << ") " << joysticks[i].GetName( key ); 358 } 359 360 HeapString name; 361 362 if (key.vKey & FCONTROL) 363 name << System::Keyboard::GetName( VK_CONTROL ) << '+'; 364 365 if (key.vKey & FALT) 366 name << System::Keyboard::GetName( VK_MENU ) << '+'; 367 368 if (key.vKey & FSHIFT) 369 name << System::Keyboard::GetName( VK_SHIFT ) << '+'; 370 371 name << System::Keyboard::GetName( key.vKey >> 8 ); 372 373 return name; 374 } 375 } 376 377 return L"..."; 378 } 379 Device(IDirectInputDevice8 & c)380 DirectInput::Device::Device(IDirectInputDevice8& c) 381 : com(c), enabled(false) {} 382 ~Device()383 DirectInput::Device::~Device() 384 { 385 com.Unacquire(); 386 com.Release(); 387 } 388 Enable(bool enable)389 void DirectInput::Device::Enable(bool enable) 390 { 391 enabled = enable; 392 } 393 Acquire(void * const data,const uint size)394 bool DirectInput::Device::Acquire(void* const data,const uint size) 395 { 396 return enabled && SUCCEEDED(com.Acquire()) && SUCCEEDED(com.Poll()) && SUCCEEDED(com.GetDeviceState( size, data )); 397 } 398 Unacquire()399 void DirectInput::Device::Unacquire() 400 { 401 com.Unacquire(); 402 } 403 Keyboard(Base & base)404 DirectInput::Keyboard::Keyboard(Base& base) 405 : Device(Create(base.com)), hWnd(base.hWnd) 406 { 407 for (uint i=0; i < MAX_KEYS; ++i) 408 keyNames[i] << i; 409 410 com.EnumObjects( EnumObjects, NULL, DIDFT_BUTTON ); 411 SetCooperativeLevel( base.hWnd, COOPERATIVE_FLAGS ); 412 Clear(); 413 } 414 Create(IDirectInput8 & base)415 IDirectInputDevice8& DirectInput::Keyboard::Create(IDirectInput8& base) 416 { 417 IDirectInputDevice8* com; 418 419 if (FAILED(base.CreateDevice( GUID_SysKeyboard, &com, NULL ))) 420 throw Application::Exception( IDS_ERR_FAILED, L"IDirectInput8::CreateDevice()" ); 421 422 if (FAILED(com->SetDataFormat( &c_dfDIKeyboard ))) 423 { 424 com->Release(); 425 throw Application::Exception( IDS_ERR_FAILED, L"IDirectInputDevice8::SetDataFormat()" ); 426 } 427 428 return *com; 429 } 430 EnumObjects(LPCDIDEVICEOBJECTINSTANCE const obj,LPVOID)431 BOOL CALLBACK DirectInput::Keyboard::EnumObjects(LPCDIDEVICEOBJECTINSTANCE const obj,LPVOID) 432 { 433 NST_VERIFY( obj->dwOfs < MAX_KEYS && *obj->tszName ); 434 435 if (obj->dwOfs < MAX_KEYS && *obj->tszName) 436 { 437 HeapString& string = keyNames[obj->dwOfs]; 438 string = obj->tszName; 439 440 ::CharUpperBuff( string.Ptr(), 1 ); 441 442 if (string.Length() > 1) 443 ::CharLowerBuff( string.Ptr() + 1, string.Length() - 1 ); 444 } 445 446 return DIENUM_CONTINUE; 447 } 448 SetCooperativeLevel(HWND const hWnd,const DWORD flags) const449 void DirectInput::Keyboard::SetCooperativeLevel(HWND const hWnd,const DWORD flags) const 450 { 451 if (FAILED(com.SetCooperativeLevel( hWnd, flags ))) 452 throw Application::Exception( IDS_ERR_FAILED, L"IDirectInputDevice8::SetCooperativeLevel()" ); 453 } 454 Map(Key & key,wcstring name) const455 bool DirectInput::Keyboard::Map(Key& key,wcstring name) const 456 { 457 for (uint i=0; i < MAX_KEYS; ++i) 458 { 459 if (keyNames[i] == name) 460 return Map( key, i ); 461 } 462 463 return false; 464 } 465 Map(Key & key,const uint code) const466 bool DirectInput::Keyboard::Map(Key& key,const uint code) const 467 { 468 if (code && code <= 0xFF && code != DIK_LWIN) 469 { 470 key.data = buffer + code; 471 key.code = KeyDown; 472 return true; 473 } 474 475 return false; 476 } 477 BeginScanMode(HWND hWndScan) const478 void DirectInput::Keyboard::BeginScanMode(HWND hWndScan) const 479 { 480 com.Unacquire(); 481 SetCooperativeLevel( hWndScan, SCAN_COOPERATIVE_FLAGS ); 482 com.Acquire(); 483 } 484 EndScanMode() const485 void DirectInput::Keyboard::EndScanMode() const 486 { 487 com.Unacquire(); 488 SetCooperativeLevel( hWnd, COOPERATIVE_FLAGS ); 489 } 490 Scan(uchar (& data)[MAX_KEYS]) const491 bool DirectInput::Keyboard::Scan(uchar (&data)[MAX_KEYS]) const 492 { 493 if (SUCCEEDED(com.Poll()) && SUCCEEDED(com.GetDeviceState( MAX_KEYS, data ))) 494 return true; 495 496 std::memset( data, 0, MAX_KEYS ); 497 498 return false; 499 } 500 Scan(Key & key) const501 DirectInput::ScanResult DirectInput::Keyboard::Scan(Key& key) const 502 { 503 uchar data[MAX_KEYS]; 504 505 if (Scan( data )) 506 { 507 for (uint i=0; i < MAX_KEYS; ++i) 508 { 509 if (data[i] & 0x80U) 510 { 511 switch (i) 512 { 513 case DIK_CAPITAL: 514 case DIK_NUMLOCK: 515 case DIK_SCROLL: 516 case DIK_KANA: 517 case DIK_KANJI: 518 continue; 519 520 default: 521 return Map( key, i ) ? SCAN_GOOD_KEY : SCAN_INVALID_KEY; 522 } 523 } 524 } 525 } 526 527 return SCAN_NO_KEY; 528 } 529 OnError(const HRESULT hResult)530 void DirectInput::Keyboard::OnError(const HRESULT hResult) 531 { 532 NST_ASSERT( FAILED(hResult) ); 533 534 switch (hResult) 535 { 536 case DIERR_INPUTLOST: 537 case DIERR_NOTACQUIRED: 538 539 if (::GetActiveWindow() == hWnd) 540 { 541 Acquire(); 542 break; 543 } 544 545 default: 546 547 Clear(); 548 break; 549 } 550 } 551 Assigned(const Key & key) const552 bool DirectInput::Keyboard::Assigned(const Key& key) const 553 { 554 return key.data >= buffer && key.data < (buffer + Buffer::SIZE); 555 } 556 GetName(const Key & key) const557 wcstring DirectInput::Keyboard::GetName(const Key& key) const 558 { 559 NST_VERIFY( Assigned(key) ); 560 return keyNames[key.data - buffer].Ptr(); 561 } 562 Clear()563 void DirectInput::Keyboard::Clear() 564 { 565 std::memset( buffer, 0, Buffer::SIZE ); 566 } 567 Acquire()568 void DirectInput::Keyboard::Acquire() 569 { 570 if (!Device::Acquire( buffer, Buffer::SIZE )) 571 Clear(); 572 } 573 Unacquire()574 void DirectInput::Keyboard::Unacquire() 575 { 576 Device::Unacquire(); 577 Clear(); 578 } 579 Joystick(Base & base,const DIDEVICEINSTANCE & instance)580 DirectInput::Joystick::Joystick(Base& base,const DIDEVICEINSTANCE& instance) 581 : 582 Device (Create(base,instance.guidInstance)), 583 caps (com,instance), 584 calibrated (false), 585 scanEnabled (true), 586 deadZone (UINT_MAX), 587 axes (DEFAULT_AXES) 588 { 589 SetAxisDeadZone( DEFAULT_DEADZONE ); 590 591 if (SUCCEEDED(com.Acquire())) 592 { 593 if (SUCCEEDED(com.Poll())) 594 com.GetDeviceState( sizeof(state), &state ); 595 596 com.Unacquire(); 597 } 598 } 599 Calibrator()600 DirectInput::Joystick::Calibrator::Calibrator() 601 : 602 lX (0), 603 lY (0), 604 lZ (0), 605 lRx (0), 606 lRy (0), 607 lRz (0) 608 {} 609 Context(Caps & c,IDirectInputDevice8 & d)610 DirectInput::Joystick::Caps::Context::Context(Caps& c,IDirectInputDevice8& d) 611 : caps(c), com(d), numButtons(0) {} 612 Caps(IDirectInputDevice8 & com,const DIDEVICEINSTANCE & instance)613 DirectInput::Joystick::Caps::Caps(IDirectInputDevice8& com,const DIDEVICEINSTANCE& instance) 614 : axes(0), guid(instance.guidInstance), name(*instance.tszProductName ? instance.tszProductName : L"unknown") 615 { 616 Context context( *this, com ); 617 618 if (FAILED(com.EnumObjects( EnumObjectsProc, &context, DIDFT_ALL )) || !(context.numButtons|axes)) 619 throw ERR_API; 620 } 621 Create(Base & base,const GUID & guid)622 IDirectInputDevice8& DirectInput::Joystick::Create(Base& base,const GUID& guid) 623 { 624 IDirectInputDevice8* com; 625 626 if (FAILED(base.com.CreateDevice( guid, &com, NULL ))) 627 throw ERR_API; 628 629 if 630 ( 631 FAILED(com->SetDataFormat( &c_dfDIJoystick )) || 632 FAILED(com->SetCooperativeLevel( base.hWnd, DISCL_BACKGROUND|DISCL_NONEXCLUSIVE )) 633 ) 634 { 635 com->Release(); 636 throw ERR_API; 637 } 638 639 return *com; 640 } 641 EnumObjectsProc(LPCDIDEVICEOBJECTINSTANCE const info,LPVOID const ref)642 BOOL CALLBACK DirectInput::Joystick::Caps::EnumObjectsProc(LPCDIDEVICEOBJECTINSTANCE const info,LPVOID const ref) 643 { 644 Context& context = *static_cast<Context*>(ref); 645 646 if (info->guidType == GUID_Button) 647 { 648 ++context.numButtons; 649 } 650 else 651 { 652 uint flag; 653 654 if ( info->guidType == GUID_XAxis ) flag = AXIS_X; 655 else if ( info->guidType == GUID_YAxis ) flag = AXIS_Y; 656 else if ( info->guidType == GUID_ZAxis ) flag = AXIS_Z; 657 else if ( info->guidType == GUID_RxAxis ) flag = AXIS_RX; 658 else if ( info->guidType == GUID_RyAxis ) flag = AXIS_RY; 659 else if ( info->guidType == GUID_RzAxis ) flag = AXIS_RZ; 660 else if ( info->guidType == GUID_POV ) 661 { 662 if (context.caps.axes & AXIS_POV_3) 663 { 664 return DIENUM_CONTINUE; 665 } 666 else if (context.caps.axes & AXIS_POV_2) 667 { 668 flag = AXIS_POV_3; 669 } 670 else if (context.caps.axes & AXIS_POV_1) 671 { 672 flag = AXIS_POV_2; 673 } 674 else if (context.caps.axes & AXIS_POV_0) 675 { 676 flag = AXIS_POV_1; 677 } 678 else 679 { 680 flag = AXIS_POV_0; 681 } 682 } 683 else if ( info->guidType == GUID_Slider ) 684 { 685 if (context.caps.axes & AXIS_SLIDER_1) 686 { 687 return DIENUM_CONTINUE; 688 } 689 else if (context.caps.axes & AXIS_SLIDER_0) 690 { 691 flag = AXIS_SLIDER_1; 692 } 693 else 694 { 695 flag = AXIS_SLIDER_0; 696 } 697 } 698 else 699 { 700 return DIENUM_CONTINUE; 701 } 702 703 if (info->dwType & DIDFT_AXIS) 704 { 705 Object::Pod<DIPROPRANGE> diprg; 706 707 diprg.diph.dwSize = sizeof(diprg); 708 diprg.diph.dwHeaderSize = sizeof(diprg.diph); 709 diprg.diph.dwHow = DIPH_BYID; 710 diprg.diph.dwObj = info->dwType; 711 diprg.lMin = AXIS_MIN_RANGE; 712 diprg.lMax = AXIS_MAX_RANGE; 713 714 if (FAILED(context.com.SetProperty( DIPROP_RANGE, &diprg.diph ))) 715 { 716 if (FAILED(context.com.GetProperty( DIPROP_RANGE, &diprg.diph )) || diprg.lMin >= 0 || diprg.lMax <= 0) 717 { 718 Io::Log() << "DirectInput: warning, SetProperty(DIPROP_RANGE) failed, skipping axis..\r\n"; 719 return DIENUM_CONTINUE; 720 } 721 } 722 } 723 724 context.caps.axes |= flag; 725 } 726 727 return DIENUM_CONTINUE; 728 } 729 SetAxisDeadZone(const uint value)730 bool DirectInput::Joystick::SetAxisDeadZone(const uint value) 731 { 732 NST_ASSERT( value <= DEADZONE_MAX ); 733 734 if (deadZone != value) 735 { 736 deadZone = value; 737 738 Object::Pod<DIPROPDWORD> diprd; 739 740 diprd.diph.dwSize = sizeof(diprd); 741 diprd.diph.dwHeaderSize = sizeof(diprd.diph); 742 diprd.diph.dwHow = DIPH_DEVICE; 743 diprd.dwData = value * 100; 744 745 com.SetProperty( DIPROP_DEADZONE, &diprd.diph ); 746 return true; 747 } 748 749 return false; 750 } 751 Clear()752 void DirectInput::Joystick::Clear() 753 { 754 state.Clear(); 755 state.rgdwPOV[3] = state.rgdwPOV[2] = state.rgdwPOV[1] = state.rgdwPOV[0] = DWORD(~0UL); 756 } 757 Acquire()758 void DirectInput::Joystick::Acquire() 759 { 760 if (Device::Acquire( &state, sizeof(state) )) 761 { 762 if (!calibrated) 763 { 764 calibrated = true; 765 calibrator.Reset( state, false ); 766 } 767 768 calibrator.Fix( state ); 769 } 770 else 771 { 772 Clear(); 773 } 774 } 775 Unacquire()776 void DirectInput::Joystick::Unacquire() 777 { 778 Device::Unacquire(); 779 Clear(); 780 } 781 Reset(DIJOYSTATE & state,bool full)782 inline void DirectInput::Joystick::Calibrator::Reset(DIJOYSTATE& state,bool full) 783 { 784 lX = full ? state.lX : 0; 785 lY = full ? state.lY : 0; 786 lZ = state.lZ; 787 lRx = state.lRx; 788 lRy = state.lRy; 789 lRz = state.lRz; 790 } 791 Calibrate()792 void DirectInput::Joystick::Calibrate() 793 { 794 if (SUCCEEDED(com.Acquire())) 795 { 796 Object::Pod<DIJOYSTATE> tmp; 797 798 if (SUCCEEDED(com.Poll()) && SUCCEEDED(com.GetDeviceState( sizeof(tmp), &tmp ))) 799 { 800 calibrated = true; 801 calibrator.Reset( tmp, true ); 802 } 803 804 com.Unacquire(); 805 } 806 } 807 BeginScanMode() const808 void DirectInput::Joystick::BeginScanMode() const 809 { 810 com.Acquire(); 811 } 812 EndScanMode() const813 void DirectInput::Joystick::EndScanMode() const 814 { 815 com.Unacquire(); 816 } 817 Scan(Key & key)818 bool DirectInput::Joystick::Scan(Key& key) 819 { 820 DIJOYSTATE tmp; 821 822 if (scanEnabled && SUCCEEDED(com.Poll()) && SUCCEEDED(com.GetDeviceState( sizeof(tmp), &tmp ))) 823 { 824 if (!calibrated) 825 { 826 calibrated = true; 827 calibrator.Reset( tmp, false ); 828 } 829 830 calibrator.Fix( tmp ); 831 832 for (uint i=0; i < Caps::NUM_BUTTONS; ++i) 833 { 834 if (tmp.rgbButtons[i] & 0x80U) 835 { 836 key.data = state.rgbButtons + i; 837 key.code = KeyDown; 838 return true; 839 } 840 } 841 842 for (uint i=0; i < TABLE_KEYS; ++i) 843 { 844 if (caps.axes & axes & table[i].axis) 845 { 846 key.data = reinterpret_cast<const BYTE*>(&tmp) + table[i].offset; 847 key.code = table[i].code; 848 849 if (key.GetState()) 850 { 851 key.data = reinterpret_cast<const BYTE*>(&state) + table[i].offset; 852 return true; 853 } 854 } 855 } 856 } 857 858 return false; 859 } 860 Map(Key & key,wcstring const name) const861 bool DirectInput::Joystick::Map(Key& key,wcstring const name) const 862 { 863 if (*name) 864 { 865 if (name[0] >= '0' && name[0] <= '9') 866 { 867 uint index = name[0] - '0'; 868 869 if (name[1] >= '0' && name[1] <= '9') 870 index = (index * 10) + (name[1] - '0'); 871 872 if (index < Caps::NUM_BUTTONS) 873 { 874 key.data = state.rgbButtons + index; 875 key.code = KeyDown; 876 return true; 877 } 878 } 879 else 880 { 881 const GenericString axis( name ); 882 883 for (uint i=TABLE_KEYS; i; ) 884 { 885 if (caps.axes & table[--i].axis) 886 { 887 if (axis == table[i].name) 888 { 889 key.data = reinterpret_cast<const BYTE*>(&state) + table[i].offset; 890 key.code = table[i].code; 891 return true; 892 } 893 } 894 } 895 } 896 } 897 898 return false; 899 } 900 Assigned(const Key & key) const901 bool DirectInput::Joystick::Assigned(const Key& key) const 902 { 903 return 904 ( 905 key.data >= reinterpret_cast<const BYTE*>(&state) && 906 key.data < reinterpret_cast<const BYTE*>(&state) + sizeof(state) 907 ); 908 } 909 GetName(const Key & key) const910 wcstring DirectInput::Joystick::GetName(const Key& key) const 911 { 912 NST_VERIFY( Assigned(key) ); 913 914 if (key.code == KeyDown) 915 { 916 static wchar_t button[] = L"xx"; 917 918 const uint index = key.data - state.rgbButtons; 919 button[0] = index < 10 ? '0' + index : '0' + index / 10; 920 button[1] = index < 10 ? '\0' : '0' + index % 10; 921 922 return button; 923 } 924 925 for (const Lookup* it = table; ; ++it) 926 { 927 if (key.data == reinterpret_cast<const BYTE*>(&state) + it->offset && key.code == it->code) 928 return it->name; 929 } 930 } 931 OnError(const HRESULT hResult)932 void DirectInput::Joystick::OnError(const HRESULT hResult) 933 { 934 NST_ASSERT( FAILED(hResult) ); 935 936 switch (hResult) 937 { 938 case DIERR_INPUTLOST: 939 case DIERR_NOTACQUIRED: 940 941 Acquire(); 942 break; 943 944 case DIERR_UNPLUGGED: 945 946 Enable( false ); 947 Io::Screen() << L"Error! Joystick unplugged!"; 948 949 default: 950 951 Clear(); 952 break; 953 } 954 } 955 956 #ifdef NST_MSVC_OPTIMIZE 957 #pragma optimize("t", on) 958 #endif 959 KeyDown(const void * const data)960 uint DirectInput::KeyDown(const void* const data) 961 { 962 return 0U - (*static_cast<const BYTE*>(data) >> 7); 963 } 964 KeyPosDir(const void * const data)965 uint DirectInput::KeyPosDir(const void* const data) 966 { 967 if (LONG_MIN >> (sizeof(long) * CHAR_BIT - 1) == ~0UL) 968 return (-*static_cast<const long*>(data) >> (sizeof(long) * CHAR_BIT - 1)); 969 else 970 return (*static_cast<const long*>(data) > 0) ? ~0U : 0U; 971 } 972 KeyNegDir(const void * const data)973 uint DirectInput::KeyNegDir(const void* const data) 974 { 975 if (LONG_MIN >> (sizeof(long) * CHAR_BIT - 1) == ~0UL) 976 return (*static_cast<const long*>(data) >> (sizeof(long) * CHAR_BIT - 1)); 977 else 978 return (*static_cast<const long*>(data) < 0) ? ~0U : 0U; 979 } 980 KeyPovUp(const void * const data)981 uint DirectInput::KeyPovUp(const void* const data) 982 { 983 const DWORD pov = *static_cast<const DWORD*>(data); 984 985 return 986 ( 987 (pov & Joystick::POV_CENTER) != Joystick::POV_CENTER && 988 (pov >= Joystick::POV_UPLEFT || pov <= Joystick::POV_UPRIGHT) 989 ) ? ~0U : 0U; 990 } 991 KeyPovRight(const void * const data)992 uint DirectInput::KeyPovRight(const void* const data) 993 { 994 const DWORD pov = *static_cast<const DWORD*>(data); 995 996 return 997 ( 998 (pov & Joystick::POV_CENTER) != Joystick::POV_CENTER && 999 (pov >= Joystick::POV_UPRIGHT && pov <= Joystick::POV_DOWNRIGHT) 1000 ) ? ~0U : 0U; 1001 } 1002 KeyPovDown(const void * const data)1003 uint DirectInput::KeyPovDown(const void* const data) 1004 { 1005 const DWORD pov = *static_cast<const DWORD*>(data); 1006 1007 return 1008 ( 1009 (pov & Joystick::POV_CENTER) != Joystick::POV_CENTER && 1010 (pov >= Joystick::POV_DOWNRIGHT && pov <= Joystick::POV_DOWNLEFT) 1011 ) ? ~0U : 0U; 1012 } 1013 KeyPovLeft(const void * const data)1014 uint DirectInput::KeyPovLeft(const void* const data) 1015 { 1016 const DWORD pov = *static_cast<const DWORD*>(data); 1017 1018 return 1019 ( 1020 (pov & Joystick::POV_CENTER) != Joystick::POV_CENTER && 1021 (pov >= Joystick::POV_DOWNLEFT && pov <= Joystick::POV_UPLEFT) 1022 ) ? ~0U : 0U; 1023 } 1024 KeyNone(const void * const)1025 uint DirectInput::KeyNone(const void* const) 1026 { 1027 return 0; 1028 } 1029 GetToggle(bool & prev) const1030 bool DirectInput::Key::GetToggle(bool& prev) const 1031 { 1032 if (GetState()) 1033 { 1034 if (!prev) 1035 { 1036 prev = true; 1037 return true; 1038 } 1039 } 1040 else 1041 { 1042 prev = false; 1043 } 1044 1045 return false; 1046 } 1047 1048 #ifdef NST_MSVC_OPTIMIZE 1049 #pragma optimize("", on) 1050 #endif 1051 MapVirtualKey(const uint code,const uint vk1,const uint vk2,const uint vk3)1052 bool DirectInput::Key::MapVirtualKey(const uint code,const uint vk1,const uint vk2,const uint vk3) 1053 { 1054 Unmap(); 1055 1056 if (!code || code > 0xFF) 1057 return false; 1058 1059 vKey = code << 8; 1060 1061 if (vk1 == VK_MENU || vk2 == VK_MENU || vk3 == VK_MENU) 1062 vKey |= FALT; 1063 1064 if (vk1 == VK_SHIFT || vk2 == VK_SHIFT || vk3 == VK_SHIFT) 1065 vKey |= FSHIFT; 1066 1067 if (vk1 == VK_CONTROL || vk2 == VK_CONTROL || vk3 == VK_CONTROL) 1068 vKey |= FCONTROL; 1069 1070 // forbidden keys: 1071 // 1072 // ALT+F4 1073 // ALT+F6 1074 // ALT+TAB 1075 // ALT+SPACE 1076 // ALT+ESC 1077 // CTRL+F4 1078 // CTRL+ESC 1079 // CTRL+ALT+DELETE 1080 // LWIN 1081 1082 switch (code) 1083 { 1084 case VK_F4: 1085 1086 if (vKey & FCONTROL) 1087 return false; 1088 1089 case VK_F6: 1090 case VK_TAB: 1091 case VK_SPACE: 1092 1093 if (vKey & FALT) 1094 return false; 1095 1096 break; 1097 1098 case VK_ESCAPE: 1099 1100 if (vKey & (FCONTROL|FALT)) 1101 return false; 1102 1103 break; 1104 1105 case VK_DELETE: 1106 1107 if ((vKey & (FCONTROL|FALT)) == (FCONTROL|FALT)) 1108 return false; 1109 1110 break; 1111 1112 case VK_LWIN: 1113 return false; 1114 } 1115 1116 return true; 1117 } 1118 MapVirtualKey(GenericString name)1119 bool DirectInput::Key::MapVirtualKey(GenericString name) 1120 { 1121 Unmap(); 1122 1123 if (name.Empty()) 1124 return false; 1125 1126 const GenericString vkNames[3] = 1127 { 1128 System::Keyboard::GetName( VK_CONTROL ), 1129 System::Keyboard::GetName( VK_MENU ), 1130 System::Keyboard::GetName( VK_SHIFT ) 1131 }; 1132 1133 uint vk[3] = {0,0,0}; 1134 1135 for (uint i=0; i < 3; ++i) 1136 { 1137 for (uint j=0; j < 3; ++j) 1138 { 1139 if (!vk[j] && name.Length() > vkNames[j].Length() && name(0,vkNames[j].Length()) == vkNames[j] && name[vkNames[j].Length()] == '+') 1140 { 1141 vk[j] = (j==0 ? VK_CONTROL : j==1 ? VK_MENU : VK_SHIFT); 1142 name = name( vkNames[j].Length() + 1 ); 1143 break; 1144 } 1145 } 1146 } 1147 1148 return MapVirtualKey( System::Keyboard::GetKey( name ), vk[0], vk[1], vk[2] ); 1149 } 1150 IsVirtualKey() const1151 bool DirectInput::Key::IsVirtualKey() const 1152 { 1153 return (code == KeyNone && data); 1154 } 1155 GetVirtualKey(ACCEL & accel) const1156 bool DirectInput::Key::GetVirtualKey(ACCEL& accel) const 1157 { 1158 if (code == KeyNone && data) 1159 { 1160 accel.fVirt = (vKey & 0xFF) | FVIRTKEY; 1161 accel.key = vKey >> 8; 1162 return true; 1163 } 1164 1165 accel.fVirt = 0; 1166 accel.key = 0; 1167 return false; 1168 } 1169 } 1170 } 1171