port input subsystem

This commit is contained in:
Arisotura 2024-05-23 18:50:29 +02:00
parent daf981e7c2
commit d50f01b774
16 changed files with 498 additions and 468 deletions

View File

@ -9,6 +9,7 @@ set(SOURCES_QT_SDL
Window.cpp Window.cpp
EmuInstance.cpp EmuInstance.cpp
EmuInstanceAudio.cpp EmuInstanceAudio.cpp
EmuInstanceInput.cpp
EmuThread.cpp EmuThread.cpp
CheatsDialog.cpp CheatsDialog.cpp
Config.cpp Config.cpp
@ -30,7 +31,6 @@ set(SOURCES_QT_SDL
ROMInfoDialog.cpp ROMInfoDialog.cpp
RAMInfoDialog.cpp RAMInfoDialog.cpp
TitleManagerDialog.cpp TitleManagerDialog.cpp
Input.cpp
LAN_PCap.cpp LAN_PCap.cpp
LAN_Socket.cpp LAN_Socket.cpp
LocalMP.cpp LocalMP.cpp

View File

@ -28,7 +28,7 @@
#include "Platform.h" #include "Platform.h"
#include "Config.h" #include "Config.h"
#include "FrontendUtil.h" #include "FrontendUtil.h"
#include "Screen.h" #include "main.h"
using namespace std::string_literals; using namespace std::string_literals;
@ -37,14 +37,6 @@ namespace Config
{ {
using namespace melonDS; using namespace melonDS;
int KeyMapping[12];
int JoyMapping[12];
int HKKeyMapping[HK_MAX];
int HKJoyMapping[HK_MAX];
int JoystickID;
int WindowWidth; int WindowWidth;
int WindowHeight; int WindowHeight;
bool WindowMaximized; bool WindowMaximized;

View File

@ -35,45 +35,6 @@ class value;
} }
#endif #endif
enum
{
HK_Lid = 0,
HK_Mic,
HK_Pause,
HK_Reset,
HK_FastForward,
HK_FastForwardToggle,
HK_FullscreenToggle,
HK_SwapScreens,
HK_SwapScreenEmphasis,
HK_SolarSensorDecrease,
HK_SolarSensorIncrease,
HK_FrameStep,
HK_PowerButton,
HK_VolumeUp,
HK_VolumeDown,
HK_MAX
};
enum
{
micInputType_Silence,
micInputType_External,
micInputType_Noise,
micInputType_Wav,
micInputType_MAX,
};
enum
{
renderer3D_Software = 0,
#ifdef OGLRENDERER_ENABLED
renderer3D_OpenGL,
renderer3D_OpenGLCompute,
#endif
renderer3D_Max,
};
namespace Config namespace Config
{ {
@ -188,14 +149,6 @@ private:
}; };
extern int KeyMapping[12];
extern int JoyMapping[12];
extern int HKKeyMapping[HK_MAX];
extern int HKJoyMapping[HK_MAX];
extern int JoystickID;
extern int WindowWidth; extern int WindowWidth;
extern int WindowHeight; extern int WindowHeight;
extern bool WindowMaximized; extern bool WindowMaximized;

View File

@ -72,6 +72,7 @@ EmuInstance::EmuInstance(int inst) : instanceID(inst),
updateConsole(nullptr, nullptr); updateConsole(nullptr, nullptr);
audioInit(); audioInit();
inputInit();
emuThread = new EmuThread(this); emuThread = new EmuThread(this);
@ -96,6 +97,7 @@ EmuInstance::~EmuInstance()
delete emuThread; delete emuThread;
audioDeInit(); audioDeInit();
inputDeInit();
} }

View File

@ -29,6 +29,48 @@
const int kMaxWindows = 16; const int kMaxWindows = 16;
enum
{
HK_Lid = 0,
HK_Mic,
HK_Pause,
HK_Reset,
HK_FastForward,
HK_FastForwardToggle,
HK_FullscreenToggle,
HK_SwapScreens,
HK_SwapScreenEmphasis,
HK_SolarSensorDecrease,
HK_SolarSensorIncrease,
HK_FrameStep,
HK_PowerButton,
HK_VolumeUp,
HK_VolumeDown,
HK_MAX
};
enum
{
micInputType_Silence,
micInputType_External,
micInputType_Noise,
micInputType_Wav,
micInputType_MAX,
};
enum
{
renderer3D_Software = 0,
#ifdef OGLRENDERER_ENABLED
renderer3D_OpenGL,
renderer3D_OpenGLCompute,
#endif
renderer3D_Max,
};
bool isRightModKey(QKeyEvent* event);
int getEventKeyVal(QKeyEvent* event);
class EmuInstance class EmuInstance
{ {
public: public:
@ -61,6 +103,17 @@ public:
melonDS::u32 (&animatedIconRef)[64][32*32], melonDS::u32 (&animatedIconRef)[64][32*32],
std::vector<int> &animatedSequenceRef); std::vector<int> &animatedSequenceRef);
static const char* buttonNames[12];
static const char* hotkeyNames[HK_MAX];
void inputInit();
void inputDeInit();
void inputLoadConfig();
void setJoystick(int id);
int getJoystickID() { return joystickID; }
SDL_Joystick* getJoystick() { return joystick; }
private: private:
static int lastSep(const std::string& path); static int lastSep(const std::string& path);
std::string getAssetPath(bool gba, const std::string& configpath, const std::string& ext, const std::string& file); std::string getAssetPath(bool gba, const std::string& configpath, const std::string& ext, const std::string& file);
@ -130,6 +183,20 @@ private:
static void audioCallback(void* data, Uint8* stream, int len); static void audioCallback(void* data, Uint8* stream, int len);
static void micCallback(void* data, Uint8* stream, int len); static void micCallback(void* data, Uint8* stream, int len);
void onKeyPress(QKeyEvent* event);
void onKeyRelease(QKeyEvent* event);
void keyReleaseAll();
void openJoystick();
void closeJoystick();
bool joystickButtonDown(int val);
void inputProcess();
bool hotkeyDown(int id) { return hotkeyMask & (1<<id); }
bool hotkeyPressed(int id) { return hotkeyPress & (1<<id); }
bool hotkeyReleased(int id) { return hotkeyRelease & (1<<id); }
int instanceID; int instanceID;
EmuThread* emuThread; EmuThread* emuThread;
@ -192,6 +259,21 @@ private:
std::string micDeviceName; std::string micDeviceName;
std::string micWavPath; std::string micWavPath;
int keyMapping[12];
int joyMapping[12];
int hkKeyMapping[HK_MAX];
int hkJoyMapping[HK_MAX];
int joystickID;
SDL_Joystick* joystick;
melonDS::u32 keyInputMask, joyInputMask;
melonDS::u32 keyHotkeyMask, joyHotkeyMask;
melonDS::u32 hotkeyMask, lastHotkeyMask;
melonDS::u32 hotkeyPress, hotkeyRelease;
melonDS::u32 inputMask;
friend class EmuThread; friend class EmuThread;
friend class MainWindow; friend class MainWindow;
}; };

