00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include "direct-input.h"
00036 #include "di-diagnostics.h"
00037
00038 #include "perf/perf.h"
00039 #include "wave-windows/wave-windows.h"
00040
00041 #include <iostream>
00042
00043
00044 namespace gamepad {
00045
00046
00047
00048
00049 static const int s_FortyFiveDegreesValue = 4500;
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066 class DirectInputDevice : public SourceDevice {
00067 public:
00068
00069 DirectInputDevice(void) throw();
00070 ~DirectInputDevice(void) throw();
00071
00072
00073
00074 virtual const char * getPublicName(void) throw() { return m_name.c_str(); }
00075 virtual const char * getUniqueId(void) throw() { return m_id.c_str(); }
00076 virtual eDeviceState getState(void) throw();
00077 virtual int getNumPots(void) throw() { return m_dcaps.nAxes; }
00078 virtual int getNumButtons(void) throw() { return m_dcaps.nButtons; }
00079 virtual int getNumRumblers(void) throw() { return 0; }
00080 virtual void poll(void) throw();
00081 virtual const pot_value_t& getPotValue(IN int potIndex);
00082 virtual eButton getButtonValue(IN int buttonIndex);
00083 virtual bool playRumble(IN int rumbleIndex,
00084 IN uint16_t highFreqMagnitude,
00085 IN uint16_t lowFreqMagnitude,
00086 IN int durationMilliseconds) { return false; }
00087
00088
00089 static smart_ptr<SourceDevice> create(IN IDirectInput8 * dinput,
00090 IN const DIDEVICEINSTANCE& ddi);
00091
00092 private:
00093
00094 typedef std::vector<pot_value_t> pot_vector_t;
00095 typedef std::vector<byte_t> byte_vector_t;
00096
00097
00098 void initialize(IN IDirectInput8 * dinput,
00099 IN const DIDEVICEINSTANCE& di);
00100
00101
00102 COM_ptr<IDirectInputDevice8> m_device;
00103 std::string m_name;
00104 std::string m_id;
00105 device_caps_t m_dcaps;
00106 pot_vector_t m_pot;
00107 byte_vector_t m_button;
00108 byte_t * m_data;
00109 };
00110
00111
00112
00113 DirectInputDevice::DirectInputDevice
00114 (
00115 void
00116 )
00117 throw()
00118 {
00119 m_data = NULL;
00120 }
00121
00122
00123
00124 DirectInputDevice::~DirectInputDevice(void) throw()
00125 {
00126 if (m_data) {
00127 delete[] m_data;
00128 }
00129 }
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139 eDeviceState
00140 DirectInputDevice::getState
00141 (
00142 void
00143 )
00144 throw()
00145 {
00146 return eDevice_Unknown;
00147 }
00148
00149
00150
00151 void
00152 DirectInputDevice::poll
00153 (
00154 void
00155 )
00156 throw()
00157 {
00158 ASSERT(m_device, "null");
00159
00160
00161 HRESULT hr = m_device->Poll();
00162 DI_VERIFY(DI_OK == hr || DI_NOEFFECT == hr, hr,
00163 "Failed to poll device");
00164 hr = m_device->GetDeviceState(m_dcaps.dataBytes, m_data);
00165 DI_VERIFY(DI_OK == hr, hr,
00166 "Failed to get device state");
00167
00168
00169 for (int i = 0; i < m_dcaps.nAxes; ++i) {
00170 m_pot[i].update(getAxisValue(m_data, m_dcaps, i));
00171 }
00172
00173
00174 for (int i = 0; i < m_dcaps.nButtons; ++i) {
00175
00176 m_button[i] &= ~eButtonWasPushed;
00177 m_button[i] &= ~eButtonWasReleased;
00178
00179 dword_t dwValue = gamepad::getButtonValue(m_data, m_dcaps, i);
00180 m_button[i] = updateButton(m_button[i], dwValue != 0);
00181 }
00182 }
00183
00184
00185
00186 const pot_value_t&
00187 DirectInputDevice::getPotValue
00188 (
00189 IN int potIndex
00190 )
00191 {
00192 ASSERT(potIndex >= 0 && potIndex < m_dcaps.nAxes,
00193 "Invalid potentiometer index: %d", potIndex);
00194
00195 return m_pot[potIndex];
00196 }
00197
00198
00199
00200 eButton
00201 DirectInputDevice::getButtonValue
00202 (
00203 IN int buttonIndex
00204 )
00205 {
00206 ASSERT(buttonIndex >= 0 && buttonIndex < m_dcaps.nButtons,
00207 "Bad button index: %d", buttonIndex);
00208
00209 return (eButton) m_button[buttonIndex];
00210 }
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220 smart_ptr<SourceDevice>
00221 DirectInputDevice::create
00222 (
00223 IN IDirectInput8 * dinput,
00224 IN const DIDEVICEINSTANCE& ddi
00225 )
00226 {
00227 ASSERT(dinput, "null");
00228
00229 smart_ptr<DirectInputDevice> local = new DirectInputDevice;
00230 ASSERT(local, "out of memory");
00231
00232 local->initialize(dinput, ddi);
00233
00234 return local;
00235 }
00236
00237
00238
00239
00240 void
00241 DirectInputDevice::initialize
00242 (
00243 IN IDirectInput8 * dinput,
00244 IN const DIDEVICEINSTANCE& ddi
00245 )
00246 {
00247 ASSERT(dinput, "null");
00248 ASSERT(!m_device, "already have a direct input device?");
00249
00250 LPUNKNOWN punkOuter = NULL;
00251 IDirectInputDevice8 * pdev = NULL;
00252 HRESULT hr = dinput->CreateDevice(ddi.guidInstance, &pdev, punkOuter);
00253 DI_VERIFY(S_OK == hr && pdev, hr,
00254 "Failed to create direct input device for gamepad");
00255 m_device = pdev;
00256
00257
00258 m_name = ddi.tszInstanceName;
00259 m_name += ": ";
00260 m_name += ddi.tszProductName;
00261
00262 const int bufsize = 64;
00263 char buffer[bufsize];
00264 m_id = getGuidString(ddi.guidInstance, buffer, bufsize);
00265
00266
00267 m_data = getDataFormatForDevice(m_device, m_dcaps);
00268 DPRINTF("Just created data format for new DirectInput device");
00269 DPRINTF(" nAxes = nPots = %d", m_dcaps.nAxes);
00270 DPRINTF(" nPOVs = %d", m_dcaps.nPOVs);
00271 DPRINTF(" nButtons = %d", m_dcaps.nButtons);
00272 DPRINTF(" data size = %d bytes", m_dcaps.dataBytes);
00273
00274
00275 hr = m_device->SetDataFormat((LPCDIDATAFORMAT) m_data);
00276 DI_VERIFY(DI_OK == hr, hr, "Failed to set data format on new device");
00277
00278
00279 hr = m_device->Acquire();
00280 DI_VERIFY(DI_OK == hr || S_FALSE == hr, hr,
00281 "Failed to Acquire() new device");
00282
00283
00284 m_pot.resize(m_dcaps.nAxes);
00285 m_button.resize(m_dcaps.nButtons, eButtonUp);
00286 }
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297 class DirectInputFactory : public SourceDeviceFactory {
00298 public:
00299
00300
00301 void initialize(void);
00302
00303
00304 virtual const char * getName(void) const throw();
00305 virtual int getCount(void);
00306 virtual smart_ptr<SourceDevice> getSourceDevice(IN int index);
00307
00308 private:
00309
00310 struct enum_device_context_t {
00311
00312 enum_device_context_t(void) throw() { this->clear(); }
00313 void clear(void) throw() {
00314 pThis = NULL;
00315 }
00316
00317
00318 DirectInputFactory * pThis;
00319 };
00320
00321 typedef std::map<std::string, smart_ptr<SourceDevice> > device_map_t;
00322
00323
00324 void refreshDevices(void);
00325 static BOOL CALLBACK deviceCallback(LPCDIDEVICEINSTANCEA lpddi,
00326 void * context);
00327 void addDevice(IN const DIDEVICEINSTANCEA& ddi);
00328
00329
00330 COM_ptr<IDirectInput8> m_dinput;
00331 device_map_t m_devices;
00332 };
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342 void
00343 DirectInputFactory::initialize
00344 (
00345 void
00346 )
00347 {
00348 DPRINTF("Creating a new DirectInput device factory...");
00349
00350 ASSERT(!m_dinput, "already have a direct input object?");
00351
00352
00353 HINSTANCE hinst = GetModuleHandle(NULL);
00354 dword_t dwVersion = DIRECTINPUT_VERSION;
00355 REFIID riid = IID_IDirectInput8;
00356 LPUNKNOWN punkOuter = NULL;
00357 HRESULT hr = DirectInput8Create(hinst, dwVersion, riid, m_dinput,
00358 punkOuter);
00359 DI_VERIFY(DI_OK == hr && m_dinput, hr,
00360 "Failed to create DirectInput object");
00361 }
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371 const char *
00372 DirectInputFactory::getName
00373 (
00374 void
00375 )
00376 const
00377 throw()
00378 {
00379 return "DirectInput Factory";
00380 }
00381
00382
00383
00384 int
00385 DirectInputFactory::getCount
00386 (
00387 void
00388 )
00389 {
00390 perf::Timer timer("DirectInputFactory::getCount");
00391 this->refreshDevices();
00392
00393 return m_devices.size();
00394 }
00395
00396
00397
00398 smart_ptr<SourceDevice>
00399 DirectInputFactory::getSourceDevice
00400 (
00401 IN int index
00402 )
00403 {
00404 ASSERT(index >= 0, "Bad device index: %d", index);
00405
00406 if (index >= (int) m_devices.size()) {
00407 DPRINTF("Device %d is now detached (?)", index);
00408 return NULL;
00409 }
00410
00411 device_map_t::iterator i = m_devices.begin();
00412 for (; index > 0; --index) {
00413 ++i;
00414 }
00415
00416 return i->second;
00417 }
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427 void
00428 DirectInputFactory::refreshDevices
00429 (
00430 void
00431 )
00432 {
00433 ASSERT(m_dinput, "null");
00434
00435
00436 dword_t dwDevType = DI8DEVCLASS_GAMECTRL;
00437 dword_t dwFlags = DIEDFL_ALLDEVICES;
00438 enum_device_context_t edc;
00439 edc.pThis = this;
00440 HRESULT hr = m_dinput->EnumDevices(dwDevType, deviceCallback, &edc,
00441 dwFlags);
00442 DI_VERIFY(DI_OK == hr, hr, "Failed to enumerate DirectInput devices");
00443 }
00444
00445
00446
00447 BOOL CALLBACK
00448 DirectInputFactory::deviceCallback
00449 (
00450 LPCDIDEVICEINSTANCEA lpddi,
00451 void * context
00452 )
00453 {
00454 ASSERT(lpddi, "null device instance?");
00455 enum_device_context_t * pedc = (enum_device_context_t *) context;
00456 ASSERT(pedc, "null context");
00457 ASSERT(pedc->pThis, "null");
00458
00459 pedc->pThis->addDevice(*lpddi);
00460
00461 return DIENUM_CONTINUE;
00462 }
00463
00464
00465
00466 void
00467 DirectInputFactory::addDevice
00468 (
00469 IN const DIDEVICEINSTANCEA& ddi
00470 )
00471 {
00472 const int bufsize = 64;
00473 char guid[bufsize];
00474 getGuidString(ddi.guidInstance, guid, bufsize);
00475
00476
00477
00478 if (m_devices.end() != m_devices.find(guid)) {
00479
00480 return;
00481 }
00482
00483
00484 DPRINTF("New direct input device: %s", guid);
00485 smart_ptr<SourceDevice> device =
00486 DirectInputDevice::create(m_dinput, ddi);
00487 ASSERT(device, "null");
00488
00489
00490 m_devices[guid] = device;
00491 }
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501 smart_ptr<SourceDeviceFactory>
00502 getDirectInputSourceDeviceFactory
00503 (
00504 void
00505 )
00506 {
00507 smart_ptr<DirectInputFactory> local = new DirectInputFactory;
00508 ASSERT(local, "out of memory");
00509
00510 local->initialize();
00511
00512 return local;
00513 }
00514
00515
00516
00517 };