void WindowsGamepadService::CheckXInputChanges(Gamepad& gamepad, XINPUT_STATE& state) { // Handle digital buttons first for (size_t b = 0; b < kNumMappings; b++) { if (state.Gamepad.wButtons & kXIButtonMap[b].button && !(gamepad.state.Gamepad.wButtons & kXIButtonMap[b].button)) { // Button pressed NewButtonEvent(gamepad.id, kXIButtonMap[b].mapped, true); } else if (!(state.Gamepad.wButtons & kXIButtonMap[b].button) && gamepad.state.Gamepad.wButtons & kXIButtonMap[b].button) { // Button released NewButtonEvent(gamepad.id, kXIButtonMap[b].mapped, false); } } // Then triggers if (state.Gamepad.bLeftTrigger != gamepad.state.Gamepad.bLeftTrigger) { bool pressed = state.Gamepad.bLeftTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD; NewButtonEvent(gamepad.id, kButtonLeftTrigger, pressed, state.Gamepad.bLeftTrigger / 255.0); } if (state.Gamepad.bRightTrigger != gamepad.state.Gamepad.bRightTrigger) { bool pressed = state.Gamepad.bRightTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD; NewButtonEvent(gamepad.id, kButtonRightTrigger, pressed, state.Gamepad.bRightTrigger / 255.0); } // Finally deal with analog sticks // TODO: bug 1001955 - Support deadzones. if (state.Gamepad.sThumbLX != gamepad.state.Gamepad.sThumbLX) { NewAxisMoveEvent(gamepad.id, kLeftStickXAxis, state.Gamepad.sThumbLX / 32767.0); } if (state.Gamepad.sThumbLY != gamepad.state.Gamepad.sThumbLY) { NewAxisMoveEvent(gamepad.id, kLeftStickYAxis, -1.0 * state.Gamepad.sThumbLY / 32767.0); } if (state.Gamepad.sThumbRX != gamepad.state.Gamepad.sThumbRX) { NewAxisMoveEvent(gamepad.id, kRightStickXAxis, state.Gamepad.sThumbRX / 32767.0); } if (state.Gamepad.sThumbRY != gamepad.state.Gamepad.sThumbRY) { NewAxisMoveEvent(gamepad.id, kRightStickYAxis, -1.0 * state.Gamepad.sThumbRY / 32767.0); } gamepad.state = state; }
void NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); // When only a digital button is available the value will be synthesized. NewButtonEvent(aIndex, aButton, aPressed, aPressed ? 1.0L : 0.0L); }
void GamepadPlatformService::NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed) { // This method is called by monitor thread populated in // platform-dependent backends MOZ_ASSERT(XRE_IsParentProcess()); MOZ_ASSERT(!NS_IsMainThread()); // When only a digital button is available the value will be synthesized. NewButtonEvent(aIndex, aButton, aPressed, aPressed ? 1.0L : 0.0L); }
void GamepadService::Update(const GamepadChangeEvent& aEvent) { if (aEvent.type() == GamepadChangeEvent::TGamepadAdded) { const GamepadAdded& a = aEvent.get_GamepadAdded(); AddGamepad(a.index(), a.id(), static_cast<GamepadMappingType>(a.mapping()), a.num_buttons(), a.num_axes()); } else if (aEvent.type() == GamepadChangeEvent::TGamepadRemoved) { const GamepadRemoved& a = aEvent.get_GamepadRemoved(); RemoveGamepad(a.index()); } else if (aEvent.type() == GamepadChangeEvent::TGamepadButtonInformation) { const GamepadButtonInformation& a = aEvent.get_GamepadButtonInformation(); NewButtonEvent(a.index(), a.button(), a.pressed(), a.value()); } else if (aEvent.type() == GamepadChangeEvent::TGamepadAxisInformation) { const GamepadAxisInformation& a = aEvent.get_GamepadAxisInformation(); NewAxisMoveEvent(a.index(), a.axis(), a.value()); } else { MOZ_CRASH("We shouldn't be here!"); } }
void GamepadService::NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed) { // Synthesize a value: 1.0 for pressed, 0.0 for unpressed. NewButtonEvent(aIndex, aButton, aPressed, aPressed ? 1.0L : 0.0L); }
bool WindowsGamepadService::HandleRawInput(HRAWINPUT handle) { if (!mHID) { return false; } // First, get data from the handle UINT size; GetRawInputData(handle, RID_INPUT, nullptr, &size, sizeof(RAWINPUTHEADER)); nsTArray<uint8_t> data(size); data.SetLength(size); if (GetRawInputData(handle, RID_INPUT, data.Elements(), &size, sizeof(RAWINPUTHEADER)) == kRawInputError) { return false; } PRAWINPUT raw = reinterpret_cast<PRAWINPUT>(data.Elements()); Gamepad* gamepad = nullptr; for (unsigned i = 0; i < mGamepads.Length(); i++) { if (mGamepads[i].type == kRawInputGamepad && mGamepads[i].handle == raw->header.hDevice) { gamepad = &mGamepads[i]; break; } } if (gamepad == nullptr) { return false; } // Second, get the preparsed data nsTArray<uint8_t> parsedbytes; if (!GetPreparsedData(raw->header.hDevice, parsedbytes)) { return false; } PHIDP_PREPARSED_DATA parsed = reinterpret_cast<PHIDP_PREPARSED_DATA>(parsedbytes.Elements()); // Get all the pressed buttons. nsTArray<USAGE> usages(gamepad->numButtons); usages.SetLength(gamepad->numButtons); ULONG usageLength = gamepad->numButtons; if (mHID.mHidP_GetUsages(HidP_Input, kButtonUsagePage, 0, usages.Elements(), &usageLength, parsed, (PCHAR)raw->data.hid.bRawData, raw->data.hid.dwSizeHid) != HIDP_STATUS_SUCCESS) { return false; } bool buttons[kMaxButtons] = { false }; usageLength = std::min<ULONG>(usageLength, kMaxButtons); for (unsigned i = 0; i < usageLength; i++) { buttons[usages[i] - 1] = true; } if (gamepad->hasDpad) { // Get d-pad position as 4 buttons. ULONG value; if (mHID.mHidP_GetUsageValue(HidP_Input, gamepad->dpadCaps.UsagePage, 0, gamepad->dpadCaps.Range.UsageMin, &value, parsed, (PCHAR)raw->data.hid.bRawData, raw->data.hid.dwSizeHid) == HIDP_STATUS_SUCCESS) { UnpackDpad(static_cast<LONG>(value), gamepad, buttons); } } for (unsigned i = 0; i < gamepad->numButtons; i++) { if (gamepad->buttons[i] != buttons[i]) { NewButtonEvent(gamepad->id, i, buttons[i]); gamepad->buttons[i] = buttons[i]; } } // Get all axis values. for (unsigned i = 0; i < gamepad->numAxes; i++) { double new_value; if (gamepad->axes[i].caps.LogicalMin < 0) { LONG value; if (mHID.mHidP_GetScaledUsageValue(HidP_Input, gamepad->axes[i].caps.UsagePage, 0, gamepad->axes[i].caps.Range.UsageMin, &value, parsed, (PCHAR)raw->data.hid.bRawData, raw->data.hid.dwSizeHid) != HIDP_STATUS_SUCCESS) { continue; } new_value = ScaleAxis(value, gamepad->axes[i].caps.LogicalMin, gamepad->axes[i].caps.LogicalMax); } else { ULONG value; if (mHID.mHidP_GetUsageValue(HidP_Input, gamepad->axes[i].caps.UsagePage, 0, gamepad->axes[i].caps.Range.UsageMin, &value, parsed, (PCHAR)raw->data.hid.bRawData, raw->data.hid.dwSizeHid) != HIDP_STATUS_SUCCESS) { continue; } new_value = ScaleAxis(value, gamepad->axes[i].caps.LogicalMin, gamepad->axes[i].caps.LogicalMax); } if (gamepad->axes[i].value != new_value) { NewAxisMoveEvent(gamepad->id, i, new_value); gamepad->axes[i].value = new_value; } } return true; }