2017-06-05 02:02:04 +02:00
/*
* This file is part of Luma3DS
2020-04-25 14:26:21 +02:00
* Copyright ( C ) 2016 - 2020 Aurora Wright , TuxSH
2017-06-05 02:02:04 +02:00
*
* This program 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 .
*
* This program 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 this program . If not , see < http : //www.gnu.org/licenses/>.
*
* Additional Terms 7. b and 7. c of GPLv3 apply to this file :
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it .
* * Prohibiting misrepresentation of the origin of that material ,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version .
*/
# include <3ds.h>
# include "menus/miscellaneous.h"
# include "input_redirection.h"
2019-06-03 00:43:44 +02:00
# include "ntp.h"
2017-06-05 02:02:04 +02:00
# include "memory.h"
# include "draw.h"
# include "hbloader.h"
2018-11-15 13:38:19 +01:00
# include "plgloader.h"
2017-06-05 02:02:04 +02:00
# include "fmt.h"
2020-04-25 14:17:23 +02:00
# include "utils.h" // for makeArmBranch
2017-06-05 02:02:04 +02:00
# include "minisoc.h"
2017-06-18 22:31:21 +02:00
# include "ifile.h"
2019-03-30 18:12:54 +01:00
# include "pmdbgext.h"
2017-06-05 02:02:04 +02:00
Menu miscellaneousMenu = {
" Miscellaneous options menu " ,
{
{ " Switch the hb. title to the current app. " , METHOD , . method = & MiscellaneousMenu_SwitchBoot3dsxTargetTitle } ,
2019-06-03 00:43:44 +02:00
{ " Change the menu combo " , METHOD , . method = & MiscellaneousMenu_ChangeMenuCombo } ,
2017-06-05 02:02:04 +02:00
{ " Start InputRedirection " , METHOD , . method = & MiscellaneousMenu_InputRedirection } ,
2019-06-03 00:43:44 +02:00
{ " Sync time and date via NTP " , METHOD , . method = & MiscellaneousMenu_SyncTimeDate } ,
2017-07-24 04:44:14 +02:00
{ " Save settings " , METHOD , . method = & MiscellaneousMenu_SaveSettings } ,
2020-05-17 17:42:44 +02:00
{ } ,
2017-06-05 02:02:04 +02:00
}
} ;
void MiscellaneousMenu_SwitchBoot3dsxTargetTitle ( void )
{
Result res ;
char failureReason [ 64 ] ;
if ( HBLDR_3DSX_TID = = HBLDR_DEFAULT_3DSX_TID )
{
2020-05-10 03:58:21 +02:00
FS_ProgramInfo progInfo ;
2019-03-31 16:12:31 +02:00
u32 pid ;
2020-05-10 03:58:21 +02:00
u32 launchFlags ;
res = PMDBG_GetCurrentAppInfo ( & progInfo , & pid , & launchFlags ) ;
2017-06-05 02:02:04 +02:00
if ( R_SUCCEEDED ( res ) )
{
2020-05-10 03:58:21 +02:00
HBLDR_3DSX_TID = progInfo . programId ;
2017-06-05 02:02:04 +02:00
miscellaneousMenu . items [ 0 ] . title = " Switch the hb. title to hblauncher_loader " ;
}
else
{
res = - 1 ;
strcpy ( failureReason , " no suitable process found " ) ;
}
}
else
{
res = 0 ;
HBLDR_3DSX_TID = HBLDR_DEFAULT_3DSX_TID ;
miscellaneousMenu . items [ 0 ] . title = " Switch the hb. title to the current app. " ;
}
Draw_Lock ( ) ;
Draw_ClearFramebuffer ( ) ;
Draw_FlushFramebuffer ( ) ;
Draw_Unlock ( ) ;
do
{
Draw_Lock ( ) ;
Draw_DrawString ( 10 , 10 , COLOR_TITLE , " Miscellaneous options menu " ) ;
if ( R_SUCCEEDED ( res ) )
Draw_DrawString ( 10 , 30 , COLOR_WHITE , " Operation succeeded. " ) ;
else
Draw_DrawFormattedString ( 10 , 30 , COLOR_WHITE , " Operation failed (%s). " , failureReason ) ;
Draw_FlushFramebuffer ( ) ;
Draw_Unlock ( ) ;
}
2020-05-15 21:00:13 +02:00
while ( ! ( waitInput ( ) & KEY_B ) & & ! menuShouldExit ) ;
2017-06-05 02:02:04 +02:00
}
static void MiscellaneousMenu_ConvertComboToString ( char * out , u32 combo )
{
2020-05-15 03:06:52 +02:00
static const char * keys [ ] = {
" A " , " B " , " Select " , " Start " , " Right " , " Left " , " Up " , " Down " , " R " , " L " , " X " , " Y " ,
" ? " , " ? " ,
" ZL " , " ZR " ,
" ? " , " ? " , " ? " , " ? " ,
" Touch " ,
" ? " , " ? " , " ? " ,
" CStick Right " , " CStick Left " , " CStick Up " , " CStick Down " ,
" CPad Right " , " CPad Left " , " CPad Up " , " CPad Down " ,
} ;
char * outOrig = out ;
out [ 0 ] = 0 ;
for ( s32 i = 31 ; i > = 0 ; i - - )
2017-06-05 02:02:04 +02:00
{
if ( combo & ( 1 < < i ) )
{
strcpy ( out , keys [ i ] ) ;
out + = strlen ( keys [ i ] ) ;
* out + + = ' + ' ;
}
}
2020-05-15 03:06:52 +02:00
if ( out ! = outOrig )
out [ - 1 ] = 0 ;
2017-06-05 02:02:04 +02:00
}
2017-07-05 05:13:48 +02:00
2017-06-05 02:02:04 +02:00
void MiscellaneousMenu_ChangeMenuCombo ( void )
{
2020-05-15 03:06:52 +02:00
char comboStrOrig [ 128 ] , comboStr [ 128 ] ;
2017-06-05 02:02:04 +02:00
u32 posY ;
Draw_Lock ( ) ;
Draw_ClearFramebuffer ( ) ;
Draw_FlushFramebuffer ( ) ;
Draw_Unlock ( ) ;
MiscellaneousMenu_ConvertComboToString ( comboStrOrig , menuCombo ) ;
Draw_Lock ( ) ;
Draw_DrawString ( 10 , 10 , COLOR_TITLE , " Miscellaneous options menu " ) ;
posY = Draw_DrawFormattedString ( 10 , 30 , COLOR_WHITE , " The current menu combo is: %s " , comboStrOrig ) ;
posY = Draw_DrawString ( 10 , posY + SPACING_Y , COLOR_WHITE , " Please enter the new combo: " ) ;
2017-06-06 01:21:52 +02:00
menuCombo = waitCombo ( ) ;
2017-06-05 02:02:04 +02:00
MiscellaneousMenu_ConvertComboToString ( comboStr , menuCombo ) ;
do
{
Draw_Lock ( ) ;
Draw_DrawString ( 10 , 10 , COLOR_TITLE , " Miscellaneous options menu " ) ;
posY = Draw_DrawFormattedString ( 10 , 30 , COLOR_WHITE , " The current menu combo is: %s " , comboStrOrig ) ;
posY = Draw_DrawFormattedString ( 10 , posY + SPACING_Y , COLOR_WHITE , " Please enter the new combo: %s " , comboStr ) + SPACING_Y ;
2017-06-18 22:31:21 +02:00
2017-06-05 02:02:04 +02:00
posY = Draw_DrawString ( 10 , posY + SPACING_Y , COLOR_WHITE , " Successfully changed the menu combo. " ) ;
Draw_FlushFramebuffer ( ) ;
Draw_Unlock ( ) ;
}
2020-05-15 21:00:13 +02:00
while ( ! ( waitInput ( ) & KEY_B ) & & ! menuShouldExit ) ;
2017-06-05 02:02:04 +02:00
}
2018-11-15 13:38:19 +01:00
Result SaveSettings ( void )
2017-06-18 22:31:21 +02:00
{
Result res ;
IFile file ;
u64 total ;
2018-05-24 00:55:38 +02:00
struct PACKED ALIGN ( 4 )
2017-06-18 22:31:21 +02:00
{
char magic [ 4 ] ;
u16 formatVersionMajor , formatVersionMinor ;
u32 config , multiConfig , bootConfig ;
u64 hbldr3dsxTitleId ;
u32 rosalinaMenuCombo ;
2018-11-15 13:38:19 +01:00
u32 rosalinaFlags ;
2017-06-18 22:31:21 +02:00
} configData ;
u32 formatVersion ;
u32 config , multiConfig , bootConfig ;
s64 out ;
bool isSdMode ;
2018-11-15 13:38:19 +01:00
2017-06-18 22:31:21 +02:00
if ( R_FAILED ( svcGetSystemInfo ( & out , 0x10000 , 2 ) ) ) svcBreak ( USERBREAK_ASSERT ) ;
formatVersion = ( u32 ) out ;
if ( R_FAILED ( svcGetSystemInfo ( & out , 0x10000 , 3 ) ) ) svcBreak ( USERBREAK_ASSERT ) ;
config = ( u32 ) out ;
if ( R_FAILED ( svcGetSystemInfo ( & out , 0x10000 , 4 ) ) ) svcBreak ( USERBREAK_ASSERT ) ;
multiConfig = ( u32 ) out ;
if ( R_FAILED ( svcGetSystemInfo ( & out , 0x10000 , 5 ) ) ) svcBreak ( USERBREAK_ASSERT ) ;
bootConfig = ( u32 ) out ;
if ( R_FAILED ( svcGetSystemInfo ( & out , 0x10000 , 0x203 ) ) ) svcBreak ( USERBREAK_ASSERT ) ;
isSdMode = ( bool ) out ;
memcpy ( configData . magic , " CONF " , 4 ) ;
configData . formatVersionMajor = ( u16 ) ( formatVersion > > 16 ) ;
configData . formatVersionMinor = ( u16 ) formatVersion ;
configData . config = config ;
configData . multiConfig = multiConfig ;
configData . bootConfig = bootConfig ;
configData . hbldr3dsxTitleId = HBLDR_3DSX_TID ;
configData . rosalinaMenuCombo = menuCombo ;
2018-11-15 13:38:19 +01:00
configData . rosalinaFlags = PluginLoader__IsEnabled ( ) ;
2017-06-18 22:31:21 +02:00
FS_ArchiveID archiveId = isSdMode ? ARCHIVE_SDMC : ARCHIVE_NAND_RW ;
res = IFile_Open ( & file , archiveId , fsMakePath ( PATH_EMPTY , " " ) , fsMakePath ( PATH_ASCII , " /luma/config.bin " ) , FS_OPEN_CREATE | FS_OPEN_WRITE ) ;
if ( R_SUCCEEDED ( res ) )
res = IFile_Write ( & file , & total , & configData , sizeof ( configData ) , 0 ) ;
2018-11-15 13:38:19 +01:00
IFile_Close ( & file ) ;
return res ;
}
void MiscellaneousMenu_SaveSettings ( void )
{
Result res = SaveSettings ( ) ;
2017-06-18 22:31:21 +02:00
Draw_Lock ( ) ;
Draw_ClearFramebuffer ( ) ;
Draw_FlushFramebuffer ( ) ;
Draw_Unlock ( ) ;
do
{
Draw_Lock ( ) ;
2017-08-15 15:01:48 +02:00
Draw_DrawString ( 10 , 10 , COLOR_TITLE , " Miscellaneous options menu " ) ;
2017-06-18 22:31:21 +02:00
if ( R_SUCCEEDED ( res ) )
Draw_DrawString ( 10 , 30 , COLOR_WHITE , " Operation succeeded. " ) ;
else
2018-05-24 00:55:38 +02:00
Draw_DrawFormattedString ( 10 , 30 , COLOR_WHITE , " Operation failed (0x%08lx). " , res ) ;
2017-06-18 22:31:21 +02:00
Draw_FlushFramebuffer ( ) ;
Draw_Unlock ( ) ;
}
2020-05-15 21:00:13 +02:00
while ( ! ( waitInput ( ) & KEY_B ) & & ! menuShouldExit ) ;
2017-06-18 22:31:21 +02:00
}
2017-06-05 02:02:04 +02:00
void MiscellaneousMenu_InputRedirection ( void )
{
bool done = false ;
Result res ;
char buf [ 65 ] ;
bool wasEnabled = inputRedirectionEnabled ;
2017-06-06 21:04:13 +02:00
bool cantStart = false ;
2017-06-05 02:02:04 +02:00
if ( wasEnabled )
{
2020-04-28 02:31:29 +02:00
res = InputRedirection_Disable ( 5 * 1000 * 1000 * 1000LL ) ;
2017-06-05 02:02:04 +02:00
if ( res ! = 0 )
2018-05-24 00:55:38 +02:00
sprintf ( buf , " Failed to stop InputRedirection (0x%08lx). " , ( u32 ) res ) ;
2017-06-05 02:02:04 +02:00
else
2017-08-06 22:51:52 +02:00
miscellaneousMenu . items [ 2 ] . title = " Start InputRedirection " ;
2017-06-05 02:02:04 +02:00
}
else
{
2018-01-18 20:44:54 +01:00
s64 dummyInfo ;
bool isN3DS = svcGetSystemInfo ( & dummyInfo , 0x10001 , 0 ) = = 0 ;
bool isSocURegistered ;
2017-06-05 02:02:04 +02:00
2018-01-18 20:44:54 +01:00
res = srvIsServiceRegistered ( & isSocURegistered , " soc:U " ) ;
cantStart = R_FAILED ( res ) | | ! isSocURegistered ;
2017-06-05 02:02:04 +02:00
if ( ! cantStart & & isN3DS )
{
2018-01-18 20:44:54 +01:00
bool isIrRstRegistered ;
res = srvIsServiceRegistered ( & isIrRstRegistered , " ir:rst " ) ;
cantStart = R_FAILED ( res ) | | ! isIrRstRegistered ;
2017-06-05 02:02:04 +02:00
}
}
2017-06-18 22:31:21 +02:00
Draw_Lock ( ) ;
Draw_ClearFramebuffer ( ) ;
Draw_FlushFramebuffer ( ) ;
Draw_Unlock ( ) ;
2017-06-05 02:02:04 +02:00
do
{
Draw_Lock ( ) ;
Draw_DrawString ( 10 , 10 , COLOR_TITLE , " Miscellaneous options menu " ) ;
if ( ! wasEnabled & & cantStart )
2018-01-18 20:44:54 +01:00
Draw_DrawString ( 10 , 30 , COLOR_WHITE , " Can't start the input redirection before the system \n has finished loading. " ) ;
2017-06-05 02:02:04 +02:00
else if ( ! wasEnabled )
{
Draw_DrawString ( 10 , 30 , COLOR_WHITE , " Starting InputRedirection... " ) ;
if ( ! done )
{
res = InputRedirection_DoOrUndoPatches ( ) ;
if ( R_SUCCEEDED ( res ) )
{
res = svcCreateEvent ( & inputRedirectionThreadStartedEvent , RESET_STICKY ) ;
if ( R_SUCCEEDED ( res ) )
{
2020-04-28 02:31:29 +02:00
inputRedirectionCreateThread ( ) ;
2017-06-05 02:02:04 +02:00
res = svcWaitSynchronization ( inputRedirectionThreadStartedEvent , 10 * 1000 * 1000 * 1000LL ) ;
if ( res = = 0 )
res = ( Result ) inputRedirectionStartResult ;
if ( res ! = 0 )
2020-04-27 22:58:40 +02:00
{
svcCloseHandle ( inputRedirectionThreadStartedEvent ) ;
2017-06-05 02:02:04 +02:00
InputRedirection_DoOrUndoPatches ( ) ;
2020-04-27 22:58:40 +02:00
inputRedirectionEnabled = false ;
}
inputRedirectionStartResult = 0 ;
2017-06-05 02:02:04 +02:00
}
}
if ( res ! = 0 )
2018-05-24 00:55:38 +02:00
sprintf ( buf , " Starting InputRedirection... failed (0x%08lx). " , ( u32 ) res ) ;
2017-06-05 02:02:04 +02:00
else
2017-08-06 22:51:52 +02:00
miscellaneousMenu . items [ 2 ] . title = " Stop InputRedirection " ;
2017-06-05 02:02:04 +02:00
done = true ;
}
if ( res = = 0 )
Draw_DrawString ( 10 , 30 , COLOR_WHITE , " Starting InputRedirection... OK. " ) ;
else
Draw_DrawString ( 10 , 30 , COLOR_WHITE , buf ) ;
}
else
{
if ( res = = 0 )
Draw_DrawString ( 10 , 30 , COLOR_WHITE , " InputRedirection stopped successfully. " ) ;
else
Draw_DrawString ( 10 , 30 , COLOR_WHITE , buf ) ;
}
Draw_FlushFramebuffer ( ) ;
Draw_Unlock ( ) ;
}
2020-05-15 21:00:13 +02:00
while ( ! ( waitInput ( ) & KEY_B ) & & ! menuShouldExit ) ;
2017-06-05 02:02:04 +02:00
}
2019-06-03 00:43:44 +02:00
void MiscellaneousMenu_SyncTimeDate ( void )
{
u32 posY ;
u32 input = 0 ;
Result res ;
bool cantStart = false ;
bool isSocURegistered ;
time_t t ;
res = srvIsServiceRegistered ( & isSocURegistered , " soc:U " ) ;
cantStart = R_FAILED ( res ) | | ! isSocURegistered ;
int utcOffset = 12 ;
2019-09-16 09:43:23 +02:00
int utcOffsetMinute = 0 ;
2019-06-03 00:43:44 +02:00
int absOffset ;
do
{
Draw_Lock ( ) ;
Draw_DrawString ( 10 , 10 , COLOR_TITLE , " Miscellaneous options menu " ) ;
absOffset = utcOffset - 12 ;
absOffset = absOffset < 0 ? - absOffset : absOffset ;
2019-09-16 09:43:23 +02:00
posY = Draw_DrawFormattedString ( 10 , 30 , COLOR_WHITE , " Current UTC offset: %c%02d%02d " , utcOffset < 12 ? ' - ' : ' + ' , absOffset , utcOffsetMinute ) ;
posY = Draw_DrawFormattedString ( 10 , posY + SPACING_Y , COLOR_WHITE , " Use DPAD Left/Right to change hour offset. \n Use DPAD Up/Down to change minute offset. \n Press A when done. " ) + SPACING_Y ;
2019-06-03 00:43:44 +02:00
input = waitInput ( ) ;
2020-05-15 03:06:52 +02:00
if ( input & KEY_LEFT ) utcOffset = ( 24 + utcOffset - 1 ) % 24 ; // ensure utcOffset >= 0
if ( input & KEY_RIGHT ) utcOffset = ( utcOffset + 1 ) % 24 ;
if ( input & KEY_UP ) utcOffsetMinute = ( utcOffsetMinute + 1 ) % 60 ;
if ( input & KEY_DOWN ) utcOffsetMinute = ( 60 + utcOffsetMinute - 1 ) % 60 ;
2019-06-03 00:43:44 +02:00
Draw_FlushFramebuffer ( ) ;
Draw_Unlock ( ) ;
}
2020-05-15 21:00:13 +02:00
while ( ! ( input & ( KEY_A | KEY_B ) ) & & ! menuShouldExit ) ;
2019-06-03 00:43:44 +02:00
2020-05-15 03:06:52 +02:00
if ( input & KEY_B )
2019-06-03 00:43:44 +02:00
return ;
utcOffset - = 12 ;
res = srvIsServiceRegistered ( & isSocURegistered , " soc:U " ) ;
cantStart = R_FAILED ( res ) | | ! isSocURegistered ;
res = 0 ;
if ( ! cantStart )
{
res = ntpGetTimeStamp ( & t ) ;
if ( R_SUCCEEDED ( res ) )
{
t + = 3600 * utcOffset ;
2020-04-18 01:29:37 +02:00
t + = 60 * utcOffsetMinute ;
2020-05-18 23:43:00 +02:00
res = ntpSetTimeDate ( t ) ;
2019-06-03 00:43:44 +02:00
}
}
do
{
Draw_Lock ( ) ;
Draw_DrawString ( 10 , 10 , COLOR_TITLE , " Miscellaneous options menu " ) ;
absOffset = utcOffset ;
absOffset = absOffset < 0 ? - absOffset : absOffset ;
Draw_DrawFormattedString ( 10 , 30 , COLOR_WHITE , " Current UTC offset: %c%02d " , utcOffset < 0 ? ' - ' : ' + ' , absOffset ) ;
if ( cantStart )
2019-06-29 17:05:43 +02:00
Draw_DrawFormattedString ( 10 , posY + 2 * SPACING_Y , COLOR_WHITE , " Can't sync time/date before the system \n has finished loading. " ) + SPACING_Y ;
2019-06-03 00:43:44 +02:00
else if ( R_FAILED ( res ) )
2019-06-29 17:05:43 +02:00
Draw_DrawFormattedString ( 10 , posY + 2 * SPACING_Y , COLOR_WHITE , " Operation failed (%08lx). " , ( u32 ) res ) + SPACING_Y ;
2019-06-03 00:43:44 +02:00
else
2019-06-29 17:05:43 +02:00
Draw_DrawFormattedString ( 10 , posY + 2 * SPACING_Y , COLOR_WHITE , " Timedate & RTC updated successfully. \n You may need to reboot to see the changes. " ) + SPACING_Y ;
2019-06-03 00:43:44 +02:00
input = waitInput ( ) ;
Draw_FlushFramebuffer ( ) ;
Draw_Unlock ( ) ;
}
2020-05-15 21:00:13 +02:00
while ( ! ( input & KEY_B ) & & ! menuShouldExit ) ;
2019-06-03 00:43:44 +02:00
2020-04-18 01:29:37 +02:00
}