Justifier: Add controller implementation
This commit is contained in:
parent
3be02c53c1
commit
d094978214
|
@ -8679,7 +8679,7 @@ SLES-00578:
|
|||
name: "Area 51 (Europe) (En,Fr,De,Es)"
|
||||
controllers:
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
- PlayStationMouse
|
||||
metadata:
|
||||
publisher: "GT Interactive / Midway"
|
||||
|
@ -8702,7 +8702,7 @@ SLES-03783:
|
|||
name: "Area 51 (Europe) (En,Fr,De,Es) (Midway Classics)"
|
||||
controllers:
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
- PlayStationMouse
|
||||
metadata:
|
||||
publisher: "GT Interactive / Midway"
|
||||
|
@ -8725,7 +8725,7 @@ SLPS-00726:
|
|||
name: "Area 51 (Japan)"
|
||||
controllers:
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
- PlayStationMouse
|
||||
metadata:
|
||||
publisher: "Soft Bank"
|
||||
|
@ -8745,7 +8745,7 @@ SLPS-00725:
|
|||
name: "Area 51 (Japan) (Special Pack)"
|
||||
controllers:
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
- PlayStationMouse
|
||||
metadata:
|
||||
publisher: "Soft Bank"
|
||||
|
@ -8768,7 +8768,7 @@ SLUS-00164:
|
|||
versionTested: "0.1-986-gfc911de1"
|
||||
controllers:
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
- PlayStationMouse
|
||||
metadata:
|
||||
publisher: "Midway"
|
||||
|
@ -31509,7 +31509,7 @@ SLES-00292:
|
|||
name: "Crypt Killer (Europe)"
|
||||
controllers:
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
metadata:
|
||||
publisher: "Konami"
|
||||
developer: "Konami"
|
||||
|
@ -31528,7 +31528,7 @@ SLUS-00335:
|
|||
name: "Crypt Killer (USA)"
|
||||
controllers:
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
metadata:
|
||||
publisher: "Konami"
|
||||
developer: "Konami"
|
||||
|
@ -37025,7 +37025,7 @@ SLES-00445:
|
|||
controllers:
|
||||
- DigitalController
|
||||
- PlayStationMouse
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
metadata:
|
||||
publisher: "Fox Interactive / Electronic Arts"
|
||||
developer: "Probe Entertainment Limited"
|
||||
|
@ -37050,7 +37050,7 @@ SLPS-00585:
|
|||
controllers:
|
||||
- DigitalController
|
||||
- PlayStationMouse
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
metadata:
|
||||
publisher: "Electronic Arts Victor"
|
||||
developer: "Probe Entertainment Limited"
|
||||
|
@ -37073,7 +37073,7 @@ SLUS-00119:
|
|||
controllers:
|
||||
- DigitalController
|
||||
- PlayStationMouse
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
metadata:
|
||||
publisher: "Fox Interactive"
|
||||
developer: "Probe Entertainment Limited"
|
||||
|
@ -37095,7 +37095,7 @@ SLES-02746:
|
|||
- DigitalController
|
||||
- PlayStationMouse
|
||||
- GunCon
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
metadata:
|
||||
publisher: "Fox Interactive"
|
||||
developer: "N-Space"
|
||||
|
@ -37117,7 +37117,7 @@ SLES-02747:
|
|||
- DigitalController
|
||||
- PlayStationMouse
|
||||
- GunCon
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
metadata:
|
||||
publisher: "Fox Interactive"
|
||||
developer: "N-Space"
|
||||
|
@ -37139,7 +37139,7 @@ SLES-02748:
|
|||
- DigitalController
|
||||
- PlayStationMouse
|
||||
- GunCon
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
metadata:
|
||||
publisher: "Fox Interactive"
|
||||
developer: "N-Space"
|
||||
|
@ -37161,7 +37161,7 @@ SLES-02749:
|
|||
- DigitalController
|
||||
- PlayStationMouse
|
||||
- GunCon
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
metadata:
|
||||
publisher: "Fox Interactive"
|
||||
developer: "N-Space"
|
||||
|
@ -37183,7 +37183,7 @@ SLUS-01015:
|
|||
- DigitalController
|
||||
- PlayStationMouse
|
||||
- GunCon
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
metadata:
|
||||
publisher: "Fox Interactive"
|
||||
developer: "N-Space"
|
||||
|
@ -48310,7 +48310,7 @@ SLUS-00654:
|
|||
- AnalogController
|
||||
- DigitalController
|
||||
- GunCon
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
- PlayStationMouse
|
||||
metadata:
|
||||
publisher: "Working Designs"
|
||||
|
@ -63836,7 +63836,7 @@ SCPS-10038:
|
|||
- AnalogController
|
||||
- DigitalController
|
||||
- GunCon
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
- PlayStationMouse
|
||||
metadata:
|
||||
publisher: "Sony"
|
||||
|
@ -70483,7 +70483,7 @@ SLPM-86021:
|
|||
name: "Henry Explorers (Japan)"
|
||||
controllers:
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
metadata:
|
||||
publisher: "Konami"
|
||||
developer: "Konami"
|
||||
|
@ -72407,7 +72407,7 @@ SCPS-10016:
|
|||
name: "Horned Owl (Japan)"
|
||||
controllers:
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
- PlayStationMouse
|
||||
codes:
|
||||
- SCPS-10016
|
||||
|
@ -79170,7 +79170,7 @@ SLES-00755:
|
|||
controllers:
|
||||
- DigitalController
|
||||
- GunCon
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
metadata:
|
||||
publisher: "Gremlin Graphics"
|
||||
developer: "Gremlin Graphics"
|
||||
|
@ -79193,7 +79193,7 @@ SLUS-00630:
|
|||
controllers:
|
||||
- DigitalController
|
||||
- GunCon
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
metadata:
|
||||
publisher: "Activision"
|
||||
developer: "Gremlin Graphics"
|
||||
|
@ -89788,7 +89788,7 @@ SLES-00542:
|
|||
name: "Lethal Enforcers (Europe)"
|
||||
controllers:
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
metadata:
|
||||
publisher: "Konami"
|
||||
developer: "Konami"
|
||||
|
@ -89807,7 +89807,7 @@ SLPM-86025:
|
|||
name: "Lethal Enforcers Deluxe Pack (Japan)"
|
||||
controllers:
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
metadata:
|
||||
publisher: "Konami"
|
||||
developer: "Konami"
|
||||
|
@ -89826,7 +89826,7 @@ SLUS-00293:
|
|||
name: "Lethal Enforcers I & II (USA)"
|
||||
controllers:
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
metadata:
|
||||
publisher: "Konami"
|
||||
developer: "Konami"
|
||||
|
@ -96536,7 +96536,7 @@ SLES-01001:
|
|||
- AnalogController
|
||||
- DigitalController
|
||||
- GunCon
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
metadata:
|
||||
publisher: "Midway"
|
||||
developer: "Tantalus Entertainment"
|
||||
|
@ -96563,7 +96563,7 @@ SLUS-00503:
|
|||
- AnalogController
|
||||
- DigitalController
|
||||
- GunCon
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
metadata:
|
||||
publisher: "Midway"
|
||||
developer: "Tantalus Entertainment"
|
||||
|
@ -99864,7 +99864,7 @@ SLPS-00583:
|
|||
name: "Mighty Hits (Japan)"
|
||||
controllers:
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
metadata:
|
||||
publisher: "Altron"
|
||||
developer: "Altron"
|
||||
|
@ -99885,7 +99885,7 @@ SLES-02244:
|
|||
- AnalogController
|
||||
- DigitalController
|
||||
- GunCon
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
metadata:
|
||||
publisher: "JVC"
|
||||
developer: "Altron"
|
||||
|
@ -99908,7 +99908,7 @@ SLPS-02165:
|
|||
- AnalogController
|
||||
- DigitalController
|
||||
- GunCon
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
metadata:
|
||||
publisher: "Altron"
|
||||
developer: "Altron"
|
||||
|
@ -126754,7 +126754,7 @@ SCUS-94408:
|
|||
name: "Project - Horned Owl (USA)"
|
||||
controllers:
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
- PlayStationMouse
|
||||
metadata:
|
||||
publisher: "Sony"
|
||||
|
@ -143583,7 +143583,7 @@ SCPS-45380:
|
|||
controllers:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
metadata:
|
||||
publisher: "Konami"
|
||||
developer: "KCET"
|
||||
|
@ -143610,7 +143610,7 @@ SLES-01514:
|
|||
controllers:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
traits:
|
||||
- ForceRecompilerICache
|
||||
metadata:
|
||||
|
@ -143641,7 +143641,7 @@ SLPM-86192:
|
|||
controllers:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
traits:
|
||||
- ForceRecompilerICache
|
||||
metadata:
|
||||
|
@ -143665,7 +143665,7 @@ SLPM-86498:
|
|||
controllers:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
codes:
|
||||
- SLPM-86498
|
||||
- SLPM-87029
|
||||
|
@ -143692,7 +143692,7 @@ SLUS-00707:
|
|||
controllers:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
traits:
|
||||
- ForceRecompilerICache
|
||||
metadata:
|
||||
|
@ -153685,7 +153685,7 @@ SLES-00654:
|
|||
- SLES-10654
|
||||
controllers:
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
settings:
|
||||
dmaMaxSliceTicks: 200
|
||||
gpuMaxRunAhead: 1
|
||||
|
@ -153712,7 +153712,7 @@ SLES-10654:
|
|||
- SLES-10654
|
||||
controllers:
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
settings:
|
||||
dmaMaxSliceTicks: 200
|
||||
gpuMaxRunAhead: 1
|
||||
|
@ -153739,7 +153739,7 @@ SLES-00656:
|
|||
- SLES-10656
|
||||
controllers:
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
settings:
|
||||
dmaMaxSliceTicks: 200
|
||||
gpuMaxRunAhead: 1
|
||||
|
@ -153766,7 +153766,7 @@ SLES-10656:
|
|||
- SLES-10656
|
||||
controllers:
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
settings:
|
||||
dmaMaxSliceTicks: 200
|
||||
gpuMaxRunAhead: 1
|
||||
|
@ -153793,7 +153793,7 @@ SLES-00584:
|
|||
- SLES-10584
|
||||
controllers:
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
settings:
|
||||
dmaMaxSliceTicks: 200
|
||||
gpuMaxRunAhead: 1
|
||||
|
@ -153820,7 +153820,7 @@ SLES-10584:
|
|||
- SLES-10584
|
||||
controllers:
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
settings:
|
||||
dmaMaxSliceTicks: 200
|
||||
gpuMaxRunAhead: 1
|
||||
|
@ -153847,7 +153847,7 @@ SLES-00643:
|
|||
- SLES-10643
|
||||
controllers:
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
settings:
|
||||
dmaMaxSliceTicks: 200
|
||||
gpuMaxRunAhead: 1
|
||||
|
@ -153874,7 +153874,7 @@ SLES-10643:
|
|||
- SLES-10643
|
||||
controllers:
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
settings:
|
||||
dmaMaxSliceTicks: 200
|
||||
gpuMaxRunAhead: 1
|
||||
|
@ -153901,7 +153901,7 @@ SLPS-00638:
|
|||
- SLPS-00639
|
||||
controllers:
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
settings:
|
||||
dmaMaxSliceTicks: 200
|
||||
gpuMaxRunAhead: 1
|
||||
|
@ -153928,7 +153928,7 @@ SLPS-00639:
|
|||
- SLPS-00639
|
||||
controllers:
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
settings:
|
||||
dmaMaxSliceTicks: 200
|
||||
gpuMaxRunAhead: 1
|
||||
|
@ -153958,7 +153958,7 @@ SLES-00644:
|
|||
versionTested: "0.1-4423-g32ab7c13"
|
||||
controllers:
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
settings:
|
||||
dmaMaxSliceTicks: 200
|
||||
gpuMaxRunAhead: 1
|
||||
|
@ -153988,7 +153988,7 @@ SLES-10644:
|
|||
versionTested: "0.1-4423-g32ab7c13"
|
||||
controllers:
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
settings:
|
||||
dmaMaxSliceTicks: 200
|
||||
gpuMaxRunAhead: 1
|
||||
|
@ -154015,7 +154015,7 @@ SLUS-00381:
|
|||
- SLUS-00386
|
||||
controllers:
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
settings:
|
||||
dmaMaxSliceTicks: 200
|
||||
gpuMaxRunAhead: 1
|
||||
|
@ -154045,7 +154045,7 @@ SLUS-00386:
|
|||
- SLUS-00386
|
||||
controllers:
|
||||
- DigitalController
|
||||
- KonamiJustifier
|
||||
- Justifier
|
||||
settings:
|
||||
dmaMaxSliceTicks: 200
|
||||
gpuMaxRunAhead: 1
|
||||
|
|
|
@ -73,6 +73,8 @@ add_library(core
|
|||
imgui_overlays.h
|
||||
interrupt_controller.cpp
|
||||
interrupt_controller.h
|
||||
justifier.cpp
|
||||
justifier.h
|
||||
mdec.cpp
|
||||
mdec.h
|
||||
memory_card.cpp
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "fmt/format.h"
|
||||
#include "guncon.h"
|
||||
#include "host.h"
|
||||
#include "justifier.h"
|
||||
#include "negcon.h"
|
||||
#include "negcon_rumble.h"
|
||||
#include "playstation_mouse.h"
|
||||
|
@ -24,6 +25,7 @@ static const Controller::ControllerInfo s_none_info = {ControllerType::None,
|
|||
static const Controller::ControllerInfo* s_controller_info[] = {
|
||||
&s_none_info, &DigitalController::INFO, &AnalogController::INFO, &AnalogJoystick::INFO,
|
||||
&NeGcon::INFO, &NeGconRumble::INFO, &GunCon::INFO, &PlayStationMouse::INFO,
|
||||
&Justifier::INFO,
|
||||
};
|
||||
|
||||
const char* Controller::ControllerInfo::GetDisplayName() const
|
||||
|
@ -100,6 +102,9 @@ std::unique_ptr<Controller> Controller::Create(ControllerType type, u32 index)
|
|||
case ControllerType::GunCon:
|
||||
return GunCon::Create(index);
|
||||
|
||||
case ControllerType::Justifier:
|
||||
return Justifier::Create(index);
|
||||
|
||||
case ControllerType::PlayStationMouse:
|
||||
return PlayStationMouse::Create(index);
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
<ClCompile Include="hotkeys.cpp" />
|
||||
<ClCompile Include="imgui_overlays.cpp" />
|
||||
<ClCompile Include="interrupt_controller.cpp" />
|
||||
<ClCompile Include="justifier.cpp" />
|
||||
<ClCompile Include="mdec.cpp" />
|
||||
<ClCompile Include="memory_card.cpp" />
|
||||
<ClCompile Include="memory_card_image.cpp" />
|
||||
|
@ -138,6 +139,7 @@
|
|||
<ClInclude Include="imgui_overlays.h" />
|
||||
<ClInclude Include="input_types.h" />
|
||||
<ClInclude Include="interrupt_controller.h" />
|
||||
<ClInclude Include="justifier.h" />
|
||||
<ClInclude Include="mdec.h" />
|
||||
<ClInclude Include="memory_card.h" />
|
||||
<ClInclude Include="memory_card_image.h" />
|
||||
|
|
|
@ -66,6 +66,7 @@
|
|||
<ClCompile Include="cpu_newrec_compiler_aarch64.cpp" />
|
||||
<ClCompile Include="cpu_newrec_compiler_riscv64.cpp" />
|
||||
<ClCompile Include="cpu_newrec_compiler_aarch32.cpp" />
|
||||
<ClCompile Include="justifier.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="types.h" />
|
||||
|
@ -138,5 +139,6 @@
|
|||
<ClInclude Include="cpu_newrec_compiler_riscv64.h" />
|
||||
<ClInclude Include="cpu_newrec_compiler_aarch32.h" />
|
||||
<ClInclude Include="achievements_private.h" />
|
||||
<ClInclude Include="justifier.h" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -273,7 +273,7 @@ static const Controller::ControllerBindingInfo s_binding_info[] = {
|
|||
}
|
||||
|
||||
// clang-format off
|
||||
BUTTON("Trigger", TRANSLATE_NOOP("GunCon", "Trigger"), nullptr, GunCon::Binding::Trigger, GenericInputBinding::R2),
|
||||
BUTTON("Trigger", TRANSLATE_NOOP("GunCon", "Trigger"), ICON_PF_CROSS, GunCon::Binding::Trigger, GenericInputBinding::R2),
|
||||
BUTTON("ShootOffscreen", TRANSLATE_NOOP("GunCon", "Shoot Offscreen"), nullptr, GunCon::Binding::ShootOffscreen, GenericInputBinding::L2),
|
||||
BUTTON("A", TRANSLATE_NOOP("GunCon", "A"), ICON_PF_BUTTON_A, GunCon::Binding::A, GenericInputBinding::Cross),
|
||||
BUTTON("B", TRANSLATE_NOOP("GunCon", "B"), ICON_PF_BUTTON_B, GunCon::Binding::B, GenericInputBinding::Circle),
|
||||
|
|
|
@ -0,0 +1,475 @@
|
|||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||
|
||||
#include "justifier.h"
|
||||
#include "gpu.h"
|
||||
#include "host.h"
|
||||
#include "interrupt_controller.h"
|
||||
#include "resources.h"
|
||||
#include "system.h"
|
||||
|
||||
#include "util/imgui_manager.h"
|
||||
#include "util/input_manager.h"
|
||||
#include "util/state_wrapper.h"
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/log.h"
|
||||
#include "common/path.h"
|
||||
#include "common/string_util.h"
|
||||
|
||||
#include "IconsPromptFont.h"
|
||||
#include <array>
|
||||
|
||||
Log_SetChannel(Justifier);
|
||||
|
||||
// #define CHECK_TIMING 1
|
||||
#ifdef CHECK_TIMING
|
||||
static u32 s_irq_current_line;
|
||||
#endif
|
||||
|
||||
static constexpr std::array<u8, static_cast<size_t>(Justifier::Binding::ButtonCount)> s_button_indices = {{15, 3, 14}};
|
||||
|
||||
Justifier::Justifier(u32 index) : Controller(index)
|
||||
{
|
||||
m_irq_event = TimingEvents::CreateTimingEvent(
|
||||
"Justifier IRQ", 1, 1, [](void* param, TickCount, TickCount) { static_cast<Justifier*>(param)->IRQEvent(); }, this,
|
||||
false);
|
||||
}
|
||||
|
||||
Justifier::~Justifier()
|
||||
{
|
||||
if (!m_cursor_path.empty())
|
||||
{
|
||||
const u32 cursor_index = GetSoftwarePointerIndex();
|
||||
if (cursor_index < InputManager::MAX_SOFTWARE_CURSORS)
|
||||
ImGuiManager::ClearSoftwareCursor(cursor_index);
|
||||
}
|
||||
}
|
||||
|
||||
ControllerType Justifier::GetType() const
|
||||
{
|
||||
return ControllerType::Justifier;
|
||||
}
|
||||
|
||||
void Justifier::Reset()
|
||||
{
|
||||
m_transfer_state = TransferState::Idle;
|
||||
}
|
||||
|
||||
bool Justifier::DoState(StateWrapper& sw, bool apply_input_state)
|
||||
{
|
||||
if (!Controller::DoState(sw, apply_input_state))
|
||||
return false;
|
||||
|
||||
u16 irq_first_line = m_irq_first_line;
|
||||
u16 irq_last_line = m_irq_last_line;
|
||||
u16 irq_tick = m_irq_tick;
|
||||
u16 button_state = m_button_state;
|
||||
bool shoot_offscreen = m_shoot_offscreen;
|
||||
bool position_valid = m_position_valid;
|
||||
|
||||
sw.Do(&irq_first_line);
|
||||
sw.Do(&irq_last_line);
|
||||
sw.Do(&irq_tick);
|
||||
sw.Do(&button_state);
|
||||
sw.Do(&shoot_offscreen);
|
||||
sw.Do(&position_valid);
|
||||
|
||||
if (apply_input_state)
|
||||
{
|
||||
m_irq_first_line = irq_first_line;
|
||||
m_irq_last_line = irq_last_line;
|
||||
m_irq_tick = irq_tick;
|
||||
m_button_state = button_state;
|
||||
m_shoot_offscreen = shoot_offscreen;
|
||||
m_position_valid = position_valid;
|
||||
}
|
||||
|
||||
sw.Do(&m_transfer_state);
|
||||
|
||||
if (sw.IsReading())
|
||||
UpdateIRQEvent();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
float Justifier::GetBindState(u32 index) const
|
||||
{
|
||||
if (index >= s_button_indices.size())
|
||||
return 0.0f;
|
||||
|
||||
const u32 bit = s_button_indices[index];
|
||||
return static_cast<float>(((m_button_state >> bit) & 1u) ^ 1u);
|
||||
}
|
||||
|
||||
void Justifier::SetBindState(u32 index, float value)
|
||||
{
|
||||
const bool pressed = (value >= 0.5f);
|
||||
if (index == static_cast<u32>(Binding::ShootOffscreen))
|
||||
{
|
||||
if (pressed)
|
||||
m_shoot_offscreen = m_shoot_offscreen ? m_shoot_offscreen : m_offscreen_oob_frames;
|
||||
|
||||
return;
|
||||
}
|
||||
else if (index >= static_cast<u32>(Binding::ButtonCount))
|
||||
{
|
||||
if (index >= static_cast<u32>(Binding::BindingCount) || !m_has_relative_binds)
|
||||
return;
|
||||
|
||||
if (m_relative_pos[index - static_cast<u32>(Binding::RelativeLeft)] != value)
|
||||
{
|
||||
m_relative_pos[index - static_cast<u32>(Binding::RelativeLeft)] = value;
|
||||
UpdateSoftwarePointerPosition();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (pressed)
|
||||
m_button_state &= ~(u16(1) << s_button_indices[static_cast<u8>(index)]);
|
||||
else
|
||||
m_button_state |= u16(1) << s_button_indices[static_cast<u8>(index)];
|
||||
}
|
||||
|
||||
bool Justifier::IsTriggerPressed() const
|
||||
{
|
||||
return ((m_button_state & (1u << 15)) != 0);
|
||||
}
|
||||
|
||||
void Justifier::ResetTransferState()
|
||||
{
|
||||
m_transfer_state = TransferState::Idle;
|
||||
}
|
||||
|
||||
bool Justifier::Transfer(const u8 data_in, u8* data_out)
|
||||
{
|
||||
static constexpr u16 ID = 0x5A31;
|
||||
|
||||
switch (m_transfer_state)
|
||||
{
|
||||
case TransferState::Idle:
|
||||
{
|
||||
// ack when sent 0x01, send ID for 0x42
|
||||
if (data_in == 0x42)
|
||||
{
|
||||
*data_out = Truncate8(ID);
|
||||
m_transfer_state = TransferState::IDMSB;
|
||||
UpdatePosition();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
*data_out = 0xFF;
|
||||
return (data_in == 0x01);
|
||||
}
|
||||
}
|
||||
|
||||
case TransferState::IDMSB:
|
||||
{
|
||||
*data_out = Truncate8(ID >> 8);
|
||||
m_transfer_state = TransferState::ButtonsLSB;
|
||||
return true;
|
||||
}
|
||||
|
||||
case TransferState::ButtonsLSB:
|
||||
{
|
||||
*data_out = Truncate8(m_button_state);
|
||||
m_transfer_state = TransferState::ButtonsMSB;
|
||||
return true;
|
||||
}
|
||||
|
||||
case TransferState::ButtonsMSB:
|
||||
{
|
||||
*data_out = Truncate8(m_button_state >> 8);
|
||||
m_transfer_state = TransferState::Idle;
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
UnreachableCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Justifier::UpdatePosition()
|
||||
{
|
||||
if (m_shoot_offscreen > 0)
|
||||
{
|
||||
if (m_shoot_offscreen == m_offscreen_trigger_frames)
|
||||
SetBindState(static_cast<u32>(Binding::Trigger), 1.0f);
|
||||
else if (m_shoot_offscreen == m_offscreen_release_frames)
|
||||
SetBindState(static_cast<u32>(Binding::Trigger), 0.0f);
|
||||
|
||||
m_shoot_offscreen--;
|
||||
m_position_valid = false;
|
||||
UpdateIRQEvent();
|
||||
return;
|
||||
}
|
||||
|
||||
float display_x, display_y;
|
||||
const auto [window_x, window_y] =
|
||||
(m_has_relative_binds) ? GetAbsolutePositionFromRelativeAxes() : InputManager::GetPointerAbsolutePosition(0);
|
||||
g_gpu->ConvertScreenCoordinatesToDisplayCoordinates(window_x, window_y, &display_x, &display_y);
|
||||
|
||||
// are we within the active display area?
|
||||
u32 tick, line;
|
||||
if (display_x < 0 || display_y < 0 ||
|
||||
!g_gpu->ConvertDisplayCoordinatesToBeamTicksAndLines(display_x, display_y, m_x_scale, &tick, &line) ||
|
||||
m_shoot_offscreen)
|
||||
{
|
||||
Log_DevFmt("Lightgun out of range for window coordinates {:.0f},{:.0f}", window_x, window_y);
|
||||
m_position_valid = false;
|
||||
UpdateIRQEvent();
|
||||
return;
|
||||
}
|
||||
|
||||
m_position_valid = true;
|
||||
|
||||
m_irq_tick = static_cast<u16>(static_cast<TickCount>(tick) +
|
||||
System::ScaleTicksToOverclock(static_cast<TickCount>(m_tick_offset)));
|
||||
m_irq_first_line = static_cast<u16>(std::clamp<s32>(static_cast<s32>(line) + m_first_line_offset,
|
||||
static_cast<s32>(g_gpu->GetCRTCActiveStartLine()),
|
||||
static_cast<s32>(g_gpu->GetCRTCActiveEndLine())));
|
||||
m_irq_last_line = static_cast<u16>(std::clamp<s32>(static_cast<s32>(line) + m_last_line_offset,
|
||||
static_cast<s32>(g_gpu->GetCRTCActiveStartLine()),
|
||||
static_cast<s32>(g_gpu->GetCRTCActiveEndLine())));
|
||||
|
||||
Log_DevFmt("Lightgun window coordinates {},{} -> dpy {},{} -> tick {} line {} [{}-{}]", window_x, window_y, display_x,
|
||||
display_y, tick, line, m_irq_first_line, m_irq_last_line);
|
||||
|
||||
UpdateIRQEvent();
|
||||
}
|
||||
|
||||
void Justifier::UpdateIRQEvent()
|
||||
{
|
||||
// TODO: Avoid deactivate and event sort.
|
||||
m_irq_event->Deactivate();
|
||||
|
||||
if (!m_position_valid)
|
||||
return;
|
||||
|
||||
u32 current_tick, current_line;
|
||||
g_gpu->GetBeamPosition(¤t_tick, ¤t_line);
|
||||
|
||||
u32 target_line;
|
||||
if (current_line < m_irq_first_line || current_line >= m_irq_last_line)
|
||||
target_line = m_irq_first_line;
|
||||
else
|
||||
target_line = current_line + 1;
|
||||
|
||||
const TickCount ticks_until_pos = g_gpu->GetSystemTicksUntilTicksAndLine(m_irq_tick, target_line);
|
||||
Log_DebugFmt("Triggering IRQ in {} ticks @ tick {} line {}", ticks_until_pos, m_irq_tick, target_line);
|
||||
m_irq_event->Schedule(ticks_until_pos);
|
||||
}
|
||||
|
||||
void Justifier::IRQEvent()
|
||||
{
|
||||
#ifdef CHECK_TIMING
|
||||
u32 ticks, line;
|
||||
g_gpu->GetBeamPosition(&ticks, &line);
|
||||
|
||||
const u32 expected_line = (s_irq_current_line == m_irq_last_line) ? m_irq_first_line : (s_irq_current_line + 1);
|
||||
if (line < expected_line)
|
||||
Log_WarningFmt("IRQ event fired {} lines too early", expected_line - line);
|
||||
else if (line > expected_line)
|
||||
Log_WarningFmt("IRQ event fired {} lines too late", line - expected_line);
|
||||
if (ticks < m_irq_tick)
|
||||
Log_WarningFmt("IRQ event fired {} ticks too early", m_irq_tick - ticks);
|
||||
else if (ticks > m_irq_tick)
|
||||
Log_WarningFmt("IRQ event fired {} ticks too late", ticks - m_irq_tick);
|
||||
s_irq_current_line = line;
|
||||
#endif
|
||||
|
||||
InterruptController::SetLineState(InterruptController::IRQ::IRQ10, true);
|
||||
InterruptController::SetLineState(InterruptController::IRQ::IRQ10, false);
|
||||
|
||||
UpdateIRQEvent();
|
||||
}
|
||||
|
||||
// TODO: Merge all this crap with guncon
|
||||
|
||||
std::pair<float, float> Justifier::GetAbsolutePositionFromRelativeAxes() const
|
||||
{
|
||||
const float screen_rel_x = (((m_relative_pos[1] > 0.0f) ? m_relative_pos[1] : -m_relative_pos[0]) + 1.0f) * 0.5f;
|
||||
const float screen_rel_y = (((m_relative_pos[3] > 0.0f) ? m_relative_pos[3] : -m_relative_pos[2]) + 1.0f) * 0.5f;
|
||||
return std::make_pair(screen_rel_x * ImGuiManager::GetWindowWidth(), screen_rel_y * ImGuiManager::GetWindowHeight());
|
||||
}
|
||||
|
||||
bool Justifier::CanUseSoftwareCursor() const
|
||||
{
|
||||
return (InputManager::MAX_POINTER_DEVICES + m_index) < InputManager::MAX_SOFTWARE_CURSORS;
|
||||
}
|
||||
|
||||
u32 Justifier::GetSoftwarePointerIndex() const
|
||||
{
|
||||
return m_has_relative_binds ? (InputManager::MAX_POINTER_DEVICES + m_index) : 0;
|
||||
}
|
||||
|
||||
void Justifier::UpdateSoftwarePointerPosition()
|
||||
{
|
||||
if (m_cursor_path.empty() || !CanUseSoftwareCursor())
|
||||
return;
|
||||
|
||||
const auto& [window_x, window_y] = GetAbsolutePositionFromRelativeAxes();
|
||||
ImGuiManager::SetSoftwareCursorPosition(GetSoftwarePointerIndex(), window_x, window_y);
|
||||
}
|
||||
|
||||
std::unique_ptr<Justifier> Justifier::Create(u32 index)
|
||||
{
|
||||
return std::make_unique<Justifier>(index);
|
||||
}
|
||||
|
||||
static const Controller::ControllerBindingInfo s_binding_info[] = {
|
||||
#define BUTTON(name, display_name, icon_name, binding, genb) \
|
||||
{ \
|
||||
name, display_name, icon_name, static_cast<u32>(binding), InputBindingInfo::Type::Button, genb \
|
||||
}
|
||||
#define HALFAXIS(name, display_name, icon_name, binding, genb) \
|
||||
{ \
|
||||
name, display_name, icon_name, static_cast<u32>(binding), InputBindingInfo::Type::HalfAxis, genb \
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
BUTTON("Trigger", TRANSLATE_NOOP("Justifier", "Trigger"), ICON_PF_CROSS, Justifier::Binding::Trigger, GenericInputBinding::R2),
|
||||
BUTTON("ShootOffscreen", TRANSLATE_NOOP("Justifier", "Shoot Offscreen"), nullptr, Justifier::Binding::ShootOffscreen, GenericInputBinding::L2),
|
||||
BUTTON("Start", TRANSLATE_NOOP("Justifier", "Start"), ICON_PF_START, Justifier::Binding::Start, GenericInputBinding::Cross),
|
||||
BUTTON("Back", TRANSLATE_NOOP("Justifier", "Back"), ICON_PF_BACK, Justifier::Binding::Back, GenericInputBinding::Circle),
|
||||
|
||||
HALFAXIS("RelativeLeft", TRANSLATE_NOOP("Justifier", "Relative Left"), ICON_PF_ANALOG_LEFT, Justifier::Binding::RelativeLeft, GenericInputBinding::Unknown),
|
||||
HALFAXIS("RelativeRight", TRANSLATE_NOOP("Justifier", "Relative Right"), ICON_PF_ANALOG_RIGHT, Justifier::Binding::RelativeRight, GenericInputBinding::Unknown),
|
||||
HALFAXIS("RelativeUp", TRANSLATE_NOOP("Justifier", "Relative Up"), ICON_PF_ANALOG_UP, Justifier::Binding::RelativeUp, GenericInputBinding::Unknown),
|
||||
HALFAXIS("RelativeDown", TRANSLATE_NOOP("Justifier", "Relative Down"), ICON_PF_ANALOG_DOWN, Justifier::Binding::RelativeDown, GenericInputBinding::Unknown),
|
||||
// clang-format on
|
||||
|
||||
#undef BUTTON
|
||||
};
|
||||
|
||||
static const SettingInfo s_settings[] = {
|
||||
{SettingInfo::Type::Path, "CrosshairImagePath", TRANSLATE_NOOP("Justifier", "Crosshair Image Path"),
|
||||
TRANSLATE_NOOP("Justifier", "Path to an image to use as a crosshair/cursor."), nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, 0.0f},
|
||||
{SettingInfo::Type::Float, "CrosshairScale", TRANSLATE_NOOP("Justifier", "Crosshair Image Scale"),
|
||||
TRANSLATE_NOOP("Justifier", "Scale of crosshair image on screen."), "1.0", "0.0001", "100.0", "0.10", "%.0f%%",
|
||||
nullptr, 100.0f},
|
||||
{SettingInfo::Type::String, "CrosshairColor", TRANSLATE_NOOP("Justifier", "Cursor Color"),
|
||||
TRANSLATE_NOOP("Justifier",
|
||||
"Applies a color to the chosen crosshair images, can be used for multiple players. Specify "
|
||||
"in HTML/CSS format (e.g. #aabbcc)"),
|
||||
"#ffffff", nullptr, nullptr, nullptr, nullptr, nullptr, 0.0f},
|
||||
{SettingInfo::Type::Float, "XScale", TRANSLATE_NOOP("Justifier", "X Scale"),
|
||||
TRANSLATE_NOOP("Justifier", "Scales X coordinates relative to the center of the screen."), "1.0", "0.01", "2.0",
|
||||
"0.01", "%.0f%%", nullptr, 100.0f},
|
||||
{SettingInfo::Type::Integer, "FirstLineOffset", TRANSLATE_NOOP("Justifier", "Line Start Offset"),
|
||||
TRANSLATE_NOOP("Justifier",
|
||||
"Offset applied to lightgun vertical position that the Justifier will first trigger on."),
|
||||
"-14", "-128", "127", "1", "%u", nullptr, 0.0f},
|
||||
{SettingInfo::Type::Integer, "LastLineOffset", TRANSLATE_NOOP("Justifier", "Line End Offset"),
|
||||
TRANSLATE_NOOP("Justifier", "Offset applied to lightgun vertical position that the Justifier will last trigger on."),
|
||||
"-8", "-128", "127", "1", "%u", nullptr, 0.0f},
|
||||
{SettingInfo::Type::Integer, "TickOffset", TRANSLATE_NOOP("Justifier", "Tick Offset"),
|
||||
TRANSLATE_NOOP("Justifier", "Offset applied to lightgun horizontal position that the Justifier will trigger on."),
|
||||
"50", "-1000", "1000", "1", "%u", nullptr, 0.0f},
|
||||
{SettingInfo::Type::Integer, "OffscreenOOBFrames", TRANSLATE_NOOP("Justifier", "Off-Screen Out-Of-Bounds Frames"),
|
||||
TRANSLATE_NOOP("Justifier", "Number of frames that the Justifier is pointed out-of-bounds for an off-screen shot."),
|
||||
"5", "0", "80", "1", "%u", nullptr, 0.0f},
|
||||
{SettingInfo::Type::Integer, "OffscreenTriggerFrames", TRANSLATE_NOOP("Justifier", "Off-Screen Trigger Frames"),
|
||||
TRANSLATE_NOOP("Justifier", "Number of frames that the trigger is held for an off-screen shot."), "5", "0", "80",
|
||||
"1", "%u", nullptr, 0.0f},
|
||||
{SettingInfo::Type::Integer, "OffscreenReleaseFrames", TRANSLATE_NOOP("Justifier", "Off-Screen Trigger Frames"),
|
||||
TRANSLATE_NOOP("Justifier", "Number of frames that the Justifier is pointed out-of-bounds after the trigger is "
|
||||
"released, for an off-screen shot."),
|
||||
"5", "0", "80", "1", "%u", nullptr, 0.0f},
|
||||
};
|
||||
|
||||
const Controller::ControllerInfo Justifier::INFO = {ControllerType::Justifier,
|
||||
"Justifier",
|
||||
TRANSLATE_NOOP("ControllerType", "Justifier"),
|
||||
nullptr,
|
||||
s_binding_info,
|
||||
s_settings,
|
||||
Controller::VibrationCapabilities::NoVibration};
|
||||
|
||||
void Justifier::LoadSettings(SettingsInterface& si, const char* section)
|
||||
{
|
||||
Controller::LoadSettings(si, section);
|
||||
|
||||
m_x_scale = si.GetFloatValue(section, "XScale", 1.0f);
|
||||
|
||||
std::string cursor_path = si.GetStringValue(section, "CrosshairImagePath");
|
||||
const float cursor_scale = si.GetFloatValue(section, "CrosshairScale", 1.0f);
|
||||
u32 cursor_color = 0xFFFFFF;
|
||||
if (std::string cursor_color_str = si.GetStringValue(section, "CrosshairColor", ""); !cursor_color_str.empty())
|
||||
{
|
||||
// Strip the leading hash, if it's a CSS style colour.
|
||||
const std::optional<u32> cursor_color_opt(StringUtil::FromChars<u32>(
|
||||
cursor_color_str[0] == '#' ? std::string_view(cursor_color_str).substr(1) : std::string_view(cursor_color_str),
|
||||
16));
|
||||
if (cursor_color_opt.has_value())
|
||||
cursor_color = cursor_color_opt.value();
|
||||
}
|
||||
|
||||
#ifndef __ANDROID__
|
||||
if (cursor_path.empty())
|
||||
cursor_path = Path::Combine(EmuFolders::Resources, "images/crosshair.png");
|
||||
#endif
|
||||
|
||||
const s32 prev_pointer_index = GetSoftwarePointerIndex();
|
||||
|
||||
m_has_relative_binds = (si.ContainsValue(section, "RelativeLeft") || si.ContainsValue(section, "RelativeRight") ||
|
||||
si.ContainsValue(section, "RelativeUp") || si.ContainsValue(section, "RelativeDown"));
|
||||
|
||||
const s32 new_pointer_index = GetSoftwarePointerIndex();
|
||||
|
||||
if (prev_pointer_index != new_pointer_index || m_cursor_path != cursor_path || m_cursor_scale != cursor_scale ||
|
||||
m_cursor_color != cursor_color)
|
||||
{
|
||||
if (prev_pointer_index != new_pointer_index &&
|
||||
static_cast<u32>(prev_pointer_index) < InputManager::MAX_SOFTWARE_CURSORS)
|
||||
{
|
||||
ImGuiManager::ClearSoftwareCursor(prev_pointer_index);
|
||||
}
|
||||
|
||||
// Pointer changed, so need to update software cursor.
|
||||
const bool had_software_cursor = m_cursor_path.empty();
|
||||
m_cursor_path = std::move(cursor_path);
|
||||
m_cursor_scale = cursor_scale;
|
||||
m_cursor_color = cursor_color;
|
||||
if (static_cast<u32>(new_pointer_index) < InputManager::MAX_SOFTWARE_CURSORS)
|
||||
{
|
||||
if (!m_cursor_path.empty())
|
||||
{
|
||||
ImGuiManager::SetSoftwareCursor(new_pointer_index, m_cursor_path, m_cursor_scale, m_cursor_color);
|
||||
if (m_has_relative_binds)
|
||||
UpdateSoftwarePointerPosition();
|
||||
}
|
||||
else if (had_software_cursor)
|
||||
{
|
||||
ImGuiManager::ClearSoftwareCursor(new_pointer_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_first_line_offset =
|
||||
static_cast<s8>(std::clamp<int>(si.GetIntValue(section, "FirstLineOffset", DEFAULT_FIRST_LINE_OFFSET),
|
||||
std::numeric_limits<s8>::min(), std::numeric_limits<s8>::max()));
|
||||
m_last_line_offset =
|
||||
static_cast<s8>(std::clamp<int>(si.GetIntValue(section, "LastLineOffset", DEFAULT_LAST_LINE_OFFSET),
|
||||
std::numeric_limits<s8>::min(), std::numeric_limits<s8>::max()));
|
||||
m_tick_offset = static_cast<s16>(std::clamp<int>(si.GetIntValue(section, "TickOffset", DEFAULT_TICK_OFFSET),
|
||||
std::numeric_limits<s16>::min(), std::numeric_limits<s16>::max()));
|
||||
|
||||
const s8 offscreen_oob_frames =
|
||||
static_cast<s8>(std::clamp<int>(si.GetIntValue(section, "OffscreenOOBFrames", DEFAULT_OFFSCREEN_OOB_FRAMES),
|
||||
std::numeric_limits<s8>::min(), std::numeric_limits<s8>::max()));
|
||||
const s8 offscreen_trigger_frames =
|
||||
static_cast<s8>(std::clamp<int>(si.GetIntValue(section, "OffscreenTriggerFrames", DEFAULT_OFFSCREEN_TRIGGER_FRAMES),
|
||||
std::numeric_limits<s8>::min(), std::numeric_limits<s8>::max()));
|
||||
const s8 offscreen_release_frames =
|
||||
static_cast<s8>(std::clamp<int>(si.GetIntValue(section, "OffscreenReleaseFrames", DEFAULT_OFFSCREEN_RELEASE_FRAMES),
|
||||
std::numeric_limits<s8>::min(), std::numeric_limits<s8>::max()));
|
||||
m_offscreen_oob_frames = offscreen_oob_frames + offscreen_trigger_frames + offscreen_release_frames;
|
||||
m_offscreen_trigger_frames = m_offscreen_oob_frames - offscreen_trigger_frames;
|
||||
m_offscreen_release_frames = m_offscreen_trigger_frames - offscreen_release_frames;
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||
|
||||
#pragma once
|
||||
#include "controller.h"
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
class TimingEvent;
|
||||
|
||||
class Justifier final : public Controller
|
||||
{
|
||||
public:
|
||||
enum class Binding : u8
|
||||
{
|
||||
Trigger = 0,
|
||||
Start = 1,
|
||||
Back = 2,
|
||||
ShootOffscreen = 3,
|
||||
ButtonCount = 4,
|
||||
|
||||
RelativeLeft = 4,
|
||||
RelativeRight = 5,
|
||||
RelativeUp = 6,
|
||||
RelativeDown = 7,
|
||||
BindingCount = 8,
|
||||
};
|
||||
|
||||
static const Controller::ControllerInfo INFO;
|
||||
|
||||
Justifier(u32 index);
|
||||
~Justifier() override;
|
||||
|
||||
static std::unique_ptr<Justifier> Create(u32 index);
|
||||
|
||||
ControllerType GetType() const override;
|
||||
|
||||
void Reset() override;
|
||||
bool DoState(StateWrapper& sw, bool apply_input_state) override;
|
||||
|
||||
void LoadSettings(SettingsInterface& si, const char* section) override;
|
||||
|
||||
float GetBindState(u32 index) const override;
|
||||
void SetBindState(u32 index, float value) override;
|
||||
|
||||
void ResetTransferState() override;
|
||||
bool Transfer(const u8 data_in, u8* data_out) override;
|
||||
|
||||
private:
|
||||
bool IsTriggerPressed() const;
|
||||
void UpdatePosition();
|
||||
void UpdateIRQEvent();
|
||||
void IRQEvent();
|
||||
|
||||
std::pair<float, float> GetAbsolutePositionFromRelativeAxes() const;
|
||||
bool CanUseSoftwareCursor() const;
|
||||
u32 GetSoftwarePointerIndex() const;
|
||||
void UpdateSoftwarePointerPosition();
|
||||
|
||||
enum class TransferState : u8
|
||||
{
|
||||
Idle,
|
||||
IDMSB,
|
||||
ButtonsLSB,
|
||||
ButtonsMSB,
|
||||
XLSB,
|
||||
XMSB,
|
||||
YLSB,
|
||||
YMSB
|
||||
};
|
||||
|
||||
static constexpr s8 DEFAULT_FIRST_LINE_OFFSET = -12;
|
||||
static constexpr s8 DEFAULT_LAST_LINE_OFFSET = -6;
|
||||
static constexpr s16 DEFAULT_TICK_OFFSET = 50;
|
||||
static constexpr u8 DEFAULT_OFFSCREEN_OOB_FRAMES = 5;
|
||||
static constexpr u8 DEFAULT_OFFSCREEN_TRIGGER_FRAMES = 5;
|
||||
static constexpr u8 DEFAULT_OFFSCREEN_RELEASE_FRAMES = 5;
|
||||
|
||||
std::unique_ptr<TimingEvent> m_irq_event;
|
||||
|
||||
s8 m_first_line_offset = 0;
|
||||
s8 m_last_line_offset = 0;
|
||||
s16 m_tick_offset = 0;
|
||||
|
||||
u8 m_offscreen_oob_frames = 0;
|
||||
u8 m_offscreen_trigger_frames = 0;
|
||||
u8 m_offscreen_release_frames = 0;
|
||||
|
||||
u16 m_irq_first_line = 0;
|
||||
u16 m_irq_last_line = 0;
|
||||
u16 m_irq_tick = 0;
|
||||
|
||||
// buttons are active low
|
||||
u16 m_button_state = UINT16_C(0xFFFF);
|
||||
u8 m_shoot_offscreen = 0;
|
||||
bool m_position_valid = false;
|
||||
|
||||
TransferState m_transfer_state = TransferState::Idle;
|
||||
|
||||
bool m_has_relative_binds = false;
|
||||
float m_relative_pos[4] = {};
|
||||
|
||||
std::string m_cursor_path;
|
||||
float m_cursor_scale = 1.0f;
|
||||
u32 m_cursor_color = 0xFFFFFFFFu;
|
||||
float m_x_scale = 1.0f;
|
||||
};
|
|
@ -195,6 +195,7 @@ enum class ControllerType : u8
|
|||
PlayStationMouse,
|
||||
NeGcon,
|
||||
NeGconRumble,
|
||||
Justifier,
|
||||
Count
|
||||
};
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ set(SRCS
|
|||
controllerbindingwidget_analog_joystick.ui
|
||||
controllerbindingwidget_digital_controller.ui
|
||||
controllerbindingwidget_guncon.ui
|
||||
controllerbindingwidget_justifier.ui
|
||||
controllerbindingwidget_mouse.ui
|
||||
controllerbindingwidget_negcon.ui
|
||||
controllerbindingwidget_negconrumble.ui
|
||||
|
|
|
@ -115,7 +115,7 @@
|
|||
<item row="2" column="0" colspan="3">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
|
@ -388,7 +388,7 @@
|
|||
<item row="2" column="1">
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
|
@ -401,7 +401,7 @@
|
|||
<item row="0" column="1">
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
|
@ -414,7 +414,7 @@
|
|||
<item row="1" column="0">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
|
@ -452,7 +452,7 @@
|
|||
<item row="1" column="2">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
|
@ -473,12 +473,12 @@
|
|||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string><p>By default, GunCon will use the mouse pointer. To use the mouse, you <strong>do not</strong> need to configure any bindings apart from the trigger and buttons.</p>
|
||||
<string><p>By default, lightguns will use the mouse pointer. To use the mouse, you <strong>do not</strong> need to configure any bindings apart from the trigger and buttons.</p>
|
||||
|
||||
<p>If you want to use a controller, or lightgun which simulates a controller instead of a mouse, then you should bind it to Relative Aiming. Otherwise, Relative Aiming should be <strong>left unbound</strong>.</p></string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
|
|
|
@ -0,0 +1,504 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ControllerBindingWidget_Justifier</class>
|
||||
<widget class="QWidget" name="ControllerBindingWidget_Justifier">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1010</width>
|
||||
<height>418</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>1000</width>
|
||||
<height>400</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="2">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Trigger</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_5">
|
||||
<property name="title">
|
||||
<string>Fire Offscreen</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="InputBindingWidget" name="ShootOffscreen">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Fire</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="InputBindingWidget" name="Trigger">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="3">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QGroupBox" name="groupBox_16">
|
||||
<property name="title">
|
||||
<string>Side Buttons</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_16">
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_17">
|
||||
<property name="title">
|
||||
<string>Back</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_17">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="InputBindingWidget" name="Back">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_19">
|
||||
<property name="title">
|
||||
<string>Start</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_19">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="InputBindingWidget" name="Start">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QGroupBox" name="groupBox_10">
|
||||
<property name="title">
|
||||
<string extracomment="Try to use Sony's official terminology for this. A good place to start would be in the console or the DualShock 2's manual. If this element was officially translated to your language by Sony in later DualShocks, you may use that term.">Relative Aiming</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_11">
|
||||
<item row="3" column="1" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_11">
|
||||
<property name="title">
|
||||
<string>Down</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_12">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="InputBindingWidget" name="RelativeDown">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_12">
|
||||
<property name="title">
|
||||
<string>Left</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_13">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="InputBindingWidget" name="RelativeLeft">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_13">
|
||||
<property name="title">
|
||||
<string>Up</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_14">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="InputBindingWidget" name="RelativeUp">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_14">
|
||||
<property name="title">
|
||||
<string>Right</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_15">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="InputBindingWidget" name="RelativeRight">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" rowspan="2">
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="2" column="1">
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>400</width>
|
||||
<height>266</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="resources/resources.qrc">:/controllers/guncon.svg</pixmap>
|
||||
</property>
|
||||
<property name="scaledContents">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QGroupBox" name="groupBox_15">
|
||||
<property name="title">
|
||||
<string>Pointer Setup</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string><p>By default, lightguns will use the mouse pointer. To use the mouse, you <strong>do not</strong> need to configure any bindings apart from the trigger and buttons.</p>
|
||||
|
||||
<p>If you want to use a controller, or lightgun which simulates a controller instead of a mouse, then you should bind it to Relative Aiming. Otherwise, Relative Aiming should be <strong>left unbound</strong>.</p></string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>InputBindingWidget</class>
|
||||
<extends>QPushButton</extends>
|
||||
<header>inputbindingwidgets.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="resources/resources.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -8,10 +8,12 @@
|
|||
#include "qtutils.h"
|
||||
#include "settingswindow.h"
|
||||
#include "settingwidgetbinder.h"
|
||||
|
||||
#include "ui_controllerbindingwidget_analog_controller.h"
|
||||
#include "ui_controllerbindingwidget_analog_joystick.h"
|
||||
#include "ui_controllerbindingwidget_digital_controller.h"
|
||||
#include "ui_controllerbindingwidget_guncon.h"
|
||||
#include "ui_controllerbindingwidget_justifier.h"
|
||||
#include "ui_controllerbindingwidget_mouse.h"
|
||||
#include "ui_controllerbindingwidget_negcon.h"
|
||||
#include "ui_controllerbindingwidget_negconrumble.h"
|
||||
|
@ -175,6 +177,15 @@ void ControllerBindingWidget::populateWidgets()
|
|||
}
|
||||
break;
|
||||
|
||||
case ControllerType::Justifier:
|
||||
{
|
||||
Ui::ControllerBindingWidget_Justifier ui;
|
||||
ui.setupUi(m_bindings_widget);
|
||||
bindBindingWidgets(m_bindings_widget);
|
||||
m_icon = QIcon::fromTheme(QStringLiteral("guncon-line"));
|
||||
}
|
||||
break;
|
||||
|
||||
case ControllerType::None:
|
||||
{
|
||||
m_icon = QIcon::fromTheme(QStringLiteral("controller-strike-line"));
|
||||
|
|
|
@ -344,6 +344,9 @@
|
|||
<QtUi Include="audiostretchsettingsdialog.ui">
|
||||
<FileType>Document</FileType>
|
||||
</QtUi>
|
||||
<QtUi Include="controllerbindingwidget_justifier.ui">
|
||||
<FileType>Document</FileType>
|
||||
</QtUi>
|
||||
<None Include="translations\duckstation-qt_es-es.ts" />
|
||||
<None Include="translations\duckstation-qt_tr.ts" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -296,6 +296,7 @@
|
|||
<QtUi Include="controllerbindingwidget_negconrumble.ui" />
|
||||
<QtUi Include="audioexpansionsettingsdialog.ui" />
|
||||
<QtUi Include="audiostretchsettingsdialog.ui" />
|
||||
<QtUi Include="controllerbindingwidget_justifier.ui" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Natvis Include="qt5.natvis" />
|
||||
|
|
|
@ -575,11 +575,12 @@ bool ImGuiManager::AddIconFonts(float size)
|
|||
0xf5aa, 0xf5aa, 0xf5e7, 0xf5e7, 0xf65d, 0xf65e, 0xf6a9, 0xf6a9, 0xf6cf, 0xf6cf, 0xf70c, 0xf70c, 0xf794, 0xf794,
|
||||
0xf7a0, 0xf7a0, 0xf7c2, 0xf7c2, 0xf807, 0xf807, 0xf815, 0xf815, 0xf818, 0xf818, 0xf84c, 0xf84c, 0xf8cc, 0xf8cc,
|
||||
0x0, 0x0};
|
||||
static constexpr ImWchar range_pf[] = {
|
||||
0x2196, 0x2199, 0x219e, 0x21a1, 0x21b0, 0x21b3, 0x21ba, 0x21c3, 0x21c7, 0x21ca, 0x21d0, 0x21d4, 0x21dc, 0x21dd,
|
||||
0x21e0, 0x21e3, 0x21ed, 0x21ee, 0x21f7, 0x21f8, 0x21fa, 0x21fb, 0x227a, 0x227f, 0x2284, 0x2284, 0x235e, 0x235e,
|
||||
0x2360, 0x2361, 0x2364, 0x2366, 0x23b2, 0x23b4, 0x23f4, 0x23f7, 0x2427, 0x243a, 0x243c, 0x243e, 0x2460, 0x246b,
|
||||
0x24f5, 0x24fd, 0x24ff, 0x24ff, 0x278a, 0x278e, 0x27fc, 0x27fc, 0xe001, 0xe001, 0xff21, 0xff3a, 0x0, 0x0};
|
||||
static constexpr ImWchar range_pf[] = {0x2196, 0x2199, 0x219e, 0x21a1, 0x21b0, 0x21b3, 0x21ba, 0x21c3, 0x21c7, 0x21ca,
|
||||
0x21d0, 0x21d4, 0x21dc, 0x21dd, 0x21e0, 0x21e3, 0x21ed, 0x21ee, 0x21f7, 0x21f8,
|
||||
0x21fa, 0x21fb, 0x227a, 0x227f, 0x2284, 0x2284, 0x235e, 0x235e, 0x2360, 0x2361,
|
||||
0x2364, 0x2366, 0x23b2, 0x23b4, 0x23ce, 0x23ce, 0x23f4, 0x23f7, 0x2427, 0x243a,
|
||||
0x243c, 0x243e, 0x2460, 0x246b, 0x24f5, 0x24fd, 0x24ff, 0x24ff, 0x2717, 0x2717,
|
||||
0x278a, 0x278e, 0x27fc, 0x27fc, 0xe001, 0xe001, 0xff21, 0xff3a, 0x0, 0x0};
|
||||
|
||||
{
|
||||
ImFontConfig cfg;
|
||||
|
|
Loading…
Reference in New Issue