2021-03-16 02:04:21 +00:00
# include "color_swapper.hpp"
2021-09-11 14:48:13 +01:00
# include <filesystem>
2021-03-16 02:04:21 +00:00
# include <fstream>
2021-09-11 14:48:13 +01:00
# include <iomanip>
2021-03-16 02:04:21 +00:00
# include <sstream>
2021-09-11 14:48:13 +01:00
# include <string>
2021-03-16 02:04:21 +00:00
# include "constants.hpp"
2022-01-06 00:35:39 +00:00
# include "download.hpp"
2021-09-11 14:48:13 +01:00
# include "fs.hpp"
2021-03-16 02:04:21 +00:00
# include "progress_event.hpp"
# include "utils.hpp"
2022-10-31 18:59:48 +00:00
using json = nlohmann : : ordered_json ;
2021-03-16 02:04:21 +00:00
2022-01-06 00:35:39 +00:00
namespace {
constexpr const char BACKUP [ ] = " _backup " ;
2021-03-16 02:04:21 +00:00
2021-09-11 14:48:13 +01:00
int hexToBGR ( const std : : string & hex )
{
2021-03-16 02:04:21 +00:00
std : : string R = hex . substr ( 0 , 2 ) ;
std : : string G = hex . substr ( 2 , 2 ) ;
std : : string B = hex . substr ( 4 , 2 ) ;
return std : : stoi ( B + G + R , 0 , 16 ) ;
}
2021-09-11 14:48:13 +01:00
std : : string BGRToHex ( int v )
{
2021-03-16 02:04:21 +00:00
std : : stringstream ss ;
v = ( ( v & 0xFF ) < < 16 ) + ( v & 0xFF00 ) + ( v > > 16 ) + 256 ;
ss < < std : : setfill ( ' 0 ' ) < < std : : setw ( 6 ) < < std : : right < < std : : hex < < v ;
return ss . str ( ) ;
}
2021-09-11 14:48:13 +01:00
bool isHexaAnd3Bytes ( const std : : string & str )
{
if ( str . size ( ) ! = 6 ) return false ;
for ( char const & c : str ) {
if ( ! isxdigit ( c ) ) return false ;
2021-03-16 02:04:21 +00:00
}
return true ;
}
2022-01-06 00:35:39 +00:00
} // namespace
2021-03-16 02:04:21 +00:00
namespace JC {
2021-09-11 14:48:13 +01:00
int setColor ( const std : : vector < int > & colors )
{
2021-03-16 02:04:21 +00:00
Result pads , ljc , rjc ;
int res = 0 ;
s32 nbEntries ;
HidsysUniquePadId UniquePadIds [ 2 ] = { } ;
2021-09-11 14:48:13 +01:00
pads = hidsysGetUniquePadsFromNpad ( HidNpadIdType_Handheld , UniquePadIds , 2 , & nbEntries ) ;
if ( R_SUCCEEDED ( pads ) ) {
2021-03-16 02:04:21 +00:00
ljc = hiddbgUpdateControllerColor ( colors [ 0 ] , colors [ 1 ] , UniquePadIds [ 0 ] ) ;
2021-09-11 14:48:13 +01:00
if ( R_FAILED ( ljc ) ) res + = 1 ;
2021-03-16 02:04:21 +00:00
rjc = hiddbgUpdateControllerColor ( colors [ 2 ] , colors [ 3 ] , UniquePadIds [ 1 ] ) ;
2021-09-11 14:48:13 +01:00
if ( R_FAILED ( rjc ) ) res + = 2 ;
2021-03-16 02:04:21 +00:00
}
2021-09-11 14:48:13 +01:00
else {
res + = 4 ;
2021-03-16 02:04:21 +00:00
}
return res ;
}
2021-09-11 14:48:13 +01:00
int backupToJSON ( json & profiles , const std : : string & path )
{
2021-03-16 02:04:21 +00:00
HidNpadControllerColor color_left ;
HidNpadControllerColor color_right ;
Result res = hidGetNpadControllerColorSplit ( HidNpadIdType_Handheld , & color_left , & color_right ) ;
std : : vector < int > oldBackups ;
if ( R_SUCCEEDED ( res ) ) {
int i = 0 ;
2021-09-11 14:48:13 +01:00
for ( const auto & x : profiles . items ( ) ) {
2022-01-06 00:35:39 +00:00
if ( x . value ( ) [ " name " ] = = BACKUP ) {
2021-03-16 02:04:21 +00:00
oldBackups . push_back ( i ) ;
}
i + + ;
}
2021-09-11 14:48:13 +01:00
for ( auto & k : oldBackups ) {
2021-03-16 02:04:21 +00:00
profiles . erase ( profiles . begin ( ) + k ) ;
}
2021-09-11 14:48:13 +01:00
json newBackup = json : : object (
2022-01-06 00:35:39 +00:00
{ { " name " , BACKUP } ,
{ " L_JC " , BGRToHex ( color_left . main ) } ,
{ " L_BTN " , BGRToHex ( color_left . sub ) } ,
{ " R_JC " , BGRToHex ( color_right . main ) } ,
{ " R_BTN " , BGRToHex ( color_right . sub ) } } ) ;
2021-03-16 02:04:21 +00:00
profiles . push_back ( newBackup ) ;
2021-03-16 14:56:46 +00:00
fs : : writeJsonToFile ( profiles , path ) ;
2021-03-16 02:04:21 +00:00
return 0 ;
}
2021-09-11 14:48:13 +01:00
else {
2021-03-16 02:04:21 +00:00
return - 1 ;
}
}
2021-09-11 14:48:13 +01:00
json backupProfile ( )
{
2021-03-16 02:04:21 +00:00
json newBackup ;
HidNpadControllerColor color_left ;
HidNpadControllerColor color_right ;
Result res = hidGetNpadControllerColorSplit ( HidNpadIdType_Handheld , & color_left , & color_right ) ;
if ( R_SUCCEEDED ( res ) ) {
2021-09-11 14:48:13 +01:00
newBackup = json : : object (
2022-01-06 00:35:39 +00:00
{ { " name " , BACKUP } ,
{ " L_JC " , BGRToHex ( color_left . main ) } ,
{ " L_BTN " , BGRToHex ( color_left . sub ) } ,
{ " R_JC " , BGRToHex ( color_right . main ) } ,
{ " R_BTN " , BGRToHex ( color_right . sub ) } } ) ;
2021-03-16 02:04:21 +00:00
}
return newBackup ;
}
2022-01-06 00:35:39 +00:00
std : : deque < std : : pair < std : : string , std : : vector < int > > > getProfiles ( const std : : string & path )
2021-09-11 14:48:13 +01:00
{
2022-01-06 00:35:39 +00:00
std : : deque < std : : pair < std : : string , std : : vector < int > > > res ;
2021-03-16 02:04:21 +00:00
bool properData ;
std : : fstream profilesFile ;
2022-01-06 00:35:39 +00:00
nlohmann : : ordered_json profilesJson ;
download : : getRequest ( JC_COLOR_URL , profilesJson ) ;
2021-09-11 14:48:13 +01:00
if ( profilesJson . empty ( ) ) {
profilesJson = { { { " L_BTN " , " 0A1E0A " } ,
{ " L_JC " , " 82FF96 " } ,
{ " R_BTN " , " 0A1E28 " } ,
{ " R_JC " , " 96F5F5 " } ,
{ " name " , " Animal Crossing: New Horizons " } } } ;
2021-03-16 02:04:21 +00:00
}
2022-01-06 00:35:39 +00:00
for ( const auto & profiles : { fs : : parseJsonFile ( path ) , profilesJson } ) {
for ( const auto & x : profiles . items ( ) ) {
std : : string name = x . value ( ) [ " name " ] ;
brls : : Logger : : warning ( name ) ;
std : : vector < std : : string > values = {
std : : string ( x . value ( ) [ " L_JC " ] ) ,
std : : string ( x . value ( ) [ " L_BTN " ] ) ,
std : : string ( x . value ( ) [ " R_JC " ] ) ,
std : : string ( x . value ( ) [ " R_BTN " ] ) } ;
properData = true ;
for ( auto & str : values ) {
if ( ! isHexaAnd3Bytes ( str ) ) {
properData = false ;
}
}
if ( properData ) {
if ( name = = " " ) name = " Unamed " ;
auto profile = std : : make_pair ( name , ( std : : vector < int > ) {
hexToBGR ( values [ 0 ] ) ,
hexToBGR ( values [ 1 ] ) ,
hexToBGR ( values [ 2 ] ) ,
hexToBGR ( values [ 3 ] ) } ) ;
if ( name = = BACKUP ) {
res . push_front ( profile ) ;
}
else {
res . push_back ( profile ) ;
}
2021-03-16 02:04:21 +00:00
}
}
}
2021-03-16 14:56:46 +00:00
return res ;
2021-03-16 02:04:21 +00:00
}
2021-09-11 14:48:13 +01:00
void changeJCColor ( const std : : vector < int > & values )
{
2021-03-16 02:04:21 +00:00
hiddbgInitialize ( ) ;
hidsysInitialize ( ) ;
ProgressEvent : : instance ( ) . setStep ( 1 ) ;
int res = setColor ( values ) ;
2021-09-11 14:48:13 +01:00
if ( res ! = 0 ) {
2022-03-30 21:23:15 +01:00
util : : showDialogBoxBlocking ( " Could not change the Joy-Cons color. Make sure they're docked and try again. \n Error : " + std : : to_string ( res ) , " Ok " ) ;
2021-03-16 02:04:21 +00:00
}
hiddbgExit ( ) ;
hidsysExit ( ) ;
ProgressEvent : : instance ( ) . setStep ( ProgressEvent : : instance ( ) . getMax ( ) ) ;
}
2021-09-11 14:48:13 +01:00
void backupJCColor ( const std : : string & path )
{
2021-03-16 02:04:21 +00:00
hiddbgInitialize ( ) ;
hidsysInitialize ( ) ;
ProgressEvent : : instance ( ) . setStep ( 1 ) ;
json backup ;
json profiles ;
std : : fstream profilesFile ;
2021-09-11 14:48:13 +01:00
if ( std : : filesystem : : exists ( path ) ) {
2021-03-16 02:04:21 +00:00
profilesFile . open ( path , std : : fstream : : in ) ;
profilesFile > > profiles ;
profilesFile . close ( ) ;
}
std : : vector < int > oldBackups ;
int i = 0 ;
2021-09-11 14:48:13 +01:00
for ( const auto & x : profiles . items ( ) ) {
2022-01-06 00:35:39 +00:00
if ( x . value ( ) [ " name " ] = = BACKUP ) {
2021-03-16 02:04:21 +00:00
oldBackups . push_back ( i ) ;
}
i + + ;
}
2021-09-11 14:48:13 +01:00
for ( auto & k : oldBackups ) {
2021-03-16 02:04:21 +00:00
profiles . erase ( profiles . begin ( ) + k ) ;
}
2021-09-11 14:48:13 +01:00
while ( backup . empty ( ) ) {
2021-03-16 02:04:21 +00:00
backup = backupProfile ( ) ;
}
profiles . push_back ( backup ) ;
//backup.push_back(profiles);
2021-03-16 14:56:46 +00:00
fs : : writeJsonToFile ( profiles , path ) ;
2021-03-16 02:04:21 +00:00
hiddbgExit ( ) ;
hidsysExit ( ) ;
ProgressEvent : : instance ( ) . setStep ( ProgressEvent : : instance ( ) . getMax ( ) ) ;
}
2021-09-11 14:48:13 +01:00
} // namespace JC
2021-03-16 02:04:21 +00:00
namespace PC {
2021-09-11 14:48:13 +01:00
int setColor ( const std : : vector < int > & colors )
{
2021-03-16 02:04:21 +00:00
Result pads , pc ;
int res = 0 ;
s32 nbEntries ;
HidsysUniquePadId UniquePadIds [ 1 ] = { } ;
2021-09-11 14:48:13 +01:00
pads = hidsysGetUniquePadsFromNpad ( HidNpadIdType_No1 , UniquePadIds , 1 , & nbEntries ) ;
if ( R_SUCCEEDED ( pads ) ) {
2021-03-16 02:04:21 +00:00
pc = hiddbgUpdateControllerColor ( colors [ 0 ] , colors [ 1 ] , UniquePadIds [ 0 ] ) ;
2021-09-11 14:48:13 +01:00
if ( R_FAILED ( pc ) ) res + = 1 ;
2021-03-16 02:04:21 +00:00
}
2021-09-11 14:48:13 +01:00
else {
res + = 4 ;
2021-03-16 02:04:21 +00:00
}
return res ;
}
2021-09-11 14:48:13 +01:00
int backupToJSON ( json & profiles , const std : : string & path )
{
2021-03-16 02:04:21 +00:00
HidNpadControllerColor color ;
Result res = hidGetNpadControllerColorSingle ( HidNpadIdType_No1 , & color ) ;
std : : vector < int > oldBackups ;
if ( R_SUCCEEDED ( res ) ) {
int i = 0 ;
2021-09-11 14:48:13 +01:00
for ( const auto & x : profiles . items ( ) ) {
2022-01-06 00:35:39 +00:00
if ( x . value ( ) [ " name " ] = = BACKUP ) {
2021-03-16 02:04:21 +00:00
oldBackups . push_back ( i ) ;
}
i + + ;
}
2021-09-11 14:48:13 +01:00
for ( auto & k : oldBackups ) {
2021-03-16 02:04:21 +00:00
profiles . erase ( profiles . begin ( ) + k ) ;
}
2021-09-11 14:48:13 +01:00
json newBackup = json : : object (
2022-01-06 00:35:39 +00:00
{ { " name " , BACKUP } ,
{ " BODY " , BGRToHex ( color . main ) } ,
{ " BTN " , BGRToHex ( color . sub ) } } ) ;
2021-03-16 02:04:21 +00:00
profiles . push_back ( newBackup ) ;
2021-03-16 14:56:46 +00:00
fs : : writeJsonToFile ( profiles , path ) ;
2021-03-16 02:04:21 +00:00
return 0 ;
}
2021-09-11 14:48:13 +01:00
else {
2021-03-16 02:04:21 +00:00
return - 1 ;
}
}
2021-09-11 14:48:13 +01:00
json backupProfile ( )
{
2021-03-16 02:04:21 +00:00
json newBackup ;
HidNpadControllerColor color ;
Result res = hidGetNpadControllerColorSingle ( HidNpadIdType_No1 , & color ) ;
if ( R_SUCCEEDED ( res ) ) {
2021-09-11 14:48:13 +01:00
newBackup = json : : object (
2022-01-06 00:35:39 +00:00
{ { " name " , BACKUP } ,
{ " BODY " , BGRToHex ( color . main ) } ,
{ " BTN " , BGRToHex ( color . sub ) } } ) ;
2021-03-16 02:04:21 +00:00
}
return newBackup ;
}
2022-01-06 00:35:39 +00:00
std : : deque < std : : pair < std : : string , std : : vector < int > > > getProfiles ( const std : : string & path )
2021-09-11 14:48:13 +01:00
{
2022-01-06 00:35:39 +00:00
std : : deque < std : : pair < std : : string , std : : vector < int > > > res ;
2021-03-16 02:04:21 +00:00
bool properData ;
std : : fstream profilesFile ;
2022-01-06 00:35:39 +00:00
nlohmann : : ordered_json profilesJson ;
download : : getRequest ( PC_COLOR_URL , profilesJson ) ;
2021-09-11 14:48:13 +01:00
if ( profilesJson . empty ( ) ) {
profilesJson = { { { " BTN " , " e6e6e6 " } ,
{ " BODY " , " 2d2d2d " } ,
{ " name " , " Default black " } } } ;
2021-03-16 02:04:21 +00:00
}
2022-01-06 00:42:31 +00:00
for ( const auto & profiles : { fs : : parseJsonFile ( path ) , profilesJson } ) {
for ( const auto & x : profiles . items ( ) ) {
std : : string name = x . value ( ) [ " name " ] ;
std : : vector < std : : string > values = {
std : : string ( x . value ( ) [ " BODY " ] ) ,
std : : string ( x . value ( ) [ " BTN " ] ) } ;
properData = true ;
for ( auto & str : values ) {
if ( ! isHexaAnd3Bytes ( str ) ) {
properData = false ;
}
2022-01-06 00:35:39 +00:00
}
2022-01-06 00:42:31 +00:00
if ( properData ) {
if ( name = = " " ) name = " Unamed " ;
auto profile = std : : make_pair ( name , ( std : : vector < int > ) {
hexToBGR ( values [ 0 ] ) ,
hexToBGR ( values [ 1 ] ) } ) ;
if ( name = = BACKUP ) {
res . push_front ( profile ) ;
}
else {
res . push_back ( profile ) ;
}
2022-01-06 00:35:39 +00:00
}
2021-03-16 02:04:21 +00:00
}
}
2021-03-16 14:56:46 +00:00
return res ;
2021-03-16 02:04:21 +00:00
}
2021-09-11 14:48:13 +01:00
void changePCColor ( const std : : vector < int > & values )
{
2021-03-16 02:04:21 +00:00
hiddbgInitialize ( ) ;
hidsysInitialize ( ) ;
ProgressEvent : : instance ( ) . setStep ( 1 ) ;
int res = setColor ( values ) ;
2021-09-11 14:48:13 +01:00
if ( res ! = 0 ) {
2022-03-30 21:23:15 +01:00
util : : showDialogBoxBlocking ( " Could not change the Pro-Con color. Make they're connected to P1. This feature may not work on unofficial controllers. \n Error : " + std : : to_string ( res ) , " Ok " ) ;
2021-03-16 02:04:21 +00:00
}
hiddbgExit ( ) ;
hidsysExit ( ) ;
ProgressEvent : : instance ( ) . setStep ( ProgressEvent : : instance ( ) . getMax ( ) ) ;
}
2021-09-11 14:48:13 +01:00
void backupPCColor ( const std : : string & path )
{
2021-03-16 02:04:21 +00:00
hiddbgInitialize ( ) ;
hidsysInitialize ( ) ;
ProgressEvent : : instance ( ) . setStep ( 1 ) ;
json backup ;
json profiles ;
std : : fstream profilesFile ;
2021-09-11 14:48:13 +01:00
if ( std : : filesystem : : exists ( path ) ) {
2021-03-16 02:04:21 +00:00
profilesFile . open ( path , std : : fstream : : in ) ;
profilesFile > > profiles ;
profilesFile . close ( ) ;
}
std : : vector < int > oldBackups ;
int i = 0 ;
2021-09-11 14:48:13 +01:00
for ( const auto & x : profiles . items ( ) ) {
2022-01-06 00:35:39 +00:00
if ( x . value ( ) [ " name " ] = = BACKUP ) {
2021-03-16 02:04:21 +00:00
oldBackups . push_back ( i ) ;
}
i + + ;
}
2021-09-11 14:48:13 +01:00
for ( auto & k : oldBackups ) {
2021-03-16 02:04:21 +00:00
profiles . erase ( profiles . begin ( ) + k ) ;
}
2021-09-11 14:48:13 +01:00
while ( backup . empty ( ) ) {
2021-03-16 02:04:21 +00:00
backup = backupProfile ( ) ;
}
profiles . push_back ( backup ) ;
//backup.push_back(profiles);
2021-03-16 14:56:46 +00:00
fs : : writeJsonToFile ( profiles , path ) ;
2021-03-16 02:04:21 +00:00
hiddbgExit ( ) ;
hidsysExit ( ) ;
ProgressEvent : : instance ( ) . setStep ( ProgressEvent : : instance ( ) . getMax ( ) ) ;
}
2021-09-11 14:48:13 +01:00
} // namespace PC