mirror of
https://github.com/SirHumza/orbisRPC.git
synced 2026-10-06 14:00:36 +02:00
196 lines
6.9 KiB
C
196 lines
6.9 KiB
C
/* ui.c - native PS4 dialogs: MsgDialog (ok / yes-no / progress) + ImeDialog.
|
|
* Everything here needs the console (dialog system calls); pure logic
|
|
* (validation, config merge) lives in icfg.c and is host-tested. */
|
|
#include "ui.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <wchar.h>
|
|
#include <orbis/CommonDialog.h>
|
|
#include <orbis/MsgDialog.h>
|
|
#include <orbis/ImeDialog.h>
|
|
#include <orbis/UserService.h>
|
|
#include <orbis/Sysmodule.h>
|
|
#include <orbis/libkernel.h>
|
|
#include <orbis/_types/user.h>
|
|
|
|
static void base_init(OrbisMsgDialogParam *param){
|
|
memset(param, 0, sizeof(*param));
|
|
param->baseParam.size = (uint32_t)sizeof(param->baseParam);
|
|
param->baseParam.magic =
|
|
(uint32_t)(ORBIS_COMMON_DIALOG_MAGIC_NUMBER + (uint64_t)¶m->baseParam);
|
|
param->size = sizeof(OrbisMsgDialogParam);
|
|
param->mode = ORBIS_MSG_DIALOG_MODE_USER_MSG;
|
|
}
|
|
|
|
static int ui_ready = 0;
|
|
|
|
int ui_init(void){
|
|
if(ui_ready) return 0;
|
|
{
|
|
/* UserService first: dialogs + pad + IME all key off the user.
|
|
* Best-effort (already-initialized is fine); uid fallbacks
|
|
* downstream keep every path forward-safe. */
|
|
OrbisUserServiceInitializeParams up;
|
|
memset(&up, 0, sizeof up);
|
|
up.priority = ORBIS_KERNEL_PRIO_FIFO_LOWEST;
|
|
(void)sceUserServiceInitialize(&up);
|
|
}
|
|
/* Internal service modules first (Payload Guest boot pattern):
|
|
* 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_COMMON_DIALOG) != 0) return -1;
|
|
if(sceSysmoduleLoadModule(ORBIS_SYSMODULE_MESSAGE_DIALOG) < 0) return -1;
|
|
if(sceSysmoduleLoadModule(ORBIS_SYSMODULE_IME_DIALOG) < 0){
|
|
sceSysmoduleUnloadModule(ORBIS_SYSMODULE_MESSAGE_DIALOG);
|
|
return -1;
|
|
}
|
|
if(sceSysmoduleLoadModule(ORBIS_SYSMODULE_IME_BACKEND) < 0){
|
|
sceSysmoduleUnloadModule(ORBIS_SYSMODULE_IME_DIALOG);
|
|
sceSysmoduleUnloadModule(ORBIS_SYSMODULE_MESSAGE_DIALOG);
|
|
return -1;
|
|
}
|
|
if(sceCommonDialogInitialize() < 0){
|
|
sceSysmoduleUnloadModule(ORBIS_SYSMODULE_IME_BACKEND);
|
|
sceSysmoduleUnloadModule(ORBIS_SYSMODULE_IME_DIALOG);
|
|
sceSysmoduleUnloadModule(ORBIS_SYSMODULE_MESSAGE_DIALOG);
|
|
return -1;
|
|
}
|
|
ui_ready = 1;
|
|
return 0;
|
|
}
|
|
|
|
int ui_ok(const char *msg){
|
|
OrbisMsgDialogParam param;
|
|
OrbisMsgDialogUserMessageParam um;
|
|
OrbisMsgDialogResult res;
|
|
memset(&res, 0, sizeof res);
|
|
sceMsgDialogInitialize();
|
|
base_init(¶m);
|
|
memset(&um, 0, sizeof um);
|
|
um.msg = msg;
|
|
um.buttonType = ORBIS_MSG_DIALOG_BUTTON_TYPE_OK;
|
|
param.userMsgParam = &um;
|
|
if(sceMsgDialogOpen(¶m) < 0){ sceMsgDialogTerminate(); return -1; }
|
|
do { } while(sceMsgDialogUpdateStatus() != ORBIS_COMMON_DIALOG_STATUS_FINISHED);
|
|
sceMsgDialogClose();
|
|
sceMsgDialogGetResult(&res);
|
|
sceMsgDialogTerminate();
|
|
return 0;
|
|
}
|
|
|
|
int ui_confirm(const char *msg){
|
|
OrbisMsgDialogParam param;
|
|
OrbisMsgDialogUserMessageParam um;
|
|
OrbisMsgDialogResult res;
|
|
memset(&res, 0, sizeof res);
|
|
sceMsgDialogInitialize();
|
|
base_init(¶m);
|
|
memset(&um, 0, sizeof um);
|
|
um.msg = msg;
|
|
um.buttonType = ORBIS_MSG_DIALOG_BUTTON_TYPE_YESNO_FOCUS_NO;
|
|
param.userMsgParam = &um;
|
|
if(sceMsgDialogOpen(¶m) < 0){ sceMsgDialogTerminate(); return -1; }
|
|
do { } while(sceMsgDialogUpdateStatus() != ORBIS_COMMON_DIALOG_STATUS_FINISHED);
|
|
sceMsgDialogClose();
|
|
sceMsgDialogGetResult(&res);
|
|
sceMsgDialogTerminate();
|
|
return res.buttonId == ORBIS_MSG_DIALOG_BUTTON_ID_YES ? 1 : 0;
|
|
}
|
|
|
|
static int progress_open = 0;
|
|
|
|
int ui_progress_open(const char *msg){
|
|
OrbisMsgDialogParam param;
|
|
OrbisMsgDialogProgressBarParam bar;
|
|
if(progress_open){
|
|
/* Self-healing: a prior session that died between open and close
|
|
* leaves the flag set with no dialog behind it. Reclaim it. */
|
|
ui_progress_close();
|
|
}
|
|
sceMsgDialogInitialize();
|
|
base_init(¶m);
|
|
param.mode = ORBIS_MSG_DIALOG_MODE_PROGRESS_BAR;
|
|
memset(&bar, 0, sizeof bar);
|
|
bar.barType = ORBIS_MSG_DIALOG_PROGRESSBAR_TYPE_PERCENTAGE;
|
|
bar.msg = msg;
|
|
param.progBarParam = &bar;
|
|
if(sceMsgDialogOpen(¶m) < 0){ sceMsgDialogTerminate(); return -1; }
|
|
progress_open = 1;
|
|
return 0;
|
|
}
|
|
|
|
void ui_progress_msg(const char *msg){
|
|
if(progress_open && msg) sceMsgDialogProgressBarSetMsg(0, msg);
|
|
}
|
|
|
|
void ui_progress_set(unsigned pct){
|
|
if(progress_open) sceMsgDialogProgressBarSetValue(0, pct > 100 ? 100 : pct);
|
|
}
|
|
|
|
void ui_progress_close(void){
|
|
if(!progress_open) return;
|
|
progress_open = 0;
|
|
sceMsgDialogClose();
|
|
sceMsgDialogTerminate();
|
|
}
|
|
|
|
int ui_input(const char *title, const char *placeholder, char *out, size_t cap){
|
|
static wchar_t wbuf[256];
|
|
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;
|
|
/* Prefill with current value (ASCII round-trip). */
|
|
for(i = 0; i < cap - 1 && out[i]; i++) wbuf[i] = (wchar_t)(unsigned char)out[i];
|
|
wbuf[i] = 0;
|
|
for(i = 0; i < 63 && title && title[i]; i++) wtitle[i] = (wchar_t)(unsigned char)title[i];
|
|
wtitle[i] = 0;
|
|
for(i = 0; i < 63 && placeholder && placeholder[i]; i++) wplace[i] = (wchar_t)(unsigned char)placeholder[i];
|
|
wplace[i] = 0;
|
|
if(sceUserServiceGetInitialUser(&uid) < 0) uid = 0;
|
|
memset(&st, 0, sizeof st);
|
|
st.userId = (uint32_t)uid;
|
|
st.type = 0;
|
|
st.supportedLanguages = 0;
|
|
st.enterLabel = ORBIS_BUTTON_LABEL_DEFAULT;
|
|
st.inputMethod = 0;
|
|
st.filter = 0;
|
|
st.option = 0;
|
|
st.maxTextLength = (uint32_t)(cap - 1);
|
|
st.inputTextBuffer = wbuf;
|
|
st.posx = 0;
|
|
st.posy = 0;
|
|
st.horizontalAlignment = ORBIS_H_CENTER;
|
|
st.verticalAlignment = ORBIS_V_CENTER;
|
|
st.placeholder = wplace;
|
|
st.title = wtitle;
|
|
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. */
|
|
{
|
|
int spins = 0;
|
|
OrbisDialogStatus ds;
|
|
while((ds = sceImeDialogGetStatus()) != ORBIS_DIALOG_STATUS_STOPPED){
|
|
if(ds == ORBIS_DIALOG_STATUS_NONE && ++spins > 250){
|
|
sceImeDialogTerm();
|
|
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;
|
|
return 1;
|
|
}
|