[HID] Redo service

This commit is contained in:
wheremyfoodat 2023-06-06 00:57:48 +03:00
parent 629e00251c
commit dea8b9ec2e
4 changed files with 109 additions and 14 deletions

View file

@ -27,7 +27,7 @@ namespace HID::Keys {
CirclePadRight = 1 << 28, // X >= 41 CirclePadRight = 1 << 28, // X >= 41
CirclePadLeft = 1 << 29, // X <= -41 CirclePadLeft = 1 << 29, // X <= -41
CirclePadUp = 1 << 30, // Y >= 41 CirclePadUp = 1 << 30, // Y >= 41
CirclePadDown = 1 << 31 // Y <= -41 CirclePadDown = 1u << 31 // Y <= -41
}; };
} }
@ -40,6 +40,16 @@ class HIDService {
Kernel& kernel; Kernel& kernel;
u8* sharedMem = nullptr; // Pointer to HID shared memory u8* sharedMem = nullptr; // Pointer to HID shared memory
uint nextPadIndex;
uint nextTouchscreenIndex;
uint nextAccelerometerIndex;
uint nextGyroIndex;
u32 newButtons; // The button state currently being edited
u32 oldButtons; // The previous pad state
s16 circlePadX, circlePadY; // Circlepad state
bool accelerometerEnabled; bool accelerometerEnabled;
bool eventsInitialized; bool eventsInitialized;
bool gyroEnabled; bool gyroEnabled;
@ -55,16 +65,50 @@ class HIDService {
void getGyroscopeCoefficient(u32 messagePointer); void getGyroscopeCoefficient(u32 messagePointer);
void getIPCHandles(u32 messagePointer); void getIPCHandles(u32 messagePointer);
// Don't call these prior to initializing shared mem pls
template <typename T>
T readSharedMem(size_t offset) {
return *(T*)&sharedMem[offset];
}
template <typename T>
void writeSharedMem(size_t offset, T value) {
*(T*)&sharedMem[offset] = value;
}
public: public:
HIDService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {} HIDService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
void reset(); void reset();
void handleSyncRequest(u32 messagePointer); void handleSyncRequest(u32 messagePointer);
void pressKey(u32 key); void pressKey(u32 mask) { newButtons |= mask; }
void releaseKey(u32 key); void releaseKey(u32 mask) { newButtons &= ~mask; }
void setCirclepadX(u16 x);
void setCirclepadY(u16 y); void setCirclepadX(s16 x) {
void updateInputs(); circlePadX = x;
// Turn bits 28 and 29 off in the new button state, which indicate whether the circlepad is steering left or right
// Then, set them according to the new value of x
newButtons &= ~0x3000'0000;
if (x >= 41) // Pressing right
newButtons |= 1 << 28;
else if (x <= -41) // Pressing left
newButtons |= 1 << 29;
}
void setCirclepadY(s16 y) {
circlePadY = y;
// Turn bits 30 and 31 off in the new button state, which indicate whether the circlepad is steering up or down
// Then, set them according to the new value of y
newButtons &= ~0xC000'0000;
if (y >= 41) // Pressing up
newButtons |= 1 << 30;
else if (y <= -41) // Pressing down
newButtons |= 1 << 31;
}
void updateInputs(u64 currentTimestamp);
void setSharedMem(u8* ptr) { void setSharedMem(u8* ptr) {
sharedMem = ptr; sharedMem = ptr;

View file

@ -89,5 +89,5 @@ public:
void releaseKey(u32 key) { hid.releaseKey(key); } void releaseKey(u32 key) { hid.releaseKey(key); }
void setCirclepadX(u16 x) { hid.setCirclepadX(x); } void setCirclepadX(u16 x) { hid.setCirclepadX(x); }
void setCirclepadY(u16 y) { hid.setCirclepadY(y); } void setCirclepadY(u16 y) { hid.setCirclepadY(y); }
void updateInputs() { hid.updateInputs(); } void updateInputs(u64 currentTimestamp) { hid.updateInputs(currentTimestamp); }
}; };

View file

@ -30,6 +30,12 @@ void HIDService::reset() {
for (auto& e : events) { for (auto& e : events) {
e = std::nullopt; e = std::nullopt;
} }
// Reset indices for the various HID shared memory entries
nextPadIndex = nextTouchscreenIndex = nextAccelerometerIndex = nextGyroIndex = 0;
// Reset button states
newButtons = oldButtons = 0;
circlePadX = circlePadY = 0;
} }
void HIDService::handleSyncRequest(u32 messagePointer) { void HIDService::handleSyncRequest(u32 messagePointer) {
@ -108,13 +114,58 @@ void HIDService::getIPCHandles(u32 messagePointer) {
} }
} }
void HIDService::pressKey(u32 key) { sharedMem[0]++; *(u32*)&sharedMem[0x28] |= key; } void HIDService::updateInputs(u64 currentTick) {
void HIDService::releaseKey(u32 key) { sharedMem[0]++; *(u32*)&sharedMem[0x28] &= ~key; } // Update shared memory if it has been initialized
void HIDService::setCirclepadX(u16 x) { sharedMem[0]++; *(u16*)&sharedMem[0x28 + 0xC] = x; } if (sharedMem) {
void HIDService::setCirclepadY(u16 y) { sharedMem[0]++; *(u16*)&sharedMem[0x28 + 0xC + 2] = y; } // First, update the pad state
if (nextPadIndex == 0) {
writeSharedMem<u64>(0x8, readSharedMem<u64>(0x0)); // Copy previous tick count
writeSharedMem<u64>(0x0, currentTick); // Write new tick count
}
writeSharedMem<u32>(0x10, nextPadIndex); // Index last updated by the HID module
writeSharedMem<u32>(0x1C, newButtons); // Current PAD state
writeSharedMem<s16>(0x20, circlePadX); // Current circle pad state
writeSharedMem<s16>(0x22, circlePadY);
const size_t padEntryOffset = 0x28 + (nextPadIndex * 0x10); // Offset in the array of 8 pad entries
nextPadIndex = (nextPadIndex + 1) % 8; // Move to next entry
const u32 pressed = (newButtons ^ oldButtons) & newButtons; // Pressed buttons
const u32 released = (newButtons ^ oldButtons) & oldButtons; // Released buttons
oldButtons = newButtons;
writeSharedMem<u32>(padEntryOffset, newButtons);
writeSharedMem<u32>(padEntryOffset + 4, pressed);
writeSharedMem<u32>(padEntryOffset + 8, released);
writeSharedMem<s16>(padEntryOffset + 12, circlePadX);
writeSharedMem<s16>(padEntryOffset + 14, circlePadY);
// Next, update touchscreen state
if (nextTouchscreenIndex == 0) {
writeSharedMem<u64>(0xB0, readSharedMem<u64>(0xA8)); // Copy previous tick count
writeSharedMem<u64>(0xA8, currentTick); // Write new tick count
}
writeSharedMem<u32>(0xB8, nextTouchscreenIndex); // Index last updated by the HID module
nextTouchscreenIndex = (nextTouchscreenIndex + 1) % 8; // Move to next entry
// Next, update accelerometer state
if (nextAccelerometerIndex == 0) {
writeSharedMem<u64>(0x110, readSharedMem<u64>(0x108)); // Copy previous tick count
writeSharedMem<u64>(0x108, currentTick); // Write new tick count
}
writeSharedMem<u32>(0x118, nextAccelerometerIndex); // Index last updated by the HID module
nextAccelerometerIndex = (nextAccelerometerIndex + 1) % 8; // Move to next entry
// Next, update gyro state
if (nextGyroIndex == 0) {
writeSharedMem<u64>(0x160, readSharedMem<u64>(0x158)); // Copy previous tick count
writeSharedMem<u64>(0x158, currentTick); // Write new tick count
}
writeSharedMem<u32>(0x168, nextGyroIndex); // Index last updated by the HID module
nextGyroIndex = (nextGyroIndex + 1) % 32; // Move to next entry
}
// TODO: We don't currently have inputs but we must at least try to signal the HID key input events now and then
void HIDService::updateInputs() {
// For some reason, the original developers decided to signal the HID events each time the OS rescanned inputs // For some reason, the original developers decided to signal the HID events each time the OS rescanned inputs
// Rather than once every time the state of a key, or the accelerometer state, etc is updated // Rather than once every time the state of a key, or the accelerometer state, etc is updated
// This means that the OS will signal the events even if literally nothing happened // This means that the OS will signal the events even if literally nothing happened

View file

@ -95,7 +95,7 @@ void Emulator::run() {
} }
// Update inputs in the HID module // Update inputs in the HID module
srv.updateInputs(); srv.updateInputs(cpu.getTicks());
SDL_GL_SwapWindow(window); SDL_GL_SwapWindow(window);
} }
} }