Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
name: Build ipswitch.nro

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
workflow_dispatch:
inputs:
version:
description: 'Release version. Leave it empty to avoid publishing a release.'
required: false
type: string

jobs:
build:
runs-on: ubuntu-latest
container:
image: devkitpro/devkita64:latest
options: --user root

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Compilar e instalar liblz4 para Switch
# No usamos dkp-pacman: pkg.devkitpro.org devuelve 403 a las IPs de
# GitHub Actions (bloqueo conocido de su Cloudflare/WAF, no soportan
# pacman en CI). En su lugar compilamos lz4 desde su código fuente
# oficial en GitHub con el toolchain devkitA64 ya presente en la imagen.
run: |
export PATH="$DEVKITPRO/devkitA64/bin:$PATH"
export CC=aarch64-none-elf-gcc
export AR=aarch64-none-elf-gcc-ar
ARCH_FLAGS="-march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIC -ftls-model=local-exec"

curl -L -o /tmp/lz4.tar.gz https://github.com/lz4/lz4/archive/refs/tags/v1.9.4.tar.gz
tar xf /tmp/lz4.tar.gz -C /tmp
cd /tmp/lz4-1.9.4/lib

make liblz4.a CC="$CC" AR="$AR" CFLAGS="-O2 $ARCH_FLAGS -D__SWITCH__"

PORTLIBS="$DEVKITPRO/portlibs/switch"
mkdir -p "$PORTLIBS/include" "$PORTLIBS/lib"
cp liblz4.a "$PORTLIBS/lib/"
cp lz4.h lz4hc.h lz4frame.h "$PORTLIBS/include/"

- name: Build
run: make
env:
DEVKITPRO: /opt/devkitpro
DEVKITA64: /opt/devkitpro/devkitA64

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ipswitch
path: '*.nro'
if-no-files-found: error

release:
needs: build
runs-on: ubuntu-latest
if: github.event_name == 'workflow_dispatch' && inputs.version != ''
permissions:
contents: write

steps:
- name: Download build artifact
uses: actions/download-artifact@v4
with:
name: ipswitch

- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: "v${{ inputs.version }}"
name: "ipswitch v${{ inputs.version }}"
files: '*.nro'
draft: false
prerelease: false
11 changes: 3 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,13 @@ include $(DEVKITPRO)/libnx/switch_rules
# - <libnx folder>/default_icon.jpg
#---------------------------------------------------------------------------------

GITREV := $(shell git rev-parse HEAD && rm -f $(notdir $(CURDIR)).nacp)

VERSION_MAJOR := 0
VERSION_MINOR := 2
VERSION_MICRO := 1
ifneq ($(GITREV),)
VERSION_MICRO := $(VERSION_MICRO)-$(GITREV)
endif
VERSION_MICRO := 3

APP_TITLE := IPSwitch
APP_AUTHOR := 3096
APP_VERSION := w${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO}
APP_VERSION := ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO}

TARGET := $(notdir $(CURDIR))
BUILD := build
Expand Down Expand Up @@ -204,4 +199,4 @@ $(OFILES_SRC) : $(HFILES_BIN)

#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------
#---------------------------------------------------------------------------------------
6 changes: 3 additions & 3 deletions source/config.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#include "config.h"
#include "patch.h"

int checkRequirement() {
int checkRequirement(PadState* pad) {
if(!isDirectory(ATMOS_DIR)) {
userConfirm("Do you even Atmosphere bro?");
userConfirm("Do you even Atmosphere bro?", pad);
return -1;
}
return 0;
}
}
4 changes: 2 additions & 2 deletions source/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
#define LINE_MAX_SIZE 0x1000

// Return 0 if all checks passed
int checkRequirement();
int checkRequirement(PadState* pad);

#endif
#endif
115 changes: 94 additions & 21 deletions source/console.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,31 +123,88 @@ void selectIndex(int* selection, StrList* str_list, int change) {
printf(menu_buffer);
}

