Our internal binding handling cares about a different set of
modifiers, compared to the kitty keyboard protocol.
To handle this, get_current_modifiers() has been modified, to no
longer strip the “unsignificant” modifiers. This is now up to the
caller to do.
To help, we keep two masks (for significant modifiers) in the seat
struct; one for our internal binding handling (and the legacy keyboard
protocol), and one for the kitty keyboard protocol. These two masks
are updated when the seat’s keymap is updated/changed.
When emitting an escape sequence for a printable character, with
modifiers (e.g. ctrl+a), use the key’s base symbol instead of
“lowering” it.
This means we now handle e.g. ctrl+2 and ctrl+shift+2, with Swedish
layout.
There’s a twist however. We *only* use the base symbol if the
modifiers that is used to “generate” the symbol are “significant”.
Significant modifiers are, in this context, modifiers we can encode in
the kitty escape sequences.
In the Swedish layout, pressing AltGr+2 results in ‘@’. AltGr cannot
be encoded in the kitty protocol. If we were to use the base symbol,
AltGr+Alt+2 would result in exactly the same escape sequence as Alt+2.
Most things appear to work as in kitty. There’s one known difference:
tri-state keys don’t generate the same unshifted symbol while holding
Shift (but e.g. Ctrl+a and Ctrl+Shift+a *does* generate the same base
symbol).
For example, the Swedish keyboard layout has double quote, ‘2’ and ‘@’
on the same key. ‘2’ is the base (unshifted) symbol. Double quote is
Shift+2. ‘@’ is AltGr+2.
Kitty generates the same base symbol for ‘2’ and double quote (the
base symbol is, as expected, ‘2’).
But, for ‘@’ kitty generates the base symbol ‘@’.
Currently, foot generates the base symbol by calling
xkb_keysym_to_lower().
I _think_ what we need to do is “consume” the shift modifier, and then
re-retrieve the symbol (given the current xkb state and key pressed).
This breaks out all handling of key escapes to-be-sent to the client,
to a separate function, legacy_kbd_protocol().
That is, the key press/release handler first handles key generic
handling, such as starting and stopping the repeat timer.
Then it checks for foot keyboard bindings. If not bindings match, we
need to pass the keyboard event to the client. This code has now been
separated out into a new function.
The URI ranges are now an array, which means we can get the next URI
range by incrementing the pointer.
Instead of checking if range is not NULL, check that it isn’t the
range terminator (which is NULL when we don’t have any ranges, and
the first address *after* the last range otherwise).
grid_row_uri_range_add() was only used while reflowing. In this case,
we know the new URIs being added are always going at the end of the
URI list (since we’re going top-to-bottom, left-to-right).
Thus, we don’t need the insertion logic, and can simply append instead.
At first, an OSC-8 URI range was added when we received the closing
OSC-8 escape (i.e. with an empty URI).
But, this meant that cursor movements while the OSC-8 escape was in
effect wasn’t handled correctly, since we’d add a range that spanned
the cursor movements.
Attempts were made to handle this in the cursor movement functions, by
closing and re-opening the URI.
However, there are too many corner cases to make this a viable
approach. Scrolling is one such example, line-wrapping another.
This patch takes a different approach; emit, or update the URI range
when we print to the grid. This models the intended behavior much more
closely, where an active OSC-8 URI act like any other SGR attribute -
it is applied to all cells printed to, but otherwise have no effect.
To avoid killing performance, this is only done in the “generic”
printer. This means OSC-8 open/close calls must now “switch” the ASCII
printer.
Note that the “fast” printer still needs to *erase* pre-existing OSC-8
URIs.
Closes#816
If a mouse selection was ongoing, and the user switched
workspace (probably using the keyboard...), and then back, the
selection was still treated as ongoing, while all other mouse state
has been reset.
This meant the user had to tap at least once to stop the selection.
The old algorithm always created a new URI, followed by (maybe)
removing the existing URI, when an URI needed to be modified.
That is, if e.g. the tail of an URI was being erased, the old
algorithm would create a new URI for the part of the URI that should
remain, and then removed the old URI.
This isn’t very effective. The new algorithm instead identifies all
possible overlap cases, and handles each one differently:
* URI ends *before* erase range starts - continue with the next URI
without further checks
* URI starts *after* the erase range ends - return, we’re done
* Erase range erases the entire URI - remove the URI
* Erase range erases a part in the middle - split the URI
* Erase range erases the head of the URI - adjust the URI’s start
* Erase range erases the tail of the URI - adjust the URI’s end
This function handles erasing of an URI range. That is, a range of the
row is being either erased, or overwritten (from the URI perspective,
these two are the same thing).
We handle both partial overwrites (split up, or truncate URI), as well
as complete overwrites (remove URI).
Instead of passing raw char** pointers to argv_compare(), pass
pointers to ‘struct argv’.
This lets argv_compare() handle both argv’s being NULL, or one of them
being NULL. That is, the caller no longer needs to check that both
argv’s are non-NULL before calling argv_compare().
Furthermore, update has_key_binding_collisions() to require the pipe
argv to match, in addition to matching the ‘action’, when allowing a
key collision.
When parsing a key binding with a pipe-argv, we failed to free the
argv vector (or to be precise, the strdup:ed entries in the array)
when failing to parse the remainder of the binding.