merge shit

This commit is contained in:
Arisotura 2021-10-28 02:50:33 +02:00
parent 5d039c5688
commit 0f59c1af4d
55 changed files with 6675 additions and 927 deletions

View File

@ -5,13 +5,13 @@ pool:
vmImage: macOS-10.14
steps:
- script: brew install sdl2 qt@6 libslirp libarchive libepoxy
- script: brew install llvm sdl2 qt@6 libslirp libarchive libepoxy
displayName: 'Install dependencies'
- script: mkdir $(Pipeline.Workspace)/build
displayName: 'Create build environment'
- script: cmake $(Build.SourcesDirectory) -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_PREFIX_PATH="$(brew --prefix qt@6);$(brew --prefix libarchive)" -DMACOS_BUNDLE_LIBS=ON -DMACOS_BUILD_DMG=ON -DUSE_QT6=ON
- script: cmake $(Build.SourcesDirectory) -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_PREFIX_PATH="$(brew --prefix qt@6);$(brew --prefix libarchive)" -DMACOS_BUNDLE_LIBS=ON -DMACOS_BUILD_DMG=ON -DUSE_QT6=ON -DCMAKE_TOOLCHAIN_FILE=$(Build.SourcesDirectory)/cmake/Toolchain-Homebrew-LLVM.cmake
displayName: 'Configure'
workingDirectory: $(Pipeline.Workspace)/build

2
.gitignore vendored
View File

@ -9,7 +9,9 @@ melon_grc.h
melon.rc
cmake-build
cmake-build-debug
compile_commands.json
.idea
.cache
*.exe

View File

@ -123,8 +123,10 @@ if (ENABLE_LTO)
if (NOT LLD STREQUAL "LLD-NOTFOUND")
add_link_options(-fuse-ld=lld)
endif()
set(CMAKE_AR "llvm-ar")
set(CMAKE_RANLIB "llvm-ranlib")
if (NOT APPLE)
set(CMAKE_AR "llvm-ar")
set(CMAKE_RANLIB "llvm-ranlib")
endif()
endif()
endif()

View File

@ -1,8 +1,8 @@
<p align="center"><img src="https://raw.githubusercontent.com/StapleButter/melonDS/master/icon/melon_128x128.png"></p>
<p align="center"><img src="https://raw.githubusercontent.com/Arisotura/melonDS/master/res/icon/melon_128x128.png"></p>
<h2 align="center"><b>melonDS</b></h2>
<p align="center">
<a href="http://melonds.kuribo64.net/" alt="melonDS website"><img src="https://img.shields.io/badge/website-melonds.kuribo64.net-%2331352e.svg"></a>
<a href="http://melonds.kuribo64.net/downloads.php" alt="Release: 0.9.2"><img src="https://img.shields.io/badge/release-0.9.2-%235c913b.svg"></a>
<a href="http://melonds.kuribo64.net/downloads.php" alt="Release: 0.9.3"><img src="https://img.shields.io/badge/release-0.9.3-%235c913b.svg"></a>
<a href="https://www.gnu.org/licenses/gpl-3.0" alt="License: GPLv3"><img src="https://img.shields.io/badge/License-GPL%20v3-%23ff554d.svg"></a>
<a href="https://kiwiirc.com/client/irc.badnik.net/?nick=IRC-Source_?#melonds" alt="IRC channel: #melonds"><img src="https://img.shields.io/badge/IRC%20chat-%23melonds-%23dd2e44.svg"></a>
<br>
@ -126,10 +126,14 @@ If everything went well, melonDS.app should now be in the current directory.
* limittox for the icon
* All of you comrades who have been testing melonDS, reporting issues, suggesting shit, etc
## License
## Licenses
[![GNU GPLv3 Image](https://www.gnu.org/graphics/gplv3-127x51.png)](http://www.gnu.org/licenses/gpl-3.0.en.html)
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.
### External
* Images used in the Input Config Dialog - see `src/frontend/qt_sdl/InputConfig/resources/LICENSE.md`

View File

@ -0,0 +1,12 @@
# Toolchain file for building with Homebrew's LLVM on macOS
# This is useful on 10.14 where std::filesystem is not supported.
set(CMAKE_C_COMPILER /usr/local/opt/llvm/bin/clang)
set(CMAKE_CXX_COMPILER /usr/local/opt/llvm/bin/clang++)
add_link_options(-L/usr/local/opt/llvm/lib)
# LLVM in Homebrew is built with latest Xcode which has a newer linker than
# what is bundled in the default install of Xcode Command Line Tools, so we
# override it to prevent it passing flags not supported by the system's ld.
add_link_options(-mlinker-version=450)

17
freebios/Makefile Executable file
View File

@ -0,0 +1,17 @@
TC_PREFIX = /home/exophase/pandora-dev
PREFIX = $(TC_PREFIX)/arm-2011.03
AS = $(PREFIX)/bin/arm-none-linux-gnueabi-gcc
OBJCOPY = $(PREFIX)/bin/arm-none-linux-gnueabi-objcopy
BIN_ARM7 = drastic_bios_arm7
BIN_ARM9 = drastic_bios_arm9
all:
$(AS) bios_common.S -DBIOS_ARM7 -march=armv4 -c -Wa,-asl=$(BIN_ARM7).list -o $(BIN_ARM7).o
$(AS) bios_common.S -DBIOS_ARM9 -march=armv5 -c -Wa,-asl=$(BIN_ARM9).list -o $(BIN_ARM9).o
$(OBJCOPY) -O binary $(BIN_ARM7).o $(BIN_ARM7).bin
$(OBJCOPY) -O binary $(BIN_ARM9).o $(BIN_ARM9).bin
clean:
rm -f $(BIN_ARM7).bin $(BIN_ARM7).o $(BIN_ARM9).bin $(BIN_ARM9).o

1135
freebios/bios_common.S Executable file

File diff suppressed because it is too large Load Diff

BIN
freebios/drastic_bios_arm7.bin Executable file

Binary file not shown.

BIN
freebios/drastic_bios_arm9.bin Executable file

Binary file not shown.

View File

@ -0,0 +1,36 @@
Custom NDS ARM7/ARM9 BIOS replacement
Copyright (c) 2013, Gilead Kutnick
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1) Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2) Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
-- Info --
This archive contains source code and assembly for a custom BIOS replacement
for the Nintendo DS system. This code is in no way affiliated with Nintendo
and is not derived from Nintendo's BIOS implementation but has been implemented
using publically available documentation.
It can be assembled using the included Makefile along with a proper ARM gcc
toolchain. Change the first four lines to point to the proper toolchain of your
choice.

View File

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/kuriboland/melonDS">
<file preprocess="to-pixdata">icon/melon_16x16.png</file>
<file preprocess="to-pixdata">icon/melon_32x32.png</file>
<file preprocess="to-pixdata">icon/melon_48x48.png</file>
<file preprocess="to-pixdata">icon/melon_64x64.png</file>
<file preprocess="to-pixdata">icon/melon_128x128.png</file>
<file preprocess="to-pixdata">icon/melon_256x256.png</file>
</gresource>
</gresources>

View File

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

View File

Before

Width:  |  Height:  |  Size: 730 B

After

Width:  |  Height:  |  Size: 730 B

View File

Before

Width:  |  Height:  |  Size: 146 KiB

After

Width:  |  Height:  |  Size: 146 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

Before

Width:  |  Height:  |  Size: 121 KiB

After

Width:  |  Height:  |  Size: 121 KiB

View File

@ -2,7 +2,7 @@
#define VFT_APP 0x00000001L
//this will set your .exe icon
100 ICON MOVEABLE PURE LOADONCALL DISCARDABLE "melon.ico"
100 ICON MOVEABLE PURE LOADONCALL DISCARDABLE "res/melon.ico"
//include version information in .exe, modify these values to match your needs
1 VERSIONINFO
@ -31,4 +31,4 @@ FILETYPE VFT_APP
}
}
1 24 "xp.manifest"
1 24 "res/xp.manifest"

View File

