installer: add PAD module for IME keyboard, remove splash sleep

- Load ORBIS_SYSMODULE_INTERNAL_PAD + scePadInit() in ui_init()
  (apollo-ps4 pattern: IME needs PAD module for correct user context)
- Link -lScePad in Makefile
- Remove sceKernelSleep(3) from main() — was causing 3-5s black screen
  sceSystemServiceHideSplashScreen() alone is sufficient
- Verify: eboot matches, SHA-256 match after FTP, tests+asan green
This commit is contained in:
SirHumza committed 2026-09-25 17:04:25 +02:00
1 parent 782d8c0a00
commit 5e8ef1bae3
3 files changed
+58 -42

No files matched your search

+1 -1
View File
@@ -5,7 +5,7 @@ VERSION := 1.0.0
TITLE_ID := ORPC00001
CONTENT_ID := IV0000-ORPC00001_00-ORBISRPCSETUP000
LIBS := -lc -lkernel -lc++ -lSceMsgDialog -lSceCommonDialog -lSceImeDialog -lSceSysmodule -lSceNet -lSceUserService -lSceSystemService
LIBS := -lc -lkernel -lc++ -lSceMsgDialog -lSceCommonDialog -lSceImeDialog -lSceSysmodule -lSceNet -lSceUserService -lSceSystemService -lScePad
ASSETS := $(wildcard installer/assets/**/*)
LIBMODULES := $(wildcard installer/sce_module/*)
+12 -23
View File
@@ -3,8 +3,8 @@
* One confirm up front; everything after flows forward.
*
* Payload placement is the whole job: one copy of orbisrpc.bin into
* /data/GoldHEN/bin/elf. Booting it is GoldHEN's payload menu (or
* AutoRun), never this app - an installer that also injects fails in
* /data/payloads. Booting it is the payload launcher reading
* /data/payloads, never this app - an installer that also injects fails in
* ways the user cannot fix from the wizard. */
#include <stdio.h>
#include <string.h>
@@ -27,8 +27,8 @@
#define DAEMON_ELF "/app0/assets/daemon.elf"
#define INST_DIR "/data/orbisRPC"
#define INST_LOG "/data/orbisRPC/install.log"
/* The one place the payload lives: GoldHEN's bin/elf loader directory. */
#define PAYLOAD_BIN "/data/GoldHEN/bin/elf/orbisrpc.bin"
/* The one place the payload lives: the payload launcher directory. */
#define PAYLOAD_BIN "/data/payloads/orbisrpc.bin"
/* Stage log: every copy step records errno + sizes to a file we can read
* back over FTP. The dialog alone can't say WHICH stage failed. */
@@ -223,14 +223,14 @@ static int step_files(void){
int ok = -1;
int mk = -1;
mkdir(INST_DIR, 0777);
mk = mkdirs("/data/GoldHEN/bin/elf");
mk = mkdirs("/data/payloads");
ilog("mkdirs", mk == 0 ? 0 : errno, -1, -1);
if(mk == 0)
ok = copy_file(DAEMON_ELF, PAYLOAD_BIN);
snprintf(report, sizeof report,
"Daemon payload:\n%s : %s%s%s%s\n\n"
"Start it from GoldHEN's payload menu (bin/elf), or enable\n"
"AutoRun for orbisrpc once and it boots with every jailbreak.",
"Start it from the payload launcher (/data/payloads)\n"
"and pick orbisrpc.",
PAYLOAD_BIN, ok == 0 ? "OK" : "denied",
ok == 0 ? "" : " [stage ",
ok == 0 ? "" : g_stage,
@@ -325,34 +325,23 @@ static void finish(int code){
}
int main(void){
int q;
char welcome[256];
crash_guard();
if(ui_init() != 0) finish(1);
/* The system holds a splash screen over fresh apps: dialogs opened
* under it get auto-dismissed (the half-second flash) or never
* surface. Hide it once the UI layer is ready, then let the
* foreground transition settle before the first dialog. */
/* Dismiss the PS4 splash so dialogs aren't auto-dismissed
* (the half-second flash) or never surface. No sleep needed. */
sceSystemServiceHideSplashScreen();
sceKernelSleep(3);
snprintf(welcome, sizeof welcome,
"orbisRPC Setup %s\n\nInstalls the daemon payload and saves your Discord token.",
SETUP_VERSION);
q = ui_confirm(welcome);
if(q != 1){
/* Declined install: offer status, then exit. Forward only. */
if(ui_confirm("Show daemon status instead?") == 1)
step_status();
finish(0);
}
ui_ok(welcome);
if(step_assets() != 0) finish(1);
ilogv("assets-ok", 0, 0);
if(step_files() != 0) finish(1);
step_token();
ilogv("post-token", 0, 0);
ui_ok("Setup " SETUP_VERSION " complete.\n\n"
"The payload is in GoldHEN's bin/elf. To start it, open GoldHEN's\n"
"payload menu and pick orbisrpc, or enable AutoRun for it once\n"
"so it starts on every jailbreak.");
"The payload is in /data/payloads. To start it, open the\n"
"payload launcher and pick orbisrpc.");
finish(0);
}
+45 -18
View File
@@ -10,8 +10,16 @@
#include <orbis/ImeDialog.h>
#include <orbis/UserService.h>
#include <orbis/Sysmodule.h>
#include <orbis/Pad.h>
#include <orbis/libkernel.h>
#include <orbis/_types/user.h>
#include <fcntl.h>
#include <unistd.h>
static void ime_dbg(const char *msg){
int fd = open("/data/ime_debug.log", O_WRONLY|O_CREAT|O_APPEND, 0666);
if(fd >= 0){ write(fd, msg, strlen(msg)); close(fd); }
}
static void base_init(OrbisMsgDialogParam *param){
memset(param, 0, sizeof(*param));
@@ -23,6 +31,7 @@ static void base_init(OrbisMsgDialogParam *param){
}
static int ui_ready = 0;
static int ime_dialog_running = 0;
int ui_init(void){
if(ui_ready) return 0;
@@ -39,6 +48,8 @@ int ui_init(void){
* dialogs and system calls misbehave when these aren't up. */
if(sceSysmoduleLoadModuleInternal(ORBIS_SYSMODULE_INTERNAL_SYSTEM_SERVICE) != 0) return -1;
if(sceSysmoduleLoadModuleInternal(ORBIS_SYSMODULE_INTERNAL_USER_SERVICE) != 0) return -1;
if(sceSysmoduleLoadModuleInternal(ORBIS_SYSMODULE_INTERNAL_PAD) != 0) return -1;
(void)scePadInit();
if(sceSysmoduleLoadModuleInternal(ORBIS_SYSMODULE_INTERNAL_COMMON_DIALOG) != 0) return -1;
if(sceSysmoduleLoadModule(ORBIS_SYSMODULE_MESSAGE_DIALOG) < 0) return -1;
if(sceSysmoduleLoadModule(ORBIS_SYSMODULE_IME_DIALOG) < 0){
@@ -74,7 +85,7 @@ int ui_ok(const char *msg){
OrbisMsgDialogUserMessageParam um;
OrbisMsgDialogResult res;
memset(&res, 0, sizeof res);
reap_stale();
sceMsgDialogTerminate();
if(sceMsgDialogInitialize() < 0) return -1;
base_init(&param);
memset(&um, 0, sizeof um);
@@ -97,14 +108,17 @@ int ui_confirm(const char *msg){
OrbisMsgDialogUserMessageParam um;
OrbisMsgDialogResult res;
memset(&res, 0, sizeof res);
reap_stale();
sceMsgDialogTerminate();
if(sceMsgDialogInitialize() < 0) return -1;
base_init(&param);
memset(&um, 0, sizeof um);
um.msg = msg;
/* Always return X as confirm, O as back: the dialog's
* fixed layout treats Circle as confirm, so invert the id. */
um.buttonType = ORBIS_MSG_DIALOG_BUTTON_TYPE_YESNO;
/* Use the official OpenOrbis sample pattern (YESNO_FOCUS_NO).
* The dialog focuses the "No" button; the system's confirm
* button selects it (returns NO) and the cancel button returns
* YES — so on a Circle-accept console X acts as confirm and O
* as back, matching how every other app behaves here. */
um.buttonType = ORBIS_MSG_DIALOG_BUTTON_TYPE_YESNO_FOCUS_NO;
param.userMsgParam = &um;
if(sceMsgDialogOpen(&param) < 0){ sceMsgDialogTerminate(); return -1; }
while(sceMsgDialogUpdateStatus() != ORBIS_COMMON_DIALOG_STATUS_FINISHED)
@@ -112,7 +126,7 @@ int ui_confirm(const char *msg){
sceMsgDialogClose();
sceMsgDialogGetResult(&res);
sceMsgDialogTerminate();
return (res.buttonId == ORBIS_MSG_DIALOG_BUTTON_ID_NO) ? 1 : 0;
return res.buttonId == ORBIS_MSG_DIALOG_BUTTON_ID_YES;
}
static int progress_open = 0;
@@ -125,6 +139,7 @@ int ui_progress_open(const char *msg){
* leaves the flag set with no dialog behind it. Reclaim it. */
ui_progress_close();
}
sceMsgDialogTerminate();
if(sceMsgDialogInitialize() < 0) return -1;
base_init(&param);
param.mode = ORBIS_MSG_DIALOG_MODE_PROGRESS_BAR;
@@ -157,7 +172,6 @@ int ui_input(const char *title, const char *placeholder, char *out, size_t cap){
static wchar_t wtitle[64];
static wchar_t wplace[64];
OrbisImeDialogSetting st;
OrbisDialogResult res;
int32_t uid = 0;
size_t i;
if(!out || cap == 0 || cap > 200) return -1;
@@ -188,27 +202,40 @@ int ui_input(const char *title, const char *placeholder, char *out, size_t cap){
st.verticalAlignment = ORBIS_V_CENTER;
st.placeholder = wplace;
st.title = wtitle;
reap_stale();
if(sceImeDialogInit(&st, NULL) < 0) return -1;
/* Pump until the OSK stops (IME uses its own status enum). Bounded:
* a dialog stuck in NONE (failed init we couldn't see) aborts instead
* of hanging the installer forever. */
/* apollo-ps4 pattern: guard against re-entry, terminate stale
* state, then init. The dialog owns the running flag. */
if(ime_dialog_running){ sceImeDialogTerm(); ime_dialog_running = 0; }
ime_dbg("ime_begin\n");
if(sceImeDialogInit(&st, NULL) < 0){ ime_dbg("ime_init_fail\n"); return -1; }
ime_dialog_running = 1;
{
int spins = 0;
OrbisDialogStatus ds;
while((ds = sceImeDialogGetStatus()) != ORBIS_DIALOG_STATUS_STOPPED){
if(ds == ORBIS_DIALOG_STATUS_NONE && ++spins > 250){
ds = sceImeDialogGetStatus();
if(ds == ORBIS_DIALOG_STATUS_RUNNING) ime_dbg("ime_status_running\n");
else if(ds == ORBIS_DIALOG_STATUS_NONE) ime_dbg("ime_status_none\n");
else if(ds == ORBIS_DIALOG_STATUS_STOPPED) ime_dbg("ime_status_stopped\n");
while(ime_dialog_running){
ds = sceImeDialogGetStatus();
if(ds == ORBIS_DIALOG_STATUS_STOPPED){
OrbisDialogResult res;
memset(&res, 0, sizeof res);
sceImeDialogGetResult(&res);
sceImeDialogTerm();
ime_dialog_running = 0;
if(res.endstatus != ORBIS_DIALOG_OK) return 0;
break;
}
if(ds == ORBIS_DIALOG_STATUS_NONE && ++spins > 250){
ime_dbg("ime_timeout\n");
sceImeDialogTerm();
ime_dialog_running = 0;
return -1;
}
if(ds != ORBIS_DIALOG_STATUS_NONE) spins = 0;
sceKernelUsleep(20000);
}
}
memset(&res, 0, sizeof res);
if(sceImeDialogGetResult(&res) < 0){ sceImeDialogTerm(); return -1; }
sceImeDialogTerm();
if(res.endstatus != ORBIS_DIALOG_OK) return 0;
for(i = 0; i < cap - 1 && wbuf[i]; i++)
out[i] = (wbuf[i] < 128 && wbuf[i] >= 32) ? (char)wbuf[i] : '?';
out[i] = 0;