View File

@ -20,7 +20,6 @@
#include "NDS.h" #include "NDS.h"
#include "SPU.h" #include "SPU.h"
#include "Platform.h" #include "Platform.h"
#include "Input.h"
#include "main.h" #include "main.h"
#include "mic_blow.h" #include "mic_blow.h"
@ -265,7 +264,7 @@ void EmuInstance::micLoadWav(const std::string& name)
void EmuInstance::micProcess() void EmuInstance::micProcess()
{ {
int type = micInputType; int type = micInputType;
bool cmd = Input::HotkeyDown(HK_Mic); bool cmd = hotkeyDown(HK_Mic);
if (type != micInputType_External && !cmd) if (type != micInputType_External && !cmd)
{ {

View File

@ -0,0 +1,307 @@
/*
Copyright 2016-2023 melonDS team
This file is part of melonDS.
melonDS is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option)
any later version.
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with melonDS. If not, see http://www.gnu.org/licenses/.
*/
#include <QKeyEvent>
#include <SDL2/SDL.h>
#include "main.h"
#include "Config.h"
using namespace melonDS;
const char* EmuInstance::buttonNames[12] =
{
"A",
"B",
"Select",
"Start",
"Right",
"Left",
"Up",
"Down",
"R",
"L",
"X",
"Y"
};
const char* EmuInstance::hotkeyNames[HK_MAX] =
{
"HK_Lid",
"HK_Mic",
"HK_Pause",
"HK_Reset",
"HK_FastForward",
"HK_FastForwardToggle",
"HK_FullscreenToggle",
"HK_SwapScreens",
"HK_SwapScreenEmphasis",
"HK_SolarSensorDecrease",
"HK_SolarSensorIncrease",
"HK_FrameStep",
"HK_PowerButton",
"HK_VolumeUp",
"HK_VolumeDown"
};
void EmuInstance::inputInit()
{
keyInputMask = 0xFFF;
joyInputMask = 0xFFF;
inputMask = 0xFFF;
keyHotkeyMask = 0;
joyHotkeyMask = 0;
hotkeyMask = 0;
lastHotkeyMask = 0;
joystick = nullptr;
inputLoadConfig();
}
void EmuInstance::inputDeInit()
{
closeJoystick();
}
void EmuInstance::inputLoadConfig()
{
Config::Table keycfg = localCfg.GetTable("Keyboard");
Config::Table joycfg = localCfg.GetTable("Joystick");
for (int i = 0; i < 12; i++)
{
keyMapping[i] = keycfg.GetInt(buttonNames[i]);
joyMapping[i] = joycfg.GetInt(buttonNames[i]);
}
for (int i = 0; i < HK_MAX; i++)
{
hkKeyMapping[i] = keycfg.GetInt(hotkeyNames[i]);
hkJoyMapping[i] = joycfg.GetInt(hotkeyNames[i]);
}
setJoystick(localCfg.GetInt("JoystickID"));
}
void EmuInstance::setJoystick(int id)
{
joystickID = id;
openJoystick();
}
void EmuInstance::openJoystick()
{
if (joystick) SDL_JoystickClose(joystick);
int num = SDL_NumJoysticks();
if (num < 1)
{
joystick = nullptr;
return;
}
if (joystickID >= num)
joystickID = 0;
joystick = SDL_JoystickOpen(joystickID);
}
void EmuInstance::closeJoystick()
{
if (joystick)
{
SDL_JoystickClose(joystick);
joystick = nullptr;
}
}
// distinguish between left and right modifier keys (Ctrl, Alt, Shift)
// Qt provides no real cross-platform way to do this, so here we go
// for Windows and Linux we can distinguish via scancodes (but both
// provide different scancodes)
bool isRightModKey(QKeyEvent* event)
{
#ifdef __WIN32__
quint32 scan = event->nativeScanCode();
return (scan == 0x11D || scan == 0x138 || scan == 0x36);
#elif __APPLE__
quint32 scan = event->nativeVirtualKey();
return (scan == 0x36 || scan == 0x3C || scan == 0x3D || scan == 0x3E);
#else
quint32 scan = event->nativeScanCode();
return (scan == 0x69 || scan == 0x6C || scan == 0x3E);
#endif
}
int getEventKeyVal(QKeyEvent* event)
{
int key = event->key();
int mod = event->modifiers();
bool ismod = (key == Qt::Key_Control ||
key == Qt::Key_Alt ||
key == Qt::Key_AltGr ||
key == Qt::Key_Shift ||
key == Qt::Key_Meta);
if (!ismod)
key |= mod;
else if (isRightModKey(event))
key |= (1<<31);
return key;
}
void EmuInstance::onKeyPress(QKeyEvent* event)
{
int keyHK = getEventKeyVal(event);
int keyKP = keyHK;
if (event->modifiers() != Qt::KeypadModifier)
keyKP &= ~event->modifiers();
for (int i = 0; i < 12; i++)
if (keyKP == keyMapping[i])
keyInputMask &= ~(1<<i);
for (int i = 0; i < HK_MAX; i++)
if (keyHK == hkKeyMapping[i])
keyHotkeyMask |= (1<<i);
}
void EmuInstance::onKeyRelease(QKeyEvent* event)
{
int keyHK = getEventKeyVal(event);
int keyKP = keyHK;
if (event->modifiers() != Qt::KeypadModifier)
keyKP &= ~event->modifiers();
for (int i = 0; i < 12; i++)
if (keyKP == keyMapping[i])
keyInputMask |= (1<<i);
for (int i = 0; i < HK_MAX; i++)
if (keyHK == hkKeyMapping[i])
keyHotkeyMask &= ~(1<<i);
}
void EmuInstance::keyReleaseAll()
{
keyInputMask = 0xFFF;
keyHotkeyMask = 0;
}
bool EmuInstance::joystickButtonDown(int val)
{
if (val == -1) return false;
bool hasbtn = ((val & 0xFFFF) != 0xFFFF);
if (hasbtn)
{
if (val & 0x100)
{
int hatnum = (val >> 4) & 0xF;
int hatdir = val & 0xF;
Uint8 hatval = SDL_JoystickGetHat(joystick, hatnum);
bool pressed = false;
if (hatdir == 0x1) pressed = (hatval & SDL_HAT_UP);
else if (hatdir == 0x4) pressed = (hatval & SDL_HAT_DOWN);
else if (hatdir == 0x2) pressed = (hatval & SDL_HAT_RIGHT);
else if (hatdir == 0x8) pressed = (hatval & SDL_HAT_LEFT);
if (pressed) return true;
}
else
{
int btnnum = val & 0xFFFF;
Uint8 btnval = SDL_JoystickGetButton(joystick, btnnum);
if (btnval) return true;
}
}
if (val & 0x10000)
{
int axisnum = (val >> 24) & 0xF;
int axisdir = (val >> 20) & 0xF;
Sint16 axisval = SDL_JoystickGetAxis(joystick, axisnum);
switch (axisdir)
{
case 0: // positive
if (axisval > 16384) return true;
break;
case 1: // negative
if (axisval < -16384) return true;
break;
case 2: // trigger
if (axisval > 0) return true;
break;
}
}
return false;
}
void EmuInstance::inputProcess()
{
SDL_JoystickUpdate();
if (joystick)
{
if (!SDL_JoystickGetAttached(joystick))
{
SDL_JoystickClose(joystick);
joystick = nullptr;
}
}
if (!joystick && (SDL_NumJoysticks() > 0))
{
openJoystick();
}
joyInputMask = 0xFFF;
if (joystick)
{
for (int i = 0; i < 12; i++)
if (joystickButtonDown(joyMapping[i]))
joyInputMask &= ~(1 << i);
}
inputMask = keyInputMask & joyInputMask;
joyHotkeyMask = 0;
if (joystick)
{
for (int i = 0; i < HK_MAX; i++)
if (joystickButtonDown(hkJoyMapping[i]))
joyHotkeyMask |= (1 << i);
}
hotkeyMask = keyHotkeyMask | joyHotkeyMask;
hotkeyPress = hotkeyMask & ~lastHotkeyMask;
hotkeyRelease = lastHotkeyMask & ~hotkeyMask;
lastHotkeyMask = hotkeyMask;
}

View File

@ -29,7 +29,6 @@
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include "main.h" #include "main.h"
#include "Input.h"
#include "types.h" #include "types.h"
#include "version.h" #include "version.h"
@ -172,8 +171,6 @@ void EmuThread::run()
updateRenderer(); updateRenderer();
Input::Init();
u32 nframes = 0; u32 nframes = 0;
double perfCountsSec = 1.0 / SDL_GetPerformanceFrequency(); double perfCountsSec = 1.0 / SDL_GetPerformanceFrequency();
double lastTime = SDL_GetPerformanceCounter() * perfCountsSec; double lastTime = SDL_GetPerformanceCounter() * perfCountsSec;
@ -196,25 +193,25 @@ void EmuThread::run()
while (EmuRunning != emuStatus_Exit) while (EmuRunning != emuStatus_Exit)
{ {
Input::Process(); emuInstance->inputProcess();
if (Input::HotkeyPressed(HK_FastForwardToggle)) emit windowLimitFPSChange(); if (emuInstance->hotkeyPressed(HK_FastForwardToggle)) emit windowLimitFPSChange();
if (Input::HotkeyPressed(HK_Pause)) emit windowEmuPause(); if (emuInstance->hotkeyPressed(HK_Pause)) emit windowEmuPause();
if (Input::HotkeyPressed(HK_Reset)) emit windowEmuReset(); if (emuInstance->hotkeyPressed(HK_Reset)) emit windowEmuReset();
if (Input::HotkeyPressed(HK_FrameStep)) emit windowEmuFrameStep(); if (emuInstance->hotkeyPressed(HK_FrameStep)) emit windowEmuFrameStep();
if (Input::HotkeyPressed(HK_FullscreenToggle)) emit windowFullscreenToggle(); if (emuInstance->hotkeyPressed(HK_FullscreenToggle)) emit windowFullscreenToggle();
if (Input::HotkeyPressed(HK_SwapScreens)) emit swapScreensToggle(); if (emuInstance->hotkeyPressed(HK_SwapScreens)) emit swapScreensToggle();
if (Input::HotkeyPressed(HK_SwapScreenEmphasis)) emit screenEmphasisToggle(); if (emuInstance->hotkeyPressed(HK_SwapScreenEmphasis)) emit screenEmphasisToggle();
if (EmuRunning == emuStatus_Running || EmuRunning == emuStatus_FrameStep) if (EmuRunning == emuStatus_Running || EmuRunning == emuStatus_FrameStep)
{ {
EmuStatus = emuStatus_Running; EmuStatus = emuStatus_Running;
if (EmuRunning == emuStatus_FrameStep) EmuRunning = emuStatus_Paused; if (EmuRunning == emuStatus_FrameStep) EmuRunning = emuStatus_Paused;
if (Input::HotkeyPressed(HK_SolarSensorDecrease)) if (emuInstance->hotkeyPressed(HK_SolarSensorDecrease))
{ {
int level = emuInstance->nds->GBACartSlot.SetInput(GBACart::Input_SolarSensorDown, true); int level = emuInstance->nds->GBACartSlot.SetInput(GBACart::Input_SolarSensorDown, true);
if (level != -1) if (level != -1)
@ -222,7 +219,7 @@ void EmuThread::run()
//mainWindow->osdAddMessage(0, "Solar sensor level: %d", level); //mainWindow->osdAddMessage(0, "Solar sensor level: %d", level);
} }
} }
if (Input::HotkeyPressed(HK_SolarSensorIncrease)) if (emuInstance->hotkeyPressed(HK_SolarSensorIncrease))
{ {
int level = emuInstance->nds->GBACartSlot.SetInput(GBACart::Input_SolarSensorUp, true); int level = emuInstance->nds->GBACartSlot.SetInput(GBACart::Input_SolarSensorUp, true);
if (level != -1) if (level != -1)
@ -237,30 +234,30 @@ void EmuThread::run()
double currentTime = SDL_GetPerformanceCounter() * perfCountsSec; double currentTime = SDL_GetPerformanceCounter() * perfCountsSec;
// Handle power button // Handle power button
if (Input::HotkeyDown(HK_PowerButton)) if (emuInstance->hotkeyDown(HK_PowerButton))
{ {
dsi->I2C.GetBPTWL()->SetPowerButtonHeld(currentTime); dsi->I2C.GetBPTWL()->SetPowerButtonHeld(currentTime);
} }
else if (Input::HotkeyReleased(HK_PowerButton)) else if (emuInstance->hotkeyReleased(HK_PowerButton))
{ {
dsi->I2C.GetBPTWL()->SetPowerButtonReleased(currentTime); dsi->I2C.GetBPTWL()->SetPowerButtonReleased(currentTime);
} }
// Handle volume buttons // Handle volume buttons
if (Input::HotkeyDown(HK_VolumeUp)) if (emuInstance->hotkeyDown(HK_VolumeUp))
{ {
dsi->I2C.GetBPTWL()->SetVolumeSwitchHeld(DSi_BPTWL::volumeKey_Up); dsi->I2C.GetBPTWL()->SetVolumeSwitchHeld(DSi_BPTWL::volumeKey_Up);
} }
else if (Input::HotkeyReleased(HK_VolumeUp)) else if (emuInstance->hotkeyReleased(HK_VolumeUp))
{ {
dsi->I2C.GetBPTWL()->SetVolumeSwitchReleased(DSi_BPTWL::volumeKey_Up); dsi->I2C.GetBPTWL()->SetVolumeSwitchReleased(DSi_BPTWL::volumeKey_Up);
} }
if (Input::HotkeyDown(HK_VolumeDown)) if (emuInstance->hotkeyDown(HK_VolumeDown))
{ {
dsi->I2C.GetBPTWL()->SetVolumeSwitchHeld(DSi_BPTWL::volumeKey_Down); dsi->I2C.GetBPTWL()->SetVolumeSwitchHeld(DSi_BPTWL::volumeKey_Down);
} }
else if (Input::HotkeyReleased(HK_VolumeDown)) else if (emuInstance->hotkeyReleased(HK_VolumeDown))
{ {
dsi->I2C.GetBPTWL()->SetVolumeSwitchReleased(DSi_BPTWL::volumeKey_Down); dsi->I2C.GetBPTWL()->SetVolumeSwitchReleased(DSi_BPTWL::volumeKey_Down);
} }
@ -275,7 +272,7 @@ void EmuThread::run()
// HACK: // HACK:
// once the fast forward hotkey is released, we need to update vsync // once the fast forward hotkey is released, we need to update vsync
// to the old setting again // to the old setting again
if (videoSettingsDirty || Input::HotkeyReleased(HK_FastForward)) if (videoSettingsDirty || emuInstance->hotkeyReleased(HK_FastForward))
{ {
if (useOpenGL) if (useOpenGL)
{ {
@ -297,9 +294,9 @@ void EmuThread::run()
} }
// process input and hotkeys // process input and hotkeys
emuInstance->nds->SetKeyMask(Input::InputMask); emuInstance->nds->SetKeyMask(emuInstance->inputMask);
if (Input::HotkeyPressed(HK_Lid)) if (emuInstance->hotkeyPressed(HK_Lid))
{ {
bool lid = !emuInstance->nds->IsLidClosed(); bool lid = !emuInstance->nds->IsLidClosed();
emuInstance->nds->SetLidClosed(lid); emuInstance->nds->SetLidClosed(lid);
@ -388,7 +385,7 @@ void EmuThread::run()
winUpdateCount = 0; winUpdateCount = 0;
} }
bool fastforward = Input::HotkeyDown(HK_FastForward); bool fastforward = emuInstance->hotkeyDown(HK_FastForward);
if (fastforward && useOpenGL && Config::ScreenVSync) if (fastforward && useOpenGL && Config::ScreenVSync)
{ {

View File

@ -1,265 +0,0 @@
/*
Copyright 2016-2023 melonDS team
This file is part of melonDS.
melonDS is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option)
any later version.
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with melonDS. If not, see http://www.gnu.org/licenses/.
*/
#include <QKeyEvent>
#include <SDL2/SDL.h>
#include "Input.h"
#include "Config.h"
using namespace melonDS;
namespace Input
{
int JoystickID;
SDL_Joystick* Joystick = nullptr;
u32 KeyInputMask, JoyInputMask;
u32 KeyHotkeyMask, JoyHotkeyMask;
u32 HotkeyMask, LastHotkeyMask;
u32 HotkeyPress, HotkeyRelease;
u32 InputMask;
void Init()
{
KeyInputMask = 0xFFF;
JoyInputMask = 0xFFF;
InputMask = 0xFFF;
KeyHotkeyMask = 0;
JoyHotkeyMask = 0;
HotkeyMask = 0;
LastHotkeyMask = 0;
}
void OpenJoystick()
{
if (Joystick) SDL_JoystickClose(Joystick);
int num = SDL_NumJoysticks();
if (num < 1)
{
Joystick = nullptr;
return;
}
if (JoystickID >= num)
JoystickID = 0;
Joystick = SDL_JoystickOpen(JoystickID);
}
void CloseJoystick()
{
if (Joystick)
{
SDL_JoystickClose(Joystick);
Joystick = nullptr;
}
}
int GetEventKeyVal(QKeyEvent* event)
{
int key = event->key();
int mod = event->modifiers();
bool ismod = (key == Qt::Key_Control ||
key == Qt::Key_Alt ||
key == Qt::Key_AltGr ||
key == Qt::Key_Shift ||
key == Qt::Key_Meta);
if (!ismod)
key |= mod;
else if (Input::IsRightModKey(event))
key |= (1<<31);
return key;
}
void KeyPress(QKeyEvent* event)
{
int keyHK = GetEventKeyVal(event);
int keyKP = keyHK;
if (event->modifiers() != Qt::KeypadModifier)
keyKP &= ~event->modifiers();
for (int i = 0; i < 12; i++)
if (keyKP == Config::KeyMapping[i])
KeyInputMask &= ~(1<<i);
for (int i = 0; i < HK_MAX; i++)
if (keyHK == Config::HKKeyMapping[i])
KeyHotkeyMask |= (1<<i);
}
void KeyRelease(QKeyEvent* event)
{
int keyHK = GetEventKeyVal(event);
int keyKP = keyHK;
if (event->modifiers() != Qt::KeypadModifier)
keyKP &= ~event->modifiers();
for (int i = 0; i < 12; i++)
if (keyKP == Config::KeyMapping[i])
KeyInputMask |= (1<<i);
for (int i = 0; i < HK_MAX; i++)
if (keyHK == Config::HKKeyMapping[i])
KeyHotkeyMask &= ~(1<<i);
}
void KeyReleaseAll()
{
KeyInputMask = 0xFFF;
KeyHotkeyMask = 0;
}
bool JoystickButtonDown(int val)
{
if (val == -1) return false;
bool hasbtn = ((val & 0xFFFF) != 0xFFFF);
if (hasbtn)
{
if (val & 0x100)
{
int hatnum = (val >> 4) & 0xF;
int hatdir = val & 0xF;
Uint8 hatval = SDL_JoystickGetHat(Joystick, hatnum);
bool pressed = false;
if (hatdir == 0x1) pressed = (hatval & SDL_HAT_UP);
else if (hatdir == 0x4) pressed = (hatval & SDL_HAT_DOWN);
else if (hatdir == 0x2) pressed = (hatval & SDL_HAT_RIGHT);
else if (hatdir == 0x8) pressed = (hatval & SDL_HAT_LEFT);
if (pressed) return true;
}
else
{
int btnnum = val & 0xFFFF;
Uint8 btnval = SDL_JoystickGetButton(Joystick, btnnum);
if (btnval) return true;
}
}
if (val & 0x10000)
{
int axisnum = (val >> 24) & 0xF;
int axisdir = (val >> 20) & 0xF;
Sint16 axisval = SDL_JoystickGetAxis(Joystick, axisnum);
switch (axisdir)
{
case 0: // positive
if (axisval > 16384) return true;
break;
case 1: // negative
if (axisval < -16384) return true;
break;
case 2: // trigger
if (axisval > 0) return true;
break;
}
}
return false;
}
void Process()
{
SDL_JoystickUpdate();
if (Joystick)
{
if (!SDL_JoystickGetAttached(Joystick))
{
SDL_JoystickClose(Joystick);
Joystick = NULL;
}
}
if (!Joystick && (SDL_NumJoysticks() > 0))
{
JoystickID = Config::JoystickID;
OpenJoystick();
}
JoyInputMask = 0xFFF;
if (Joystick)
{
for (int i = 0; i < 12; i++)
if (JoystickButtonDown(Config::JoyMapping[i]))
JoyInputMask &= ~(1 << i);
}
InputMask = KeyInputMask & JoyInputMask;
JoyHotkeyMask = 0;
if (Joystick)
{
for (int i = 0; i < HK_MAX; i++)
if (JoystickButtonDown(Config::HKJoyMapping[i]))
JoyHotkeyMask |= (1 << i);
}
HotkeyMask = KeyHotkeyMask | JoyHotkeyMask;
HotkeyPress = HotkeyMask & ~LastHotkeyMask;
HotkeyRelease = LastHotkeyMask & ~HotkeyMask;
LastHotkeyMask = HotkeyMask;
}
bool HotkeyDown(int id) { return HotkeyMask & (1<<id); }
bool HotkeyPressed(int id) { return HotkeyPress & (1<<id); }
bool HotkeyReleased(int id) { return HotkeyRelease & (1<<id); }
// distinguish between left and right modifier keys (Ctrl, Alt, Shift)
// Qt provides no real cross-platform way to do this, so here we go
// for Windows and Linux we can distinguish via scancodes (but both
// provide different scancodes)
#ifdef __WIN32__
bool IsRightModKey(QKeyEvent* event)
{
quint32 scan = event->nativeScanCode();
return (scan == 0x11D || scan == 0x138 || scan == 0x36);
}
#elif __APPLE__
bool IsRightModKey(QKeyEvent* event)
{
quint32 scan = event->nativeVirtualKey();
return (scan == 0x36 || scan == 0x3C || scan == 0x3D || scan == 0x3E);
}
#else
bool IsRightModKey(QKeyEvent* event)
{
quint32 scan = event->nativeScanCode();
return (scan == 0x69 || scan == 0x6C || scan == 0x3E);
}
#endif
}

View File

@ -1,56 +0,0 @@
/*
Copyright 2016-2023 melonDS team
This file is part of melonDS.
melonDS is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option)
any later version.
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with melonDS. If not, see http://www.gnu.org/licenses/.
*/
#ifndef INPUT_H
#define INPUT_H
#include <SDL2/SDL.h>
#include <QKeyEvent>
#include "types.h"
namespace Input
{
using namespace melonDS;
extern int JoystickID;
extern SDL_Joystick* Joystick;
extern u32 InputMask;
void Init();
// set joystickID before calling openJoystick()
void OpenJoystick();
void CloseJoystick();
void KeyPress(QKeyEvent* event);
void KeyRelease(QKeyEvent* event);
void KeyReleaseAll();
void Process();
bool HotkeyDown(int id);
bool HotkeyPressed(int id);
bool HotkeyReleased(int id);
bool IsRightModKey(QKeyEvent* event);
}
#endif // INPUT_H

View File

@ -26,10 +26,9 @@
#include "types.h" #include "types.h"
#include "Platform.h" #include "Platform.h"
#include "MapButton.h"
#include "Input.h"
#include "InputConfigDialog.h" #include "InputConfigDialog.h"
#include "ui_InputConfigDialog.h" #include "ui_InputConfigDialog.h"
#include "MapButton.h"
using namespace melonDS; using namespace melonDS;
@ -43,31 +42,42 @@ InputConfigDialog::InputConfigDialog(QWidget* parent) : QDialog(parent), ui(new
ui->setupUi(this); ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose); setAttribute(Qt::WA_DeleteOnClose);
emuInstance = ((MainWindow*)parent)->getEmuInstance();
Config::Table& instcfg = emuInstance->getLocalConfig();
Config::Table keycfg = instcfg.GetTable("Keyboard");
Config::Table joycfg = instcfg.GetTable("Joystick");
for (int i = 0; i < keypad_num; i++) for (int i = 0; i < keypad_num; i++)
{ {
keypadKeyMap[i] = Config::KeyMapping[dskeyorder[i]]; const char* btn = EmuInstance::buttonNames[dskeyorder[i]];
keypadJoyMap[i] = Config::JoyMapping[dskeyorder[i]]; keypadKeyMap[i] = keycfg.GetInt(btn);
keypadJoyMap[i] = joycfg.GetInt(btn);
} }
int i = 0; int i = 0;
for (int hotkey : hk_addons) for (int hotkey : hk_addons)
{ {
addonsKeyMap[i] = Config::HKKeyMapping[hotkey]; const char* btn = EmuInstance::hotkeyNames[hotkey];
addonsJoyMap[i] = Config::HKJoyMapping[hotkey]; addonsKeyMap[i] = keycfg.GetInt(btn);
addonsJoyMap[i] = joycfg.GetInt(btn);
i++; i++;
} }
i = 0; i = 0;
for (int hotkey : hk_general) for (int hotkey : hk_general)
{ {
hkGeneralKeyMap[i] = Config::HKKeyMapping[hotkey]; const char* btn = EmuInstance::hotkeyNames[hotkey];
hkGeneralJoyMap[i] = Config::HKJoyMapping[hotkey]; hkGeneralKeyMap[i] = keycfg.GetInt(btn);
hkGeneralJoyMap[i] = joycfg.GetInt(btn);
i++; i++;
} }
populatePage(ui->tabAddons, hk_addons_labels, addonsKeyMap, addonsJoyMap); populatePage(ui->tabAddons, hk_addons_labels, addonsKeyMap, addonsJoyMap);
populatePage(ui->tabHotkeysGeneral, hk_general_labels, hkGeneralKeyMap, hkGeneralJoyMap); populatePage(ui->tabHotkeysGeneral, hk_general_labels, hkGeneralKeyMap, hkGeneralJoyMap);
joystickID = instcfg.GetInt("JoystickID");
int njoy = SDL_NumJoysticks(); int njoy = SDL_NumJoysticks();
if (njoy > 0) if (njoy > 0)
{ {
@ -76,7 +86,7 @@ InputConfigDialog::InputConfigDialog(QWidget* parent) : QDialog(parent), ui(new
const char* name = SDL_JoystickNameForIndex(i); const char* name = SDL_JoystickNameForIndex(i);
ui->cbxJoystick->addItem(QString(name)); ui->cbxJoystick->addItem(QString(name));
} }
ui->cbxJoystick->setCurrentIndex(Input::JoystickID); ui->cbxJoystick->setCurrentIndex(joystickID);
} }
else else
{ {
@ -86,7 +96,7 @@ InputConfigDialog::InputConfigDialog(QWidget* parent) : QDialog(parent), ui(new
setupKeypadPage(); setupKeypadPage();
int inst = Platform::InstanceID(); int inst = emuInstance->getInstanceID();
if (inst > 0) if (inst > 0)
ui->lblInstanceNum->setText(QString("Configuring mappings for instance %1").arg(inst+1)); ui->lblInstanceNum->setText(QString("Configuring mappings for instance %1").arg(inst+1));
else else
@ -174,38 +184,47 @@ void InputConfigDialog::populatePage(QWidget* page,
void InputConfigDialog::on_InputConfigDialog_accepted() void InputConfigDialog::on_InputConfigDialog_accepted()
{ {
Config::Table& instcfg = emuInstance->getLocalConfig();
Config::Table keycfg = instcfg.GetTable("Keyboard");
Config::Table joycfg = instcfg.GetTable("Joystick");
for (int i = 0; i < keypad_num; i++) for (int i = 0; i < keypad_num; i++)
{ {
Config::KeyMapping[dskeyorder[i]] = keypadKeyMap[i]; const char* btn = EmuInstance::buttonNames[dskeyorder[i]];
Config::JoyMapping[dskeyorder[i]] = keypadJoyMap[i]; keycfg.SetInt(btn, keypadKeyMap[i]);
joycfg.SetInt(btn, keypadJoyMap[i]);
} }
int i = 0; int i = 0;
for (int hotkey : hk_addons) for (int hotkey : hk_addons)
{ {
Config::HKKeyMapping[hotkey] = addonsKeyMap[i]; const char* btn = EmuInstance::hotkeyNames[hotkey];
Config::HKJoyMapping[hotkey] = addonsJoyMap[i]; keycfg.SetInt(btn, addonsKeyMap[i]);
joycfg.SetInt(btn, addonsJoyMap[i]);
i++; i++;
} }
i = 0; i = 0;
for (int hotkey : hk_general) for (int hotkey : hk_general)
{ {
Config::HKKeyMapping[hotkey] = hkGeneralKeyMap[i]; const char* btn = EmuInstance::hotkeyNames[hotkey];
Config::HKJoyMapping[hotkey] = hkGeneralJoyMap[i]; keycfg.SetInt(btn, hkGeneralKeyMap[i]);
joycfg.SetInt(btn, hkGeneralJoyMap[i]);
i++; i++;
} }
Config::JoystickID = Input::JoystickID; instcfg.SetInt("JoystickID", joystickID);
Config::Save(); Config::Save();
emuInstance->inputLoadConfig();
closeDlg(); closeDlg();
} }
void InputConfigDialog::on_InputConfigDialog_rejected() void InputConfigDialog::on_InputConfigDialog_rejected()
{ {
Input::JoystickID = Config::JoystickID; Config::Table& instcfg = emuInstance->getLocalConfig();
Input::OpenJoystick(); emuInstance->setJoystick(instcfg.GetInt("JoystickID"));
closeDlg(); closeDlg();
} }
@ -225,6 +244,11 @@ void InputConfigDialog::on_cbxJoystick_currentIndexChanged(int id)
// prevent a spurious change // prevent a spurious change
if (ui->cbxJoystick->count() < 2) return; if (ui->cbxJoystick->count() < 2) return;
Input::JoystickID = id; joystickID = id;
Input::OpenJoystick(); emuInstance->setJoystick(id);
}
SDL_Joystick* InputConfigDialog::getJoystick()
{
return emuInstance->getJoystick();
} }

View File

@ -24,6 +24,7 @@
#include <initializer_list> #include <initializer_list>
#include "Config.h" #include "Config.h"
#include "EmuInstance.h"
static constexpr int keypad_num = 12; static constexpr int keypad_num = 12;
@ -89,6 +90,8 @@ public:
explicit InputConfigDialog(QWidget* parent); explicit InputConfigDialog(QWidget* parent);
~InputConfigDialog(); ~InputConfigDialog();
SDL_Joystick* getJoystick();
static InputConfigDialog* currentDlg; static InputConfigDialog* currentDlg;
static InputConfigDialog* openDlg(QWidget* parent) static InputConfigDialog* openDlg(QWidget* parent)
{ {
@ -123,9 +126,12 @@ private:
Ui::InputConfigDialog* ui; Ui::InputConfigDialog* ui;
EmuInstance* emuInstance;
int keypadKeyMap[12], keypadJoyMap[12]; int keypadKeyMap[12], keypadJoyMap[12];
int addonsKeyMap[hk_addons.size()], addonsJoyMap[hk_addons.size()]; int addonsKeyMap[hk_addons.size()], addonsJoyMap[hk_addons.size()];
int hkGeneralKeyMap[hk_general.size()], hkGeneralJoyMap[hk_general.size()]; int hkGeneralKeyMap[hk_general.size()], hkGeneralJoyMap[hk_general.size()];
int joystickID;
}; };

View File

@ -23,8 +23,10 @@
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include "Input.h"
#include "Platform.h" #include "Platform.h"
#include "EmuInstance.h"
class InputConfigDialog;
class KeyMapButton : public QPushButton class KeyMapButton : public QPushButton
{ {
@ -76,7 +78,7 @@ protected:
if (!ismod) if (!ismod)
key |= mod; key |= mod;
else if (Input::IsRightModKey(event)) else if (isRightModKey(event))
key |= (1<<31); key |= (1<<31);
*mapping = key; *mapping = key;
@ -162,6 +164,9 @@ public:
this->mapping = mapping; this->mapping = mapping;
this->isHotkey = hotkey; this->isHotkey = hotkey;
// the parent will be set later when this button is added to a layout
parentDialog = nullptr;
setCheckable(true); setCheckable(true);
setText(mappingText()); setText(mappingText());
setFocusPolicy(Qt::StrongFocus); //Fixes binding keys in macOS setFocusPolicy(Qt::StrongFocus); //Fixes binding keys in macOS
@ -176,6 +181,20 @@ public:
} }
protected: protected:
void showEvent(QShowEvent* event) override
{
if (event->spontaneous()) return;
QWidget* w = parentWidget();
for (;;)
{
parentDialog = qobject_cast<InputConfigDialog*>(w);
if (parentDialog) break;
w = w->parentWidget();
if (!w) break;
}
}
void keyPressEvent(QKeyEvent* event) override void keyPressEvent(QKeyEvent* event) override
{ {
if (!isChecked()) return QPushButton::keyPressEvent(event); if (!isChecked()) return QPushButton::keyPressEvent(event);
@ -203,7 +222,7 @@ protected:
void timerEvent(QTimerEvent* event) override void timerEvent(QTimerEvent* event) override
{ {
SDL_Joystick* joy = Input::Joystick; SDL_Joystick* joy = parentDialog->getJoystick();
if (!joy) { click(); return; } if (!joy) { click(); return; }
if (!SDL_JoystickGetAttached(joy)) { click(); return; } if (!SDL_JoystickGetAttached(joy)) { click(); return; }
@ -279,13 +298,15 @@ private slots:
timerID = startTimer(50); timerID = startTimer(50);
memset(axesRest, 0, sizeof(axesRest)); memset(axesRest, 0, sizeof(axesRest));
if (Input::Joystick && SDL_JoystickGetAttached(Input::Joystick))
SDL_Joystick* joy = parentDialog->getJoystick();
if (joy && SDL_JoystickGetAttached(joy))
{ {
int naxes = SDL_JoystickNumAxes(Input::Joystick); int naxes = SDL_JoystickNumAxes(joy);
if (naxes > 16) naxes = 16; if (naxes > 16) naxes = 16;
for (int a = 0; a < naxes; a++) for (int a = 0; a < naxes; a++)
{ {
axesRest[a] = SDL_JoystickGetAxis(Input::Joystick, a); axesRest[a] = SDL_JoystickGetAxis(joy, a);
} }
} }
} }
@ -349,6 +370,8 @@ private:
return str; return str;
} }
InputConfigDialog* parentDialog;
int* mapping; int* mapping;
bool isHotkey; bool isHotkey;

View File

@ -24,6 +24,7 @@
#include "Platform.h" #include "Platform.h"
#include "Config.h" #include "Config.h"
#include "GPU.h" #include "GPU.h"
#include "main.h"
#include "VideoSettingsDialog.h" #include "VideoSettingsDialog.h"
#include "ui_VideoSettingsDialog.h" #include "ui_VideoSettingsDialog.h"

View File

@ -51,7 +51,6 @@
#endif #endif
#include "main.h" #include "main.h"
#include "Input.h"
#include "CheatsDialog.h" #include "CheatsDialog.h"
#include "DateTimeDialog.h" #include "DateTimeDialog.h"
#include "EmuSettingsDialog.h" #include "EmuSettingsDialog.h"
@ -846,14 +845,14 @@ void MainWindow::keyPressEvent(QKeyEvent* event)
// TODO!! REMOVE ME IN RELEASE BUILDS!! // TODO!! REMOVE ME IN RELEASE BUILDS!!
//if (event->key() == Qt::Key_F11) emuThread->NDS->debug(0); //if (event->key() == Qt::Key_F11) emuThread->NDS->debug(0);
Input::KeyPress(event); emuInstance->onKeyPress(event);
} }
void MainWindow::keyReleaseEvent(QKeyEvent* event) void MainWindow::keyReleaseEvent(QKeyEvent* event)
{ {
if (event->isAutoRepeat()) return; if (event->isAutoRepeat()) return;
Input::KeyRelease(event); emuInstance->onKeyRelease(event);
} }
@ -955,7 +954,7 @@ void MainWindow::onAppStateChanged(Qt::ApplicationState state)
{ {
if (state == Qt::ApplicationInactive) if (state == Qt::ApplicationInactive)
{ {
Input::KeyReleaseAll(); emuInstance->keyReleaseAll();
if (Config::PauseLostFocus && emuThread->emuIsRunning()) if (Config::PauseLostFocus && emuThread->emuIsRunning())
emuThread->emuPause(); emuThread->emuPause();
} }

View File

@ -56,48 +56,19 @@
#include "duckstation/gl/context.h" #include "duckstation/gl/context.h"
#include "main.h" #include "main.h"
#include "Input.h"
#include "CheatsDialog.h" #include "CheatsDialog.h"
#include "DateTimeDialog.h" #include "DateTimeDialog.h"
#include "EmuSettingsDialog.h" #include "EmuSettingsDialog.h"
#include "InputConfig/InputConfigDialog.h" #include "InputConfig/InputConfigDialog.h"
#include "VideoSettingsDialog.h" #include "VideoSettingsDialog.h"
#include "CameraSettingsDialog.h"
#include "AudioSettingsDialog.h"
#include "FirmwareSettingsDialog.h"
#include "PathSettingsDialog.h"
#include "MPSettingsDialog.h"
#include "WifiSettingsDialog.h"
#include "InterfaceSettingsDialog.h"
#include "ROMInfoDialog.h" #include "ROMInfoDialog.h"
#include "RAMInfoDialog.h" #include "RAMInfoDialog.h"
#include "TitleManagerDialog.h"
#include "PowerManagement/PowerManagementDialog.h" #include "PowerManagement/PowerManagementDialog.h"
#include "types.h"
#include "version.h" #include "version.h"
#include "FrontendUtil.h"
#include "Args.h"
#include "NDS.h"
#include "NDSCart.h"
#include "GBACart.h"
#include "GPU.h"
#include "SPU.h"
#include "Wifi.h"
#include "Platform.h"
#include "LocalMP.h"
#include "Config.h" #include "Config.h"
#include "RTC.h"
#include "DSi.h" #include "DSi.h"
#include "DSi_I2C.h"
#include "GPU3D_Soft.h"
#include "GPU3D_OpenGL.h"
#include "Savestate.h"
//#include "main_shaders.h"
#include "EmuInstance.h" #include "EmuInstance.h"
#include "ArchiveUtil.h" #include "ArchiveUtil.h"
@ -369,9 +340,6 @@ int main(int argc, char** argv)
QApplication::setStyle(QString::fromStdString(Config::UITheme)); QApplication::setStyle(QString::fromStdString(Config::UITheme));
} }
Input::JoystickID = Config::JoystickID;
Input::OpenJoystick();
/* mainWindow = new MainWindow(); /* mainWindow = new MainWindow();
if (options->fullscreen) if (options->fullscreen)
ToggleFullscreen(mainWindow); ToggleFullscreen(mainWindow);
@ -422,8 +390,6 @@ int main(int argc, char** argv)
delete emuThread;*/ delete emuThread;*/
delete testinst; delete testinst;
Input::CloseJoystick();
//AudioInOut::DeInit(); //AudioInOut::DeInit();
delete camManager[0]; delete camManager[0];
delete camManager[1]; delete camManager[1];