123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- #pragma once
- auto CALLBACK DirectInput_EnumJoypadsCallback(const DIDEVICEINSTANCE* instance, void* p) -> BOOL;
- auto CALLBACK DirectInput_EnumJoypadAxesCallback(const DIDEVICEOBJECTINSTANCE* instance, void* p) -> BOOL;
- auto CALLBACK DirectInput_EnumJoypadEffectsCallback(const DIDEVICEOBJECTINSTANCE* instance, void* p) -> BOOL;
- struct InputJoypadDirectInput {
- Input& input;
- InputJoypadDirectInput(Input& input) : input(input) {}
- struct Joypad {
- shared_pointer<HID::Joypad> hid{new HID::Joypad};
- LPDIRECTINPUTDEVICE8 device = nullptr;
- LPDIRECTINPUTEFFECT effect = nullptr;
- uint32_t pathID = 0;
- uint16_t vendorID = 0;
- uint16_t productID = 0;
- bool isXInputDevice = false;
- };
- vector<Joypad> joypads;
- uintptr_t handle = 0;
- LPDIRECTINPUT8 context = nullptr;
- LPDIRECTINPUTDEVICE8 device = nullptr;
- bool xinputAvailable = false;
- uint effects = 0;
- auto assign(shared_pointer<HID::Joypad> hid, uint groupID, uint inputID, int16_t value) -> void {
- auto& group = hid->group(groupID);
- if(group.input(inputID).value() == value) return;
- input.doChange(hid, groupID, inputID, group.input(inputID).value(), value);
- group.input(inputID).setValue(value);
- }
- auto poll(vector<shared_pointer<HID::Device>>& devices) -> void {
- for(auto& jp : joypads) {
- if(FAILED(jp.device->Poll())) jp.device->Acquire();
- DIJOYSTATE2 state;
- if(FAILED(jp.device->GetDeviceState(sizeof(DIJOYSTATE2), &state))) continue;
- for(auto n : range(4)) {
- assign(jp.hid, HID::Joypad::GroupID::Axis, 0, state.lX);
- assign(jp.hid, HID::Joypad::GroupID::Axis, 1, state.lY);
- assign(jp.hid, HID::Joypad::GroupID::Axis, 2, state.lZ);
- assign(jp.hid, HID::Joypad::GroupID::Axis, 3, state.lRx);
- assign(jp.hid, HID::Joypad::GroupID::Axis, 4, state.lRy);
- assign(jp.hid, HID::Joypad::GroupID::Axis, 5, state.lRz);
- uint pov = state.rgdwPOV[n];
- int16_t xaxis = 0;
- int16_t yaxis = 0;
- if(pov < 36000) {
- if(pov >= 31500 || pov <= 4500) yaxis = -32767;
- if(pov >= 4500 && pov <= 13500) xaxis = +32767;
- if(pov >= 13500 && pov <= 22500) yaxis = +32767;
- if(pov >= 22500 && pov <= 31500) xaxis = -32767;
- }
- assign(jp.hid, HID::Joypad::GroupID::Hat, n * 2 + 0, xaxis);
- assign(jp.hid, HID::Joypad::GroupID::Hat, n * 2 + 1, yaxis);
- }
- for(auto n : range(128)) {
- assign(jp.hid, HID::Joypad::GroupID::Button, n, (bool)state.rgbButtons[n]);
- }
- devices.append(jp.hid);
- }
- }
- auto rumble(uint64_t id, bool enable) -> bool {
- for(auto& jp : joypads) {
- if(jp.hid->id() != id) continue;
- if(jp.effect == nullptr) continue;
- if(enable) jp.effect->Start(1, 0);
- else jp.effect->Stop();
- return true;
- }
- return false;
- }
- auto initialize(uintptr handle, LPDIRECTINPUT8 context, bool xinputAvailable) -> bool {
- if(!handle) return false;
- this->handle = handle;
- this->context = context;
- this->xinputAvailable = xinputAvailable;
- context->EnumDevices(DI8DEVCLASS_GAMECTRL, DirectInput_EnumJoypadsCallback, (void*)this, DIEDFL_ATTACHEDONLY);
- return true;
- }
- auto terminate() -> void {
- for(auto& jp : joypads) {
- jp.device->Unacquire();
- if(jp.effect) jp.effect->Release();
- jp.device->Release();
- }
- joypads.reset();
- context = nullptr;
- }
- auto initJoypad(const DIDEVICEINSTANCE* instance) -> bool {
- Joypad jp;
- jp.vendorID = instance->guidProduct.Data1 >> 0;
- jp.productID = instance->guidProduct.Data1 >> 16;
- jp.isXInputDevice = false;
- if(auto device = rawinput.find(jp.vendorID, jp.productID)) {
- jp.isXInputDevice = device().isXInputDevice;
- }
-
-
-
-
-
- if(jp.isXInputDevice && xinputAvailable) return DIENUM_CONTINUE;
- if(FAILED(context->CreateDevice(instance->guidInstance, &device, 0))) return DIENUM_CONTINUE;
- jp.device = device;
- device->SetDataFormat(&c_dfDIJoystick2);
- device->SetCooperativeLevel((HWND)handle, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND);
- effects = 0;
- device->EnumObjects(DirectInput_EnumJoypadAxesCallback, (void*)this, DIDFT_ABSAXIS);
- device->EnumObjects(DirectInput_EnumJoypadEffectsCallback, (void*)this, DIDFT_FFACTUATOR);
- jp.hid->setRumble(effects > 0);
- DIPROPGUIDANDPATH property;
- memset(&property, 0, sizeof(DIPROPGUIDANDPATH));
- property.diph.dwSize = sizeof(DIPROPGUIDANDPATH);
- property.diph.dwHeaderSize = sizeof(DIPROPHEADER);
- property.diph.dwObj = 0;
- property.diph.dwHow = DIPH_DEVICE;
- device->GetProperty(DIPROP_GUIDANDPATH, &property.diph);
- string devicePath = (const char*)utf8_t(property.wszPath);
- jp.pathID = Hash::CRC32(devicePath).value();
- jp.hid->setVendorID(jp.vendorID);
- jp.hid->setProductID(jp.productID);
- jp.hid->setPathID(jp.pathID);
- if(jp.hid->rumble()) {
-
- DIPROPDWORD property;
- memset(&property, 0, sizeof(DIPROPDWORD));
- property.diph.dwSize = sizeof(DIPROPDWORD);
- property.diph.dwHeaderSize = sizeof(DIPROPHEADER);
- property.diph.dwObj = 0;
- property.diph.dwHow = DIPH_DEVICE;
- property.dwData = false;
- device->SetProperty(DIPROP_AUTOCENTER, &property.diph);
- DWORD dwAxes[2] = {(DWORD)DIJOFS_X, (DWORD)DIJOFS_Y};
- LONG lDirection[2] = {0, 0};
- DICONSTANTFORCE force;
- force.lMagnitude = DI_FFNOMINALMAX;
- DIEFFECT effect;
- memset(&effect, 0, sizeof(DIEFFECT));
- effect.dwSize = sizeof(DIEFFECT);
- effect.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
- effect.dwDuration = INFINITE;
- effect.dwSamplePeriod = 0;
- effect.dwGain = DI_FFNOMINALMAX;
- effect.dwTriggerButton = DIEB_NOTRIGGER;
- effect.dwTriggerRepeatInterval = 0;
- effect.cAxes = 2;
- effect.rgdwAxes = dwAxes;
- effect.rglDirection = lDirection;
- effect.lpEnvelope = 0;
- effect.cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
- effect.lpvTypeSpecificParams = &force;
- effect.dwStartDelay = 0;
- device->CreateEffect(GUID_ConstantForce, &effect, &jp.effect, NULL);
- }
- for(auto n : range(6)) jp.hid->axes().append(n);
- for(auto n : range(8)) jp.hid->hats().append(n);
- for(auto n : range(128)) jp.hid->buttons().append(n);
- joypads.append(jp);
- return DIENUM_CONTINUE;
- }
- auto initAxis(const DIDEVICEOBJECTINSTANCE* instance) -> bool {
- DIPROPRANGE range;
- memset(&range, 0, sizeof(DIPROPRANGE));
- range.diph.dwSize = sizeof(DIPROPRANGE);
- range.diph.dwHeaderSize = sizeof(DIPROPHEADER);
- range.diph.dwHow = DIPH_BYID;
- range.diph.dwObj = instance->dwType;
- range.lMin = -32768;
- range.lMax = +32767;
- device->SetProperty(DIPROP_RANGE, &range.diph);
- return DIENUM_CONTINUE;
- }
- auto initEffect(const DIDEVICEOBJECTINSTANCE* instance) -> bool {
- effects++;
- return DIENUM_CONTINUE;
- }
- };
- auto CALLBACK DirectInput_EnumJoypadsCallback(const DIDEVICEINSTANCE* instance, void* p) -> BOOL {
- return ((InputJoypadDirectInput*)p)->initJoypad(instance);
- }
- auto CALLBACK DirectInput_EnumJoypadAxesCallback(const DIDEVICEOBJECTINSTANCE* instance, void* p) -> BOOL {
- return ((InputJoypadDirectInput*)p)->initAxis(instance);
- }
- auto CALLBACK DirectInput_EnumJoypadEffectsCallback(const DIDEVICEOBJECTINSTANCE* instance, void* p) -> BOOL {
- return ((InputJoypadDirectInput*)p)->initEffect(instance);
- }
|