diff options
| author | Anders Betts <anders.betts@gmail.com> | 2026-09-21 15:50:37 +0200 |
|---|---|---|
| committer | Anders Betts <anders.betts@gmail.com> | 2026-09-21 15:50:37 +0200 |
| commit | 69777086ffad917b7a48d57df9dccf4e21a0a364 (patch) | |
| tree | 91a0d4a2e02dd589e9d5066248a031776892d772 | |
| parent | db03b0b2875e6981fdb86c5c3c23d1a59280f222 (diff) | |
| download | bokf-69777086ffad917b7a48d57df9dccf4e21a0a364.tar.gz bokf-69777086ffad917b7a48d57df9dccf4e21a0a364.zip | |
tui: level-2 modifyOtherKeys, Kitty keyboard protocol and ^Enter/F9 hintsv0.1.59
| -rw-r--r-- | clients/bokftui.c | 1 | ||||
| -rw-r--r-- | clients/screens_bokslut.c | 2 | ||||
| -rw-r--r-- | clients/screens_ib.c | 2 | ||||
| -rw-r--r-- | clients/screens_invoices.c | 2 | ||||
| -rw-r--r-- | clients/screens_payroll.c | 5 | ||||
| -rw-r--r-- | clients/screens_templates.c | 2 | ||||
| -rw-r--r-- | clients/screens_vouchers.c | 2 | ||||
| -rw-r--r-- | clients/tui.c | 35 | ||||
| -rw-r--r-- | docs/TUI-GUIDELINES.md | 2 | ||||
| -rwxr-xr-x | scripts/tui-golden.py | 60 |
10 files changed, 99 insertions, 14 deletions
diff --git a/clients/bokftui.c b/clients/bokftui.c index 2dc23ba..69d6690 100644 --- a/clients/bokftui.c +++ b/clients/bokftui.c @@ -346,6 +346,7 @@ static void usage(FILE *f) static void reset_modify_keys(void) { + putp("\033[<u"); putp("\033[>4m"); fflush(stdout); } diff --git a/clients/screens_bokslut.c b/clients/screens_bokslut.c index df47196..3f69982 100644 --- a/clients/screens_bokslut.c +++ b/clients/screens_bokslut.c @@ -242,7 +242,7 @@ void bokslut_screen(struct app *a) ff[7].cap = sizeof rate; ff[7].kind = TUI_F_TEXT; tui_form_hint("upp/ned/Tab = flytta Enter = ändra/utför F5 = visa" - " bokslutsplan ^Enter = bokför planen (frågar" + " bokslutsplan ^Enter/F9 = bokför planen (frågar" " först) Esc/q = tillbaka ^C = avsluta"); int r = tui_form_run_actions("Bokslut", ff, nf + 2, can_edit, acts, 5, NULL, &sel); diff --git a/clients/screens_ib.c b/clients/screens_ib.c index ca35562..8950667 100644 --- a/clients/screens_ib.c +++ b/clients/screens_ib.c @@ -272,7 +272,7 @@ static int ib_form(struct app *a, char **old_acc, int64_t *old_amt, int nold) for (;;) { int rr = tui_rt_run("Ingående balans", &ib.rt, "Tab = byta fält F5 = validera ^X = rensa rad" - " ^Enter = spara Esc = avbryt"); + " ^Enter/F9 = spara Esc = avbryt"); if (rr == -1) return 0; char msg[256]; diff --git a/clients/screens_invoices.c b/clients/screens_invoices.c index b8cc8dd..ca59eef 100644 --- a/clients/screens_invoices.c +++ b/clients/screens_invoices.c @@ -1092,7 +1092,7 @@ static int64_t invoices_new(struct app *a) tui_rt_set_fields(&f.rt, ff, 7); const char *hint = "Enter = välj/ändra Tab = byta fält F5 = förhandsvisa" - " ^Enter = utfärda Esc = avbryt"; + " ^Enter/F9 = utfärda Esc = avbryt"; int64_t out = 0; for (;;) { int rr = tui_rt_run("Ny faktura", &f.rt, hint); diff --git a/clients/screens_payroll.c b/clients/screens_payroll.c index 9bfaf38..23d765f 100644 --- a/clients/screens_payroll.c +++ b/clients/screens_payroll.c @@ -1101,7 +1101,8 @@ static int64_t payroll_run_screen(struct app *a, int64_t id) { status, -1, NULL }, { totals, -1, NULL }, { "Förhandsvisa (F5)", 1, NULL }, - { "Bokför körning (^Enter)", post_reason ? 0 : 1, post_reason }, + { "Bokför körning (^Enter/F9)", post_reason ? 0 : 1, + post_reason }, { "Lönebesked (PDF)", payslip_reason ? 0 : 1, payslip_reason }, { "AGI-underlag", agi_reason ? 0 : 1, agi_reason }, { "Betala skatt & avgifter", pay_reason ? 0 : 1, pay_reason }, @@ -1123,7 +1124,7 @@ static int64_t payroll_run_screen(struct app *a, int64_t id) snprintf(title, sizeof title, "Ny lönekörning"); int editable = can_write && !posted; tui_form_hint("upp/ned/Tab = flytta Enter = ändra/utför" - " F5 = förhandsvisa ^Enter = bokför" + " F5 = förhandsvisa ^Enter/F9 = bokför" " Esc/q = tillbaka ^C = avsluta"); int ret = tui_form_run_actions(title, ff, 2, editable, acts, 7, NULL, &focus); diff --git a/clients/screens_templates.c b/clients/screens_templates.c index b2cd7ab..5777742 100644 --- a/clients/screens_templates.c +++ b/clients/screens_templates.c @@ -234,7 +234,7 @@ static int template_form(struct app *a, const char *load_name) tui_rt_set_fields(&tf.rt, ff, 3); const char *title = load_name ? "Redigera mall" : "Ny mall"; const char *hint = "Enter = ändra fält Tab = byta fält F5 = validera" - " ^X = rensa rad ^Enter = spara Esc = avbryt"; + " ^X = rensa rad ^Enter/F9 = spara Esc = avbryt"; for (;;) { int rr = tui_rt_run(title, &tf.rt, hint); if (rr == -1) diff --git a/clients/screens_vouchers.c b/clients/screens_vouchers.c index fedffe9..5e1b006 100644 --- a/clients/screens_vouchers.c +++ b/clients/screens_vouchers.c @@ -836,7 +836,7 @@ int64_t vouchers_new_prefill(struct app *a, const struct voucher_prefill *p) tui_rt_normalize(&vf.rt); const char *hint = "Enter = ändra fält Tab = byta fält F4 = mall" " ^F = bifoga fil F5 = validera ^X = rensa rad" - " ^Enter = bokför Esc = avbryt"; + " ^Enter/F9 = bokför Esc = avbryt"; for (;;) { int rr = tui_rt_run("Nytt verifikat", &vf.rt, hint); if (rr == -1) diff --git a/clients/tui.c b/clients/tui.c index 031fad0..30761a8 100644 --- a/clients/tui.c +++ b/clients/tui.c @@ -159,9 +159,34 @@ int tui_sticky_split(char **lines, int n, char **head, int *nhead) void tui_keys_setup(void) { - /* ^Enter has no control code; enable xterm modifyOtherKeys and bind the - sequence it produces. Terminals without it ignore the request. */ + /* ^Enter has no control code; enable xterm modifyOtherKeys level 2 (level + 1 leaves control+Enter alone) and the Kitty keyboard protocol, then bind + the sequences they produce. Terminals with neither keep F9 working. */ + putp("\033[>4;2m"); + putp("\033[>1u"); + fflush(stdout); define_key("\033[27;5;13~", TUI_KEY_CTRL_ENTER); + define_key("\033[13;5u", TUI_KEY_CTRL_ENTER); + define_key("\033[27;2;9~", KEY_BTAB); + define_key("\033[9;2u", KEY_BTAB); + define_key("\033[27u", 27); + define_key("\033[27;1u", 27); + define_key("\033[27;5;97~", 1); + define_key("\033[97;5u", 1); + define_key("\033[27;5;99~", 3); + define_key("\033[99;5u", 3); + define_key("\033[27;5;101~", 5); + define_key("\033[101;5u", 5); + define_key("\033[27;5;102~", 6); + define_key("\033[102;5u", 6); + define_key("\033[27;5;110~", 14); + define_key("\033[110;5u", 14); + define_key("\033[27;5;114~", 18); + define_key("\033[114;5u", 18); + define_key("\033[27;5;117~", 21); + define_key("\033[117;5u", 21); + define_key("\033[27;5;120~", 24); + define_key("\033[120;5u", 24); /* Home/End arrive as CSI or SS3 depending on the terminal */ define_key("\033[1~", KEY_HOME); define_key("\033OH", KEY_HOME); @@ -184,8 +209,6 @@ void tui_keys_setup(void) init_pair(TUI_CP_RULE, COLOR_BLUE, -1); init_pair(TUI_CP_STATUS, COLOR_CYAN, -1); } - putp("\033[>4;1m"); - fflush(stdout); } @@ -1592,7 +1615,7 @@ static int form_run(const char *title, struct tui_form_field *f, int nf, h = na > 0 ? (can_edit ? "upp/ned/Tab = flytta Enter = ändra/utför" - " F5 = uppdatera ^Enter = spara" + " F5 = uppdatera ^Enter/F9 = spara" " Esc/q = tillbaka ^C = avsluta" : "upp/ned/Tab = flytta Enter = utför" " F5 = uppdatera Esc/q = tillbaka" @@ -1600,7 +1623,7 @@ static int form_run(const char *title, struct tui_form_field *f, int nf, " (endast behöriga kan ändra)") : (can_edit ? "upp/ned/Home/End Enter = ändra" - " F5 = uppdatera ^Enter = spara" + " F5 = uppdatera ^Enter/F9 = spara" " Esc/q = tillbaka ^C = avsluta" : "upp/ned/Home/End F5 = uppdatera" " Esc/q = tillbaka ^C = avsluta" diff --git a/docs/TUI-GUIDELINES.md b/docs/TUI-GUIDELINES.md index 94c3b5c..190a5c5 100644 --- a/docs/TUI-GUIDELINES.md +++ b/docs/TUI-GUIDELINES.md @@ -33,7 +33,7 @@ there. | `Ctrl+F` | Attach a file via the file browser (voucher form and voucher detail) | | `k` | Underlag: link the highlighted attachment to a voucher picked from a list | | `Ctrl+X` | Clear the current row — only inside row editors (never "new") | -| `Ctrl+Enter` | Save/post the current form. Enabled via xterm `modifyOtherKeys`; terminals that cannot send it keep `F9` working | +| `Ctrl+Enter` | Save/post the current form. Enabled via xterm `modifyOtherKeys` level 2 or the Kitty keyboard protocol; terminals that send neither keep `F9` working, and the hints show `^Enter/F9` | Every screen prints its keys in the footer via `hints()`. If a key exists, the footer shows it; if the footer shows it, the key works. Control keys are diff --git a/scripts/tui-golden.py b/scripts/tui-golden.py index 9df5ed4..f5d5b7f 100755 --- a/scripts/tui-golden.py +++ b/scripts/tui-golden.py @@ -56,7 +56,9 @@ KEYS = { "ctrlc": "\x03", "ctrln": "\x0e", "ctrlenter": "\x1b[27;5;13~", + "ctrlenter-kitty": "\x1b[13;5u", "f5": "\x1b[15~", + "f9": "\x1b[20~", } # {org_name} {org_nr} {fy_label} {fy_start} {fy_end} are substituted at run @@ -234,6 +236,58 @@ SCENARIOS = [ "expect": ["Anställda", "Testanställd", "Ny anställd"], }, { + "name": "employee-new-f9", + "screen": "employees", + "steps": [ + { + "keys": ["ctrln"], + "expect": ["Ny anställd", "Personnummer"], + }, + { + "keys": ["enter", "Testperson", "enter"], + "expect": ["Ny anställd", "Testperson"], + }, + { + "keys": ["down", "enter", "19900101-1234", "enter"], + "expect": ["19900101-1234"], + }, + { + "keys": ["f9"], + "expect": ["Anställd skapad."], + }, + { + "keys": ["enter"], + "expect": ["Anställda", "Testperson"], + }, + ], + }, + { + "name": "employee-new-kitty", + "screen": "employees", + "steps": [ + { + "keys": ["ctrln"], + "expect": ["Ny anställd", "Personnummer"], + }, + { + "keys": ["enter", "Kitty Person", "enter"], + "expect": ["Kitty Person"], + }, + { + "keys": ["down", "enter", "19900202-5678", "enter"], + "expect": ["19900202-5678"], + }, + { + "keys": ["ctrlenter-kitty"], + "expect": ["Anställd skapad."], + }, + { + "keys": ["enter"], + "expect": ["Anställda", "Kitty Person"], + }, + ], + }, + { "name": "company", "screen": "company", "expect": ["Bolaget", "Företagsuppgifter", "Fakturauppgifter", @@ -947,6 +1001,12 @@ def main(argv): report_failure(name, missing, "", before) failures += 1 continue + if (b"\x1b[>4;2m" not in app.raw or + b"\x1b[>1u" not in app.raw): + report_failure(name, ["keyboard protocol enable " + "sequence"], "", before) + failures += 1 + continue current = before for step in sc.get("steps", []): keys = resolve_keys(step["keys"]) |
