Commit graph

433 commits

Author SHA1 Message Date
Daniel Eklöf
cfa178ab25
input: kitty: unittest: don't fail if system has no compose tables 2025-03-11 08:42:03 +01:00
Daniel Eklöf
7976975a8a
input: kitty: send release events for composed keys 2025-03-11 08:36:37 +01:00
Daniel Eklöf
04fcc5f5b5
input: kitty: regression test for #1987 2025-03-11 08:23:23 +01:00
Daniel Eklöf
8d2627b1ef
input: kitty: always use shifted key when it's the result of a compose
Closes #1987
2025-03-10 15:47:20 +01:00
Daniel Eklöf
051cd6ecfc
config+url: add support for user-defined regex patterns
Users can now define their own regex patterns, and use them via key
bindings:

    [regex:foo]
    regex=foo(bar)?
    launch=path-to-script-or-application {match}

    [key-bindings]
    regex-launch=[foo] Control+Shift+q
    regex-copy=[foo] Control+Mod1+Shift+q

That is, add a section called 'regex:', followed by an
identifier. Define a regex and a launcher command line.

Add a key-binding, regex-launch and/or regex-copy (similar to
show-urls-launch and show-urls-copy), and connect them to the regex
with the "[regex-name]" syntax (similar to how the pipe-* bindings
work).
2025-02-05 13:35:17 +01:00
Daniel Eklöf
51128a3484
input: match unshifted key-bindings before shifted
That is, try to match e.g. Control+shift+a, before trying to match
Control+A.

In most cases, order doesn't matter. There are however a couple of
symbols where the layout consumes the shift-modifier, and the
generated symbol is the same in both the shifted and unshifted
form. One such example is backspace.

Before this patch, key-bindings with shift-backspace would be ignored,
if there were another key-binding with backspace.

So, for example, if we had one key-binding with Control+Backspace, and
another with Control+Shift+Backspace, the latter would never trigger,
as we would always match the first one.

By checking for unshifted matches first, we ensure
Control+Shift+Backspace does match.
2025-01-31 09:07:42 +01:00
Daniel Eklöf
bee17a95b8
input: ignore key-bindings without modifiers when matching untranslated/raw
When matching the unshifted symbol, or the raw key code, ignore all
key bindings that don't have any modifiers.

This fixes an issue where it was impossible to enter (some of the)
numbers on the keypad, **if** there was a key-binding for
e.g. KP_Page_Up, or KP_Page_Down.
2025-01-31 07:35:54 +01:00
Attila Fidan
5286808b6c
input: close fd on no/unrecognized keymap format 2025-01-30 10:58:19 +00:00
Daniel Eklöf
8d6f0d0583
key-bindings: try all bindings in translated mode before matching untranslated, and then finally raw
When trying to match key bindings, we do three types of matching:

* Match the _translated_ symbol (e.g. Control+C)
* Match the _untranslated_ symbol (e.g. Control+Shift+c)
* Match raw keyboard codes

This was done for *each* key binding. This meant we sometimes matched
a keybinding in raw mode, even though there was a
translated/untranslated binding that would match it too. All depending
on the internal order of the key binding list.

This patch changes it, so that we first try all bindings in translated
mode, then all bindings in untranslated mode, and finally all bindings
in raw mode.

Closes #1929
2025-01-27 12:31:40 +01:00
Daniel Eklöf
ba7ecc4669
input: kitty: refactor, try to simplify and be less confusing
Use better named variables while juggling the shifted vs. unshifted
key codes.

