Wii: Initial OSK implementation

This commit is contained in:
Vicki Pfau 2021-09-09 14:28:15 -07:00
parent d96a19420d
commit f176c096b0
7 changed files with 508 additions and 0 deletions

View File

@ -48,6 +48,17 @@ enum GUIKeyboardStatus {
GUI_KEYBOARD_CANCEL,
};
enum GUIKeyFunction {
GUI_KEYFUNC_INPUT_DATA = 0,
GUI_KEYFUNC_CHANGE_KB,
GUI_KEYFUNC_SHIFT_KB,
GUI_KEYFUNC_BACKSPACE,
GUI_KEYFUNC_ENTER,
GUI_KEYFUNC_CANCEL,
GUI_KEYFUNC_LEFT,
GUI_KEYFUNC_RIGHT,
};
enum {
BATTERY_EMPTY = 0,
BATTERY_LOW = 25,
@ -72,6 +83,21 @@ struct GUIKeyboardParams {
bool multiline;
};
struct GUIKey {
const char* name;
const void* data;
int width;
enum GUIKeyFunction function;
};
struct GUIKeyboard {
struct {
int offset;
struct GUIKey* keys;
} rows[5];
int width;
};
struct GUIParams {
unsigned width;
unsigned height;

View File

@ -84,6 +84,18 @@ enum GUIIcon {
GUI_ICON_9SLICE_CAP_SWW,
GUI_ICON_9SLICE_CAP_SSE,
GUI_ICON_9SLICE_CAP_SEE,
GUI_ICON_9SLICE_FILL_ONLY_NW,
GUI_ICON_9SLICE_FILL_ONLY_N,
GUI_ICON_9SLICE_FILL_ONLY_NE,
GUI_ICON_9SLICE_FILL_ONLY_W,
GUI_ICON_9SLICE_FILL_ONLY_C,
GUI_ICON_9SLICE_FILL_ONLY_E,
GUI_ICON_9SLICE_FILL_ONLY_SW,
GUI_ICON_9SLICE_FILL_ONLY_S,
GUI_ICON_9SLICE_FILL_ONLY_SE,
GUI_ICON_BACKSPACE,
GUI_ICON_KBD_SHIFT,
GUI_ICON_CAPSLOCK,
GUI_ICON_MAX,
};
@ -109,6 +121,7 @@ enum GUI9SliceStyle {
GUI_9SLICE_FILLED,
GUI_9SLICE_EMPTY,
GUI_9SLICE_EMPTY_CAPPED,
GUI_9SLICE_FILL_ONLY,
};
unsigned GUIFontHeight(const struct GUIFont*);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 663 B

After

Width:  |  Height:  |  Size: 761 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -89,6 +89,8 @@ static void _drawEnd(void);
static uint32_t _pollInput(const struct mInputMap*);
static enum GUICursorState _pollCursor(unsigned* x, unsigned* y);
static void _guiPrepare(void);
static enum GUIKeyboardStatus _keyboardRun(struct GUIKeyboardParams* keyboard);
static struct GUIParams* params; // XXX
static void _setup(struct mGUIRunner* runner);
static void _gameLoaded(struct mGUIRunner* runner);
@ -355,6 +357,7 @@ int main(int argc, char* argv[]) {
_pollInput, _pollCursor,
0,
_guiPrepare, 0,
_keyboardRun,
},
.keySources = (struct GUIInputKeys[]) {
{
@ -600,6 +603,9 @@ int main(int argc, char* argv[]) {
mGUIInit(&runner, "wii");
reconfigureScreen(&runner);
// XXX
params = &runner.params;
// Make sure screen is properly initialized by drawing a blank frame
_drawStart();
_drawEnd();
@ -844,6 +850,432 @@ void _guiPrepare(void) {
_reproj2(vmode->fbWidth * guiScale * wAdjust, vmode->efbHeight * guiScale * hAdjust);
}
static const struct GUIKeyboard qwertyLower;
static const struct GUIKeyboard qwertyUpper;
static const struct GUIKeyboard symbols;
static const struct GUIKeyboard qwertyLower = {
.rows = {
{
.offset = 0,
.keys = (struct GUIKey[]) {
{ "1", "1" },
{ "2", "2" },
{ "3", "3" },
{ "4", "4" },
{ "5", "5" },
{ "6", "6" },
{ "7", "7" },
{ "8", "8" },
{ "9", "9" },
{ "0", "0" },
{ "-", "-" },
{ "", NULL, 2, GUI_KEYFUNC_BACKSPACE },
{}
}
},
{
.offset = 0,
.keys = (struct GUIKey[]) {
{ "q", "q" },
{ "w", "w" },
{ "e", "e" },
{ "r", "r" },
{ "t", "t" },
{ "y", "y" },
{ "u", "u" },
{ "i", "i" },
{ "o", "o" },
{ "p", "p" },
{ "[", "[" },
{ "]", "]" },
{}
}
},
{
.offset = 0,
.keys = (struct GUIKey[]) {
{ "a", "a" },
{ "s", "s" },
{ "d", "d" },
{ "f", "f" },
{ "g", "g" },
{ "h", "h" },
{ "j", "j" },
{ "k", "k" },
{ "l", "l" },
{ ";", ";" },
{ "'", "'" },
{ "\\", "\\" },
{}
}
},
{
.offset = 0,
.keys = (struct GUIKey[]) {
{ "z", "z" },
{ "x", "x" },
{ "c", "c" },
{ "v", "v" },
{ "b", "b" },
{ "n", "n" },
{ "m", "m" },
{ ",", "," },
{ ".", "." },
{ "/", "/" },
{ "", NULL, 2, GUI_KEYFUNC_LEFT },
{ "", NULL, 2, GUI_KEYFUNC_RIGHT },
{}
}
},
{
.offset = 0,
.keys = (struct GUIKey[]) {
{ "", &qwertyUpper, 3, GUI_KEYFUNC_SHIFT_KB },
{ "!@#", &symbols, 3, GUI_KEYFUNC_CHANGE_KB },
{ "Space", " ", 10 },
{ "OK", NULL, 4, GUI_KEYFUNC_ENTER },
{ "Cancel", NULL, 4, GUI_KEYFUNC_CANCEL },
{}
}
},
},
.width = 24
};
static const struct GUIKeyboard qwertyUpper = {
.rows = {
{
.offset = 0,
.keys = (struct GUIKey[]) {
{ "1", "1" },
{ "2", "2" },
{ "3", "3" },
{ "4", "4" },
{ "5", "5" },
{ "6", "6" },
{ "7", "7" },
{ "8", "8" },
{ "9", "9" },
{ "0", "0" },
{ "_", "_" },
{ "", NULL, 2, GUI_KEYFUNC_BACKSPACE },
{}
}
},
{
.offset = 0,
.keys = (struct GUIKey[]) {
{ "Q", "Q" },
{ "W", "W" },
{ "E", "E" },
{ "R", "R" },
{ "T", "T" },
{ "Y", "Y" },
{ "U", "U" },
{ "I", "I" },
{ "O", "O" },
{ "P", "P" },
{ "{", "}" },
{ "{", "}" },
{}
}
},
{
.offset = 0,
.keys = (struct GUIKey[]) {
{ "A", "A" },
{ "S", "S" },
{ "D", "D" },
{ "F", "F" },
{ "G", "G" },
{ "H", "H" },
{ "J", "J" },
{ "K", "K" },
{ "L", "L" },
{ ":", ":" },
{ "\"", "\"" },
{ "|", "|" },
{}
}
},
{
.offset = 0,
.keys = (struct GUIKey[]) {
{ "Z", "Z" },
{ "X", "X" },
{ "C", "C" },
{ "V", "V" },
{ "B", "B" },
{ "N", "N" },
{ "M", "M" },
{ "<", "<" },
{ ">", ">" },
{ "?", "?" },
{ "", NULL, 2, GUI_KEYFUNC_LEFT },
{ "", NULL, 2, GUI_KEYFUNC_RIGHT },
{}
}
},
{
.offset = 0,
.keys = (struct GUIKey[]) {
{ "", &qwertyUpper, 3, GUI_KEYFUNC_CHANGE_KB },
{ "!@#", &symbols, 3, GUI_KEYFUNC_CHANGE_KB },
{ "Space", " ", 10 },
{ "OK", NULL, 4, GUI_KEYFUNC_ENTER },
{ "Cancel", NULL, 4, GUI_KEYFUNC_CANCEL },
{}
}
},
},
.width = 24
};
static const struct GUIKeyboard symbols = {
.rows = {
{
.offset = 0,
.keys = (struct GUIKey[]) {
{ "1", "1" },
{ "2", "2" },
{ "3", "3" },
{ "4", "4" },
{ "5", "5" },
{ "6", "6" },
{ "7", "7" },
{ "8", "8" },
{ "9", "9" },
{ "0", "0" },
{ "-", "-" },
{ "", NULL, 2, GUI_KEYFUNC_BACKSPACE },
{}
}
},
{
.offset = 0,
.keys = (struct GUIKey[]) {
{ ".", "." },
{ ",", "," },
{ ":", ":" },
{ ";", ";" },
{ "?", "?" },
{ "!", "!" },
{ "'", "'" },
{ "\"", "\"" },
{ "*", "*" },
{ "`", "`" },
{ "~", "~" },
{ "_", "_" },
{}
}
},
{
.offset = 0,
.keys = (struct GUIKey[]) {
{ "<", "<" },
{ ">", ">" },
{ "{", "{" },
{ "}", "}" },
{ "+", "+" },
{ "=", "=" },
{ "#", "#" },
{ "&", "&" },
{ "$", "$" },
{}
}
},
{
.offset = 0,
.keys = (struct GUIKey[]) {
{ "(", "(" },
{ ")", ")" },
{ "[", "[" },
{ "]", "]" },
{ "/", "/" },
{ "|", "|" },
{ "\\", "\\" },
{ "%", "%" },
{ "@", "@" },
{ "^", "^" },
{ "", NULL, 2, GUI_KEYFUNC_LEFT },
{ "", NULL, 2, GUI_KEYFUNC_RIGHT },
{}
}
},
{
.offset = 3,
.keys = (struct GUIKey[]) {
{ "abc", &qwertyLower, 3, GUI_KEYFUNC_CHANGE_KB },
{ "Space", " ", 10 },
{ "OK", NULL, 4, GUI_KEYFUNC_ENTER },
{ "Cancel", NULL, 4, GUI_KEYFUNC_CANCEL },
{}
}
},
},
.width = 24
};
static void _backspace(char* string) {
size_t len = strlen(string);
if (len) {
string[len - 1] = '\0';
}
}
enum GUIKeyboardStatus _keyboardRun(struct GUIKeyboardParams* keyboard) {
GUIInvalidateKeys(params);
int curX = 0;
int curY = 0;
const struct GUIKey* curKey = NULL;
const struct GUIKeyboard* currentKbd = &qwertyLower;
const struct GUIKeyboard* prevKbd = currentKbd;
bool tempKbd = false;
while (true) {
uint32_t newInput = 0;
GUIPollInput(params, &newInput, 0);
unsigned cx, cy;
enum GUICursorState cursor = GUIPollCursor(params, &cx, &cy);
if (newInput & (1 << GUI_INPUT_UP)) {
--curY;
if (curY < 0) {
curY = 4;
}
curKey = NULL;
}
if (newInput & (1 << GUI_INPUT_DOWN)) {
++curY;
if (curY > 4) {
curY = 0;
}
curKey = NULL;
}
if (newInput & (1 << GUI_INPUT_LEFT)) {
--curX;
if (curX < 0) {
curX = currentKbd->width / 2;
}
curKey = NULL;
}
if (newInput & (1 << GUI_INPUT_RIGHT)) {
if (curKey) {
curX += curKey->width ? (curKey->width + 1) / 2 : 1;
} else {
++curX;
}
if (curX >= currentKbd->width / 2) {
curX = 0;
}
curKey = NULL;
}
if (newInput & (1 << GUI_INPUT_BACK)) {
_backspace(keyboard->result);
}
if (newInput & (1 << GUI_INPUT_CANCEL)) {
return GUI_KEYBOARD_CANCEL;
}
params->drawStart();
if (params->guiPrepare) {
params->guiPrepare();
}
GUIFontPrint(params->font, 8, GUIFontHeight(params->font), GUI_ALIGN_LEFT, 0xFFFFFFFF, keyboard->title);
unsigned height = GUIFontHeight(params->font) * 2;
unsigned width = (GUIFontGlyphWidth(params->font, 'W') | 1) + 1; // Round up
int offset = (params->width - (width + 32) / 2 * currentKbd->width) / 2;
int row;
int col;
for (row = 0; row < 5; ++row) {
int y = params->height / 2 + (height + 16) * (row - 1);
int x = currentKbd->rows[row].offset;
for (col = 0; currentKbd->rows[row].keys[col].name; ++col) {
const struct GUIKey* key = &currentKbd->rows[row].keys[col];
int w = key->width ? key->width : 2;
if (row == curY) {
if (curX >= x / 2 && curX < (x + w) / 2) {
curKey = key;
} else if (col == 0 && curX < x / 2) {
curKey = key;
} else if (!currentKbd->rows[row].keys[col + 1].name && curX >= x / 2) {
curKey = key;
}
}
if (key->name[0]) {
int xOff = offset + x * (width + 32) / 2;
if (curKey == key) {
curX = x / 2;
GUIFontDraw9Slice(params->font, xOff, y, (width + 4) * w, height + 12, 0xFFFFFFFF, GUI_9SLICE_FILLED);
} else {
uint32_t fill = 0xFF606060;
if (key->function != GUI_KEYFUNC_INPUT_DATA) {
fill = 0xFFD0D0D0;
}
GUIFontDraw9Slice(params->font, xOff - 2, y - 2, (width + 4) * w + 4, height + 16, fill, GUI_9SLICE_FILL_ONLY);
}
GUIFontPrint(params->font, offset + (x * 2 + w) * (width + 32) / 4, y + height * 3 / 4 + 1, GUI_ALIGN_HCENTER | GUI_ALIGN_VCENTER, 0xFFFFFFFF, key->name);
}
x += w;
}
}
if (newInput & (1 << GUI_INPUT_SELECT) && curKey) {
switch (curKey->function) {
case GUI_KEYFUNC_INPUT_DATA:
strncat(keyboard->result, curKey->data, keyboard->maxLen + 1);
if (tempKbd) {
tempKbd = false;
currentKbd = prevKbd;
}
break;
case GUI_KEYFUNC_BACKSPACE:
_backspace(keyboard->result);
break;
case GUI_KEYFUNC_SHIFT_KB:
tempKbd = true;
prevKbd = currentKbd;
currentKbd = curKey->data;
break;
case GUI_KEYFUNC_CHANGE_KB:
if (currentKbd == curKey->data) {
// Switching to itself while temporary removes temporary status;
// then switching once more goes back to previous keyboard
if (!tempKbd) {
currentKbd = prevKbd;
}
} else {
currentKbd = curKey->data;
}
tempKbd = false;
break;
case GUI_KEYFUNC_ENTER:
return GUI_KEYBOARD_DONE;
case GUI_KEYFUNC_CANCEL:
return GUI_KEYBOARD_CANCEL;
}
}
int inputSize = keyboard->maxLen;
if (inputSize * width > params->width) {
inputSize = params->width / width - 2;
}
GUIFontDraw9Slice(params->font, (params->width - width * inputSize) / 2 - 8, height * 3, width * inputSize + 16, height + 8, 0xFFFFFFFF, GUI_9SLICE_EMPTY);
GUIFontPrint(params->font, (params->width - width * inputSize) / 2, height * 4 - 8, GUI_ALIGN_LEFT, 0xFFFFFFFF, keyboard->result);
GUIDrawBattery(params);
GUIDrawClock(params);
if (params->guiFinish) {
params->guiFinish();
}
params->drawEnd();
}
}
void _setup(struct mGUIRunner* runner) {
runner->core->setPeripheral(runner->core, mPERIPH_ROTATION, &rotation);
runner->core->setPeripheral(runner->core, mPERIPH_RUMBLE, &rumble);

View File

@ -183,4 +183,16 @@ const struct GUIIconMetric defaultIconMetrics[] = {
[GUI_ICON_9SLICE_CAP_SWW] = { 226, 8, 6, 8 },
[GUI_ICON_9SLICE_CAP_SSE] = { 232, 24, 8, 7 },
[GUI_ICON_9SLICE_CAP_SEE] = { 248, 8, 6, 8 },
[GUI_ICON_9SLICE_FILL_ONLY_NW] = { 194, 33, 8, 8 },
[GUI_ICON_9SLICE_FILL_ONLY_N] = { 202, 33, 12, 8 },
[GUI_ICON_9SLICE_FILL_ONLY_NE] = { 214, 33, 8, 8 },
[GUI_ICON_9SLICE_FILL_ONLY_W] = { 194, 41, 8, 12 },
[GUI_ICON_9SLICE_FILL_ONLY_C] = { 202, 41, 12, 12 },
[GUI_ICON_9SLICE_FILL_ONLY_E] = { 214, 41, 8, 12 },
[GUI_ICON_9SLICE_FILL_ONLY_SW] = { 194, 55, 8, 8 },
[GUI_ICON_9SLICE_FILL_ONLY_S] = { 202, 55, 12, 8 },
[GUI_ICON_9SLICE_FILL_ONLY_SE] = { 214, 55, 8, 8 },
[GUI_ICON_BACKSPACE] = { 82, 18, 12, 12 },
[GUI_ICON_KBD_SHIFT] = { 114, 18, 12, 12 },
[GUI_ICON_CAPSLOCK] = { 130, 18, 12, 12 },
};

View File

@ -55,10 +55,22 @@ void GUIFontPrint(struct GUIFont* font, int x, int y, enum GUIAlignment align, u
c = GUI_ICON_LEFT + c - 0x2190;
icon = true;
break;
case 0x232B:
c = GUI_ICON_BACKSPACE;
icon = true;
break;
case 0x23E9:
c = GUI_ICON_STATUS_FAST_FORWARD;
icon = true;
break;
case 0x21E7:
c = GUI_ICON_KBD_SHIFT;
icon = true;
break;
case 0x21EA:
c = GUI_ICON_CAPSLOCK;
icon = true;
break;
case 0x1F507:
c = GUI_ICON_STATUS_MUTE;
icon = true;
@ -102,6 +114,12 @@ void GUIFontDraw9Slice(struct GUIFont* font, int x, int y, int width, int height
GUIFontDrawIcon(font, x , y + height, GUI_ALIGN_LEFT | GUI_ALIGN_BOTTOM, GUI_ORIENT_0, color, GUI_ICON_9SLICE_FILLED_SW);
GUIFontDrawIcon(font, x + width, y + height, GUI_ALIGN_RIGHT | GUI_ALIGN_BOTTOM, GUI_ORIENT_0, color, GUI_ICON_9SLICE_FILLED_SE);
break;
case GUI_9SLICE_FILL_ONLY:
GUIFontDrawIcon(font, x , y , GUI_ALIGN_LEFT | GUI_ALIGN_TOP , GUI_ORIENT_0, color, GUI_ICON_9SLICE_FILL_ONLY_NW);
GUIFontDrawIcon(font, x + width, y , GUI_ALIGN_RIGHT | GUI_ALIGN_TOP , GUI_ORIENT_0, color, GUI_ICON_9SLICE_FILL_ONLY_NE);
GUIFontDrawIcon(font, x , y + height, GUI_ALIGN_LEFT | GUI_ALIGN_BOTTOM, GUI_ORIENT_0, color, GUI_ICON_9SLICE_FILL_ONLY_SW);
GUIFontDrawIcon(font, x + width, y + height, GUI_ALIGN_RIGHT | GUI_ALIGN_BOTTOM, GUI_ORIENT_0, color, GUI_ICON_9SLICE_FILL_ONLY_SE);
break;
}
unsigned offX, offY;
@ -123,6 +141,13 @@ void GUIFontDraw9Slice(struct GUIFont* font, int x, int y, int width, int height
GUIFontDrawIconSize(font, x + width - endX, y + offY, offX, height - offY - endY, color, GUI_ICON_9SLICE_FILLED_E);
GUIFontDrawIconSize(font, x + offX, y + offY, width - offX - endX, height - offY - endY, color, GUI_ICON_9SLICE_FILLED_C);
break;
case GUI_9SLICE_FILL_ONLY:
GUIFontDrawIconSize(font, x + offX, y, width - offX - endX, offY, color, GUI_ICON_9SLICE_FILL_ONLY_N);
GUIFontDrawIconSize(font, x, y + offY, offX, height - offY - endY, color, GUI_ICON_9SLICE_FILL_ONLY_W);
GUIFontDrawIconSize(font, x + offX, y + height - endY, width - offX - endX, offY, color, GUI_ICON_9SLICE_FILL_ONLY_S);
GUIFontDrawIconSize(font, x + width - endX, y + offY, offX, height - offY - endY, color, GUI_ICON_9SLICE_FILL_ONLY_E);
GUIFontDrawIconSize(font, x + offX, y + offY, width - offX - endX, height - offY - endY, color, GUI_ICON_9SLICE_FILL_ONLY_C);
break;
case GUI_9SLICE_EMPTY_CAPPED:
GUIFontDrawIcon(font, x + offX, y, GUI_ALIGN_LEFT | GUI_ALIGN_TOP, GUI_ORIENT_0, color, GUI_ICON_9SLICE_CAP_NNW);
GUIFontDrawIcon(font, x, y + offY, GUI_ALIGN_LEFT | GUI_ALIGN_TOP, GUI_ORIENT_0, color, GUI_ICON_9SLICE_CAP_NWW);