diff --git a/Core/HLE/FunctionWrappers.h b/Core/HLE/FunctionWrappers.h index 1a33383cf0..d58a726029 100644 --- a/Core/HLE/FunctionWrappers.h +++ b/Core/HLE/FunctionWrappers.h @@ -99,6 +99,11 @@ template void WrapI_III() { RETURN(retval); } +template void WrapI_IIU() { + int retval = func(PARAM(0), PARAM(1), PARAM(2)); + RETURN(retval); +} + template void WrapV_IU() { func(PARAM(0), PARAM(1)); } @@ -137,6 +142,10 @@ template void WrapV_IUU() { func(PARAM(0), PARAM(1), PARAM(2)); } +template void WrapV_IIU() { + func(PARAM(0), PARAM(1), PARAM(2)); +} + template void WrapV_IUUUU() { func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); } diff --git a/Core/HLE/sceCtrl.cpp b/Core/HLE/sceCtrl.cpp index 83ba95ff71..04b3107b70 100644 --- a/Core/HLE/sceCtrl.cpp +++ b/Core/HLE/sceCtrl.cpp @@ -66,48 +66,6 @@ void SampleControls() { _ctrl_data &data = ctrl; data.frame=1;//frame; frame++; -#ifdef _WIN32 - // TODO: Move this outta here! - data.buttons = 0; - int analogX = 128; - int analogY = 128; - if (GetAsyncKeyState(VK_SPACE)) - data.buttons|=CTRL_START; - if (GetAsyncKeyState('V')) - data.buttons|=CTRL_SELECT; - if (GetAsyncKeyState('A')) - data.buttons|=CTRL_SQUARE; - if (GetAsyncKeyState('S')) - data.buttons|=CTRL_TRIANGLE; - if (GetAsyncKeyState('X')) - data.buttons|=CTRL_CIRCLE; - if (GetAsyncKeyState('Z')) - data.buttons|=CTRL_CROSS; - if (GetAsyncKeyState('Q')) - data.buttons|=CTRL_LTRIGGER; - if (GetAsyncKeyState('W')) - data.buttons|=CTRL_RTRIGGER; - if (GetAsyncKeyState(VK_UP)) { - data.buttons|=CTRL_UP; - analogY -= 100; - } - if (GetAsyncKeyState(VK_DOWN)) { - data.buttons|=CTRL_DOWN; - analogY += 100; - } - if (GetAsyncKeyState(VK_LEFT)) { - data.buttons|=CTRL_LEFT; - analogX -= 100; - } - if (GetAsyncKeyState(VK_RIGHT)) - { - data.buttons|=CTRL_RIGHT; - analogX += 100; - } - - data.analog[0] = analogX; - data.analog[1] = analogY; -#endif } diff --git a/Core/HLE/sceImpose.cpp b/Core/HLE/sceImpose.cpp index 4562c39535..d37ac1f171 100644 --- a/Core/HLE/sceImpose.cpp +++ b/Core/HLE/sceImpose.cpp @@ -19,9 +19,24 @@ #include "FunctionWrappers.h" #include "../MIPS/MIPS.h" -static u32 iLanguage = 0; + +const int PSP_LANGUAGE_JAPANESE = 0; +const int PSP_LANGUAGE_ENGLISH = 1; +const int PSP_LANGUAGE_FRENCH = 2; +const int PSP_LANGUAGE_SPANISH = 3; +const int PSP_LANGUAGE_GERMAN = 4; +const int PSP_LANGUAGE_ITALIAN = 5; +const int PSP_LANGUAGE_DUTCH = 6; +const int PSP_LANGUAGE_PORTUGUESE = 7; +const int PSP_LANGUAGE_RUSSIAN = 8; +const int PSP_LANGUAGE_KOREAN = 9; +const int PSP_LANGUAGE_TRADITIONAL_CHINESE = 10; +const int PSP_LANGUAGE_SIMPLIFIED_CHINESE = 11; + +static u32 iLanguage = PSP_LANGUAGE_ENGLISH; static u32 iButtonValue = 0; + u32 sceImposeGetBatteryIconStatus(u32 chargingPtr, u32 iconStatusPtr) { DEBUG_LOG(HLE,"%i=sceImposeGetBatteryIconStatus(%08x, %08x)", chargingPtr, iconStatusPtr); @@ -40,10 +55,6 @@ u32 sceImposeSetLanguageMode(u32 languageVal, u32 buttonVal) return 0; } - - - - u32 sceImposeGetLanguageMode(u32 languagePtr, u32 btnPtr) { DEBUG_LOG(HLE,"%i=sceImposeGetLanguageMode(%08x, %08x)", languagePtr, btnPtr); diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index 3b390406f6..8f160946eb 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -327,14 +327,14 @@ const HLEFunction ThreadManForUser[] = {0xCD203292,&WrapU_V, "sceKernelCancelEventFlag"}, {0xA66B0120,&WrapU_IU, "sceKernelReferEventFlagStatus"}, - {0x8FFDF9A2,sceKernelCancelSema, "sceKernelCancelSema"}, - {0xD6DA4BA1,sceKernelCreateSema, "sceKernelCreateSema"}, - {0x28b6489c,sceKernelDeleteSema, "sceKernelDeleteSema"}, - {0x58b1f937,sceKernelPollSema, "sceKernelPollSema"}, - {0xBC6FEBC5,sceKernelReferSemaStatus,"sceKernelReferSemaStatus"}, - {0x3F53E640,sceKernelSignalSema, "sceKernelSignalSema"}, - {0x4E3A1105,sceKernelWaitSema, "sceKernelWaitSema"}, - {0x6d212bac,sceKernelWaitSemaCB, "sceKernelWaitSemaCB"}, + {0x8FFDF9A2,&WrapV_IIU, "sceKernelCancelSema"}, + {0xD6DA4BA1,sceKernelCreateSema, "sceKernelCreateSema"}, + {0x28b6489c,&WrapV_I, "sceKernelDeleteSema"}, + {0x58b1f937,&WrapI_II, "sceKernelPollSema"}, + {0xBC6FEBC5,&WrapI_IU, "sceKernelReferSemaStatus"}, + {0x3F53E640,&WrapV_II, "sceKernelSignalSema"}, + {0x4E3A1105,&WrapV_IIU, "sceKernelWaitSema"}, + {0x6d212bac,&WrapV_IIU, "sceKernelWaitSemaCB"}, {0x60107536,0,"sceKernelDeleteLwMutex"}, {0x19CFF145,0,"sceKernelCreateLwMutex"}, diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index 11d71ceaf6..600c6e59ab 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -57,11 +57,60 @@ struct Semaphore : public KernelObject std::vector waitingThreads; }; -void sceKernelCancelSema() +// Resume all waiting threads (for delete / cancel.) +// Returns true if it woke any threads. +bool __KernelClearSemaThreads(Semaphore *s, int reason) { - SceUID id = PARAM(0); - ERROR_LOG(HLE,"UNIMPL sceKernelCancelSema(%i)", id); - RETURN(0); + bool wokeThreads = false; + + std::vector::iterator iter; + for (iter = s->waitingThreads.begin(); iter!=s->waitingThreads.end(); iter++) + { + SceUID threadID = *iter; + + // TODO: Set returnValue = reason? + __KernelResumeThreadFromWait(threadID); + wokeThreads = true; + } + s->waitingThreads.empty(); + + return wokeThreads; +} + +// int sceKernelCancelSema(SceUID id, int newCount, int *numWaitThreads); +// void because it changes threads. +void sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr) +{ + DEBUG_LOG(HLE,"sceKernelCancelSema(%i)", id); + + u32 error; + Semaphore *s = kernelObjects.Get(id, error); + if (s) + { + if (numWaitThreadsPtr) + { + u32* numWaitThreads = (u32*)Memory::GetPointer(numWaitThreadsPtr); + *numWaitThreads = s->ns.numWaitThreads; + } + + if (newCount == -1) + s->ns.currentCount = s->ns.initCount; + else + s->ns.currentCount = newCount; + s->ns.numWaitThreads = 0; + + // We need to set the return value BEFORE rescheduling threads. + RETURN(0); + + // TODO: Should this reschedule? + if (__KernelClearSemaThreads(s, SCE_KERNEL_ERROR_WAIT_CANCEL)) + __KernelReSchedule("semaphore cancelled"); + } + else + { + ERROR_LOG(HLE, "sceKernelCancelSema : Trying to cancel invalid semaphore %i", id); + RETURN(error); + } } //SceUID sceKernelCreateSema(const char *name, SceUInt attr, int initVal, int maxVal, SceKernelSemaOptParam *option); @@ -72,6 +121,7 @@ void sceKernelCreateSema() Semaphore *s = new Semaphore; SceUID id = kernelObjects.Create(s); + s->ns.size = sizeof(NativeSemaphore); strncpy(s->ns.name, name, 32); s->ns.attr = PARAM(1); s->ns.initCount = PARAM(2); @@ -85,60 +135,82 @@ void sceKernelCreateSema() } //int sceKernelDeleteSema(SceUID semaid); -void sceKernelDeleteSema() +// void because it changes threads. +void sceKernelDeleteSema(SceUID id) { - SceUID id = PARAM(0); DEBUG_LOG(HLE,"sceKernelDeleteSema(%i)", id); - RETURN(kernelObjects.Destroy(id)); -} -void sceKernelReferSemaStatus() -{ - SceUID id = PARAM(0); u32 error; Semaphore *s = kernelObjects.Get(id, error); if (s) { - DEBUG_LOG(HLE,"sceKernelReferSemaStatus(%i, %08x)", id, PARAM(1)); - NativeSemaphore *outptr = (NativeSemaphore*)Memory::GetPointer(PARAM(1)); - int szToCopy = outptr->size - 4; - memcpy((char*)outptr + 4, (char*)s + 4, szToCopy); - RETURN(0); + if (__KernelClearSemaThreads(s, SCE_KERNEL_ERROR_WAIT_DELETE)) + { + RETURN(kernelObjects.Destroy(id)); + __KernelReSchedule("semaphore deleted"); + } + else + RETURN(kernelObjects.Destroy(id)); + } + else + { + ERROR_LOG(HLE, "sceKernelDeleteSema : Trying to delete invalid semaphore %i", id); + RETURN(error); + } +} + +int sceKernelReferSemaStatus(SceUID id, u32 infoPtr) +{ + u32 error; + Semaphore *s = kernelObjects.Get(id, error); + if (s) + { + DEBUG_LOG(HLE,"sceKernelReferSemaStatus(%i, %08x)", id, infoPtr); + NativeSemaphore *outptr = (NativeSemaphore*)Memory::GetPointer(infoPtr); + memcpy((char*)outptr, (char*)&s->ns, s->ns.size); + return 0; } else { ERROR_LOG(HLE,"Error %08x", error); - RETURN(error); + return error; } } //int sceKernelSignalSema(SceUID semaid, int signal); -void sceKernelSignalSema() +// void because it changes threads. +void sceKernelSignalSema(SceUID id, int signal) { //TODO: check that this thing really works :) - SceUID id = PARAM(0); - u32 signal = PARAM(1); u32 error; Semaphore *s = kernelObjects.Get(id, error); if (s) { int oldval = s->ns.currentCount; - s->ns.currentCount += signal; + if (s->ns.currentCount + signal > s->ns.maxCount) + s->ns.currentCount += s->ns.maxCount; + else + s->ns.currentCount += signal; DEBUG_LOG(HLE,"sceKernelSignalSema(%i, %i) (old: %i, new: %i)", id, signal, oldval, s->ns.currentCount); - + + // We need to set the return value BEFORE processing other threads. + RETURN(0); + bool wokeThreads = false; retry: //TODO: check for threads to wake up - wake them std::vector::iterator iter; for (iter = s->waitingThreads.begin(); iter!=s->waitingThreads.end(); s++) { - SceUID id = *iter; - int wVal = (int)__KernelGetWaitValue(id, error); + SceUID threadID = *iter; + int wVal = (int)__KernelGetWaitValue(threadID, error); if (wVal <= s->ns.currentCount) { - __KernelResumeThreadFromWait(id); s->ns.currentCount -= wVal; + s->ns.numWaitThreads--; + + __KernelResumeThreadFromWait(threadID); wokeThreads = true; s->waitingThreads.erase(iter); goto retry; @@ -148,111 +220,87 @@ retry: break; } } - // RETURN(0); //pop the thread that were released from waiting // I don't think we should reschedule here //if (wokeThreads) // __KernelReSchedule("semaphore signalled"); - } else { ERROR_LOG(HLE, "sceKernelSignalSema : Trying to signal invalid semaphore %i", id); + RETURN(error;) + } +} + +void __KernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr, const char *badSemaMessage, bool processCallbacks) +{ + u32 error; + Semaphore *s = kernelObjects.Get(id, error); + if (s) + { + // We need to set the return value BEFORE processing callbacks / etc. + RETURN(0); + + if (s->ns.currentCount >= wantedCount) //TODO fix + s->ns.currentCount -= wantedCount; + else + { + s->ns.numWaitThreads++; + s->waitingThreads.push_back(__KernelGetCurThread()); + // TODO: timeoutPtr? + __KernelWaitCurThread(WAITTYPE_SEMA, id, wantedCount, 0, processCallbacks); + if (processCallbacks) + __KernelCheckCallbacks(); + } + } + else + { + ERROR_LOG(HLE, badSemaMessage, id); RETURN(error); } } //int sceKernelWaitSema(SceUID semaid, int signal, SceUInt *timeout); -void sceKernelWaitSema() +// void because it changes threads. +void sceKernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr) { - SceUID id = PARAM(0); - int wantedCount = PARAM(1); - u32 timeoutPtr = PARAM(2); - - u32 error; - Semaphore *s = kernelObjects.Get(id, error); - if (s) - { - DEBUG_LOG(HLE,"sceKernelWaitSema(%i, %i, %i)", id, wantedCount, timeoutPtr); - if (s->ns.currentCount >= wantedCount) //TODO fix - { - s->ns.currentCount -= wantedCount; - RETURN(0); - } - else - { - s->waitingThreads.push_back(__KernelGetCurThread()); - __KernelWaitCurThread(WAITTYPE_SEMA, id, wantedCount, 0, false); - return; - } - } - else - { - ERROR_LOG(HLE, "sceKernelWaitSema : Trying to wait for invalid semaphore %i", id); - RETURN(error); - } + DEBUG_LOG(HLE,"sceKernelWaitSema(%i, %i, %i)", id, wantedCount, timeoutPtr); + + __KernelWaitSema(id, wantedCount, timeoutPtr, "sceKernelWaitSema: Trying to wait for invalid semaphore %i", false); } //int sceKernelWaitSemaCB(SceUID semaid, int signal, SceUInt *timeout); -void sceKernelWaitSemaCB() +// void because it changes threads. +void sceKernelWaitSemaCB(SceUID id, int wantedCount, u32 timeoutPtr) { - SceUID id = PARAM(0); - int wantedCount = PARAM(1); - int timeout = PARAM(2); - DEBUG_LOG(HLE,"sceKernelWaitSemaCB(%i, %i, %i)", id, wantedCount, timeout); - u32 error; - Semaphore *s = kernelObjects.Get(id, error); - if (s) - { - DEBUG_LOG(HLE,"CurrentCount: %i, Signal: %i", s->ns.currentCount, wantedCount); - if (s->ns.currentCount >= wantedCount) //TODO fix - { - DEBUG_LOG(HLE,"Subtracting"); - s->ns.currentCount -= wantedCount; - } - else - { - s->waitingThreads.push_back(__KernelGetCurThread()); - __KernelWaitCurThread(WAITTYPE_SEMA, id, wantedCount, 0, true); - __KernelCheckCallbacks(); - return; - } - DEBUG_LOG(HLE,"After: CurrentCount: %i, Signal: %i", s->ns.currentCount, wantedCount); - RETURN(0); - } - else - { - ERROR_LOG(HLE,"sceKernelWaitSemaCB - Bad semaphore"); - RETURN(error); - } + DEBUG_LOG(HLE,"sceKernelWaitSemaCB(%i, %i, %i)", id, wantedCount, timeoutPtr); + + __KernelWaitSema(id, wantedCount, timeoutPtr, "sceKernelWaitSemaCB: Trying to wait for invalid semaphore %i", true); } // Should be same as WaitSema but without the wait, instead returning SCE_KERNEL_ERROR_SEMA_ZERO -void sceKernelPollSema() +int sceKernelPollSema(SceUID id, int wantedCount) { - SceUID id = PARAM(0); - int wantedCount = PARAM(1); + DEBUG_LOG(HLE,"sceKernelPollSema(%i, %i)", id, wantedCount); u32 error; Semaphore *s = kernelObjects.Get(id, error); if (s) { - DEBUG_LOG(HLE,"sceKernelPollSema(%i, %i)", id, wantedCount); if (s->ns.currentCount >= wantedCount) //TODO fix - { s->ns.currentCount -= wantedCount; - RETURN(0); - } else { - RETURN(SCE_KERNEL_ERROR_SEMA_ZERO); + return SCE_KERNEL_ERROR_SEMA_ZERO; } + + return 0; } else { - ERROR_LOG(HLE, "sceKernelPollSema : Trying to poll invalid semaphore %i", id); - RETURN(error); + ERROR_LOG(HLE, "sceKernelPollSema: Trying to poll invalid semaphore %i", id); + return error; } } diff --git a/Core/HLE/sceKernelSemaphore.h b/Core/HLE/sceKernelSemaphore.h index e3e5a2925b..185976f788 100644 --- a/Core/HLE/sceKernelSemaphore.h +++ b/Core/HLE/sceKernelSemaphore.h @@ -17,11 +17,11 @@ #pragma once -void sceKernelCancelSema(); +void sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr); void sceKernelCreateSema(); -void sceKernelDeleteSema(); -void sceKernelPollSema(); -void sceKernelReferSemaStatus(); -void sceKernelSignalSema(); -void sceKernelWaitSema(); -void sceKernelWaitSemaCB(); +void sceKernelDeleteSema(SceUID id); +int sceKernelPollSema(SceUID id, int wantedCount); +int sceKernelReferSemaStatus(SceUID id, u32 infoPtr); +void sceKernelSignalSema(SceUID id, int signal); +void sceKernelWaitSema(SceUID semaid, int signal, u32 timeoutPtr); +void sceKernelWaitSemaCB(SceUID semaid, int signal, u32 timeoutPtr); diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index 8b2e6c3c6f..6784bab6ce 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -859,7 +859,7 @@ u32 sceKernelStartThread() startThread->nt.status = THREADSTATUS_READY; u32 sp = startThread->context.r[MIPS_REG_SP]; - if (argBlockPtr) + if (argBlockPtr && argSize > 0) { startThread->context.r[MIPS_REG_A0] = argSize; startThread->context.r[MIPS_REG_A1] = sp; diff --git a/Windows/InputDevice.cpp b/Windows/InputDevice.cpp new file mode 100644 index 0000000000..ad882a2c73 --- /dev/null +++ b/Windows/InputDevice.cpp @@ -0,0 +1,13 @@ +#include "InputDevice.h" +#include "XinputDevice.h" +#include "KeyboardDevice.h" +#include +#include + +#define PUSH_BACK(Cls) do { list.push_back(std::shared_ptr(new Cls())); } while (0) +std::list> getInputDevices() { + std::list> list; + PUSH_BACK(XinputDevice); + PUSH_BACK(KeyboardDevice); + return list; +} diff --git a/Windows/InputDevice.h b/Windows/InputDevice.h new file mode 100644 index 0000000000..8c50214dfc --- /dev/null +++ b/Windows/InputDevice.h @@ -0,0 +1,13 @@ +#include "../Common/CommonTypes.h" +#include "../Core/HLE/sceCtrl.h" + +#pragma once +class InputDevice +{ +public: + virtual int UpdateState() = 0; +}; + +#include +#include +std::list> getInputDevices(); diff --git a/Windows/KeyboardDevice.cpp b/Windows/KeyboardDevice.cpp new file mode 100644 index 0000000000..c69f97b90c --- /dev/null +++ b/Windows/KeyboardDevice.cpp @@ -0,0 +1,46 @@ +#include "KeyboardDevice.h" +#include "../Common/CommonTypes.h" +#include "../Core/HLE/sceCtrl.h" +#include "WinUser.h" + +static const unsigned short key_ctrl_map[] = { + VK_SPACE, CTRL_START, + 'V', CTRL_SELECT, + 'A', CTRL_SQUARE, + 'S', CTRL_TRIANGLE, + 'X', CTRL_CIRCLE, + 'Z', CTRL_CROSS, + 'Q', CTRL_LTRIGGER, + 'W', CTRL_RTRIGGER, + VK_UP, CTRL_UP, + VK_DOWN, CTRL_DOWN, + VK_LEFT, CTRL_LEFT, + VK_RIGHT, CTRL_RIGHT, +}; +int KeyboardDevice::UpdateState() { + float analogX = 0; + float analogY = 0; + for (int i = 0; i < sizeof(key_ctrl_map)/sizeof(key_ctrl_map[0]); i += 2) { + if (!GetAsyncKeyState(key_ctrl_map[i])) + __CtrlButtonUp(key_ctrl_map[i+1]); + else { + __CtrlButtonDown(key_ctrl_map[i+1]); + switch (key_ctrl_map[i]) { + case VK_UP: + analogY -= .8f; + break; + case VK_DOWN: + analogY += .8f; + break; + case VK_LEFT: + analogX -= .8f; + break; + case VK_RIGHT: + analogX += .8f; + break; + } + } + } + __CtrlSetAnalog(analogX, analogY); + return 0; +} \ No newline at end of file diff --git a/Windows/KeyboardDevice.h b/Windows/KeyboardDevice.h new file mode 100644 index 0000000000..79d238348c --- /dev/null +++ b/Windows/KeyboardDevice.h @@ -0,0 +1,7 @@ +#pragma once +#include "InputDevice.h" + +class KeyboardDevice : public InputDevice { +public: + virtual int UpdateState(); +}; diff --git a/Windows/PPSSPP.vcxproj b/Windows/PPSSPP.vcxproj index 4a9074e9de..ea240ed01b 100644 --- a/Windows/PPSSPP.vcxproj +++ b/Windows/PPSSPP.vcxproj @@ -141,7 +141,7 @@ MultiThreadedDebugDLL - Winmm.lib;Ws2_32.lib;opengl32.lib;glu32.lib;comctl32.lib;dsound.lib;%(AdditionalDependencies) + Winmm.lib;Ws2_32.lib;opengl32.lib;glu32.lib;comctl32.lib;dsound.lib;xinput.lib;%(AdditionalDependencies) true $(OutDir)$(ProjectName).pdb Windows @@ -364,6 +364,8 @@ + + $(IntDir)%(Filename)2.obj @@ -390,6 +392,7 @@ Create Create + @@ -403,6 +406,8 @@ + + @@ -417,6 +422,7 @@ + diff --git a/Windows/PPSSPP.vcxproj.filters b/Windows/PPSSPP.vcxproj.filters index b7769f3b28..7df8759760 100644 --- a/Windows/PPSSPP.vcxproj.filters +++ b/Windows/PPSSPP.vcxproj.filters @@ -23,6 +23,9 @@ {d53d0871-8572-4393-822e-d14db0a88dab} + + {a1963305-bf88-43ef-8ba2-bb3933584b38} + @@ -92,6 +95,15 @@ Android + + Windows\Input + + + Windows\Input + + + Windows\Input + @@ -161,6 +173,15 @@ Android + + Windows\Input + + + Windows\Input + + + Windows\Input + diff --git a/Windows/WindowsHost.cpp b/Windows/WindowsHost.cpp index 580b1e12ec..1ae42e6b08 100644 --- a/Windows/WindowsHost.cpp +++ b/Windows/WindowsHost.cpp @@ -85,6 +85,9 @@ void WindowsHost::SetDebugMode(bool mode) void WindowsHost::BeginFrame() { + for (auto iter = this->input.begin(); iter != this->input.end(); iter++) + if ((*iter)->UpdateState() == 0) + break; // *iter is std::shared_ptr, **iter is InputDevice GL_BeginFrame(); } void WindowsHost::EndFrame() diff --git a/Windows/WindowsHost.h b/Windows/WindowsHost.h index 3e7728d552..adbb24a876 100644 --- a/Windows/WindowsHost.h +++ b/Windows/WindowsHost.h @@ -1,4 +1,7 @@ #include "../Core/Host.h" +#include "InputDevice.h" +#include +#include class WindowsHost : public Host { @@ -6,6 +9,7 @@ public: WindowsHost(HWND _displayWindow) { displayWindow = _displayWindow; + input = getInputDevices(); } void UpdateMemView(); void UpdateDisassembly(); @@ -30,4 +34,5 @@ public: private: HWND displayWindow; + std::list> input; }; \ No newline at end of file diff --git a/Windows/XinputDevice.cpp b/Windows/XinputDevice.cpp new file mode 100644 index 0000000000..3c1ac1041f --- /dev/null +++ b/Windows/XinputDevice.cpp @@ -0,0 +1,110 @@ +#include "stdafx.h" +#include "XinputDevice.h" +#include +#include + +XinputDevice::XinputDevice() { + ZeroMemory( &this->prevState, sizeof(this->prevState) ); + this->check_delay = 0; + this->gamepad_idx = -1; +} + +struct Stick { + float x; + float y; +}; +static Stick NormalizedDeadzoneFilter(XINPUT_STATE &state); + +int XinputDevice::UpdateState() { + if (this->check_delay-- > 0) return -1; + XINPUT_STATE state; + ZeroMemory( &state, sizeof(XINPUT_STATE) ); + + DWORD dwResult; + if (this->gamepad_idx >= 0) + dwResult = XInputGetState( this->gamepad_idx, &state ); + else { + // use the first gamepad that responds + for (int i = 0; i < XUSER_MAX_COUNT; i++) { + dwResult = XInputGetState( i, &state ); + if (dwResult == ERROR_SUCCESS) { + this->gamepad_idx = i; + break; + } + } + } + + if ( dwResult == ERROR_SUCCESS ) { + this->ApplyDiff(state); + Stick left = NormalizedDeadzoneFilter(state); + __CtrlSetAnalog(left.x, left.y); + this->prevState = state; + this->check_delay = 0; + return 0; + } else { + // wait check_delay frames before polling the controller again + this->gamepad_idx = -1; + this->check_delay = 100; + return -1; + } +} + +// We only filter the left stick since PSP has no analog triggers or right stick +static Stick NormalizedDeadzoneFilter(XINPUT_STATE &state) { + static const short DEADZONE = XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; + Stick left; + left.x = state.Gamepad.sThumbLX; + left.y = state.Gamepad.sThumbLY; + + float magnitude = sqrt(left.x*left.x + left.y*left.y); + + Stick norm; + norm.x = left.x / magnitude; + norm.y = left.y / magnitude; + + if (magnitude > DEADZONE) { + if (magnitude > 32767) magnitude = 32767; + // normalize the magnitude + magnitude -= DEADZONE; + magnitude /= (32767 - DEADZONE); + + // normalize the axis + left.x = norm.x * magnitude; + left.y = norm.y * magnitude; + } else + left.x = left.y = 0; + + return left; +} + +static const unsigned short xinput_ctrl_map[] = { + XINPUT_GAMEPAD_DPAD_UP, CTRL_UP, + XINPUT_GAMEPAD_DPAD_DOWN, CTRL_DOWN, + XINPUT_GAMEPAD_DPAD_LEFT, CTRL_LEFT, + XINPUT_GAMEPAD_DPAD_RIGHT, CTRL_RIGHT, + XINPUT_GAMEPAD_START, CTRL_START, + XINPUT_GAMEPAD_BACK, CTRL_SELECT, + XINPUT_GAMEPAD_LEFT_SHOULDER, CTRL_LTRIGGER, + XINPUT_GAMEPAD_RIGHT_SHOULDER, CTRL_RTRIGGER, + XINPUT_GAMEPAD_A, CTRL_CROSS, + XINPUT_GAMEPAD_B, CTRL_CIRCLE, + XINPUT_GAMEPAD_X, CTRL_SQUARE, + XINPUT_GAMEPAD_Y, CTRL_TRIANGLE, +}; +static inline u32 CtrlForXinput(int xinput) { + for (int i = 0; i < sizeof(xinput_ctrl_map)/sizeof(xinput_ctrl_map[0]); i += 2) + if (xinput_ctrl_map[i] == xinput) return (u32) xinput_ctrl_map[i+1]; + return 0; +} + +void XinputDevice::ApplyDiff(XINPUT_STATE &state) { + unsigned short pressed = state.Gamepad.wButtons & ~this->prevState.Gamepad.wButtons; + unsigned short released = ~state.Gamepad.wButtons & this->prevState.Gamepad.wButtons; + + for (int i = 1; i < USHRT_MAX; i <<= 1) { + if (pressed & i) + __CtrlButtonDown(CtrlForXinput(i)); + if (released & i) + __CtrlButtonUp(CtrlForXinput(i)); + } +} \ No newline at end of file diff --git a/Windows/XinputDevice.h b/Windows/XinputDevice.h new file mode 100644 index 0000000000..71a31becfe --- /dev/null +++ b/Windows/XinputDevice.h @@ -0,0 +1,17 @@ +#pragma once +#include "InputDevice.h" +#include "Xinput.h" + +class XinputDevice : + public InputDevice +{ +public: + XinputDevice(); + virtual int UpdateState(); +private: + void ApplyDiff(XINPUT_STATE &state); + int gamepad_idx; + int check_delay; + XINPUT_STATE prevState; +}; + diff --git a/test.py b/test.py index c086eebda8..ec12519053 100644 --- a/test.py +++ b/test.py @@ -31,6 +31,7 @@ tests_good = [ "string/string", "gpu/callbacks/ge_callbacks", "threads/mbx/mbx", + "threads/semaphores/semaphores", "power/power", "rtc/rtc", "umd/callbacks/umd", @@ -58,6 +59,14 @@ tests_next = [ "io/iodrv/iodrv", "malloc/malloc", "modules/loadexec/loader", + "threads/fpl/fpl", + "threads/msgpipe/msgpipe", + "threads/mutex/mutex", + "threads/scheduling/scheduling", + "threads/threads/threads", + "threads/vpl/vpl", + "threads/vtimers/vtimers", + "threads/wakeup/wakeup", "umd/io/umd_io", "umd/raw_access/raw_acess", "utility/systemparam/systemparam", @@ -68,9 +77,8 @@ tests_next = [ # These should be fixed, but currently hang or crash and are thus inconvenient to have # in the general test. tests_hang = [ - "audio/atrac/atractest", "threads/events/events", - "threads/semaphores/semaphores", + "audio/atrac/atractest", ] # These don't even run (or run correctly) on the real PSP