// Callback that lists all gamepads. static BOOL CALLBACK gamepadCallback(LPCDIDEVICEINSTANCE device, LPVOID userData) { Impl* pimpl = static_cast<Impl*>(userData); IDirectInputDevice8* gamepad; if (FAILED(pimpl->input->CreateDevice(device->guidInstance, &gamepad, 0))) { return DIENUM_CONTINUE; } if (FAILED(gamepad->SetDataFormat(&c_dfDIJoystick)) || FAILED(gamepad->SetCooperativeLevel(pimpl->window, DISCL_EXCLUSIVE | DISCL_FOREGROUND)) || FAILED(gamepad->EnumObjects(axisCallback, gamepad, DIDFT_AXIS))) { gamepad->Release(); return DIENUM_CONTINUE; } pimpl->gamepads.push_back(Win::shareComPtr(gamepad)); return DIENUM_CONTINUE; }
// enumerate the dinput devices int __stdcall plDInputMgr::EnumGamepadCallback(const DIDEVICEINSTANCE* device, void* pRef) { HRESULT hr; plDInput* pDI = (plDInput*)pRef; IDirectInputDevice8* fStick = nil; hr = pDI->fDInput->CreateDevice(device->guidInstance, &fStick, NULL); if(!FAILED(hr)) { pDI->fSticks.Append(new plDIDevice(fStick)); // the following code pertaining to the action map shouldn't be here. // in fact this shouldn't work at all according to MS, but this is // currently the only way this works. Whatever - the correct // code is here and commented out in case this ever gets fixed by MS // in a future release of dinput. HRESULT hr = fStick->BuildActionMap(pDI->fActionFormat, NULL, NULL); if (!FAILED(hr)) { hr = fStick->SetActionMap( pDI->fActionFormat, NULL, NULL ); DIPROPDWORD dipW; dipW.diph.dwSize = sizeof(DIPROPDWORD); dipW.diph.dwHeaderSize = sizeof(DIPROPHEADER); dipW.diph.dwHow = DIPH_DEVICE; dipW.diph.dwObj = 0; dipW.dwData = 500; // 5% of axis range for deadzone hr = fStick->SetProperty(DIPROP_DEADZONE , &dipW.diph); } return DIENUM_CONTINUE; } return DIENUM_STOP; }
//In morrowind this only got called for keyboards when typing into the console. Probably no point in overriding it //And so it turns out that oblivion uses this whever it's in menumode instead of just consoles. Figures. HRESULT _stdcall GetDeviceData(DWORD a,DIDEVICEOBJECTDATA* b,DWORD* c,DWORD d) { if (bufferedPresses.empty()) return RealDevice->GetDeviceData(a,b,c,d); if(!b) { DWORD temp=*c; HRESULT hr = RealDevice->GetDeviceData(a,b,c,d); if(c) *c=min(bufferedPresses.size(),temp); if(!(d|DIGDD_PEEK)) while(!bufferedPresses.empty()) bufferedPresses.pop(); return hr; } int count=0; while (bufferedPresses.size()) { //Stricktly speaking, should return a buffer overflow by here, but if you do it breaks? //Presumably, if you could mash your keyboard fast enough, no keypresses would register... if(count==*c) return DI_OK; //DI_BUFFEROVERFLOW; //This will not work correctly if DIGDD_PEEK is specified. afaik, it's only ever used if b == NULL *b=bufferedPresses.front(); bufferedPresses.pop(); b+=sizeof(void*); count++; } if(count==*c) return DI_OK; //Can probably just return DI_OK here, because afaik *c is only ever 1 unless oblivion is trying to empty the buffer *c-=count; HRESULT hr=RealDevice->GetDeviceData(a,b,c,d); *c+=count; return hr; }
ULONG _stdcall Release(void) { if(--Refs==0) { RealDevice->Release(); delete this; return 0; } else { return Refs; } }
// Callback that adjusts all found axes to [-stickRange, +stickRange]. static BOOL CALLBACK axisCallback(LPCDIDEVICEOBJECTINSTANCE instance, LPVOID userData) { IDirectInputDevice8* dev = static_cast<IDirectInputDevice8*>(userData); DIPROPRANGE range; range.diph.dwSize = sizeof(DIPROPRANGE); range.diph.dwHeaderSize = sizeof(DIPROPHEADER); range.diph.dwHow = DIPH_BYID; range.diph.dwObj = instance->dwType; range.lMin = -stickRange; range.lMax = +stickRange; dev->SetProperty(DIPROP_RANGE, &range.diph); return DIENUM_CONTINUE; }
sge::dinput::joypad::ff::dinput_effect_unique_ptr sge::dinput::joypad::ff::create_effect( IDirectInputDevice8 &_device, REFGUID _guid, DIEFFECT const &_effect ) { IDirectInputEffect *result; if( _device.CreateEffect( _guid, &_effect, &result, nullptr ) != DI_OK ) throw sge::input::exception{ FCPPT_TEXT("CreateEffect failed") }; return sge::dinput::joypad::ff::dinput_effect_unique_ptr{ result }; }
IDirectInputDevice8 *BaseInputDevice::create_device(IDirectInput8 *pDI, GUID guid) { IDirectInputDevice8 *device; HRESULT hr; hr = pDI->CreateDevice(guid, &device, NULL); if(FAILED(hr)) return NULL; hr = device->SetCooperativeLevel(Render::hWnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND); if(FAILED(hr)) { device->Release(); return NULL; } device->Acquire(); return device; }
bool sge::dinput::device::funcs::acquire( IDirectInputDevice8 &_device ) { switch( _device.Acquire() ) { case S_FALSE: case DI_OK: return true; case DIERR_OTHERAPPHASPRIO: return false; default: throw sge::input::exception( FCPPT_TEXT("Acquire() failed!") ); } }
HRESULT _stdcall Unacquire(void) { return RealDevice->Unacquire(); }
HRESULT _stdcall SetProperty(REFGUID a,const DIPROPHEADER* b) { return RealDevice->SetProperty(a,b); }
HRESULT _stdcall Acquire(void) { return RealDevice->Acquire(); }
HRESULT _stdcall Escape(LPDIEFFESCAPE a) { return RealDevice->Escape(a); }
HRESULT _stdcall GetProperty(REFGUID a,DIPROPHEADER* b) { return RealDevice->GetProperty(a,b); }
Gosu::Input::Input(HWND window) : pimpl(new Impl) { pimpl->window = window; pimpl->mouseFactorX = pimpl->mouseFactorY = 1.0; // Create the main input object (only necessary for setup). IDirectInput8* inputRaw; Impl::check("creating the main DirectInput object", ::DirectInput8Create(Win::instance(), DIRECTINPUT_VERSION, IID_IDirectInput8, reinterpret_cast<void**>(&inputRaw), 0)); pimpl->input = Win::shareComPtr(inputRaw); // Prepare property struct for setting the amount of data to buffer. DIPROPDWORD bufferSize; bufferSize.diph.dwSize = sizeof(DIPROPDWORD); bufferSize.diph.dwHeaderSize = sizeof(DIPROPHEADER); bufferSize.diph.dwHow = DIPH_DEVICE; bufferSize.diph.dwObj = 0; bufferSize.dwData = Impl::inputBufferSize; // Set up the system keyboard. IDirectInputDevice8* kbRaw; Impl::check("creating the keyboard device object", pimpl->input->CreateDevice(GUID_SysKeyboard, &kbRaw, 0)); pimpl->keyboard = Win::shareComPtr(kbRaw); Impl::check("setting the keyboard's data format", kbRaw->SetDataFormat(&c_dfDIKeyboard)); Impl::check("setting the keyboard's cooperative level", kbRaw->SetCooperativeLevel(window, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE)); Impl::check("setting the keyboard's buffer size", kbRaw->SetProperty(DIPROP_BUFFERSIZE, &bufferSize.diph)); kbRaw->Acquire(); // Set up the system mouse. IDirectInputDevice8* mouseRaw; Impl::check("creating the mouse device object", pimpl->input->CreateDevice(GUID_SysMouse, &mouseRaw, 0)); pimpl->mouse = Win::shareComPtr(mouseRaw); Impl::check("setting the mouse's data format", mouseRaw->SetDataFormat(&c_dfDIMouse)); Impl::check("setting the mouse's cooperative level", mouseRaw->SetCooperativeLevel(window, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE)); Impl::check("setting the mouse's buffer size", mouseRaw->SetProperty(DIPROP_BUFFERSIZE, &bufferSize.diph)); mouseRaw->Acquire(); pimpl->swapMouse = ::GetSystemMetrics(SM_SWAPBUTTON) != 0; // Set up all gamepads. pimpl->input->EnumDevices(DI8DEVCLASS_GAMECTRL, Impl::gamepadCallback, pimpl.get(), DIEDFL_ATTACHEDONLY); // Get into a usable default state. pimpl->mouseX = pimpl->mouseY = 0; pimpl->updateMousePos(); buttons.assign(false); }
HRESULT _stdcall CreateEffect(REFGUID a,LPCDIEFFECT b,LPDIRECTINPUTEFFECT *c,LPUNKNOWN d) { return RealDevice->CreateEffect(a,b,c,d); }
HRESULT _stdcall SendForceFeedbackCommand(DWORD a) { return RealDevice->SendForceFeedbackCommand(a); }
/*** IUnknown methods ***/ HRESULT _stdcall QueryInterface (REFIID riid, LPVOID * ppvObj) { return RealDevice->QueryInterface(riid,ppvObj); }
HRESULT _stdcall WriteEffectToFile(LPCSTR a,DWORD b,LPDIFILEEFFECT c,DWORD d) { return RealDevice->WriteEffectToFile(a,b,c,d); }
HRESULT _stdcall SetActionMap(LPDIACTIONFORMATA a,LPCSTR b,DWORD c) { return RealDevice->SetActionMap(a,b,c); }
HRESULT _stdcall EnumEffectsInFile(LPCSTR a,LPDIENUMEFFECTSINFILECALLBACK b,LPVOID c,DWORD d) { return RealDevice->EnumEffectsInFile(a,b,c,d); }
HRESULT _stdcall SendDeviceData(DWORD a,LPCDIDEVICEOBJECTDATA b,LPDWORD c,DWORD d) { return RealDevice->SendDeviceData(a,b,c,d); }
HRESULT _stdcall Poll(void) { return RealDevice->Poll(); }
HRESULT _stdcall GetDeviceState(DWORD a,LPVOID b) { if(DeviceType==kDeviceType_KEYBOARD) { //This is a keyboard, so get a list of bytes (Dont forget the mouse too) BYTE bytes[kMaxMacros]; HRESULT hr=RealDevice->GetDeviceState(256,bytes); if(hr!=DI_OK) return hr; CopyMemory(&bytes[256],&DI_data.MouseOut,10); //Get any extra key presses DI_data.GlobalHammer = !DI_data.GlobalHammer; BYTE * hammerList = DI_data.GlobalHammer ? DI_data.HammerStates : DI_data.AHammerStates; for(DWORD byte=0;byte<kMaxMacros-2;byte++) { if(!ShouldIgnoreKey(byte)) bytes[byte] |= hammerList[byte]; } for(DWORD byte=0;byte<256;byte++) { if(!ShouldIgnoreKey(byte)) { bytes[byte]|=DI_data.FakeStates[byte]; bytes[byte]&=DI_data.DisallowStates[byte]; } if(DI_data.TapStates[byte]) { bytes[byte]=0x80; DI_data.TapStates[byte]=0; } } for(DWORD byte=256;byte<kMaxMacros-2;byte++) bytes[byte]|=DI_data.FakeStates[byte]; ::CopyMemory(b,bytes,a); ::CopyMemory(DI_data.LastBytes,bytes,kMaxMacros); ::CopyMemory(DI_data.MouseIn,&bytes[256],10); return DI_OK; } else { //This is a mouse //measure length of last frame DWORD time=GetTickCount(); fps_LastFrameLength=(float)(time-fps_LastTime)/1000.0f; fps_LastTime=time; fps_FrameTimeHistory[fps_FrameTimeHistoryIdx] = fps_LastFrameLength; if(fps_FrameTimeHistoryIdx < kFrameTimeHistoryLength) fps_FrameTimeHistoryIdx++; else fps_FrameTimeHistoryIdx = 0; if(fps_FrameTimeHistoryNum < kFrameTimeHistoryLength) fps_FrameTimeHistoryNum++; else { float total = 0; for(UInt32 i = 0; i < kFrameTimeHistoryLength; i++) total += fps_FrameTimeHistory[i]; total /= ((float)kFrameTimeHistoryLength); fps_AverageFrameTime = total; } //Mouse control gunk DIMOUSESTATE2* MouseState=(DIMOUSESTATE2*)b; HRESULT hr=RealDevice->GetDeviceState(sizeof(DIMOUSESTATE2),MouseState); if(hr!=DI_OK) return hr; if(MouseState->lZ>0) { DI_data.MouseOut[8]=0x80; DI_data.MouseOut[9]=0; } else if(MouseState->lZ<0) { DI_data.MouseOut[8]=0; DI_data.MouseOut[9]=0x80; } else { DI_data.MouseOut[8]=0; DI_data.MouseOut[9]=0; } if(DI_data.MouseDisable) { MouseState->lX=0; MouseState->lY=0; } if(DI_data.MouseXMov) { MouseState->lX+=DI_data.MouseXMov; DI_data.MouseXMov=0; } if(DI_data.MouseYMov) { MouseState->lY+=DI_data.MouseYMov; DI_data.MouseYMov=0; } if(DI_data.MouseXSpeed) { float move=DI_data.MouseXSpeed*fps_LastFrameLength; MouseState->lX+=(long)move; if(DI_data.MouseXSpeed>0) { DI_data.MouseXLeft+=fmodf(move,1.0f); if(DI_data.MouseXLeft>1) { MouseState->lX+=1; DI_data.MouseXLeft-=1; } } else { DI_data.MouseXLeft-=fmodf(-move,1.0f); if(DI_data.MouseXLeft<-1) { MouseState->lX-=1; DI_data.MouseXLeft+=1; } } } if(DI_data.MouseYSpeed) { float move=DI_data.MouseYSpeed*fps_LastFrameLength; MouseState->lY+=(long)move; if(DI_data.MouseYSpeed>0) { DI_data.MouseYLeft+=fmodf(move,1.0f); if(DI_data.MouseYLeft>1) { MouseState->lY+=1; DI_data.MouseYLeft-=1; } } else { DI_data.MouseYLeft-=fmodf(-move,1.0f); if(DI_data.MouseYLeft<-1) { MouseState->lY-=1; DI_data.MouseYLeft+=1; } } } for(DWORD i=0;i<8;i++) { DI_data.MouseOut[i]=MouseState->rgbButtons[i]; MouseState->rgbButtons[i]|=DI_data.MouseIn[i]; MouseState->rgbButtons[i]&=DI_data.DisallowStates[i+256]; if(DI_data.TapStates[i+256]) { MouseState->rgbButtons[i]=0x80; DI_data.TapStates[i+256]=0x00; } } return DI_OK; } }
HRESULT _stdcall GetForceFeedbackState(LPDWORD a) { return RealDevice->GetForceFeedbackState(a); }
HRESULT _stdcall GetEffectInfo(LPDIEFFECTINFOA a,REFGUID b) { return RealDevice->GetEffectInfo(a,b); }
/*** IDirectInputDevice8A methods ***/ HRESULT _stdcall GetCapabilities(LPDIDEVCAPS a) { return RealDevice->GetCapabilities(a); }
HRESULT _stdcall EnumEffects(LPDIENUMEFFECTSCALLBACKA a,LPVOID b,DWORD c) { return RealDevice->EnumEffects(a,b,c); }
HRESULT _stdcall EnumObjects(LPDIENUMDEVICEOBJECTSCALLBACKA a,LPVOID b,DWORD c) { return RealDevice->EnumObjects(a,b,c); }
HRESULT _stdcall GetImageInfo(LPDIDEVICEIMAGEINFOHEADERA a) { return RealDevice->GetImageInfo(a); }
HRESULT _stdcall EnumCreatedEffectObjects(LPDIENUMCREATEDEFFECTOBJECTSCALLBACK a,LPVOID b,DWORD c) { return RealDevice->EnumCreatedEffectObjects(a,b,c); }