@ -40,6 +40,7 @@ add_library(core STATIC
NDSCart_SRAMManager.cpp
Platform.h
ROMList.h
FreeBIOS.h
RTC.cpp
Savestate.cpp
SPI.cpp

View File

@ -28,12 +28,21 @@ namespace Config
const char* kConfigFile = "melonDS.ini";
int ExternalBIOSEnable;
char BIOS9Path[1024];
char BIOS7Path[1024];
char FirmwarePath[1024];
//int DLDIEnable;
//char DLDISDPath[1024];
char FirmwareUsername[64];
int FirmwareLanguage;
bool FirmwareOverrideSettings;
int FirmwareBirthdayMonth;
int FirmwareBirthdayDay;
int FirmwareFavouriteColour;
char FirmwareMessage[1024];
char DSiBIOS9Path[1024];
char DSiBIOS7Path[1024];
char DSiFirmwarePath[1024];
@ -54,10 +63,19 @@ int JIT_FastMemory = true;
ConfigEntry ConfigFile[] =
{
{"ExternalBIOSEnable", 0, &ExternalBIOSEnable, 0, NULL, 0},
{"BIOS9Path", 1, BIOS9Path, 0, "", 1023},
{"BIOS7Path", 1, BIOS7Path, 0, "", 1023},
{"FirmwarePath", 1, FirmwarePath, 0, "", 1023},
{"FirmwareUsername", 1, FirmwareUsername, 0, "melonDS", 63},
{"FirmwareLanguage", 0, &FirmwareLanguage, 1, NULL, 0},
{"FirmwareOverrideSettings", 0, &FirmwareOverrideSettings, false, NULL, 0},
{"FirmwareBirthdayMonth", 0, &FirmwareBirthdayMonth, 0, NULL, 0},
{"FirmwareBirthdayDay", 0, &FirmwareBirthdayDay, 0, NULL, 0},
{"FirmwareFavouriteColour", 0, &FirmwareFavouriteColour, 0, NULL, 0},
{"FirmwareMessage", 1, FirmwareMessage, 0, "", 1023},
{"DSiBIOS9Path", 1, DSiBIOS9Path, 0, "", 1023},
{"DSiBIOS7Path", 1, DSiBIOS7Path, 0, "", 1023},
{"DSiFirmwarePath", 1, DSiFirmwarePath, 0, "", 1023},

View File

@ -41,10 +41,19 @@ bool HasConfigFile(const char* fileName);
void Load();
void Save();
extern int ExternalBIOSEnable;
extern char BIOS9Path[1024];
extern char BIOS7Path[1024];
extern char FirmwarePath[1024];
extern char FirmwareUsername[64];
extern int FirmwareLanguage;
extern bool FirmwareOverrideSettings;
extern int FirmwareBirthdayMonth;
extern int FirmwareBirthdayDay;
extern int FirmwareFavouriteColour;
extern char FirmwareMessage[1024];
extern char DSiBIOS9Path[1024];
extern char DSiBIOS7Path[1024];
extern char DSiFirmwarePath[1024];

View File

@ -572,18 +572,6 @@ void DSi_NWifi::SendCMD(u8 cmd, u32 param)
{
switch (cmd)
{
case 3: // SEND_RELATIVE_ADDR
Host->SendResponse(0, true);
return;
case 5: // IO_SEND_OP_COND, dummy response
Host->SendResponse(0x80000000, true);
return;
case 7: // SELECT_CARD
Host->SendResponse(0, true);
return;
case 12:
// stop command
// CHECKME: does the SDIO controller actually send those??
@ -739,16 +727,12 @@ void DSi_NWifi::HandleCommand()
void DSi_NWifi::BMI_Command()
{
// Need a full command written
if (Mailbox[0].Level() < 0x4) return;
u32 cmd = MB_Peek32(0);
u32 cmd = MB_Read32(0);
switch (cmd)
{
case 0x01: // BMI_DONE
{
MB_Read32(0); // cmd pop
printf("BMI_DONE\n");
EEPROMReady = 1; // GROSS FUCKING HACK
u8 ready_msg[6] = {0x0A, 0x00, 0x08, 0x06, 0x16, 0x00};
@ -759,12 +743,6 @@ void DSi_NWifi::BMI_Command()
case 0x03: // BMI_WRITE_MEMORY
{
if (Mailbox[0].Level() < 0xC)
{
printf("BMI_WRITE_MEMORY wait for data...\n");
return;
}
MB_Read32(0); // cmd pop
u32 addr = MB_Read32(0);
u32 len = MB_Read32(0);
printf("BMI mem write %08X %08X\n", addr, len);
@ -780,12 +758,6 @@ void DSi_NWifi::BMI_Command()
case 0x04: // BMI_EXECUTE
{
if (Mailbox[0].Level() < 0xC)
{
printf("BMI_EXECUTE wait for data...\n");
return;
}
u32 entry = MB_Read32(0);
u32 arg = MB_Read32(0);
@ -795,12 +767,6 @@ void DSi_NWifi::BMI_Command()
case 0x06: // BMI_READ_SOC_REGISTER
{
if (Mailbox[0].Level() < 0x8)
{
printf("BMI_READ_SOC_REGISTER wait for data...\n");
return;
}
MB_Read32(0); // cmd pop
u32 addr = MB_Read32(0);
u32 val = WindowRead(addr);
MB_Write32(4, val);
@ -809,12 +775,6 @@ void DSi_NWifi::BMI_Command()
case 0x07: // BMI_WRITE_SOC_REGISTER
{
if (Mailbox[0].Level() < 0xC)
{
printf("BMI_WRITE_SOC_REGISTER wait for data...\n");
return;
}
MB_Read32(0); // cmd pop
u32 addr = MB_Read32(0);
u32 val = MB_Read32(0);
WindowWrite(addr, val);
@ -822,7 +782,6 @@ void DSi_NWifi::BMI_Command()
return;
case 0x08: // BMI_GET_TARGET_ID
MB_Read32(0); // cmd pop
MB_Write32(4, 0xFFFFFFFF);
MB_Write32(4, 0x0000000C);
MB_Write32(4, ROMID);
@ -831,12 +790,6 @@ void DSi_NWifi::BMI_Command()
case 0x0D: // BMI_LZ_STREAM_START
{
if (Mailbox[0].Level() < 0x8)
{
printf("BMI_LZ_STREAM_START wait for data...\n");
return;
}
MB_Read32(0); // cmd pop
u32 addr = MB_Read32(0);
printf("BMI_LZ_STREAM_START %08X\n", addr);
}
@ -844,13 +797,6 @@ void DSi_NWifi::BMI_Command()
case 0x0E: // BMI_LZ_DATA
{
if (Mailbox[0].Level() < 0x8)
{
printf("BMI_LZ_DATA wait for data...\n");
return;
}
MB_Read32(0); // cmd pop
u32 len = MB_Read32(0);
printf("BMI LZ write %08X\n", len);
//FILE* f = fopen("debug/wififirm.bin", "ab");

View File

@ -95,20 +95,6 @@ private:
Mailbox[n].Write(val & 0xFF);
}
u32 MB_Peek32(int n)
{
return MB_Peek32(n, 0);
}
u32 MB_Peek32(int n, int offs)
{
u32 ret = Mailbox[n].Peek(offs+0);
ret |= (Mailbox[n].Peek(offs+1) << 8);
ret |= (Mailbox[n].Peek(offs+2) << 16);
ret |= (Mailbox[n].Peek(offs+3) << 24);
return ret;
}
u32 MB_Read32(int n)
{
u32 ret = Mailbox[n].Read();

View File

@ -461,7 +461,6 @@ u16 DSi_SDHost::Read(u32 addr)
case 0x028: return SDOption;
case 0x02C: return 0; // TODO
case 0x02E: return 0; // TODO
case 0x034: return CardIRQCtl;
case 0x036: return CardIRQStatus;

1747
src/FreeBIOS.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -34,6 +34,7 @@
#include "AREngine.h"
#include "Platform.h"
#include "NDSCart_SRAMManager.h"
#include "FreeBIOS.h"
#ifdef JIT_ENABLED
#include "ARMJIT.h"
@ -88,6 +89,7 @@ u64 FrameStartTimestamp;
int CurCPU;
const s32 kMaxIterationCycles = 64;
const s32 kIterationCycleMargin = 8;
u32 ARM9ClockShift;
@ -463,38 +465,46 @@ void Reset()
// DS BIOSes are always loaded, even in DSi mode
// we need them for DS-compatible mode
f = Platform::OpenLocalFile(Config::BIOS9Path, "rb");
if (!f)
if (Config::ExternalBIOSEnable)
{
printf("ARM9 BIOS not found\n");
f = Platform::OpenLocalFile(Config::BIOS9Path, "rb");
if (!f)
{
printf("ARM9 BIOS not found\n");
for (i = 0; i < 16; i++)
((u32*)ARM9BIOS)[i] = 0xE7FFDEFF;
for (i = 0; i < 16; i++)
((u32*)ARM9BIOS)[i] = 0xE7FFDEFF;
}
else
{
fseek(f, 0, SEEK_SET);
fread(ARM9BIOS, 0x1000, 1, f);
printf("ARM9 BIOS loaded\n");
fclose(f);
}
f = Platform::OpenLocalFile(Config::BIOS7Path, "rb");
if (!f)
{
printf("ARM7 BIOS not found\n");
for (i = 0; i < 16; i++)
((u32*)ARM7BIOS)[i] = 0xE7FFDEFF;
}
else
{
fseek(f, 0, SEEK_SET);
fread(ARM7BIOS, 0x4000, 1, f);
printf("ARM7 BIOS loaded\n");
fclose(f);
}
}
else
{
fseek(f, 0, SEEK_SET);
fread(ARM9BIOS, 0x1000, 1, f);
printf("ARM9 BIOS loaded\n");
fclose(f);
}
f = Platform::OpenLocalFile(Config::BIOS7Path, "rb");
if (!f)
{
printf("ARM7 BIOS not found\n");
for (i = 0; i < 16; i++)
((u32*)ARM7BIOS)[i] = 0xE7FFDEFF;
}
else
{
fseek(f, 0, SEEK_SET);
fread(ARM7BIOS, 0x4000, 1, f);
printf("ARM7 BIOS loaded\n");
fclose(f);
memcpy(ARM9BIOS, bios_arm9_bin, bios_arm9_bin_len);
memcpy(ARM7BIOS, bios_arm7_bin, bios_arm7_bin_len);
}
#ifdef JIT_ENABLED
@ -917,7 +927,7 @@ void RelocateSave(const char* path, bool write)
u64 NextTarget()
{
u64 ret = SysTimestamp + kMaxIterationCycles;
u64 minEvent = UINT64_MAX;
u32 mask = SchedListMask;
for (int i = 0; i < Event_MAX; i++)
@ -925,14 +935,19 @@ u64 NextTarget()
if (!mask) break;
if (mask & 0x1)
{
if (SchedList[i].Timestamp < ret)
ret = SchedList[i].Timestamp;
if (SchedList[i].Timestamp < minEvent)
minEvent = SchedList[i].Timestamp;
}
mask >>= 1;
}
return ret;
u64 max = SysTimestamp + kMaxIterationCycles;
if (minEvent < max + kIterationCycleMargin)
return minEvent;
return max;
}
void RunSystem(u64 timestamp)
@ -969,7 +984,6 @@ u32 RunFrame()
while (Running && GPU::TotalScanlines==0)
{
// TODO: give it some margin, so it can directly do 17 cycles instead of 16 then 1
u64 target = NextTarget();
ARM9Target = target << ARM9ClockShift;
CurCPU = 0;

View File

@ -19,6 +19,10 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <string>
#include <algorithm>
#include <codecvt>
#include <locale>
#include "Config.h"
#include "NDS.h"
#include "DSi.h"
@ -112,25 +116,25 @@ u32 FixFirmwareLength(u32 originalLength)
return originalLength;
}
void Reset()
void LoadDefaultFirmware()
{
if (Firmware) delete[] Firmware;
Firmware = NULL;
FirmwareLength = 0x20000;
Firmware = new u8[FirmwareLength];
memset(Firmware, 0xFF, FirmwareLength);
FirmwareMask = FirmwareLength - 1;
if (NDS::ConsoleType == 1)
strncpy(FirmwarePath, Config::DSiFirmwarePath, 1023);
else
strncpy(FirmwarePath, Config::FirmwarePath, 1023);
u32 userdata = 0x7FE00 & FirmwareMask;
FILE* f = Platform::OpenLocalFile(FirmwarePath, "rb");
if (!f)
{
printf("Firmware not found\n");
memset(Firmware + userdata, 0, 0x74);
// TODO: generate default firmware
return;
}
// user settings offset
*(u16*)&Firmware[0x20] = (FirmwareLength - 0x200) >> 3;
Firmware[userdata+0x00] = 5; // version
}
void LoadFirmwareFromFile(FILE* f)
{
fseek(f, 0, SEEK_END);
FirmwareLength = FixFirmwareLength((u32)ftell(f));
@ -143,19 +147,76 @@ void Reset()
fclose(f);
// take a backup
char firmbkp[1028];
char fwBackupPath[sizeof(FirmwarePath) + 4];
int fplen = strlen(FirmwarePath);
strncpy(&firmbkp[0], FirmwarePath, fplen);
strncpy(&firmbkp[fplen], ".bak", 1028-fplen);
firmbkp[fplen+4] = '\0';
f = Platform::OpenLocalFile(firmbkp, "rb");
if (f) fclose(f);
strcpy(&fwBackupPath[0], FirmwarePath);
strncpy(&fwBackupPath[fplen], ".bak", sizeof(fwBackupPath) - fplen);
fwBackupPath[fplen+4] = '\0';
f = Platform::OpenLocalFile(fwBackupPath, "rb");
if (!f)
{
f = Platform::OpenLocalFile(fwBackupPath, "wb");
if (f)
{
fwrite(Firmware, 1, FirmwareLength, f);
fclose(f);
}
else
{
printf("Could not write firmware backup!\n");
}
}
else
{
f = Platform::OpenLocalFile(firmbkp, "wb");
fwrite(Firmware, 1, FirmwareLength, f);
fclose(f);
}
}
void LoadUserSettingsFromConfig()
{
// setting up username
std::u16string username = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(Config::FirmwareUsername);
size_t usernameLength = std::min(username.length(), (size_t) 10);
memcpy(Firmware + UserSettings + 0x06, username.data(), usernameLength * sizeof(char16_t));
Firmware[UserSettings+0x1A] = usernameLength;
// setting language
Firmware[UserSettings+0x64] = Config::FirmwareLanguage;
// setting up color
Firmware[UserSettings+0x02] = Config::FirmwareFavouriteColour;
// setting up birthday
Firmware[UserSettings+0x03] = Config::FirmwareBirthdayMonth;
Firmware[UserSettings+0x04] = Config::FirmwareBirthdayDay;
// setup message
std::u16string message = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(Config::FirmwareMessage);
size_t messageLength = std::min(message.length(), (size_t) 26);
memcpy(Firmware + UserSettings + 0x1C, message.data(), messageLength * sizeof(char16_t));
Firmware[UserSettings+0x50] = messageLength;
}
void Reset()
{
if (Firmware) delete[] Firmware;
Firmware = NULL;
if (NDS::ConsoleType == 1)
strncpy(FirmwarePath, Config::DSiFirmwarePath, sizeof(FirmwarePath) - 1);
else
strncpy(FirmwarePath, Config::FirmwarePath, sizeof(FirmwarePath) - 1);
FILE* f = Platform::OpenLocalFile(FirmwarePath, "rb");
if (!f)
{
printf("Firmware not found! Generating default firmware.\n");
LoadDefaultFirmware();
}
else
{
LoadFirmwareFromFile(f);
}
FirmwareMask = FirmwareLength - 1;
@ -168,6 +229,9 @@ void Reset()
UserSettings = userdata;
if (!f || Config::FirmwareOverrideSettings)
LoadUserSettingsFromConfig();
// fix touchscreen coords
*(u16*)&Firmware[userdata+0x58] = 0;
*(u16*)&Firmware[userdata+0x5A] = 0;

View File

@ -92,6 +92,8 @@ int VerifyDSBIOS()
FILE* f;
long len;
if (!Config::ExternalBIOSEnable) return Load_OK;
f = Platform::OpenLocalFile(Config::BIOS9Path, "rb");
if (!f) return Load_BIOS9Missing;
@ -163,7 +165,7 @@ int VerifyDSFirmware()
long len;
f = Platform::OpenLocalFile(Config::FirmwarePath, "rb");
if (!f) return Load_FirmwareMissing;
if (!f) return Load_FirmwareNotBootable;
fseek(f, 0, SEEK_END);
len = ftell(f);

View File

@ -5,13 +5,16 @@ SET(SOURCES_QT_SDL
main_shaders.h
CheatsDialog.cpp
EmuSettingsDialog.cpp
InputConfigDialog.cpp
InputConfig/InputConfigDialog.cpp
InputConfig/MapButton.h
InputConfig/resources/ds.qrc
VideoSettingsDialog.cpp
AudioSettingsDialog.cpp
FirmwareSettingsDialog.cpp
WifiSettingsDialog.cpp
InterfaceSettingsDialog.cpp
ROMInfoDialog.cpp
TitleManagerDialog.cpp
TitleManagerDialog.cpp
Input.cpp
LAN_PCap.cpp
LAN_Socket.cpp
@ -31,7 +34,7 @@ SET(SOURCES_QT_SDL
../FrontendUtil.h
../mic_blow.h
../../../melon.qrc
${CMAKE_SOURCE_DIR}/res/melon.qrc
)
option(USE_QT6 "Build using Qt 6 instead of 5" OFF)
@ -97,6 +100,7 @@ target_link_libraries(melonDS core)
if (BUILD_STATIC)
target_link_libraries(melonDS -static ${SDL2_STATIC_LIBRARIES} ${SLIRP_STATIC_LIBRARIES} ${LIBARCHIVE_STATIC_LIBRARIES})
qt_import_plugins(melonDS INCLUDE Qt::QSvgPlugin)
else()
target_link_libraries(melonDS ${SDL2_LIBRARIES} ${SLIRP_LIBRARIES} ${LIBARCHIVE_LIBRARIES})
endif()
@ -113,7 +117,7 @@ if (UNIX)
endif()
elseif (WIN32)
option(PORTABLE "Make a portable build that looks for its configuration in the current directory" ON)
configure_file("${CMAKE_SOURCE_DIR}/melon.rc.in" "${CMAKE_SOURCE_DIR}/melon.rc")
configure_file("${CMAKE_SOURCE_DIR}/res/melon.rc.in" "${CMAKE_SOURCE_DIR}/melon.rc")
target_sources(melonDS PUBLIC "${CMAKE_SOURCE_DIR}/melon.rc")
target_link_libraries(melonDS comctl32 d2d1 dwrite uxtheme ws2_32 iphlpapi gdi32)
@ -129,15 +133,16 @@ if (PORTABLE)
endif()
if (APPLE)
set_target_properties(melonDS PROPERTIES
MACOSX_BUNDLE true
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/melon.plist.in
OUTPUT_NAME melonDS
)
# Copy icon into the bundle
target_sources(melonDS PRIVATE "${CMAKE_SOURCE_DIR}/melon.icns")
set_source_files_properties("${CMAKE_SOURCE_DIR}/melon.icns" PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
set(RESOURCE_FILES "${CMAKE_SOURCE_DIR}/res/melon.icns")
target_sources(melonDS PUBLIC "${RESOURCE_FILES}")
set_target_properties(melonDS PROPERTIES
MACOSX_BUNDLE true
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/res/melon.plist.in
OUTPUT_NAME melonDS
RESOURCE "${RESOURCE_FILES}")
# Qt 6 requires macOS 10.15 if building on 10.15 or greater
if(CMAKE_SYSTEM_VERSION VERSION_GREATER_EQUAL 19.0.0)
@ -159,11 +164,13 @@ if (APPLE)
endif()
endif()
install(FILES ../../../net.kuribo64.melonDS.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications)
install(FILES ../../../icon/melon_16x16.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/16x16/apps RENAME net.kuribo64.melonDS.png)
install(FILES ../../../icon/melon_32x32.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/32x32/apps RENAME net.kuribo64.melonDS.png)
install(FILES ../../../icon/melon_48x48.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/48x48/apps RENAME net.kuribo64.melonDS.png)
install(FILES ../../../icon/melon_64x64.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/64x64/apps RENAME net.kuribo64.melonDS.png)
install(FILES ../../../icon/melon_128x128.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/128x128/apps RENAME net.kuribo64.melonDS.png)
install(FILES ../../../icon/melon_256x256.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/256x256/apps RENAME net.kuribo64.melonDS.png)
install(TARGETS melonDS BUNDLE DESTINATION ${CMAKE_BINARY_DIR} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
if (UNIX AND NOT APPLE)
foreach(SIZE 16 32 48 64 128 256)
install(FILES ${CMAKE_SOURCE_DIR}/res/icon/melon_${SIZE}x${SIZE}.png
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/${SIZE}x${SIZE}/apps
RENAME net.kuribo64.melonDS.png)
endforeach()
install(FILES ${CMAKE_SOURCE_DIR}/res/net.kuribo64.melonDS.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications)
install(TARGETS melonDS BUNDLE DESTINATION ${CMAKE_BINARY_DIR} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
endif()

View File

@ -19,6 +19,8 @@
#include <stdio.h>
#include <QFileDialog>
#include <QMessageBox>
#include <QList>
#include <QDateEdit>
#include "types.h"
#include "Platform.h"
@ -41,6 +43,7 @@ EmuSettingsDialog::EmuSettingsDialog(QWidget* parent) : QDialog(parent), ui(new
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
ui->chkExternalBIOS->setChecked(Config::ExternalBIOSEnable != 0);
ui->txtBIOS9Path->setText(Config::BIOS9Path);
ui->txtBIOS7Path->setText(Config::BIOS7Path);
ui->txtFirmwarePath->setText(Config::FirmwarePath);
@ -74,6 +77,7 @@ EmuSettingsDialog::EmuSettingsDialog(QWidget* parent) : QDialog(parent), ui(new
#endif
on_chkEnableJIT_toggled();
on_chkExternalBIOS_toggled();
const int imgsizes[] = {256, 512, 1024, 2048, 4096, 0};
@ -180,6 +184,7 @@ void EmuSettingsDialog::done(int r)
int jitLiteralOptimisations = ui->chkJITLiteralOptimisations->isChecked() ? 1:0;
int jitFastMemory = ui->chkJITFastMemory->isChecked() ? 1:0;
int externalBiosEnable = ui->chkExternalBIOS->isChecked() ? 1:0;
std::string bios9Path = ui->txtBIOS9Path->text().toStdString();
std::string bios7Path = ui->txtBIOS7Path->text().toStdString();
std::string firmwarePath = ui->txtFirmwarePath->text().toStdString();
@ -212,6 +217,7 @@ void EmuSettingsDialog::done(int r)
|| jitLiteralOptimisations != Config::JIT_LiteralOptimisations
|| jitFastMemory != Config::JIT_FastMemory
#endif
|| externalBiosEnable != Config::ExternalBIOSEnable
|| strcmp(Config::BIOS9Path, bios9Path.c_str()) != 0
|| strcmp(Config::BIOS7Path, bios7Path.c_str()) != 0
|| strcmp(Config::FirmwarePath, firmwarePath.c_str()) != 0
@ -238,6 +244,7 @@ void EmuSettingsDialog::done(int r)
QMessageBox::Ok, QMessageBox::Cancel) != QMessageBox::Ok)
return;
Config::ExternalBIOSEnable = externalBiosEnable;
strncpy(Config::BIOS9Path, bios9Path.c_str(), 1023); Config::BIOS9Path[1023] = '\0';
strncpy(Config::BIOS7Path, bios7Path.c_str(), 1023); Config::BIOS7Path[1023] = '\0';
strncpy(Config::FirmwarePath, firmwarePath.c_str(), 1023); Config::FirmwarePath[1023] = '\0';
@ -465,3 +472,10 @@ void EmuSettingsDialog::on_chkEnableJIT_toggled()
#endif
ui->spnJITMaximumBlockSize->setDisabled(disabled);
}
void EmuSettingsDialog::on_chkExternalBIOS_toggled()
{
bool disabled = !ui->chkExternalBIOS->isChecked();
ui->txtBIOS7Path->setDisabled(disabled);
ui->txtBIOS9Path->setDisabled(disabled);
}

View File

@ -75,6 +75,7 @@ private slots:
void on_btnDSiSDFolderBrowse_clicked();
void on_chkEnableJIT_toggled();
void on_chkExternalBIOS_toggled();
private:
void verifyFirmware();

View File

@ -26,7 +26,7 @@
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
<number>1</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
@ -89,72 +89,41 @@
<string>DS-mode</string>
</attribute>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="1">
<widget class="QPathInput" name="txtBIOS7Path">
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DS-mode ARM7 BIOS&lt;/p&gt;&lt;p&gt;Size should be 16 KB&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPathInput" name="txtFirmwarePath">
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DS-mode firmware&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Possible firmwares:&lt;/p&gt;&lt;p&gt;* 128 KB: DS-mode firmware from a DSi or 3DS. Not bootable.&lt;/p&gt;&lt;p&gt;* 256 KB: regular DS firmware.&lt;/p&gt;&lt;p&gt;* 512 KB: iQue DS firmware.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>DS firmware:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>DS ARM7 BIOS:</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="btnBIOS7Browse">
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
<item row="2" column="2">
<item row="3" column="2">
<widget class="QPushButton" name="btnFirmwareBrowse">
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="btnBIOS9Browse">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<item row="4" column="0">
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>DS firmware:</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="btnBIOS7Browse">
<property name="text">
<string>Browse...</string>
</property>
<property name="autoDefault">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>DS ARM9 BIOS:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<item row="1" column="1">
<widget class="QPathInput" name="txtBIOS9Path">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
@ -176,18 +145,56 @@
</property>
</widget>
</item>
<item row="3" column="0">
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>DS ARM7 BIOS:</string>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</widget>
</item>
<item row="2" column="1">
<widget class="QPathInput" name="txtBIOS7Path">
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DS-mode ARM7 BIOS&lt;/p&gt;&lt;p&gt;Size should be 16 KB&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</spacer>
</widget>
</item>
<item row="3" column="1">
<widget class="QPathInput" name="txtFirmwarePath">
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DS-mode firmware&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Possible firmwares:&lt;/p&gt;&lt;p&gt;* 128 KB: DS-mode firmware from a DSi or 3DS. Not bootable.&lt;/p&gt;&lt;p&gt;* 256 KB: regular DS firmware.&lt;/p&gt;&lt;p&gt;* 512 KB: iQue DS firmware.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>DS ARM9 BIOS:</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="btnBIOS9Browse">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Browse...</string>
</property>
<property name="autoDefault">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0" colspan="3">
<widget class="QCheckBox" name="chkExternalBIOS">
<property name="text">
<string>Use external BIOS files</string>
</property>
</widget>
</item>
</layout>
</widget>

View File

@ -0,0 +1,72 @@
/*
Copyright 2016-2020 Arisotura
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 "Config.h"
#include "FirmwareSettingsDialog.h"
#include "ui_FirmwareSettingsDialog.h"
FirmwareSettingsDialog* FirmwareSettingsDialog::currentDlg = nullptr;
FirmwareSettingsDialog::FirmwareSettingsDialog(QWidget* parent) : QDialog(parent), ui(new Ui::FirmwareSettingsDialog)
{
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
ui->usernameEdit->setText(Config::FirmwareUsername);
ui->languageBox->addItems(languages);
ui->languageBox->setCurrentIndex(Config::FirmwareLanguage);
QDate birthDate = QDate(QDate::currentDate().year(), Config::FirmwareBirthdayMonth, Config::FirmwareBirthdayDay);
ui->birthdayEdit->setDate(birthDate);
ui->colorsEdit->addItems(colours);
ui->colorsEdit->setCurrentIndex(Config::FirmwareFavouriteColour);
ui->messageEdit->setText(Config::FirmwareMessage);
ui->overrideFirmwareBox->setChecked(Config::FirmwareOverrideSettings);
}
FirmwareSettingsDialog::~FirmwareSettingsDialog()
{
delete ui;
}
void FirmwareSettingsDialog::on_dialogButtons_accepted()
{
std::string newName = ui->usernameEdit->text().toStdString();
strncpy(Config::FirmwareUsername, newName.c_str(), 63); Config::FirmwareUsername[63] = '\0';
Config::FirmwareLanguage = ui->languageBox->currentIndex();
Config::FirmwareFavouriteColour = ui->colorsEdit->currentIndex();
Config::FirmwareBirthdayDay = ui->birthdayEdit->date().day();
Config::FirmwareBirthdayMonth = ui->birthdayEdit->date().month();
Config::FirmwareOverrideSettings = ui->overrideFirmwareBox->isChecked();
std::string newMessage = ui->messageEdit->text().toStdString();
strncpy(Config::FirmwareMessage, newMessage.c_str(), 1023); Config::FirmwareMessage[1023] = '\0';
Config::Save();
closeDlg();
}
void FirmwareSettingsDialog::on_dialogButtons_rejected()
{
closeDlg();
}

View File

@ -0,0 +1,92 @@
/*
Copyright 2016-2020 Arisotura
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 FIRMWARESETTINGSDIALOG_H
#define FIRMWARESETTINGSDIALOG_H
#include <QDialog>
#include <QWidget>
namespace Ui { class FirmwareSettingsDialog; }
class FirmwareSettingsDialog;
class FirmwareSettingsDialog : public QDialog
{
Q_OBJECT
public:
const QStringList colours
{
"Greyish Blue",
"Brown",
"Red",
"Light Pink",
"Orange",
"Yellow",
"Lime",
"Light Green",
"Dark Green",
"Turqoise",
"Light Blue",
"Blue",
"Dark Blue",
"Dark Purple",
"Light Purple",
"Dark Pink"
};
const QStringList languages
{
"Japanese",
"English",
"French",
"German",
"Italian",
"Spanish"
};
explicit FirmwareSettingsDialog(QWidget* parent);
~FirmwareSettingsDialog();
static FirmwareSettingsDialog* currentDlg;
static FirmwareSettingsDialog* openDlg(QWidget* parent)
{
if (currentDlg)
{
currentDlg->activateWindow();
return currentDlg;
}
currentDlg = new FirmwareSettingsDialog(parent);
currentDlg->show();
return currentDlg;
}
static void closeDlg()
{
currentDlg = nullptr;
}
private slots:
void on_dialogButtons_accepted();
void on_dialogButtons_rejected();
private:
Ui::FirmwareSettingsDialog* ui;
};
#endif // FIRMWARESETTINGSDIALOG_H

View File

@ -0,0 +1,144 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FirmwareSettingsDialog</class>
<widget class="QDialog" name="FirmwareSettingsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>511</width>
<height>272</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Firmware settings - melonDS</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetFixedSize</enum>
</property>
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="usernameLabel">
<property name="text">
<string>Username</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="usernameEdit">
<property name="text">
<string>MelonDS</string>
</property>
<property name="maxLength">
<number>10</number>
</property>
<property name="clearButtonEnabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Language</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="languageBox"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Birthday</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDateEdit" name="birthdayEdit"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Color</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="colorsEdit"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Message</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="messageEdit"/>
</item>
<item row="5" column="0" colspan="2">
<widget class="QCheckBox" name="overrideFirmwareBox">
<property name="text">
<string>Override firmware settings</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="dialogButtons">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>dialogButtons</sender>
<signal>accepted()</signal>
<receiver>FirmwareSettingsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>255</x>
<y>250</y>
</hint>
<hint type="destinationlabel">
<x>255</x>
<y>135</y>
</hint>
</hints>
</connection>
<connection>
<sender>dialogButtons</sender>
<signal>rejected()</signal>
<receiver>FirmwareSettingsDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>255</x>
<y>250</y>
</hint>
<hint type="destinationlabel">
<x>255</x>
<y>135</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,253 @@
/*
Copyright 2016-2021 Arisotura
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 <QGroupBox>
#include <QLabel>
#include <QKeyEvent>
#include <QDebug>
#include <SDL2/SDL.h>
#include "types.h"
#include "Config.h"
#include "PlatformConfig.h"
#include "MapButton.h"
#include "Input.h"
#include "InputConfigDialog.h"
#include "ui_InputConfigDialog.h"
InputConfigDialog* InputConfigDialog::currentDlg = nullptr;
const int dskeyorder[12] = {0, 1, 10, 11, 5, 4, 6, 7, 9, 8, 2, 3};
const char* dskeylabels[12] = {"A", "B", "X", "Y", "Left", "Right", "Up", "Down", "L", "R", "Select", "Start"};
const int hk_addons[] =
{
HK_SolarSensorIncrease,
HK_SolarSensorDecrease,
};
const char* hk_addons_labels[] =
{
"[Boktai] Sunlight + ",
"[Boktai] Sunlight - ",
};
const int hk_general[] =
{
HK_Pause,
HK_Reset,
HK_FrameStep,
HK_FastForward,
HK_FastForwardToggle,
HK_FullscreenToggle,
HK_Lid,
HK_Mic,
HK_SwapScreens
};
const char* hk_general_labels[] =
{
"Pause/resume",
"Reset",
"Frame step",
"Fast forward",
"Toggle FPS limit",
"Toggle Fullscreen",
"Close/open lid",
"Microphone",
"Swap screens"
};
const int keypad_num = 12;
const int hk_addons_num = 2;
const int hk_general_num = 9;
InputConfigDialog::InputConfigDialog(QWidget* parent) : QDialog(parent), ui(new Ui::InputConfigDialog)
{
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
for (int i = 0; i < keypad_num; i++)
{
keypadKeyMap[i] = Config::KeyMapping[dskeyorder[i]];
keypadJoyMap[i] = Config::JoyMapping[dskeyorder[i]];
}
for (int i = 0; i < hk_addons_num; i++)
{
addonsKeyMap[i] = Config::HKKeyMapping[hk_addons[i]];
addonsJoyMap[i] = Config::HKJoyMapping[hk_addons[i]];
}
for (int i = 0; i < hk_general_num; i++)
{
hkGeneralKeyMap[i] = Config::HKKeyMapping[hk_general[i]];
hkGeneralJoyMap[i] = Config::HKJoyMapping[hk_general[i]];
}
populatePage(ui->tabAddons, hk_addons_num, hk_addons_labels, addonsKeyMap, addonsJoyMap);
populatePage(ui->tabHotkeysGeneral, hk_general_num, hk_general_labels, hkGeneralKeyMap, hkGeneralJoyMap);
int njoy = SDL_NumJoysticks();
if (njoy > 0)
{
for (int i = 0; i < njoy; i++)
{
const char* name = SDL_JoystickNameForIndex(i);
ui->cbxJoystick->addItem(QString(name));
}
ui->cbxJoystick->setCurrentIndex(Input::JoystickID);
}
else
{
ui->cbxJoystick->addItem("(no joysticks available)");
ui->cbxJoystick->setEnabled(false);
}
setupKeypadPage();
}
InputConfigDialog::~InputConfigDialog()
{
delete ui;
}
void InputConfigDialog::setupKeypadPage()
{
for (int i = 0; i < keypad_num; i++)
{
QPushButton* pushButtonKey = this->findChild<QPushButton*>(QStringLiteral("btnKey") + dskeylabels[i]);
QPushButton* pushButtonJoy = this->findChild<QPushButton*>(QStringLiteral("btnJoy") + dskeylabels[i]);
KeyMapButton* keyMapButtonKey = new KeyMapButton(&keypadKeyMap[i], false);
JoyMapButton* keyMapButtonJoy = new JoyMapButton(&keypadJoyMap[i], false);
pushButtonKey->parentWidget()->layout()->replaceWidget(pushButtonKey, keyMapButtonKey);
pushButtonJoy->parentWidget()->layout()->replaceWidget(pushButtonJoy, keyMapButtonJoy);
delete pushButtonKey;
delete pushButtonJoy;
if (ui->cbxJoystick->isEnabled())
{
ui->stackMapping->setCurrentIndex(1);
}
}
}
void InputConfigDialog::populatePage(QWidget* page, int num, const char** labels, int* keymap, int* joymap)
{
// kind of a hack
bool ishotkey = (page != ui->tabInput);
QHBoxLayout* main_layout = new QHBoxLayout();
QGroupBox* group;
QGridLayout* group_layout;
group = new QGroupBox("Keyboard mappings:");
main_layout->addWidget(group);
group_layout = new QGridLayout();
group_layout->setSpacing(1);
for (int i = 0; i < num; i++)
{
QLabel* label = new QLabel(QString(labels[i])+":");
KeyMapButton* btn = new KeyMapButton(&keymap[i], ishotkey);
group_layout->addWidget(label, i, 0);
group_layout->addWidget(btn, i, 1);
}
group_layout->setRowStretch(num, 1);
group->setLayout(group_layout);
group->setMinimumWidth(275);
group = new QGroupBox("Joystick mappings:");
main_layout->addWidget(group);
group_layout = new QGridLayout();
group_layout->setSpacing(1);
for (int i = 0; i < num; i++)
{
QLabel* label = new QLabel(QString(labels[i])+":");
JoyMapButton* btn = new JoyMapButton(&joymap[i], ishotkey);
group_layout->addWidget(label, i, 0);
group_layout->addWidget(btn, i, 1);
}
group_layout->setRowStretch(num, 1);
group->setLayout(group_layout);
group->setMinimumWidth(275);
page->setLayout(main_layout);
}
void InputConfigDialog::on_InputConfigDialog_accepted()
{
for (int i = 0; i < keypad_num; i++)
{
Config::KeyMapping[dskeyorder[i]] = keypadKeyMap[i];
Config::JoyMapping[dskeyorder[i]] = keypadJoyMap[i];
}
for (int i = 0; i < hk_addons_num; i++)
{
Config::HKKeyMapping[hk_addons[i]] = addonsKeyMap[i];
Config::HKJoyMapping[hk_addons[i]] = addonsJoyMap[i];
}
for (int i = 0; i < hk_general_num; i++)
{
Config::HKKeyMapping[hk_general[i]] = hkGeneralKeyMap[i];
Config::HKJoyMapping[hk_general[i]] = hkGeneralJoyMap[i];
}
Config::JoystickID = Input::JoystickID;
Config::Save();
closeDlg();
}
void InputConfigDialog::on_InputConfigDialog_rejected()
{
Input::JoystickID = Config::JoystickID;
Input::OpenJoystick();
closeDlg();
}
void InputConfigDialog::on_btnKeyMapSwitch_clicked()
{
ui->stackMapping->setCurrentIndex(0);
}
void InputConfigDialog::on_btnJoyMapSwitch_clicked()
{
ui->stackMapping->setCurrentIndex(1);
}
void InputConfigDialog::on_cbxJoystick_currentIndexChanged(int id)
{
// prevent a spurious change
if (ui->cbxJoystick->count() < 2) return;
Input::JoystickID = id;
Input::OpenJoystick();
}

View File

@ -55,10 +55,13 @@ private slots:
void on_InputConfigDialog_accepted();
void on_InputConfigDialog_rejected();
void on_btnKeyMapSwitch_clicked();
void on_btnJoyMapSwitch_clicked();
void on_cbxJoystick_currentIndexChanged(int id);
private:
void populatePage(QWidget* page, int num, const char** labels, int* keymap, int* joymap);
void setupKeypadPage();
Ui::InputConfigDialog* ui;
@ -68,56 +71,4 @@ private:
};
class KeyMapButton : public QPushButton
{
Q_OBJECT
public:
explicit KeyMapButton(int* mapping, bool hotkey);
~KeyMapButton();
protected:
void keyPressEvent(QKeyEvent* event) override;
void focusOutEvent(QFocusEvent* event) override;
bool focusNextPrevChild(bool next) override { return false; }
private slots:
void onClick();
private:
QString mappingText();
int* mapping;
bool isHotkey;
};
class JoyMapButton : public QPushButton
{
Q_OBJECT
public:
explicit JoyMapButton(int* mapping, bool hotkey);
~JoyMapButton();
protected:
void keyPressEvent(QKeyEvent* event) override;
void focusOutEvent(QFocusEvent* event) override;
void timerEvent(QTimerEvent* event) override;
bool focusNextPrevChild(bool next) override { return false; }
private slots:
void onClick();
private:
QString mappingText();
int* mapping;
bool isHotkey;
int timerID;
int axesRest[16];
};
#endif // INPUTCONFIGDIALOG_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,355 @@
/*
Copyright 2016-2021 Arisotura
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 MAPBUTTON_H
#define MAPBUTTON_H
#include <QPushButton>
#include <SDL2/SDL.h>
#include "Input.h"
class KeyMapButton : public QPushButton
{
Q_OBJECT
public:
KeyMapButton(int* mapping, bool hotkey) : QPushButton()
{
this->mapping = mapping;
this->isHotkey = hotkey;
setCheckable(true);
setText(mappingText());
setFocusPolicy(Qt::StrongFocus); //Fixes binding keys in macOS
connect(this, &KeyMapButton::clicked, this, &KeyMapButton::onClick);
}
~KeyMapButton()
{
}
protected:
void keyPressEvent(QKeyEvent* event) override
{
if (!isChecked()) return QPushButton::keyPressEvent(event);
printf("KEY PRESSED = %08X %08X | %08X %08X %08X\n", event->key(), (int)event->modifiers(), event->nativeVirtualKey(), event->nativeModifiers(), event->nativeScanCode());
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 (!mod)
{
if (key == Qt::Key_Escape) { click(); return; }
if (key == Qt::Key_Backspace) { *mapping = -1; click(); return; }
}
if (isHotkey)
{
if (ismod)
return;
}
if (!ismod)
key |= mod;
else if (Input::IsRightModKey(event))
key |= (1<<31);
*mapping = key;
click();
}
void focusOutEvent(QFocusEvent* event) override
{
if (isChecked())
{
// if we lost the focus while mapping, consider it 'done'
click();
}
QPushButton::focusOutEvent(event);
}
bool focusNextPrevChild(bool next) override { return false; }
private slots:
void onClick()
{
if (isChecked())
{
setText("[press key]");
}
else
{
setText(mappingText());
}
}
private:
QString mappingText()
{
int key = *mapping;
if (key == -1) return "None";
QString isright = (key & (1<<31)) ? "Right " : "Left ";
key &= ~(1<<31);
#ifndef __APPLE__
switch (key)
{
case Qt::Key_Control: return isright + "Ctrl";
case Qt::Key_Alt: return "Alt";
case Qt::Key_AltGr: return "AltGr";
case Qt::Key_Shift: return isright + "Shift";
case Qt::Key_Meta: return "Meta";
}
#else
switch (key)
{
case Qt::Key_Control: return isright + "";
case Qt::Key_Alt: return isright + "";
case Qt::Key_Shift: return isright + "";
case Qt::Key_Meta: return isright + "";
}
#endif
QKeySequence seq(key);
QString ret = seq.toString(QKeySequence::NativeText);
// weak attempt at detecting garbage key names
//if (ret.length() == 2 && ret[0].unicode() > 0xFF)
// return QString("[%1]").arg(key, 8, 16);
return ret.replace("&", "&&");
}
int* mapping;
bool isHotkey;
};
class JoyMapButton : public QPushButton
{
Q_OBJECT
public:
JoyMapButton(int* mapping, bool hotkey) : QPushButton()
{
this->mapping = mapping;
this->isHotkey = hotkey;
setCheckable(true);
setText(mappingText());
connect(this, &JoyMapButton::clicked, this, &JoyMapButton::onClick);
timerID = 0;
}
~JoyMapButton()
{
}
protected:
void keyPressEvent(QKeyEvent* event) override
{
if (!isChecked()) return QPushButton::keyPressEvent(event);
int key = event->key();
int mod = event->modifiers();
if (!mod)
{
if (key == Qt::Key_Escape) { click(); return; }
if (key == Qt::Key_Backspace) { *mapping = -1; click(); return; }
}
}
void focusOutEvent(QFocusEvent* event) override
{
if (isChecked())
{
// if we lost the focus while mapping, consider it 'done'
click();
}
QPushButton::focusOutEvent(event);
}
void timerEvent(QTimerEvent* event) override
{
SDL_Joystick* joy = Input::Joystick;
if (!joy) { click(); return; }
if (!SDL_JoystickGetAttached(joy)) { click(); return; }
int oldmap;
if (*mapping == -1) oldmap = 0xFFFF;
else oldmap = *mapping;
int nbuttons = SDL_JoystickNumButtons(joy);
for (int i = 0; i < nbuttons; i++)
{
if (SDL_JoystickGetButton(joy, i))
{
*mapping = (oldmap & 0xFFFF0000) | i;
click();
return;
}
}
int nhats = SDL_JoystickNumHats(joy);
if (nhats > 16) nhats = 16;
for (int i = 0; i < nhats; i++)
{
Uint8 blackhat = SDL_JoystickGetHat(joy, i);
if (blackhat)
{
if (blackhat & 0x1) blackhat = 0x1;
else if (blackhat & 0x2) blackhat = 0x2;
else if (blackhat & 0x4) blackhat = 0x4;
else blackhat = 0x8;
*mapping = (oldmap & 0xFFFF0000) | 0x100 | blackhat | (i << 4);
click();
return;
}
}
int naxes = SDL_JoystickNumAxes(joy);
if (naxes > 16) naxes = 16;
for (int i = 0; i < naxes; i++)
{
Sint16 axisval = SDL_JoystickGetAxis(joy, i);
int diff = abs(axisval - axesRest[i]);
if (axesRest[i] < -16384 && axisval >= 0)
{
*mapping = (oldmap & 0xFFFF) | 0x10000 | (2 << 20) | (i << 24);
click();
return;
}
else if (diff > 16384)
{
int axistype;
if (axisval > 0) axistype = 0;
else axistype = 1;
*mapping = (oldmap & 0xFFFF) | 0x10000 | (axistype << 20) | (i << 24);
click();
return;
}
}
}
bool focusNextPrevChild(bool next) override { return false; }
private slots:
void onClick()
{
if (isChecked())
{
setText("[press button/axis]");
timerID = startTimer(50);
memset(axesRest, 0, sizeof(axesRest));
if (Input::Joystick && SDL_JoystickGetAttached(Input::Joystick))
{
int naxes = SDL_JoystickNumAxes(Input::Joystick);
if (naxes > 16) naxes = 16;
for (int a = 0; a < naxes; a++)
{
axesRest[a] = SDL_JoystickGetAxis(Input::Joystick, a);
}
}
}
else
{
setText(mappingText());
if (timerID) { killTimer(timerID); timerID = 0; }
}
}
private:
QString mappingText()
{
int id = *mapping;
if (id == -1) return "None";
bool hasbtn = ((id & 0xFFFF) != 0xFFFF);
QString str;
if (hasbtn)
{
if (id & 0x100)
{
int hatnum = ((id >> 4) & 0xF) + 1;
switch (id & 0xF)
{
case 0x1: str = "Hat %1 up"; break;
case 0x2: str = "Hat %1 right"; break;
case 0x4: str = "Hat %1 down"; break;
case 0x8: str = "Hat %1 left"; break;
}
str = str.arg(hatnum);
}
else
{
str = QString("Button %1").arg((id & 0xFFFF) + 1);
}
}
else
{
str = "";
}
if (id & 0x10000)
{
int axisnum = ((id >> 24) & 0xF) + 1;
if (hasbtn) str += " / ";
switch ((id >> 20) & 0xF)
{
case 0: str += QString("Axis %1 +").arg(axisnum); break;
case 1: str += QString("Axis %1 -").arg(axisnum); break;
case 2: str += QString("Trigger %1").arg(axisnum); break;
}
}
return str;
}
int* mapping;
bool isHotkey;
int timerID;
int axesRest[16];
};
#endif // MAPBUTTON_H

View File

@ -0,0 +1,6 @@
These vector images are modified from the [Nintendo DS Lite illustration on dimensions.com](https://www.dimensions.com/element/nintendo-ds-lite).
These have been used with the permission of the copyright holders.
> "We restrict the usage of our drawings and 3D models in commercial software, but as long as it's a free and open source community project, that would be approved. Any reference/backlink to Dimensions.com that could be provided in the developer notes and/or credits for the project would be sufficient for use."
https://www.dimensions.com/legal

View File

@ -0,0 +1,6 @@
<RCC>
<qresource prefix="ds">
<file>ds_open.svg</file>
<file>ds_back.svg</file>
</qresource>
</RCC>

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 30 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 102 KiB

View File

@ -1,511 +0,0 @@
/*
Copyright 2016-2021 Arisotura
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 <QGroupBox>
#include <QLabel>
#include <QKeyEvent>
#include <SDL2/SDL.h>
#include "types.h"
#include "Config.h"
#include "PlatformConfig.h"
#include "Input.h"
#include "InputConfigDialog.h"
#include "ui_InputConfigDialog.h"
InputConfigDialog* InputConfigDialog::currentDlg = nullptr;
const int dskeyorder[12] = {0, 1, 10, 11, 5, 4, 6, 7, 9, 8, 2, 3};
const char* dskeylabels[12] = {"A", "B", "X", "Y", "Left", "Right", "Up", "Down", "L", "R", "Select", "Start"};
const int hk_addons[] =
{
HK_SolarSensorIncrease,
HK_SolarSensorDecrease,
};
const char* hk_addons_labels[] =
{
"[Boktai] Sunlight + ",
"[Boktai] Sunlight - ",
};
const int hk_general[] =
{
HK_Pause,
HK_Reset,
HK_FrameStep,
HK_FastForward,
HK_FastForwardToggle,
HK_FullscreenToggle,
HK_Lid,
HK_Mic,
HK_SwapScreens
};
const char* hk_general_labels[] =
{
"Pause/resume",
"Reset",
"Frame step",
"Fast forward",
"Toggle FPS limit",
"Toggle Fullscreen",
"Close/open lid",
"Microphone",
"Swap screens"
};
InputConfigDialog::InputConfigDialog(QWidget* parent) : QDialog(parent), ui(new Ui::InputConfigDialog)
{
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
for (int i = 0; i < 12; i++)
{
keypadKeyMap[i] = Config::KeyMapping[dskeyorder[i]];
keypadJoyMap[i] = Config::JoyMapping[dskeyorder[i]];
}
for (int i = 0; i < 2; i++)
{
addonsKeyMap[i] = Config::HKKeyMapping[hk_addons[i]];
addonsJoyMap[i] = Config::HKJoyMapping[hk_addons[i]];
}
for (int i = 0; i < 9; i++)
{
hkGeneralKeyMap[i] = Config::HKKeyMapping[hk_general[i]];
hkGeneralJoyMap[i] = Config::HKJoyMapping[hk_general[i]];
}
populatePage(ui->tabInput, 12, dskeylabels, keypadKeyMap, keypadJoyMap);
populatePage(ui->tabAddons, 2, hk_addons_labels, addonsKeyMap, addonsJoyMap);
populatePage(ui->tabHotkeysGeneral, 9, hk_general_labels, hkGeneralKeyMap, hkGeneralJoyMap);
int njoy = SDL_NumJoysticks();
if (njoy > 0)
{
for (int i = 0; i < njoy; i++)
{
const char* name = SDL_JoystickNameForIndex(i);
ui->cbxJoystick->addItem(QString(name));
}
ui->cbxJoystick->setCurrentIndex(Input::JoystickID);
}
else
{
ui->cbxJoystick->addItem("(no joysticks available)");
ui->cbxJoystick->setEnabled(false);
}
}
InputConfigDialog::~InputConfigDialog()
{
delete ui;
}
void InputConfigDialog::populatePage(QWidget* page, int num, const char** labels, int* keymap, int* joymap)
{
// kind of a hack
bool ishotkey = (page != ui->tabInput);
QHBoxLayout* main_layout = new QHBoxLayout();
QGroupBox* group;
QGridLayout* group_layout;
group = new QGroupBox("Keyboard mappings:");
main_layout->addWidget(group);
group_layout = new QGridLayout();
group_layout->setSpacing(1);
for (int i = 0; i < num; i++)
{
QLabel* label = new QLabel(QString(labels[i])+":");
KeyMapButton* btn = new KeyMapButton(&keymap[i], ishotkey);
group_layout->addWidget(label, i, 0);
group_layout->addWidget(btn, i, 1);
}
group_layout->setRowStretch(num, 1);
group->setLayout(group_layout);
group->setMinimumWidth(275);
group = new QGroupBox("Joystick mappings:");
main_layout->addWidget(group);
group_layout = new QGridLayout();
group_layout->setSpacing(1);
for (int i = 0; i < num; i++)
{
QLabel* label = new QLabel(QString(labels[i])+":");
JoyMapButton* btn = new JoyMapButton(&joymap[i], ishotkey);
group_layout->addWidget(label, i, 0);
group_layout->addWidget(btn, i, 1);
}
group_layout->setRowStretch(num, 1);
group->setLayout(group_layout);
group->setMinimumWidth(275);
page->setLayout(main_layout);
}
void InputConfigDialog::on_InputConfigDialog_accepted()
{
for (int i = 0; i < 12; i++)
{
Config::KeyMapping[dskeyorder[i]] = keypadKeyMap[i];
Config::JoyMapping[dskeyorder[i]] = keypadJoyMap[i];
}
for (int i = 0; i < 2; i++)
{
Config::HKKeyMapping[hk_addons[i]] = addonsKeyMap[i];
Config::HKJoyMapping[hk_addons[i]] = addonsJoyMap[i];
}
for (int i = 0; i < 9; i++)
{
Config::HKKeyMapping[hk_general[i]] = hkGeneralKeyMap[i];
Config::HKJoyMapping[hk_general[i]] = hkGeneralJoyMap[i];
}
Config::JoystickID = Input::JoystickID;
Config::Save();
closeDlg();
}
void InputConfigDialog::on_InputConfigDialog_rejected()
{
Input::JoystickID = Config::JoystickID;
Input::OpenJoystick();
closeDlg();
}
void InputConfigDialog::on_cbxJoystick_currentIndexChanged(int id)
{
// prevent a spurious change
if (ui->cbxJoystick->count() < 2) return;
Input::JoystickID = id;
Input::OpenJoystick();
}
KeyMapButton::KeyMapButton(int* mapping, bool hotkey) : QPushButton()
{
this->mapping = mapping;
this->isHotkey = hotkey;
setCheckable(true);
setText(mappingText());
setFocusPolicy(Qt::StrongFocus); //Fixes binding keys in macOS
connect(this, &KeyMapButton::clicked, this, &KeyMapButton::onClick);
}
KeyMapButton::~KeyMapButton()
{
}
void KeyMapButton::keyPressEvent(QKeyEvent* event)
{
if (!isChecked()) return QPushButton::keyPressEvent(event);
printf("KEY PRESSED = %08X %08X | %08X %08X %08X\n", event->key(), (int)event->modifiers(), event->nativeVirtualKey(), event->nativeModifiers(), event->nativeScanCode());
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 (!mod)
{
if (key == Qt::Key_Escape) { click(); return; }
if (key == Qt::Key_Backspace) { *mapping = -1; click(); return; }
}
if (isHotkey)
{
if (ismod)
return;
}
if (!ismod)
key |= mod;
else if (Input::IsRightModKey(event))
key |= (1<<31);
*mapping = key;
click();
}
void KeyMapButton::focusOutEvent(QFocusEvent* event)
{
if (isChecked())
{
// if we lost the focus while mapping, consider it 'done'
click();
}
QPushButton::focusOutEvent(event);
}
void KeyMapButton::onClick()
{
if (isChecked())
{
setText("[press key]");
}
else
{
setText(mappingText());
}
}
QString KeyMapButton::mappingText()
{
int key = *mapping;
if (key == -1) return "None";
QString isright = (key & (1<<31)) ? "Right " : "Left ";
key &= ~(1<<31);
#ifndef __APPLE__
switch (key)
{
case Qt::Key_Control: return isright + "Ctrl";
case Qt::Key_Alt: return "Alt";
case Qt::Key_AltGr: return "AltGr";
case Qt::Key_Shift: return isright + "Shift";
case Qt::Key_Meta: return "Meta";
}
#else
switch (key)
{
case Qt::Key_Control: return isright + "";
case Qt::Key_Alt: return isright + "";
case Qt::Key_Shift: return isright + "";
case Qt::Key_Meta: return isright + "";
}
#endif
QKeySequence seq(key);
QString ret = seq.toString(QKeySequence::NativeText);
// weak attempt at detecting garbage key names
//if (ret.length() == 2 && ret[0].unicode() > 0xFF)
// return QString("[%1]").arg(key, 8, 16);
return ret.replace("&", "&&");
}
JoyMapButton::JoyMapButton(int* mapping, bool hotkey) : QPushButton()
{
this->mapping = mapping;
this->isHotkey = hotkey;
setCheckable(true);
setText(mappingText());
connect(this, &JoyMapButton::clicked, this, &JoyMapButton::onClick);
timerID = 0;
}
JoyMapButton::~JoyMapButton()
{
}
void JoyMapButton::keyPressEvent(QKeyEvent* event)
{
if (!isChecked()) return QPushButton::keyPressEvent(event);
int key = event->key();
int mod = event->modifiers();
if (!mod)
{
if (key == Qt::Key_Escape) { click(); return; }
if (key == Qt::Key_Backspace) { *mapping = -1; click(); return; }
}
}
void JoyMapButton::focusOutEvent(QFocusEvent* event)
{
if (isChecked())
{
// if we lost the focus while mapping, consider it 'done'
click();
}
QPushButton::focusOutEvent(event);
}
void JoyMapButton::timerEvent(QTimerEvent* event)
{
SDL_Joystick* joy = Input::Joystick;
if (!joy) { click(); return; }
if (!SDL_JoystickGetAttached(joy)) { click(); return; }
int oldmap;
if (*mapping == -1) oldmap = 0xFFFF;
else oldmap = *mapping;
int nbuttons = SDL_JoystickNumButtons(joy);
for (int i = 0; i < nbuttons; i++)
{
if (SDL_JoystickGetButton(joy, i))
{
*mapping = (oldmap & 0xFFFF0000) | i;
click();
return;
}
}
int nhats = SDL_JoystickNumHats(joy);
if (nhats > 16) nhats = 16;
for (int i = 0; i < nhats; i++)
{
Uint8 blackhat = SDL_JoystickGetHat(joy, i);
if (blackhat)
{
if (blackhat & 0x1) blackhat = 0x1;
else if (blackhat & 0x2) blackhat = 0x2;
else if (blackhat & 0x4) blackhat = 0x4;
else blackhat = 0x8;
*mapping = (oldmap & 0xFFFF0000) | 0x100 | blackhat | (i << 4);
click();
return;
}
}
int naxes = SDL_JoystickNumAxes(joy);
if (naxes > 16) naxes = 16;
for (int i = 0; i < naxes; i++)
{
Sint16 axisval = SDL_JoystickGetAxis(joy, i);
int diff = abs(axisval - axesRest[i]);
if (axesRest[i] < -16384 && axisval >= 0)
{
*mapping = (oldmap & 0xFFFF) | 0x10000 | (2 << 20) | (i << 24);
click();
return;
}
else if (diff > 16384)
{
int axistype;
if (axisval > 0) axistype = 0;
else axistype = 1;
*mapping = (oldmap & 0xFFFF) | 0x10000 | (axistype << 20) | (i << 24);
click();
return;
}
}
}
void JoyMapButton::onClick()
{
if (isChecked())
{
setText("[press button/axis]");
timerID = startTimer(50);
memset(axesRest, 0, sizeof(axesRest));
if (Input::Joystick && SDL_JoystickGetAttached(Input::Joystick))
{
int naxes = SDL_JoystickNumAxes(Input::Joystick);
if (naxes > 16) naxes = 16;
for (int a = 0; a < naxes; a++)
{
axesRest[a] = SDL_JoystickGetAxis(Input::Joystick, a);
}
}
}
else
{
setText(mappingText());
if (timerID) { killTimer(timerID); timerID = 0; }
}
}
QString JoyMapButton::mappingText()
{
int id = *mapping;
if (id == -1) return "None";
bool hasbtn = ((id & 0xFFFF) != 0xFFFF);
QString str;
if (hasbtn)
{
if (id & 0x100)
{
int hatnum = ((id >> 4) & 0xF) + 1;
switch (id & 0xF)
{
case 0x1: str = "Hat %1 up"; break;
case 0x2: str = "Hat %1 right"; break;
case 0x4: str = "Hat %1 down"; break;
case 0x8: str = "Hat %1 left"; break;
}
str = str.arg(hatnum);
}
else
{
str = QString("Button %1").arg((id & 0xFFFF) + 1);
}
}
else
{
str = "";
}
if (id & 0x10000)
{
int axisnum = ((id >> 24) & 0xF) + 1;
if (hasbtn) str += " / ";
switch ((id >> 20) & 0xF)
{
case 0: str += QString("Axis %1 +").arg(axisnum); break;
case 1: str += QString("Axis %1 -").arg(axisnum); break;
case 2: str += QString("Trigger %1").arg(axisnum); break;
}
}
return str;
}

View File

@ -1,131 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>InputConfigDialog</class>
<widget class="QDialog" name="InputConfigDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>488</width>
<height>365</height>
</rect>
</property>
<property name="windowTitle">
<string>Input and hotkeys - melonDS</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetFixedSize</enum>
</property>
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tabInput">
<attribute name="title">
<string>DS keypad</string>
</attribute>
</widget>
<widget class="QWidget" name="tabAddons">
<attribute name="title">
<string>Add-ons</string>
</attribute>
</widget>
<widget class="QWidget" name="tabHotkeysGeneral">
<attribute name="title">
<string>General hotkeys</string>
</attribute>
</widget>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Joystick:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cbxJoystick">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Selects which joystick will be used for joystick input, if any is present.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>InputConfigDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>InputConfigDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -18,6 +18,7 @@
#include <stdio.h>
#include <QFileDialog>
#include <QtGlobal>
#include "types.h"
#include "Platform.h"
@ -47,7 +48,11 @@ VideoSettingsDialog::VideoSettingsDialog(QWidget* parent) : QDialog(parent), ui(
grp3DRenderer = new QButtonGroup(this);
grp3DRenderer->addButton(ui->rb3DSoftware, 0);
grp3DRenderer->addButton(ui->rb3DOpenGL, 1);
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
connect(grp3DRenderer, SIGNAL(buttonClicked(int)), this, SLOT(onChange3DRenderer(int)));
#else
connect(grp3DRenderer, SIGNAL(idClicked(int)), this, SLOT(onChange3DRenderer(int)));
#endif
grp3DRenderer->button(Config::_3DRenderer)->setChecked(true);
#ifndef OGLRENDERER_ENABLED

View File

@ -52,9 +52,10 @@
#include "Input.h"
#include "CheatsDialog.h"
#include "EmuSettingsDialog.h"
#include "InputConfigDialog.h"
#include "InputConfig/InputConfigDialog.h"
#include "VideoSettingsDialog.h"
#include "AudioSettingsDialog.h"
#include "FirmwareSettingsDialog.h"
#include "WifiSettingsDialog.h"
#include "InterfaceSettingsDialog.h"
#include "ROMInfoDialog.h"
@ -1411,6 +1412,9 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
actInterfaceSettings = menu->addAction("Interface settings");
connect(actInterfaceSettings, &QAction::triggered, this, &MainWindow::onOpenInterfaceSettings);
actFirmwareSettings = menu->addAction("Firmware settings");
connect(actFirmwareSettings, &QAction::triggered, this, &MainWindow::onOpenFirmwareSettings);
{
QMenu* submenu = menu->addMenu("Savestate settings");
@ -2446,6 +2450,14 @@ void MainWindow::onOpenAudioSettings()
connect(dlg, &AudioSettingsDialog::finished, this, &MainWindow::onAudioSettingsFinished);
}
void MainWindow::onOpenFirmwareSettings()
{
FirmwareSettingsDialog* dlg = FirmwareSettingsDialog::openDlg(this);
connect(dlg, &FirmwareSettingsDialog::finished, this, &MainWindow::onFirmwareSettingsFinished);
}
void MainWindow::onFirmwareSettingsFinished(int res) {}
void MainWindow::onUpdateAudioSettings()
{
SPU::SetInterpolation(Config::AudioInterp);

View File

@ -256,10 +256,12 @@ private slots:
void onInputConfigFinished(int res);
void onOpenVideoSettings();
void onOpenAudioSettings();
void onOpenFirmwareSettings();
void onUpdateAudioSettings();
void onAudioSettingsFinished(int res);
void onOpenWifiSettings();
void onWifiSettingsFinished(int res);
void onFirmwareSettingsFinished(int res);
void onOpenInterfaceSettings();
void onInterfaceSettingsFinished(int res);
void onUpdateMouseTimer();
@ -331,6 +333,7 @@ public:
QAction* actVideoSettings;
QAction* actAudioSettings;
QAction* actWifiSettings;
QAction* actFirmwareSettings;
QAction* actInterfaceSettings;
QAction* actSavestateSRAMReloc;
QAction* actScreenSize[4];

View File

@ -56,6 +56,10 @@ def expand_load_path(lib, path)
file = $fallback_rpaths
.map { |it| File.join(it, file_name) }
.find { |it| File.exist? it }
if file == nil
path = File.join(File.dirname(lib), file_name)
file = path if File.exist? path
end
return file, :rpath if file
when "executable_path"
file = File.join(File.dirname(executable), file_name)
@ -85,7 +89,6 @@ def install_name_tool(exec, action, path1, path2 = nil)
args = ["-#{action.to_s}", path1]
args << path2 if path2 != nil
FileUtils.chmod("u+w", exec)
out, status = Open3.capture2e("install_name_tool", *args, exec)
if status != 0
puts out
@ -129,6 +132,7 @@ def fixup_libs(prog, orig_path)
next if File.exist? File.join(frameworks_dir, fwname)
expath, _ = expand_load_path(orig_path, framework)
FileUtils.cp_r(expath, frameworks_dir, preserve: true)
FileUtils.chmod_R("u+w", File.join(frameworks_dir, fwname))
fixup_libs File.join(frameworks_dir, fwname, fwlib), libpath
else
libname = File.basename(libpath)
@ -141,6 +145,7 @@ def fixup_libs(prog, orig_path)
next if File.exist? dest
expath, _ = expand_load_path(orig_path, libpath)
FileUtils.copy expath, frameworks_dir
FileUtils.chmod("u+w", dest)
fixup_libs dest, libpath
end
end
@ -198,7 +203,7 @@ fixup_libs(executable, executable)
bundle_plugins = File.join($bundle, "Contents", "PlugIns")
want_plugins = ["styles/libqmacstyle.dylib", "platforms/libqcocoa.dylib"]
want_plugins = ["styles/libqmacstyle.dylib", "platforms/libqcocoa.dylib", "imageformats/libqsvg.dylib"]
want_plugins.each do |plug|
destdir = File.join(bundle_plugins, File.dirname(plug))
FileUtils.mkdir_p(destdir)