mirror of
https://git.citron-emu.org/citron/emulator
synced 2025-12-19 10:43:33 +00:00
hid_core: Add NpadCondition to shared memory to fix no-controller crash
Fix crash when launching games without a connected controller by adding a global NpadCondition structure at offset 0x3E200 in HID shared memory. Games read this structure on startup to verify controller state validity, and crash with a userspace PANIC if the data is uninitialized. The NpadCondition structure contains: - is_initialized flag (set to 1) - hold_type (controller orientation) - is_valid flag (set to 1) These fields are properly initialized when shared memory is created, ensuring games see valid controller state data even before any controllers are physically connected. Fixes crash in The Legend of Zelda: Echoes of Wisdom and other titles that validate controller state on startup. Based on LotP's implementation of the NpadCondition structure. Signed-off-by: Zephyron <zephyron@citron-emu.org>
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Zephyron, LotP
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -159,6 +161,15 @@ struct NpadGcTriggerState {
|
|||||||
};
|
};
|
||||||
static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size");
|
static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size");
|
||||||
|
|
||||||
|
// This is nn::hid::NpadCondition (global controller condition structure)
|
||||||
|
struct NpadCondition {
|
||||||
|
u32 _00{};
|
||||||
|
u32 is_initialized{1}; // Must be 1 to prevent crashes
|
||||||
|
u32 hold_type{static_cast<u32>(NpadJoyHoldType::Horizontal)}; // Store enum as u32
|
||||||
|
u32 is_valid{1}; // Must be 1 to prevent crashes
|
||||||
|
};
|
||||||
|
static_assert(sizeof(NpadCondition) == 0x10, "NpadCondition is an invalid size");
|
||||||
|
|
||||||
// This is nn::hid::NpadSystemProperties
|
// This is nn::hid::NpadSystemProperties
|
||||||
struct NPadSystemProperties {
|
struct NPadSystemProperties {
|
||||||
union {
|
union {
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Zephyron, LotP
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -201,7 +203,10 @@ static_assert(sizeof(ConsoleSixAxisSensorSharedMemoryFormat) == 0x20,
|
|||||||
|
|
||||||
// This is nn::hid::detail::SharedMemoryFormat
|
// This is nn::hid::detail::SharedMemoryFormat
|
||||||
struct SharedMemoryFormat {
|
struct SharedMemoryFormat {
|
||||||
void Initialize() {}
|
void Initialize() {
|
||||||
|
// Initialize the global NpadCondition to prevent crashes when no controller is connected
|
||||||
|
npad_condition = NpadCondition{};
|
||||||
|
}
|
||||||
|
|
||||||
DebugPadSharedMemoryFormat debug_pad;
|
DebugPadSharedMemoryFormat debug_pad;
|
||||||
TouchScreenSharedMemoryFormat touch_screen;
|
TouchScreenSharedMemoryFormat touch_screen;
|
||||||
@@ -218,7 +223,9 @@ struct SharedMemoryFormat {
|
|||||||
ConsoleSixAxisSensorSharedMemoryFormat console;
|
ConsoleSixAxisSensorSharedMemoryFormat console;
|
||||||
INSERT_PADDING_BYTES(0x19E0);
|
INSERT_PADDING_BYTES(0x19E0);
|
||||||
MouseSharedMemoryFormat debug_mouse;
|
MouseSharedMemoryFormat debug_mouse;
|
||||||
INSERT_PADDING_BYTES(0x2000);
|
INSERT_PADDING_BYTES(0x200);
|
||||||
|
NpadCondition npad_condition;
|
||||||
|
INSERT_PADDING_BYTES(0x1DF0);
|
||||||
};
|
};
|
||||||
static_assert(offsetof(SharedMemoryFormat, debug_pad) == 0x0, "debug_pad has wrong offset");
|
static_assert(offsetof(SharedMemoryFormat, debug_pad) == 0x0, "debug_pad has wrong offset");
|
||||||
static_assert(offsetof(SharedMemoryFormat, touch_screen) == 0x400, "touch_screen has wrong offset");
|
static_assert(offsetof(SharedMemoryFormat, touch_screen) == 0x400, "touch_screen has wrong offset");
|
||||||
@@ -236,6 +243,7 @@ static_assert(offsetof(SharedMemoryFormat, npad) == 0x9A00, "npad has wrong offs
|
|||||||
static_assert(offsetof(SharedMemoryFormat, gesture) == 0x3BA00, "gesture has wrong offset");
|
static_assert(offsetof(SharedMemoryFormat, gesture) == 0x3BA00, "gesture has wrong offset");
|
||||||
static_assert(offsetof(SharedMemoryFormat, console) == 0x3C200, "console has wrong offset");
|
static_assert(offsetof(SharedMemoryFormat, console) == 0x3C200, "console has wrong offset");
|
||||||
static_assert(offsetof(SharedMemoryFormat, debug_mouse) == 0x3DC00, "debug_mouse has wrong offset");
|
static_assert(offsetof(SharedMemoryFormat, debug_mouse) == 0x3DC00, "debug_mouse has wrong offset");
|
||||||
|
static_assert(offsetof(SharedMemoryFormat, npad_condition) == 0x3E200, "npad_condition has wrong offset");
|
||||||
static_assert(sizeof(SharedMemoryFormat) == 0x40000, "SharedMemoryFormat is an invalid size");
|
static_assert(sizeof(SharedMemoryFormat) == 0x40000, "SharedMemoryFormat is an invalid size");
|
||||||
|
|
||||||
} // namespace Service::HID
|
} // namespace Service::HID
|
||||||
|
|||||||
Reference in New Issue
Block a user