ime composition support (#589)

This commit is contained in:
Michael 2024-12-28 07:45:34 -06:00 committed by GitHub
parent c8faa22072
commit ba037771bd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 95 additions and 7 deletions

View file

@ -66,6 +66,10 @@ void keyboard_on_text_input(char* text) {
djui_interactable_on_text_input(text);
}
void keyboard_on_text_editing(char* text, int cursorPos) {
djui_interactable_on_text_editing(text, cursorPos);
}
static void keyboard_add_binds(int mask, unsigned int *scancode) {
for (int i = 0; i < MAX_BINDS && num_keybinds < MAX_KEYBINDS; ++i) {
if (scancode[i] < VK_BASE_KEYBOARD + VK_SIZE) {

View file

@ -42,6 +42,7 @@ bool keyboard_on_key_down(int scancode);
bool keyboard_on_key_up(int scancode);
void keyboard_on_all_keys_up(void);
void keyboard_on_text_input(char* text);
void keyboard_on_text_editing(char* text, int cursorPos);
#ifdef __cplusplus
}

View file

@ -651,7 +651,8 @@ static void crash_handler(const int signalNum, siginfo_t *info, UNUSED ucontext_
// In case the game crashed before the game window opened
if (!gGfxInited) {
gfx_init(&WAPI, &RAPI, TITLE);
WAPI.set_keyboard_callbacks(keyboard_on_key_down, keyboard_on_key_up, keyboard_on_all_keys_up, keyboard_on_text_input);
WAPI.set_keyboard_callbacks(keyboard_on_key_down, keyboard_on_key_up, keyboard_on_all_keys_up,
keyboard_on_text_input, keyboard_on_text_editing);
}
if (!gGameInited) djui_unicode_init();

View file

@ -498,6 +498,10 @@ static void djui_chat_box_input_on_text_input(struct DjuiBase *base, char* text)
}
}
static void djui_chat_box_input_on_text_editing(struct DjuiBase *base, char* text, int cursorPos) {
djui_inputbox_on_text_editing(base, text, cursorPos);
}
void djui_chat_box_toggle(void) {
if (gDjuiChatBox == NULL) { return; }
if (!gDjuiChatBoxFocus) { sDjuiChatBoxClearText = true; }
@ -550,6 +554,7 @@ struct DjuiChatBox* djui_chat_box_create(void) {
djui_base_set_alignment(ciBase, DJUI_HALIGN_LEFT, DJUI_VALIGN_BOTTOM);
djui_interactable_hook_key(&chatInput->base, djui_chat_box_input_on_key_down, djui_inputbox_on_key_up);
djui_interactable_hook_text_input(&chatInput->base, djui_chat_box_input_on_text_input);
djui_interactable_hook_text_editing(&chatInput->base, djui_chat_box_input_on_text_editing);
chatBox->chatInput = chatInput;
gDjuiChatBox = chatBox;

View file

@ -397,6 +397,31 @@ void djui_inputbox_on_text_input(struct DjuiBase *base, char* text) {
inputbox->selection[1] = inputbox->selection[0];
sCursorBlink = 0;
djui_inputbox_on_change(inputbox);
inputbox->imePos = 0;
if (inputbox->imeBuffer != NULL) {
free(inputbox->imeBuffer);
inputbox->imeBuffer = NULL;
}
}
void djui_inputbox_on_text_editing(struct DjuiBase *base, char* text, int cursorPos) {
struct DjuiInputbox *inputbox = (struct DjuiInputbox *) base;
inputbox->imePos = (u16)cursorPos;
if (inputbox->imeBuffer != NULL) free(inputbox->imeBuffer);
if (*text == '\0') {
inputbox->imeBuffer = NULL;
}
else {
size_t size = strlen(text);
char* copy = malloc(size + 1);
strcpy(copy,text);
inputbox->imeBuffer = copy;
}
djui_inputbox_on_change(inputbox);
}
static void djui_inputbox_render_char(struct DjuiInputbox* inputbox, char* c, f32* drawX, f32* additionalShift) {
@ -445,10 +470,21 @@ static void djui_inputbox_render_selection(struct DjuiInputbox* inputbox) {
sCursorBlink = (sCursorBlink + 1) % DJUI_INPUTBOX_MAX_BLINK;
f32 renderX = x;
u16 imePos = inputbox->imePos;
if (imePos != 0) {
char* ime = inputbox->imeBuffer;
for (u16 i = 0; i < imePos; i++) {
renderX += font->char_width(ime);
ime = djui_unicode_next_char(ime);
}
}
// render only cursor when there is no selection width
if (selection[0] == selection[1]) {
if (sCursorBlink < DJUI_INPUTBOX_MID_BLINK && djui_interactable_is_input_focus(&inputbox->base)) {
create_dl_translation_matrix(DJUI_MTX_PUSH, x - DJUI_INPUTBOX_CURSOR_WIDTH / 2.0f, -0.1f, 0);
create_dl_translation_matrix(DJUI_MTX_PUSH, renderX - DJUI_INPUTBOX_CURSOR_WIDTH / 2.0f, -0.1f, 0);
create_dl_scale_matrix(DJUI_MTX_NOPUSH, DJUI_INPUTBOX_CURSOR_WIDTH, 0.8f, 1.0f);
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 255);
gSPDisplayList(gDisplayListHead++, dl_djui_simple_rect);
@ -554,6 +590,16 @@ static bool djui_inputbox_render(struct DjuiBase* base) {
f32 additionalShift = 0;
bool wasInsideSelection = false;
for (u16 i = 0; i < inputbox->bufferSize; i++) {
//render composition text
if (selection[0] == i && inputbox->imeBuffer != NULL) {
char *ime = inputbox->imeBuffer;
while (*ime != '\0') {
djui_inputbox_render_char(inputbox, ime, &drawX, &additionalShift);
ime = djui_unicode_next_char(ime);
}
}
if (*c == '\0') { break; }
// deal with seleciton color
@ -598,6 +644,7 @@ struct DjuiInputbox* djui_inputbox_create(struct DjuiBase* parent, u16 bufferSiz
djui_interactable_hook_key(base, djui_inputbox_on_key_down, djui_inputbox_on_key_up);
djui_interactable_hook_focus(base, djui_inputbox_on_focus_begin, NULL, djui_inputbox_on_focus_end);
djui_interactable_hook_text_input(base, djui_inputbox_on_text_input);
djui_interactable_hook_text_editing(base, djui_inputbox_on_text_editing);
djui_inputbox_update_style(base);

View file

@ -11,6 +11,8 @@ struct DjuiInputbox {
struct DjuiColor textColor;
void (*on_enter_press)(struct DjuiInputbox*);
void (*on_escape_press)(struct DjuiInputbox*);
char* imeBuffer;
u16 imePos;
};
void djui_inputbox_on_focus_begin(UNUSED struct DjuiBase* base);
@ -25,5 +27,6 @@ void djui_inputbox_hook_escape_press(struct DjuiInputbox* inputbox, void (*on_es
bool djui_inputbox_on_key_down(struct DjuiBase* base, int scancode);
void djui_inputbox_on_key_up(struct DjuiBase* base, int scancode);
void djui_inputbox_on_text_input(struct DjuiBase *base, char* text);
void djui_inputbox_on_text_editing(struct DjuiBase *base, char* text, int cursorPos);
struct DjuiInputbox* djui_inputbox_create(struct DjuiBase* parent, u16 bufferSize);

View file

@ -328,6 +328,13 @@ void djui_interactable_on_text_input(char* text) {
gInteractableFocus->interactable->on_text_input(gInteractableFocus, text);
}
void djui_interactable_on_text_editing(char* text, int cursorPos) {
if (gInteractableFocus == NULL) { return; }
if (gInteractableFocus->interactable == NULL) { return; }
if (gInteractableFocus->interactable->on_text_editing == NULL) { return; }
gInteractableFocus->interactable->on_text_editing(gInteractableFocus, text, cursorPos);
}
void djui_interactable_update_pad(void) {
OSContPad* pad = &gInteractablePad;
@ -521,6 +528,12 @@ void djui_interactable_hook_text_input(struct DjuiBase *base,
interactable->on_text_input = on_text_input;
}
void djui_interactable_hook_text_editing(struct DjuiBase* base,
void (*on_text_editing)(struct DjuiBase*, char*, int)) {
struct DjuiInteractable *interactable = base->interactable;
interactable->on_text_editing = on_text_editing;
}
void djui_interactable_hook_enabled_change(struct DjuiBase *base,
void (*on_enabled_change)(struct DjuiBase*)) {
struct DjuiInteractable *interactable = base->interactable;

View file

@ -42,6 +42,7 @@ struct DjuiInteractable {
bool (*on_key_down)(struct DjuiBase*, int scancode);
void (*on_key_up)(struct DjuiBase*, int scancode);
void (*on_text_input)(struct DjuiBase*, char* text);
void (*on_text_editing)(struct DjuiBase*, char* text, int cursorPos);
void (*on_enabled_change)(struct DjuiBase*);
};
@ -62,6 +63,7 @@ bool djui_interactable_is_input_focus(struct DjuiBase* base);
bool djui_interactable_on_key_down(int scancode);
void djui_interactable_on_key_up(int scancode);
void djui_interactable_on_text_input(char *text);
void djui_interactable_on_text_editing(char* text, int cursorPos);
void djui_interactable_update(void);
@ -95,6 +97,9 @@ void djui_interactable_hook_key(struct DjuiBase* base,
void djui_interactable_hook_text_input(struct DjuiBase* base,
void (*on_text_input)(struct DjuiBase*, char*));
void djui_interactable_hook_text_editing(struct DjuiBase* base,
void (*on_text_editing)(struct DjuiBase*, char*, int));
void djui_interactable_hook_enabled_change(struct DjuiBase *base,
void (*on_enabled_change)(struct DjuiBase*));

View file

@ -65,6 +65,7 @@ static kb_callback_t kb_key_down = NULL;
static kb_callback_t kb_key_up = NULL;
static void (*kb_all_keys_up)(void) = NULL;
static void (*kb_text_input)(char*) = NULL;
static void (*kb_text_editing)(char*, int) = NULL;
#define IS_FULLSCREEN() ((SDL_GetWindowFlags(wnd) & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0)
@ -211,6 +212,9 @@ static void gfx_sdl_handle_events(void) {
case SDL_TEXTINPUT:
kb_text_input(event.text.text);
break;
case SDL_TEXTEDITING: //IME composition
kb_text_editing(event.edit.text,event.edit.start);
break;
case SDL_KEYDOWN:
gfx_sdl_onkeydown(event.key.keysym.scancode);
break;
@ -249,11 +253,14 @@ static void gfx_sdl_handle_events(void) {
}
}
static void gfx_sdl_set_keyboard_callbacks(kb_callback_t on_key_down, kb_callback_t on_key_up, void (*on_all_keys_up)(void), void (*on_text_input)(char*)) {
static void gfx_sdl_set_keyboard_callbacks(kb_callback_t on_key_down, kb_callback_t on_key_up,
void (*on_all_keys_up)(void), void (*on_text_input)(char*), void (*on_text_editing)(char*, int))
{
kb_key_down = on_key_down;
kb_key_up = on_key_up;
kb_all_keys_up = on_all_keys_up;
kb_text_input = on_text_input;
kb_text_editing = on_text_editing;
}
static bool gfx_sdl_start_frame(void) {

View file

@ -13,7 +13,8 @@ typedef bool (*kb_callback_t)(int code);
struct GfxWindowManagerAPI {
void (*init)(const char *window_title);
void (*set_keyboard_callbacks)(kb_callback_t on_key_down, kb_callback_t on_key_up, void (*on_all_keys_up)(void), void (*on_text_input)(char*));
void (*set_keyboard_callbacks)(kb_callback_t on_key_down, kb_callback_t on_key_up, void (*on_all_keys_up)(void),
void (*on_text_input)(char*), void (*on_text_editing)(char*, int));
void (*main_loop)(void (*run_one_game_iter)(void));
void (*get_dimensions)(uint32_t *width, uint32_t *height);
void (*handle_events)(void);

View file

@ -439,7 +439,8 @@ int main(int argc, char *argv[]) {
// create the window almost straight away
if (!gGfxInited) {
gfx_init(&WAPI, &RAPI, TITLE);
WAPI.set_keyboard_callbacks(keyboard_on_key_down, keyboard_on_key_up, keyboard_on_all_keys_up, keyboard_on_text_input);
WAPI.set_keyboard_callbacks(keyboard_on_key_down, keyboard_on_key_up, keyboard_on_all_keys_up,
keyboard_on_text_input, keyboard_on_text_editing);
}
// render the rom setup screen