Add undo/redo infrastructure and buffer management additions.
This commit is contained in:
@@ -5,12 +5,42 @@
|
||||
|
||||
|
||||
static bool
|
||||
map_key(const SDL_Keycode key, const SDL_Keymod mod, bool &k_prefix, MappedInput &out)
|
||||
map_key(const SDL_Keycode key, const SDL_Keymod mod, bool &k_prefix, bool &esc_meta, MappedInput &out)
|
||||
{
|
||||
// Ctrl handling
|
||||
const bool is_ctrl = (mod & KMOD_CTRL) != 0;
|
||||
const bool is_alt = (mod & (KMOD_ALT | KMOD_LALT | KMOD_RALT)) != 0;
|
||||
|
||||
// If previous key was ESC, interpret this as Meta via ESC keymap
|
||||
if (esc_meta) {
|
||||
int ascii_key = 0;
|
||||
if (key >= SDLK_a && key <= SDLK_z) {
|
||||
ascii_key = static_cast<int>('a' + (key - SDLK_a));
|
||||
} else if (key == SDLK_COMMA) {
|
||||
ascii_key = '<';
|
||||
} else if (key == SDLK_PERIOD) {
|
||||
ascii_key = '>';
|
||||
} else if (key == SDLK_LESS) {
|
||||
ascii_key = '<';
|
||||
} else if (key == SDLK_GREATER) {
|
||||
ascii_key = '>';
|
||||
}
|
||||
if (ascii_key != 0) {
|
||||
ascii_key = KLowerAscii(ascii_key);
|
||||
CommandId id;
|
||||
if (KLookupEscCommand(ascii_key, id)) {
|
||||
// Only consume the ESC-meta prefix if we actually mapped a command
|
||||
esc_meta = false;
|
||||
out = {true, id, "", 0};
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Unhandled meta chord at KEYDOWN: do not clear esc_meta here.
|
||||
// Leave it set so SDL_TEXTINPUT fallback can translate and suppress insertion.
|
||||
out.hasCommand = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Movement and basic keys
|
||||
switch (key) {
|
||||
case SDLK_LEFT:
|
||||
@@ -56,7 +86,8 @@ map_key(const SDL_Keycode key, const SDL_Keymod mod, bool &k_prefix, MappedInput
|
||||
return true;
|
||||
case SDLK_ESCAPE:
|
||||
k_prefix = false;
|
||||
out = {true, CommandId::Refresh, "", 0};
|
||||
esc_meta = true; // next key will be treated as Meta
|
||||
out.hasCommand = false; // no immediate command for bare ESC in GUI
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
@@ -108,8 +139,19 @@ map_key(const SDL_Keycode key, const SDL_Keymod mod, bool &k_prefix, MappedInput
|
||||
|
||||
// Alt/Meta bindings (ESC f/b equivalent)
|
||||
if (is_alt) {
|
||||
int ascii_key = 0;
|
||||
if (key >= SDLK_a && key <= SDLK_z) {
|
||||
int ascii_key = static_cast<int>('a' + (key - SDLK_a));
|
||||
ascii_key = static_cast<int>('a' + (key - SDLK_a));
|
||||
} else if (key == SDLK_COMMA) {
|
||||
ascii_key = '<';
|
||||
} else if (key == SDLK_PERIOD) {
|
||||
ascii_key = '>';
|
||||
} else if (key == SDLK_LESS) {
|
||||
ascii_key = '<';
|
||||
} else if (key == SDLK_GREATER) {
|
||||
ascii_key = '>';
|
||||
}
|
||||
if (ascii_key != 0) {
|
||||
CommandId id;
|
||||
if (KLookupEscCommand(ascii_key, id)) {
|
||||
out = {true, id, "", 0};
|
||||
@@ -133,13 +175,14 @@ GUIInputHandler::ProcessSDLEvent(const SDL_Event &e)
|
||||
case SDL_KEYDOWN: {
|
||||
// Remember whether we were in k-prefix before handling this key
|
||||
bool was_k_prefix = k_prefix_;
|
||||
bool was_esc_meta = esc_meta_;
|
||||
SDL_Keymod mods = SDL_Keymod(e.key.keysym.mod);
|
||||
const SDL_Keycode key = e.key.keysym.sym;
|
||||
produced = map_key(key, mods, k_prefix_, mi);
|
||||
produced = map_key(key, mods, k_prefix_, esc_meta_, mi);
|
||||
// Suppress the immediate following SDL_TEXTINPUT only in cases where
|
||||
// SDL would also emit a text input for the same physical keystroke:
|
||||
// - k-prefix printable suffix keys (no Ctrl), and
|
||||
// - Alt/Meta modified printable letters.
|
||||
// - Alt/Meta modified printable letters (or ESC+letter/symbol).
|
||||
// Do NOT suppress for non-text keys like Tab/Enter/Backspace/arrows/etc.,
|
||||
// otherwise the next normal character would be dropped.
|
||||
if (produced && mi.hasCommand) {
|
||||
@@ -159,7 +202,14 @@ GUIInputHandler::ProcessSDLEvent(const SDL_Event &e)
|
||||
should_suppress = true;
|
||||
}
|
||||
// Alt/Meta + letter can also generate TEXTINPUT on some platforms
|
||||
if (is_alt && key >= SDLK_a && key <= SDLK_z) {
|
||||
const bool is_meta_symbol = (
|
||||
key == SDLK_COMMA || key == SDLK_PERIOD || key == SDLK_LESS || key ==
|
||||
SDLK_GREATER);
|
||||
if (is_alt && ((key >= SDLK_a && key <= SDLK_z) || is_meta_symbol)) {
|
||||
should_suppress = true;
|
||||
}
|
||||
// ESC-as-meta followed by printable
|
||||
if (was_esc_meta && (is_printable_letter || is_meta_symbol)) {
|
||||
should_suppress = true;
|
||||
}
|
||||
}
|
||||
@@ -176,6 +226,45 @@ GUIInputHandler::ProcessSDLEvent(const SDL_Event &e)
|
||||
produced = true; // consumed input
|
||||
break;
|
||||
}
|
||||
// Handle ESC-as-meta fallback on TEXTINPUT: some platforms emit only TEXTINPUT
|
||||
// for the printable part after ESC. If esc_meta_ is set, translate first char.
|
||||
if (esc_meta_) {
|
||||
esc_meta_ = false; // consume meta prefix
|
||||
const char *txt = e.text.text;
|
||||
if (txt && *txt) {
|
||||
// Parse first UTF-8 codepoint (we care only about common ASCII cases)
|
||||
unsigned char c0 = static_cast<unsigned char>(txt[0]);
|
||||
// Map a few common symbols/letters used in our ESC map
|
||||
int ascii_key = 0;
|
||||
if (c0 < 0x80) {
|
||||
// ASCII path
|
||||
ascii_key = static_cast<int>(c0);
|
||||
ascii_key = KLowerAscii(ascii_key);
|
||||
} else {
|
||||
// Basic handling for macOS Option combos that might produce ≤/≥
|
||||
// Compare the UTF-8 prefix for these two symbols
|
||||
std::string s(txt);
|
||||
if (s.rfind("\xE2\x89\xA4", 0) == 0) {
|
||||
// U+2264 '≤'
|
||||
ascii_key = '<';
|
||||
} else if (s.rfind("\xE2\x89\xA5", 0) == 0) {
|
||||
// U+2265 '≥'
|
||||
ascii_key = '>';
|
||||
}
|
||||
}
|
||||
if (ascii_key != 0) {
|
||||
CommandId id;
|
||||
if (KLookupEscCommand(ascii_key, id)) {
|
||||
mi = {true, id, "", 0};
|
||||
produced = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If we get here, swallow the TEXTINPUT (do not insert stray char)
|
||||
produced = true;
|
||||
break;
|
||||
}
|
||||
if (!k_prefix_ && e.text.text[0] != '\0') {
|
||||
mi.hasCommand = true;
|
||||
mi.id = CommandId::InsertText;
|
||||
|
||||
Reference in New Issue
Block a user