Commit graph

439 commits

Author SHA1 Message Date
Daniel Eklöf
3e1e3ea38c
libxkbcommon: don't require 1.8.0
The version bump was done since we now use XKB_VMOD_NAME_*; macros
added in libxkbcommon 1.8.0.

Not all distros have updated libxkbcommon yet (read: Debian). Since
it's fairly easy to work around, let's do that.

Closes #2103
2025-05-18 11:36:57 +02:00
Daniel Eklöf
10e7f29149
csi: implement private mode 2031 (dark/light mode detection)
* Recognize 'CSI ? 996 n', and respond with
  - 'CSI ? 997 ; 1 n' if the primary theme is active
  - 'CSI ? 997 ; 2 n' if the alternative theme is actice
* Implement private mode 2031, where changing the color
  theme (currently only possible via key bindings) causes the terminal
  to send the same CSI sequences as above.

In this context, foot's primary theme is considered dark, and the
alternative theme light (since the default theme is dark).

Closes #2025
2025-04-26 14:23:34 +02:00
Daniel Eklöf
6bc91b5e28
key-bindings: add bindings to switch between color themes
* color-theme-switch-1: select the primary color theme
* color-theme-switch-2: select the alternative color theme
* color-theme-toggle: toggle between the primary and alternative color themes
2025-04-26 14:20:58 +02:00
Daniel Eklöf
ef4a680ae8
input: reset modifiers in keyboard_leave()
Closes #2034
2025-04-19 13:36:13 +02:00
Daniel Eklöf
23431e3ecf
wayland+input: add support for toplevel edge constraints
Edge constraints are new (not yet available in a wayland-protocols
release) toplevel states, acting as a complement to the existing tiled
states.

Tiled tells us we shouldn't draw shadows etc *outside our window
geometry*.

Constrained tells us the window cannot be resized in the constrained
direction.

This patch does a couple of things:

* Recognize the new states when debug logging

* Change is_top_left() etc to look at the new constrained state
  instead of the tiled state. These functions are used when both
  choosing cursor shape, and when determining if/how to resize a
  window on a CSD edge click-and-drag.

* Update cursor shape selection to use the default (left_ptr) shape
  when on a constrained edge (or corner).

* Update CSD resize triggering, to not trigger a resize when attempted
  on a constrained edge (or corner).

See
86750c99ed:

    An edge constraint is an complementery state to the tiled state,
    meaning that it's not only tiled, but constrained in a way that it
    can't resize in that direction.

    This typically means that the constrained edge is tiled against a
    monitor edge. An example configuration is two windows tiled next
    to each other on a single monitor. Together they cover the whole
    work area.

    The left window would have the following tiled and edge constraint
    state:

        [ tiled_top, tiled_right, tiled_bottom, tiled_left,
          constrained_top, constrained_bottom, constrained_left ]

    while the right window would have the following:

        [ tiled_top, tiled_right, tiled_bottom, tiled_left,
          constrained_top, constrained_bottom, constrained_right ]

    This aims to replace and deprecate the
    `gtk_surface1.configure_edges` event and the
    `gtk_surface1.edge_constraint` enum.
2025-04-07 13:41:37 +02:00
Daniel Eklöf
58910856c8
input: xkb: ignore virtual modifiers
Some compositors (mutter/GNOME is one) adds _virtual_ modifiers to the
set of active modifiers when e.g. Alt, Meta, Super or Hyper is
pressed. For example, pressing Alt+b would result in *both* the Alt
*and* the Mod1 modifier being set.

Since foot makes close to zero assumptions on how the modifiers should
be interpreted, this causes various breakages.

For example, a foot shortcut defined as Mod1+b will not match, since
the Alt modifiers is also set. This has forced users to
redefine/override some of the default key bindings to include the
additional modifiers.

It also causes issues with the kitty keyboard protocol, for some key
combinations. Mainly whether or not to use unshifted key or not,
resulting in incorrect escape sequences.

Since all the "real" modifiers are always set as well, we can safely
ignore the virtual modifiers.

Closes #2009
2025-03-31 08:08:43 +02:00
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