v0.1.0 d9218d6

libinput_test.go RawHistoryFolder

1package libinput
2
3import (
4	"testing"
5
6	"github.com/bnema/neferwl/internal/ports"
7)
8
9func TestHotkey(t *testing.T) {
10	ca := ports.ModCtrl | ports.ModAlt
11	for _, tc := range []struct {
12		name   string
13		ev     ports.KeyEvent
14		action hotkeyAction
15		vt     int
16	}{
17		{"ctrl alt backspace", ports.KeyEvent{Keysym: "BackSpace", Keycode: 14, Mods: ca, Pressed: true}, hotkeyQuit, 0},
18		{"release ignored", ports.KeyEvent{Keysym: "BackSpace", Keycode: 14, Mods: ca}, hotkeyNone, 0},
19		{"ctrl only", ports.KeyEvent{Keysym: "BackSpace", Keycode: 14, Mods: ports.ModCtrl, Pressed: true}, hotkeyNone, 0},
20		{"xkb vt sym", ports.KeyEvent{Keysym: "XF86Switch_VT_3", Keycode: 61, Mods: ca, Pressed: true}, hotkeyVT, 3},
21		{"ctrl alt f2 raw", ports.KeyEvent{Keysym: "F2", Keycode: 60, Mods: ca, Pressed: true}, hotkeyVT, 2},
22		{"ctrl alt f12 raw", ports.KeyEvent{Keysym: "F12", Keycode: 88, Mods: ca, Pressed: true}, hotkeyVT, 12},
23		{"plain f2", ports.KeyEvent{Keysym: "F2", Keycode: 60, Pressed: true}, hotkeyNone, 0},
24	} {
25		a, vt := hotkey(tc.ev)
26		if a != tc.action || vt != tc.vt {
27			t.Errorf("%s: got %v %d", tc.name, a, vt)
28		}
29	}
30}
31
32func TestPointerAcrossOutputs(t *testing.T) {
33	layout := ports.Layout{
34		{Info: ports.OutputInfo{Name: "A"}, Width: 100, Height: 50, Scale: 1},
35		{Info: ports.OutputInfo{Name: "B"}, X: 100, Width: 200, Height: 100, Scale: 2},
36	}
37	p := newPointer(layout)
38	if p.x != 50 || p.y != 25 {
39		t.Fatal(p.x, p.y)
40	}
41	// Off the bottom of A: clamped to A.
42	if m := p.move(-80, 100); m.X != 0 || m.Y != 49 {
43		t.Fatalf("got %v %v", m.X, m.Y)
44	}
45	// Into B, where deltas count in physical pixels (scale 2).
46	p.set(150, 20)
47	if m := p.move(20, 10); m.X != 160 || m.Y != 25 || m.DX != 10 || m.DY != 5 {
48		t.Fatalf("got %+v", m)
49	}
50	var out string
51	var px, py float64
52	p.moved(func(o string, x, y float64) { out, px, py = o, x, y })
53	if out != "B" || px != 120 || py != 50 {
54		t.Fatal(out, px, py)
55	}
56	// B unplugged: the pointer lands on A.
57	p.setLayout(layout[:1])
58	if p.x != 99 || p.y != 25 {
59		t.Fatal(p.x, p.y)
60	}
61}
62
63func TestPointerStartsOnPrimary(t *testing.T) {
64	p := newPointer(ports.Layout{
65		{Info: ports.OutputInfo{Name: "A"}, Width: 100, Height: 50, Scale: 1},
66		{Info: ports.OutputInfo{Name: "B"}, X: 100, Width: 200, Height: 100, Scale: 1, Primary: true},
67	})
68	if p.x != 200 || p.y != 50 {
69		t.Fatal(p.x, p.y)
70	}
71}
72
73func TestPointerConstraints(t *testing.T) {
74	p := newPointer(ports.Layout{{Info: ports.OutputInfo{Name: "A"}, Width: 100, Height: 100, Scale: 1}})
75	p.constrain(ports.PointerConstraint{Mode: ports.ConstraintLock, X: 50, Y: 50})
76	if m := p.move(10, -5); m.X != 50 || m.Y != 50 || m.DX != 10 || m.DY != -5 {
77		t.Fatalf("locked: %+v", m)
78	}
79	// Confining moves the pointer inside, then keeps it there.
80	p.constrain(ports.PointerConstraint{Mode: ports.ConstraintConfine, Rect: ports.Rect{X: 60, Y: 10, W: 20, H: 20}, X: 50, Y: 50})
81	if p.x != 60 || p.y != 29 {
82		t.Fatal(p.x, p.y)
83	}
84	if m := p.move(100, 0); m.X != 79 || m.DX != 100 {
85		t.Fatalf("confined: %+v", m)
86	}
87	p.constrain(ports.PointerConstraint{})
88	if m := p.move(10, 0); m.X != 89 {
89		t.Fatalf("free: %+v", m)
90	}
91	// A lock takes core's cursor position, and so does its release.
92	p.constrain(ports.PointerConstraint{Mode: ports.ConstraintLock, X: 20, Y: 30})
93	if p.x != 20 || p.y != 30 {
94		t.Fatal(p.x, p.y)
95	}
96	p.move(40, 40)
97	p.constrain(ports.PointerConstraint{X: 21, Y: 31})
98	if p.x != 21 || p.y != 31 {
99		t.Fatal(p.x, p.y)
100	}
101}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 23

Tags 10

↑↓ moveenter openesc close