Switch to variable names appropriate for the kitty keyboard protocol
once we have all the unshifted, shifted and base key codes done. It's
not until then we can decide which key code to use as the main key,
and whether or not to report the alternate key code.
2025-01-22 12:37:36 +01:00
Daniel Eklöf
f301f6eccc
input: kitty: add more test cases 2025-01-22 12:24:06 +01:00
Daniel Eklöf
6ca1a2c2dc
input: kitty: only set 'alternate' if the "unshifted" code is printable
Fixes a regression where alt+backspace was reported as ^[[8:127;3u
instead of ^[[127;3u.
2025-01-22 10:26:44 +01:00
Daniel Eklöf
f62a5ed1ff
input: codespell: indiciates -> indicates 2025-01-22 08:04:17 +01:00
Daniel Eklöf
09f718878f
input: kitty: add initial unit test
Test a couple of key combos from the se and de(neo) layouts.

This unit test isn't intended to test _all_ key combinations, for all
kitty flag combinations, but to be more of a regression test -
whenever we discover a buggy, weird combo, add it here.
2025-01-22 08:04:17 +01:00
Daniel Eklöf
786037791c
input: kitty: improve handling of alternate+base keys even more
* Always do a base key lookup. Before this, we didn't do that if we
  matched the XKB sym to a lookup table entry (i.e. keypads, cursor keys
  etc.)
* Try to retrieve the unshifted symbol also when we matched the symbol
  to a lookup table entry. When successful, we now report an alternate
  key for keypad and cursor keys; before this patch, we only did that
  for keys that didn't have an entry in the lookup table (i.e. ASCII
  chars etc).

This improves compatibility with kitty (and the kitty keyboard
protocol) in more corner cases. One particular example is the neo
keyboard layout, where part of the regular keys act as keypad keys
when num-lock is active.
2025-01-20 10:34:45 +01:00
Daniel Eklöf
2ff38e86a7
input: kitty: fix alternate codepoint sometimes not being reported
When alternate key reporting is enabled (i.e. when we're supposed to
report the shifted key along with the unshifted key), we try to figure
out whether the key really is shifted or not (and thus which xkb
keysym to use for the unshifted and shifted keys in the escape).

This was done by getting the layout's *all* modifier combinations that
produce the shifted keysym, and if any of of them contained a modifier
that isn't supported by the kitty protocol, the shifted and unshifted
keys are derived from the same keysym. This is to ensure we handle
things like AltGr-combos correctly.

The issue is, since there may be more than one modifier combination
generating the shifted keysym, we may end up using the wrong keysym
just because _another_ combination set contains modifiers not
supported by the kitty protocol. What we're interrested in is whether
the *pressed* set of modifiers contains such modifiers.

Closes #1918
2025-01-20 09:08:47 +01:00
Daniel Eklöf
e851d44ac9
kitty kbd: don't generate release events for plain Enter+Tab+Backspace
From the specification:

    The Enter, Tab and Backspace keys will not have release events
    unless Report all keys as escape codes is also set, so that the
    user can still type reset at a shell prompt when a program that
    sets this mode ends without resetting it.

Closes #1892
2025-01-01 08:06:52 +01:00
Daniel Eklöf
bef613e656
csd: track pointer when rendering and handling CSD button clicks
* Render button as highlighted only when pointer is above them
* Releasing the mouse button while *not* on the button does *not*
  activate the button

When pressing, and holding, a mouse button, the compositor keeps
sending motion events for the surface where the button was pressed,
even if the mouse has moved outside it.

We also don't get any surface leave/enter events.

This meant that the button was rendered as highlighted, and a click
registered, if the user pressed the mouse button while on the button,
and then moved the cursor away from the button before releasing the
button.

This patch fixes it, by checking if the current cursor coordinates
fall within the button surface.
2024-08-09 08:20:59 +02:00
Daniel Eklöf
7ec9ca2b95
input: CSD buttons are now triggered when releasing the mouse button
This is how most UIs work.

Note that we (at least on River) don't get any surface enter/leave
events while a button is held. This means we can't detect if the user
pressed the mouse button while on a CSD button, but then moves the
mouse outside. Releasing the mouse button will still activate the CSD
button.

Closes #1787
2024-08-09 08:20:36 +02:00
Daniel Eklöf
a42f990818
spawn: add optional reaper callback, return pid_t
This will allow spawn() callers to do things when the spawned process
has terminated.
2024-07-23 07:17:21 +02:00
Daniel Eklöf
45c7cd3f74
input: allow mouse selections to start inside the margins
Before this, margins were special cased:

* The mouse cursor was always a pointer, and never an I-beam (thus
  signaling selections cannot be made).
* The internal mouse coords where set to -1 when the cursor was inside
  the margins, causing:
    - text selections from being made
    - mouse events being passed to mouse grabbing applications

In particular, even with a one-pixel margin, making selections was
unnecessarily hard in e.g. fullscreen mode, where you'd expect to be
able to throw the cursor into the corner of the screen and then start
a selection.

With this patch, the cursor is treated as if it was in the first/last
column/row, when inside the margin(s).

An unintended side-effect of this, initially, was that auto-scrolling
selections where way too easy to trigger, since part of its logic is
checking if the cursor is inside the margins.

That problem has been reduced by two things:

* auto-scrolling does not occur unless a selection has been
  started. That is, just holding down the mouse in the margins and
  moving up/down doesn't cause scrolling. You have to first select at
  least one cell in the visible viewport.
* A selection isn't fully started (i.e. a cell is actually selected)
  unless the cursor is inside the actual grid, and *not* in the
  margins.

What does the last point mean? We now allow a selection to be
_started_ when clicking in the margin. What this means internally is
we set a start coordinate for a selection, but *not* and end
coordinate. At this point, we don't have an actual selection. Nothing
is selected, and no cells are highlighted, graphically.

This happens when we set an end coordinate. Without the last bullet
point, that would happen as soon as the cursor was _moved_, even if
still inside the margins. Now, we require the cursor to leave the
margins and touch an actual cell before we set an end coordinate.

Closes #1702
2024-07-19 06:55:28 +02:00
Daniel Eklöf
1136108c97
input: don't map wheel events to BTN_{BACK,FORWARD}
BTN_BACK and BTN_FORWARD are separate buttons. The scroll wheel don't
have any button mappings in libinput/wayland, so make up our own
defines.

This allows us to map them in mouse bindings.

Also expose BTN_WHEEL_{LEFT,RIGHT}. These were already defined, and
used, internally, to handle wheel tilt events. With this, they can
also be used in mouse bindings.

Finally, fix encoding used for BTN_{BACK,FORWARD} when sending mouse
button events to the client application. Before this, they were mapped
to buttons 4/5. But, button 4/5 are for the scroll wheel, and as
mentioned above, BTN_{BACK,FORWARD} are not the same as scroll wheel
"buttons".

Closes #1763
2024-07-13 10:41:10 +02:00
Daniel Eklöf
c45231ef89
input: don't reset the XKB compose state in keymap()
When the compositor sends a new keymap, don't reset the XKB compose
state.

This is done by initializing the XKB context, along with the compose
state, when binding the seat, instead of in keymap().

Then, in keymap(), simply stop destroying the old xkb state. Only
destroy, and re-create the keymap state.

Closes #1744
2024-06-22 08:00:13 +02:00
Daniel Eklöf
aea16ba5d2
input: implement wl_pointer::axis_value120()
This implements high resolution mouse wheel scroll events. A "normal"
scroll step corresponds to the value 120. Anything less than that is a
partial scroll step.

This event replaces axis_discrete(), when we bind wl_seat v8 (which we
now do, when available).

We calculate the number of degrees that is required to scroll a single
line, based off of the scrollback.multiplier value.

Each high-res event accumulates, until we have at least the number of
degress required to scroll one, or more lines.

The remaining degrees are kept, and added to in the next scroll event.

Closes #1738
2024-06-18 14:09:03 +02:00
Daniel Eklöf
18b702b249
unicode-mode: move state from seat to term
This fixes an issue where entering unicode-mode in one foot client,
also enabled unicode-mode on other foot clients. Both
visually (although glitchy), and in effect.

The reason the state was originally in the seat objects, was to fully
support multi-seat. That is, one seat/keyboard entering unicode-mode
should not affect other seats/keyboards.

The issue with this is that seat objects are Wayland global. Thus, in
server mode, all seat objects are shared between the foot clients.

There is a similarity with IME, which also keeps state in the
seat. There's one big difference, however, and that is IME has Wayland
native enter/leave events, that the compositor emits when windows are
focused/unfocused. These events allow us to reset IME state. For our
own Unicode mode, there is nothing similar.

This patch moves the Unicode state from seats, to the terminal
struct. This does mean that if one seat/keyboard enters Unicode mode,
then *all* seats/keyboards will affect the unicode state. This
potential downside is outweighed by the fact that different foot
clients no longer affect each other.

Closes #1717
2024-05-21 08:36:56 +02:00
Daniel Eklöf
b400903e25
config: add new key-binding 'quit', unbound by default
Closes #1475
2024-04-11 15:12:45 +02:00
Daniel Eklöf
702d3ae6ca
kitty kbd: update handling of locked modifiers
The kitty keyboard specification has been updated/clarified yet
again. Locked modifiers are to be ignored if the key event would
result in plain text without the locked modifier being enabled.

In short, locked modifiers are included in the set of modifiers
reported in a key event. But having a locked modifier enabled doesn't
turn all key events into CSIu sequences.

For example, with only the disambiguate mode enabled, pressing 'a', or
'shift+a' results in a/A regardless of the state of Caps- or NumLock.

But 'ctrl+a', which always results in a CSIu, will have a different
modifier list, depending on whether Caps- or NumLock are enabled.
2024-03-06 16:33:24 +01:00
Daniel Eklöf
ec73e4d10d
kitty kbd: switch from GTK to XKB mode for 'consumed' modifiers
This fixes an issue where some key combinations resulted in different
output (e.g. escape code vs. plain text) depending on the state of
e.g. the NumLock key. One such example is Shift+space. Another example
is Shift+BackSpace.

This patch also removes the hardcoded CapsLock filter, when
determining whether a key combo produces text or not, and instead uses
the locked modifiers as reported by XKB.
2024-03-02 10:28:25 +01:00
Tim Culverhouse
749d36d321 input: don't clear text selection on modifier keypresses
When kitty keyboard is enabled, pressing a modifier key will clear the
text selection. This makes it difficult to copy text because the
selection clears as soon as the user presses "ctrl".

Tested-by: Robin Jarry <robin@jarry.cc>
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
2024-02-22 15:23:40 -06:00
Daniel Eklöf
09d856f2ff
input: improved debug logging of key press/release
* Log which it is: press or release
* Include locked modifiers
* Include human-readable names of the modifiers
2024-02-20 16:18:55 +01:00
Daniel Eklöf
ebbee61f14
input: remove debug logging 2024-02-06 14:04:59 +01:00
Daniel Eklöf
7999975016
Don't use fancy Unicode quotes, stick to ASCII 2024-02-06 12:36:45 +01:00
Daniel Eklöf
1c70a84fde
config: add pipe-command-output key-binding 2024-02-06 12:12:57 +01:00
Daniel Eklöf
f8e875a7cd
term: move row->prompt_marker into new struct, row->shell_integration 2024-02-06 12:12:56 +01:00
Daniel Eklöf
0aefc2c65d
input: remove the concept of "significant" modifiers
For the purpose of matching key bindings, "significant" modifiers are
no more.

We're really only interested in filtering out "locked"
modifiers. We're already doing this, so there's no need to *also*
match against a set of "significant" modifiers.

Furthermore, we *never* want to consider locked keys (e.g. when
emitting escapes to the client application), thus we can filter those
out already when retrieving the set of active modifiers.

The exception is the kitty keyboard protocol, which has support for
CapsLock and NumLock. Since we're already re-retrieving the "consumed"
modifiers (using the GTK style, rather than normal "XKB" style, to
better match the kitty terminal), we might as well re-retrieve the
effective modifiers as well.
2024-02-06 11:08:42 +01:00
Daniel Eklöf
4730ff8d08
input/config: support *all* modifier names
That is, allow custom modifiers (i.e. other than ctrl/shift/alt etc)
in key bindings.

This is done by no longer validating/translating modifier names to
booleans for a pre-configured set of modifiers (ctrl, shift, alt,
super).

Instead, we keep the modifier *names* in a list, in the key binding
struct.

When a keymap is loaded, and we "convert" the key binding, _then_ we
do modifier translation. For invalid modifier names, we print an
error, and then ignore it. I.e. we no longer fail to load a config due
to invalid modifier names.

We also need to update how we determine the set of significant
modifiers. Any modifier not in this list will be ignored when matching
key bindings.

Before this patch, we hardcoded this to shift/alt/ctrl/super. Now, to
handle custom modifiers as well, we simply treat *all* modifiers
defined by the current layout as significant.

Typically, the only unwanted modifiers are "locked" modifiers. We are
already filtering these out.
2024-02-06 11:05:20 +01:00
Craig Barnes
e0f3703ae6
util: add streq() function and use in place of strcmp(...) == 0 2024-02-05 12:09:52 +01:00
Daniel Eklöf
4ee4f47065
input: kitty: update to latest version of the spec
Starting with kitty 0.32.0, the modifier bits during modifier key
events behave differently, compared to before. Or, rather, they have
now been spec:ed; before, behavior was different on e.g. MacOS, and
Linux.

The new behavior is this:

On key press, the modifier bits in the kitty key event *includes* the
pressed modifier key.

On key release, the modifier bits in the kitty key event does *not*
include the released modifier key.

In other words, The modifier bits reflects the state *after* the key
event.

This is the exact opposite of what foot did before this patch.

The patch is really pretty small: in order to include the key in the
modifier set, we simulate a key press to update the XKB state, using
xkb_state_uppate_key(). For key pressed, we simulate an XKB_KEY_DOWN
event, and for key releases we simulate an XKB_KEY_UP event.

Then we re-retrieve the modifers, both the full set, and the consumed
set.

Closes #1561
2024-01-24 19:57:32 +01:00
Daniel Eklöf
1719ff93a7
selection: add support for selecting the contents of a quote
This patch changes the default of triple clicking, from selecting the
current logical row, to first trying to select the contents of the
quote under the cursor, and if failing to find a quote, selecting the
current row (like before).

This is implemented by adding a new key binding, 'select-quote'.

It will search for surrounding quote characters, and if one is found
on each side of the cursor, the quote is selected. If not, the entire
row is selected instead.

Subsequent selection operations will behave as if the selection is
either a word selection (a quote was found), or a row selection (no
quote found).

Escaped quote characters are not supported: "foo \" bar" will match
'foo \', and not 'foo " bar'.

Mismatched quotes are not custom handled. They will simply not match.

Nested quotes ("123 'abc def' 456") are supported.

Closes #1364
2023-09-19 16:23:34 +02:00
Daniel Eklöf
fe7aa25ad8
input: make wheel events mappable
Un-grabbed wheel events are now passed through the mouse binding
matching logic, instead of being hardcoded to scrolling the terminal
contents.

They are mappable through the BTN_BACK and BTN_FORWARD buttons.

Since they're not actually button *presses*, they never generate a
click count other than 1. This limitation is documented, but not
checked in the config. This means it's possible to create bindings
like "BTN_BACK+3" (i.e. triple "click"). They will however never
trigger.

The old, hardcoded logic is now accessible through the new
scrollback-up-mouse and scrollback-down-mouse mouse
bindings. They (obiously) default to BTN_BACK and BTN_FORWARD,
respectively.

Example usage: keep the default of scrolling terminal contents with
the wheel, when used without modifiers, but map Control+wheel to font
zoom in/out:

  [mouse-bindings]
  font-increase=Control+BTN_FORWARD
  font-decrease=Control+BTN_BACK

(this also keeps the default key bindings to zoom in/out; ctrl-+ and
ctrl+-)

Closes #1077
2023-09-18 16:36:39 +02:00
CismonX
f0f0d02bf7
input: improve touch handling on pointer presense
No longer inhibits touch event handling when terminal window
has pointer focus.  Instead, inhibit touch event when at least
one pointer button is held down.

This change improves user experience when using foot with both
a mouse and a touchscreen.

Closes #1428.
2023-08-24 00:45:20 +08:00
CismonX
8b4cb2457a
input: do not ignore touch events on the CSDs 2023-07-16 20:41:33 +08:00
Daniel Eklöf
3f7be59062
config: add csd.double-click-to-maximize=no|yes option
When enabled, double-clicking the CSD titlebar will (un)maximize the
window.

Defaults to ‘yes’ (since this is the old hard-coded behavior).

Closes #1293
2023-07-14 12:03:35 +02:00
CismonX
d2fcb5343f
input: add basic support for touchscreen input
Closes #517
2023-07-05 16:22:28 +02:00
Daniel Eklöf
ee794a121e
refactor: track current xcursor using an enum, instead of a char pointer 2023-07-03 14:36:32 +02:00
Daniel Eklöf
e71e7f5cf6
input: kitty: don’t treat zero-length utf8/utf32 strings as text
This is a regression introduced in 3215d54f31

Symptoms: e.g. arrow keys not working in vim/neovim
2023-03-31 11:34:04 +02:00
Daniel Eklöf
3215d54f31
input: (kitty kbd): the resulting UTF-8 string may translate to multiple UTF-32 codepoints
When this happened (for example, by specifying a custom compose
sequence), the kitty keyboard protocol didn’t emit any text at all.

This was caused by the utf32 codepoint being -1. This in turned was
caused by us trying to convert the utf8 sequence to a *single* utf32
codepoint.

This patch replaces the use of mbrtoc32() with a call to
ambstoc32(), and the utf32 codepoint with an utf32 string.

The kitty keyboard protocol is updated:

* When determining if we’re dealing with text, check *all* codepoints
  in the utf32 string.

* Add support for multiple codepoints when reporting "associated
  text". The first codepoint is the actual parameter in the emitted
  sequence, and the remaining codepoints are sub-parameters. I.e. the
  codepoints are colon separated.

Closes #1288
2023-03-30 16:12:17 +02:00
Daniel Eklöf
1c072856eb
input: pipe-*: set current CWD when spawning the sub-process
Closes #1166
2022-09-10 12:04:39 +02:00
Daniel Eklöf
d2e67689ea
terminal: don’t unref a not-yet-referenced key-binding set
Key-binding sets are bound to a seat/configuration pair. The conf
reference is done when a new terminal instance is created.

When that same terminal instance is destroyed, the key binding set is
unref:ed.

If the terminal instance is destroyed *before* the key binding set has
been referenced, we’ll still unref it. This creates an imbalance.

In particular, when the there is exactly one other terminal instance
referencing that same key binding set, that terminal instance will
trigger a foot server crash as soon as it receives a key press/release
event. This happens because the next-to-last terminal instance brought
the reference count of the binding set down to 0, causing it to be
free:d.

Thus, we *must* reference the binding set *before* we can error
out (when instantiating a new terminal instance).

At this point, we don’t yet have a valid terminal instance. But,
that’s ok, because all the key_binding_new_for_term() did with the
terminal instance was get the "struct wayland" and "struct config"
pointers. So, rename the function and simply pass these pointers
explicitly.

Similarly, change key_binding_for() to take a "struct config" pointer,
rather than a "struct terminal" pointer.

Also rename key_binding_unref_term() -> key_binding_unref().
2022-09-06 20:44:05 +02:00
Daniel Eklöf
45803791cf
input: ignore pointer motion events on unknown surfaces
In some cases, the compositor sends a pointer enter event with a NULL
surface. It’s unclear if this is a compositor bug, or a race (where
the compositor sends an enter event on a CSD surface at the same time
foot unmaps the CSDs). Regardless, this causes seat->mouse_focus to be
unset, which triggers a crash in foot on the next pointer motion
event.

This patch does two things:

a) log a warning when we receive a pointer event with a NULL surface
b) ignore motion events where seat->mouse_focus is NULL
2022-08-12 16:13:25 +02:00