From 8a45b7e1e7fca0cbda353a4e3edf786546cff8a3 Mon Sep 17 00:00:00 2001 From: Zeno Rogue Date: Fri, 28 Jun 2024 12:20:26 +0200 Subject: [PATCH] correct text handling in SDL2 --- archimedean.cpp | 1 + basegraph.cpp | 9 ++++++++- control.cpp | 20 ++++++++++++++++++++ dialogs.cpp | 50 +++++++++++++++++++++++++++++++++++++++++++------ graph.cpp | 5 +---- 5 files changed, 74 insertions(+), 11 deletions(-) diff --git a/archimedean.cpp b/archimedean.cpp index 5a7c3de4..5b3dce0e 100644 --- a/archimedean.cpp +++ b/archimedean.cpp @@ -1520,6 +1520,7 @@ EX void show() { dialog::addBack(); dialog::display(); + se.handle_textinput(); keyhandler = [] (int sym, int uni) { if(symbol_editing && sym == SDLK_RETURN) sym = uni = '/'; dialog::handleNavigation(sym, uni); diff --git a/basegraph.cpp b/basegraph.cpp index e1cbb30c..5bb6634f 100644 --- a/basegraph.cpp +++ b/basegraph.cpp @@ -89,7 +89,7 @@ EX unsigned backcolor = 0; EX unsigned bordcolor = 0; EX unsigned forecolor = 0xFFFFFF; -int utfsize(char c) { +EX int utfsize(char c) { unsigned char cu = c; if(cu < 128) return 1; if(cu < 224) return 2; @@ -97,6 +97,13 @@ int utfsize(char c) { return 4; } +EX int utfsize_before(const string& s, int pos) { + if(!pos) return 0; + int npos = pos - 1; + while(npos && ((unsigned char)s[npos]) >= 128 && ((unsigned char)s[npos]) < 192) npos--; + return pos - npos; + } + EX int get_sightrange() { return getDistLimit() + sightrange_bonus; } EX int get_sightrange_ambush() { diff --git a/control.cpp b/control.cpp index 0b54a3a5..93bf5c14 100644 --- a/control.cpp +++ b/control.cpp @@ -32,6 +32,19 @@ EX int slider_x; EX function keyhandler = [] (int sym, int uni) {}; EX function joyhandler = [] (SDL_Event &ev) {return false;}; +#if CAP_SDL2 +EX void ignore_text(const SDL_TextInputEvent&) {} +EX function texthandler = ignore_text; +#endif + +EX void reset_handlers() { + keyhandler = [] (int sym, int uni) {}; + joyhandler = [] (SDL_Event &ev) {return false;}; + #if CAP_SDL2 + texthandler = ignore_text; + #endif + } + #if HDR // what part of the compass does 'skip turn' static constexpr auto SKIPFAC = .4; @@ -1162,6 +1175,12 @@ EX void handle_event(SDL_Event& ev) { } } + #if CAP_SDL2 + if(ev.type == SDL_TEXTINPUT) { + texthandler(ev.text); + } + #endif + dialog::handleZooming(ev); if(sym == SDLK_F1 && normal && playermoved) @@ -1318,6 +1337,7 @@ EX void handle_event(SDL_Event& ev) { if(sym || uni) { if(need_refresh) { just_refreshing = true; + reset_handlers(); screens.back()(); just_refreshing = false; } diff --git a/dialogs.cpp b/dialogs.cpp index d9986702..7d3f02aa 100644 --- a/dialogs.cpp +++ b/dialogs.cpp @@ -1443,16 +1443,26 @@ EX namespace dialog { } display(); + + #if CAP_SDL2 + texthandler = [&ne] (const SDL_TextInputEvent& ev) { + if(key_actions.count(ev.text[0])) return; + ne.s += ev.text; + ne.apply_edit(); + }; + #endif keyhandler = [this, &ne] (int sym, int uni) { handleNavigation(sym, uni); if((uni >= '0' && uni <= '9') || among(uni, '.', '+', '-', '*', '/', '^', '(', ')', ',', '|', 3) || (uni >= 'a' && uni <= 'z')) { + #if !CAP_SDL2 if(uni == 3) ne.s += "pi"; else ne.s += uni; apply_edit(); + #endif } else if(uni == '\b' || uni == '\t') { - ne.s = ne.s. substr(0, isize(ne.s)-1); + ne.s = ne.s. substr(0, isize(ne.s)-utfsize_before(ne.s, isize(ne.s))); sscanf(ne.s.c_str(), LDF, ne.editwhat); apply_edit(); } @@ -1770,6 +1780,13 @@ EX namespace dialog { dialog::addItem("cancel", SDLK_ESCAPE); dialog::display(); + #if CAP_SDL2 + texthandler = [this] (const SDL_TextInputEvent& ev) { + int i = isize(*cfileptr) - (editext?0:4); + cfileptr->insert(i, ev.text); + }; + #endif + keyhandler = handleKeyFile; } @@ -1786,15 +1803,18 @@ EX namespace dialog { if(ac) popScreen(); } else if(sym == SDLK_BACKSPACE && i) { - s.erase(i-1, 1); + int len = utfsize_before(s, i); + s.erase(i-len, len); highlight_text = "//missing"; list_skip = 0; } + #if !CAP_SDL2 else if(uni >= 32 && uni < 127) { s.insert(i, s0 + char(uni)); highlight_text = "//missing"; list_skip = 0; } + #endif return; } @@ -1880,6 +1900,7 @@ EX namespace dialog { void draw() override; void start_editing(string& s); bool handle_edit_string(int sym, int uni, function checker = editchecker); + void handle_textinput(); }; #endif @@ -1899,25 +1920,40 @@ EX namespace dialog { bool string_dialog::handle_edit_string(int sym, int uni, function checker) { auto& es = *edited_string; string u2; - if(DKEY == SDLK_LEFT) editpos--; - else if(DKEY == SDLK_RIGHT) editpos++; + if(DKEY == SDLK_LEFT) editpos -= utfsize_before(es, editpos); + else if(DKEY == SDLK_RIGHT) editpos += utfsize(es[editpos]); else if(uni == 8) { if(editpos == 0) return true; - es.replace(editpos-1, 1, ""); - editpos--; + int len = utfsize_before(es, editpos); + es.replace(editpos-len, len, ""); + editpos -= len; if(reaction) reaction(); } else if((u2 = checker(sym, uni)) != "") { + #if !CAP_SDL2 for(char c: u2) { es.insert(editpos, 1, c); editpos ++; } + #endif if(reaction) reaction(); } else return false; return true; } + void string_dialog::handle_textinput() { + #if CAP_SDL2 + texthandler = [this] (const SDL_TextInputEvent& ev) { + auto& es = *edited_string; + string txt = ev.text; + es.insert(editpos, txt); + editpos += isize(txt); + if(reaction) reaction(); + }; + #endif + } + void string_dialog::draw() { cmode = sm::NUMBER | dialogflags; gamescreen(); @@ -1942,6 +1978,8 @@ EX namespace dialog { if(handle_edit_string(sym, uni)) ; else if(doexiton(sym, uni)) popfinal(); }; + + handle_textinput(); } EX void edit_string(string& s, string title, string help) { diff --git a/graph.cpp b/graph.cpp index 8c5354fb..63124e3c 100644 --- a/graph.cpp +++ b/graph.cpp @@ -5925,10 +5925,7 @@ EX void drawscreen() { mouseovers = " "; cmode = 0; - keyhandler = [] (int sym, int uni) {}; - #if CAP_SDL - joyhandler = [] (SDL_Event& ev) { return false; }; - #endif + reset_handlers(); if(!isize(screens)) pushScreen(normalscreen); screens.back()();