u64 selectFromList(int* selection, StrList* str_list) {
u64 selectFromList(int* selection, StrList* str_list, PadState* pad) {
if(str_list->size <= 0) {
if(userConfirm("Error: list is empty"))
if(userConfirm("Error: list is empty", pad))
return 0;
else
return KEY_PLUS;
return HidNpadButton_Plus;
}

selectIndex(selection, str_list, 0);

u64 kDownPrevious = 0xFFFFFFFFFFFFFFFF;
static u64 stick_cooldown = 0;

while(appletMainLoop()) {
hidScanInput();
u64 kDown = hidKeysDown(CONTROLLER_P1_AUTO);
kDown = kDown&(0xFFFFFFFFFFFFFFFF-KEY_TOUCH); // "can't touch this"

if (kDown & KEY_UP)
padUpdate(pad);
u64 kDown = padGetButtonsDown(pad);

// Get analog stick positions
HidAnalogStickState analog_stick_l = padGetStickPos(pad, 0);
HidAnalogStickState analog_stick_r = padGetStickPos(pad, 1);

bool direction_pressed = false;

// Handle directional buttons first
if (kDown & HidNpadButton_Up) {
selectIndex(selection, str_list, -1);
else if (kDown & KEY_DOWN)
stick_cooldown = 15;
direction_pressed = true;
}
else if (kDown & HidNpadButton_Down) {
selectIndex(selection, str_list, 1);
else if (kDown & KEY_LEFT)
stick_cooldown = 15;
direction_pressed = true;
}
else if (kDown & HidNpadButton_Left) {
selectIndex(selection, str_list, -5);
else if (kDown & KEY_RIGHT)
stick_cooldown = 15;
direction_pressed = true;
}
else if (kDown & HidNpadButton_Right) {
selectIndex(selection, str_list, 5);
else if (kDown & KEY_A) {
stick_cooldown = 15;
direction_pressed = true;
}
// Check analog sticks only if cooldown expired and no button was pressed
else if (stick_cooldown == 0) {
const s32 STICK_THRESHOLD = 25000;

if (analog_stick_l.y > STICK_THRESHOLD || analog_stick_r.y > STICK_THRESHOLD) {
selectIndex(selection, str_list, -1);
stick_cooldown = 15;
direction_pressed = true;
}
else if (analog_stick_l.y < -STICK_THRESHOLD || analog_stick_r.y < -STICK_THRESHOLD) {
selectIndex(selection, str_list, 1);
stick_cooldown = 15;
direction_pressed = true;
}
else if (analog_stick_l.x < -STICK_THRESHOLD || analog_stick_r.x < -STICK_THRESHOLD) {
selectIndex(selection, str_list, -5);
stick_cooldown = 15;
direction_pressed = true;
}
else if (analog_stick_l.x > STICK_THRESHOLD || analog_stick_r.x > STICK_THRESHOLD) {
selectIndex(selection, str_list, 5);
stick_cooldown = 15;
direction_pressed = true;
}
}

// Decrease cooldown
if (stick_cooldown > 0) {
stick_cooldown--;
}

// If we moved with direction, skip checking action buttons
if (direction_pressed) {
consoleUpdate(NULL);
continue;
}

// Now check action buttons
if (kDown & HidNpadButton_A) {
char* cur_str = str_list->str_list[*selection];
u16 str_tail = getStringTailU16(cur_str);
if(str_tail == TOGGLE_ENABLED) {
Expand All @@ -161,28 +218,44 @@ u64 selectFromList(int* selection, StrList* str_list) {
return kDown;
}
}
else if(kDown > kDownPrevious) {
else if(kDown & HidNpadButton_B) {
printf("\n");
return kDown;
}
kDownPrevious = kDown;
else if(kDown & HidNpadButton_Plus) {
printf("\n");
return kDown;
}
else if(kDown & HidNpadButton_Minus) {
printf("\n");
return kDown;
}
else if(kDown & HidNpadButton_X) {
printf("\n");
return kDown;
}
else if(kDown & HidNpadButton_Y) {
printf("\n");
return kDown;
}

consoleUpdate(NULL);
}

return 0;
}

bool userConfirm(const char * msg) {
bool userConfirm(const char * msg, PadState* pad) {
printf("\n%s\nPress A to confirm, any other button to cancel\n", msg);

u64 kDownPrevious = hidKeysDown(CONTROLLER_P1_AUTO);
u64 kDownPrevious = padGetButtonsDown(pad);
while(appletMainLoop())
{
hidScanInput();
u64 kDown = hidKeysDown(CONTROLLER_P1_AUTO);
padUpdate(pad);
u64 kDown = padGetButtonsDown(pad);

if(kDown > kDownPrevious) {
if (kDown & KEY_A)
if (kDown & HidNpadButton_A)
return true;
else {
printf("Canceled\n");
Expand Down Expand Up @@ -210,4 +283,4 @@ void printBytesAsHex(const u8* bytes, size_t size) {
for(size_t i = 0; i < size; i++) {
printf("%02X", bytes[i]);
}
}
}
4 changes: 2 additions & 2 deletions source/console.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@

u16 getStringTailU16(char* str);

u64 selectFromList(int* selection, StrList* str_list);
u64 selectFromList(int* selection, StrList* str_list, PadState* pad);

bool userConfirm(const char* msg);
bool userConfirm(const char* msg, PadState* pad);

void printInProgress(const char* msg);
void printDone();
Expand Down
15 changes: 11 additions & 4 deletions source/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,20 @@
int main(int argc, char **argv) {
consoleInit(NULL);

if (checkRequirement() == 0) {
// Configure input - 1 player using standard controller
padConfigureInput(1, HidNpadStyleSet_NpadStandard);

// Initialize the default gamepad (Player 1 controller)
PadState pad;
padInitializeDefault(&pad);

if (checkRequirement(&pad) == 0) {
printf(CONSOLE_ESC(35;1m)
"Welcome to IPSwitch. Do no evil.\n\n" CONSOLE_ESC(m));
"Welcome to IPSwitch\n\n" CONSOLE_ESC(m));

mainMenu();
mainMenu(&pad);
}

consoleExit(NULL);
return 0;
}
}
Loading