-
-
Notifications
You must be signed in to change notification settings - Fork 42
Kitty Keyboard Protocol support #4769
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
|
Hi @egmontkob and @krobelus, any chance you could leave a review? Thank you! |
|
Supersedes #4768. |
|
My question would be: do we really need the |
|
As I've already noted in #4663 (and it hasn't changed since), I'm absolutely not familiar with Kitty's keyboard protocol, so I'm sorry but I can't help here. |
The hope dies last - I think of you when I think of terminals :) Sorry for the noise. |
|
@horkykuba could you please fix the formatting ( |
Done. |
|
@horkykuba I've fixed everything for the CI to pass. Could you please add some tests for https://github.com/MidnightCommander/mc/blob/master/tests/lib/terminal.c |
Thanks, it was already past Midnight when I was making the last edits :) I've also modified the
Ok, but it will take me a while. Should I implement console input by mocking it using |
5c71db3 to
eda9b61
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i did mostly only a formal review, without checking the actual protocol impl. before i do the latter, please add a comment with a high-level overview of what that code is supposed to do (basically a tldr version of the protocol spec, with a link to the actual spec), and short comments that outline the particular cases.
i'd prefer it if you clean up the series (that is, squash most commits to achieve atomicity), though zyv might disagree ...
I have no objections. I have added my commits on top just to show what I did to fix formatting, linters, and CI. Probably it would be still good to address your comments in a separate commit though, just to make it easier to evaluate that they are indeed addressed before we move further. |
Good question! I think this function is a scary, hairy, hardly testable monster. However, making it even more complicated is not helpful. Perhaps you could extract the parsing code into smaller functions that work on buffers. Then these functions could be easily tested, and you wouldn't need to mock things like There is no hurry. I would really like to have something like this included, but please understand that I also don't want to introduce a lot of potential breakage, which I can't deal with. And the worst part is that I don't have time. So even if it takes you a long time to come up with a tested and reviewable solution, it's absolutely worth it, because then it can be included. |
@ossilator It simply waits if a sequence is found in the
If it matches, it retrieves the modifier bits, checks for non-alphabet keys using a predefined table, and then corrects shifted keys as described in previous comment. Next, it checks if it is a non-Basic Latin Unicode character. If so, it converts it to UTF-8 and inserts the remaining bytes into the pending queue. Finally, it masks the resulting value with Throughout the process, it carefully handles possible following sequences, leaving them in the pending queue. Examples:
|
This is actually a very nice explanation! I'd love to see it as a comment in the code. |
|
Thanks, I've fixed library dependency issue which prevented to build on some systems, split mocking code to two commits, and updated commit messages. |
faf4583 to
ce57fcf
Compare
Hmmm, this didn't seem to help. If you have linking problems, then maybe #4806 would fix that. Very unfortunately, I didn't have time yet to follow up on the removal of the dynamic library. For now, maybe you can replace just one LIB with LDADD... |
I can't reproduce it. It succeeds on my system in both Ubuntu and Fedora. Is it possible to get the test-suite.log somehow? And if the test-suite.log is the same as you posted previously, is it possible to get the core dump of tests/lib/tty? |
Yes, it's the same. I don't think there is an easy way to get to the core dump. I have to try to reproduce it locally. |
|
Maybe it is because TERM variable is not set in CI worker, I've tried to hardcode it in mock |
Wow, bingo, CI (mostly) runs headless (except for Solaris), so |
lib/tty/key.c
Outdated
|
|
||
| for (i = 0; pending_keys[i] != '\0'; i++) | ||
| seq_char_buffer[i] = pending_keys[i]; | ||
| seq_char_buffer[i] = '\0'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Memmove() or memcpy() instead of loop?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that would be more of a strcpy() thing.
but i wonder whether this is robust against malformed (unterminated) sequences?
(hmm, i think i already asked this ...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These functions can't be used as this is conversion from 32bit to 8bit array.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is robust because pending_keys is filled by push_char(), which checks for buffer overflow, and seq_char_buffer has the same size.
|
|
||
| /** Enable or disable Kitty Keyboard Protocol */ | ||
| void | ||
| tty_kitty (gboolean set) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is used only in lib/tty. Should it be declared/defined in tty-internal.[hc]?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is used in src/execute.c also.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so now i made some effort to actually understand what this code does.
i didn't check the wider context this is embedded into.
but with these disclaimers in place, i'd say it looks reasonable.
lib/tty/key.c
Outdated
| || (csi.final_byte >= 'A' && csi.final_byte <= 'F') || (csi.final_byte == 'H') | ||
| || (csi.final_byte >= 'P' && csi.final_byte <= 'S')) | ||
| { | ||
| // Private mode is used for reporting protocol presence and mode from terminal |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fwiw, as i had to look it up: "private mode" is a kinda misleading naming for what it does. it's basically a private namespace for vendor-specific features.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, it is "private mode" of parameter string format. ISO/IEC 6429, section 5.4.1, specifies that the parameter string must follow precise rules if it does not begin with [<=>?], but may have an arbitrary format if it does. The standard doesn't split the final byte to two namespaces (private vs. non-private parameter string). The term "private mode" is also used in the current mc source code in the description of CSI format in lib/terminal.c.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i know. it's still a stupid name. not your fault. you could still extend the comment for clarity if you want to, but whatever.
lib/tty/key.c
Outdated
|
|
||
| for (i = 0; pending_keys[i] != '\0'; i++) | ||
| seq_char_buffer[i] = pending_keys[i]; | ||
| seq_char_buffer[i] = '\0'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that would be more of a strcpy() thing.
but i wonder whether this is robust against malformed (unterminated) sequences?
(hmm, i think i already asked this ...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think, changes after changes is not a good practice. Since this PR is not merged, all these fixes should be moved to commits where appropriate changed were introduced.
b9dbba9 to
54cde8a
Compare
|
Squashed commits and done changes suggested by @aborodin |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just nitpicks.
lib/tty/key.c
Outdated
| || (csi.final_byte >= 'A' && csi.final_byte <= 'F') || (csi.final_byte == 'H') | ||
| || (csi.final_byte >= 'P' && csi.final_byte <= 'S')) | ||
| { | ||
| // Private mode is used for reporting protocol presence and mode from terminal |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i know. it's still a stupid name. not your fault. you could still extend the comment for clarity if you want to, but whatever.
Signed-off-by: Jakub Horký <jakub.git@horky.net>
Make functions tty_lowlevel_getch() and getch_with_timeout() mockable by defining them as weak. Fake key input can be passed by mock_input(). Signed-off-by: Jakub Horký <jakub.git@horky.net>
The protocol is described here: https://sw.kovidgoyal.net/kitty/keyboard-protocol/ The old functionality that "eats" all characters following an unknown escape sequence has been removed, as it causes severe side effects (such as not responding to any keys following an unknown sequence for some time). This is superseded by parsing CSI and SS3 sequences, which are the de facto standard for sending any function keys. Signed-off-by: Jakub Horký <jakub.git@horky.net>
|
Made changes suggested by @ossilator and removed key sequence definitions duplicate to kitty in misc/mc.lib |
Kitty Keyboard Protocol support
Proposed changes
I've added support for Kitty Keyboard Protocol.
I've done some basic testing it WezTerm and kitty terminals, and it appears to work. However, I haven't tested it thoroughly. In particular, please review the integrity of the
get_key_code()function, as I'm not entirely sure I understand all of its functionality in detail.Resolves: #4762