detached fe9795c

feat: add seat with pointer, keyboard, repeat timer, cursor shape and secret input

commit
fe9795cc0cf0219b585af04ba5c91c2a69b2354a
author
brice · · 2026-10-01 18:32 UTC
parent
afc6dac
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
10 files · +3815 -1
M conn.go +16 -0
@@ -82,6 +82,8 @@ type Conn struct {
8282 nextLock uint32
8383 curLock *Lock // the live session lock, if any
8484 tableBuf []byte
85+ seat *Seat
86+ seatErr error // a seat bind failure, reported by the next Dispatch
8587
8688 ready bool // Connect finished; announcements go to the Handler
8789 dispatching bool
@@ -338,6 +340,10 @@ func (c *Conn) Dispatch(h Handler) error {
338340 }
339341 c.dispatching = true
340342 defer func() { c.dispatching = false }()
343+ if err := c.seatErr; err != nil {
344+ c.seatErr = nil
345+ h.Error(err)
346+ }
341347 var ev event
342348 for range ringSize {
343349 if !c.q.pop(&ev) {
@@ -364,6 +370,7 @@ func (c *Conn) apply(ev *event, h Handler) {
364370 }
365371 case evGlobalRemove:
366372 c.removeOutput(ev.global, h)
373+ c.seatGlobalRemoved(ev.global, h)
367374 case evOutputName:
368375 if o := c.entry(ev.global); o != nil {
369376 o.nameLen = copy(o.nameBuf[:], ev.nameBytes())
@@ -381,6 +388,10 @@ func (c *Conn) apply(ev *event, h Handler) {
381388 c.commitOutput(o, h)
382389 }
383390 case evFDReady:
391+ if c.seatTimer(ev.fd) {
392+ c.seatRepeat(h)
393+ return
394+ }
384395 id, ok := c.watched[ev.fd]
385396 if !ok {
386397 return // unwatched while the event was queued
@@ -395,6 +406,10 @@ func (c *Conn) apply(ev *event, h Handler) {
395406 }
396407 }
397408 default:
409+ if ev.kind >= evSeatCaps {
410+ c.applySeat(ev, h)
411+ return
412+ }
398413 c.applySurface(ev, h)
399414 }
400415 }
@@ -590,6 +605,7 @@ func (c *Conn) Close() error {
590605 if c.efd >= 0 {
591606 _ = unix.Close(c.efd)
592607 }
608+ c.closeSeat()
593609 c.q.closeFDs() // both producers are gone: close what nobody will drain
594610 return err
595611 }
@@ -82,6 +82,8 @@ type Conn struct {
82 nextLock uint3282 nextLock uint32
83 curLock *Lock // the live session lock, if any83 curLock *Lock // the live session lock, if any
84 tableBuf []byte84 tableBuf []byte
85+ seat *Seat
86+ seatErr error // a seat bind failure, reported by the next Dispatch
85 87
86 ready bool // Connect finished; announcements go to the Handler88 ready bool // Connect finished; announcements go to the Handler
87 dispatching bool89 dispatching bool
@@ -338,6 +340,10 @@ func (c *Conn) Dispatch(h Handler) error {
338 }340 }
339 c.dispatching = true341 c.dispatching = true
340 defer func() { c.dispatching = false }()342 defer func() { c.dispatching = false }()
343+ if err := c.seatErr; err != nil {
344+ c.seatErr = nil
345+ h.Error(err)
346+ }
341 var ev event347 var ev event
342 for range ringSize {348 for range ringSize {
343 if !c.q.pop(&ev) {349 if !c.q.pop(&ev) {
@@ -364,6 +370,7 @@ func (c *Conn) apply(ev *event, h Handler) {
364 }370 }
365 case evGlobalRemove:371 case evGlobalRemove:
366 c.removeOutput(ev.global, h)372 c.removeOutput(ev.global, h)
373+ c.seatGlobalRemoved(ev.global, h)
367 case evOutputName:374 case evOutputName:
368 if o := c.entry(ev.global); o != nil {375 if o := c.entry(ev.global); o != nil {
369 o.nameLen = copy(o.nameBuf[:], ev.nameBytes())376 o.nameLen = copy(o.nameBuf[:], ev.nameBytes())
@@ -381,6 +388,10 @@ func (c *Conn) apply(ev *event, h Handler) {
381 c.commitOutput(o, h)388 c.commitOutput(o, h)
382 }389 }
383 case evFDReady:390 case evFDReady:
391+ if c.seatTimer(ev.fd) {
392+ c.seatRepeat(h)
393+ return
394+ }
384 id, ok := c.watched[ev.fd]395 id, ok := c.watched[ev.fd]
385 if !ok {396 if !ok {
386 return // unwatched while the event was queued397 return // unwatched while the event was queued
@@ -395,6 +406,10 @@ func (c *Conn) apply(ev *event, h Handler) {
395 }406 }
396 }407 }
397 default:408 default:
409+ if ev.kind >= evSeatCaps {
410+ c.applySeat(ev, h)
411+ return
412+ }
398 c.applySurface(ev, h)413 c.applySurface(ev, h)
399 }414 }
400 }415 }
@@ -590,6 +605,7 @@ func (c *Conn) Close() error {
590 if c.efd >= 0 {605 if c.efd >= 0 {
591 _ = unix.Close(c.efd)606 _ = unix.Close(c.efd)
592 }607 }
608+ c.closeSeat()
593 c.q.closeFDs() // both producers are gone: close what nobody will drain609 c.q.closeFDs() // both producers are gone: close what nobody will drain
594 return err610 return err
595 }611 }
M handler.go +23 -0
@@ -50,6 +50,24 @@ type Handler interface {
5050 // LockFinished reports ext_session_lock_v1.finished: the compositor
5151 // refused or ended the lock. Destroy it with [Lock.Close].
5252 LockFinished()
53+
54+ // Pointer reports pointer input over one of the connection's surfaces:
55+ // enter, leave, motion, buttons and scrolling. ev is valid only during the
56+ // call.
57+ Pointer(ev *PointerEvent)
58+ // Key reports a key press, repeat or release for the surface that has
59+ // keyboard focus. Text is the text the key produced (nil for releases and
60+ // keys without text) and is valid only during the call. While a
61+ // [SecretBuffer] is installed with [Seat.SetSecret], Text is always nil
62+ // and the text goes into the buffer; see [Handler.SecretChanged]. ev is
63+ // valid only during the call.
64+ Key(ev *KeyEvent)
65+ // KeyboardFocus reports that a surface gained or lost keyboard focus.
66+ KeyboardFocus(id SurfaceID, focused bool)
67+ // SecretChanged reports that a key press, repeat or backspace changed the
68+ // installed [SecretBuffer]; count is its length in code points. It is
69+ // called after the [Handler.Key] call of that key.
70+ SecretChanged(count int)
5371 }
5472
5573 // NopHandler implements every Handler method as a no-op. Embed it in a handler
@@ -69,3 +87,8 @@ func (NopHandler) Closed(SurfaceID) {}
6987 func (NopHandler) FeedbackDone(SurfaceID) {}
7088 func (NopHandler) Locked() {}
7189 func (NopHandler) LockFinished() {}
90+
91+func (NopHandler) Pointer(*PointerEvent) {}
92+func (NopHandler) Key(*KeyEvent) {}
93+func (NopHandler) KeyboardFocus(SurfaceID, bool) {}
94+func (NopHandler) SecretChanged(int) {}
@@ -50,6 +50,24 @@ type Handler interface {
50 // LockFinished reports ext_session_lock_v1.finished: the compositor50 // LockFinished reports ext_session_lock_v1.finished: the compositor
51 // refused or ended the lock. Destroy it with [Lock.Close].51 // refused or ended the lock. Destroy it with [Lock.Close].
52 LockFinished()52 LockFinished()
53+
54+ // Pointer reports pointer input over one of the connection's surfaces:
55+ // enter, leave, motion, buttons and scrolling. ev is valid only during the
56+ // call.
57+ Pointer(ev *PointerEvent)
58+ // Key reports a key press, repeat or release for the surface that has
59+ // keyboard focus. Text is the text the key produced (nil for releases and
60+ // keys without text) and is valid only during the call. While a
61+ // [SecretBuffer] is installed with [Seat.SetSecret], Text is always nil
62+ // and the text goes into the buffer; see [Handler.SecretChanged]. ev is
63+ // valid only during the call.
64+ Key(ev *KeyEvent)
65+ // KeyboardFocus reports that a surface gained or lost keyboard focus.
66+ KeyboardFocus(id SurfaceID, focused bool)
67+ // SecretChanged reports that a key press, repeat or backspace changed the
68+ // installed [SecretBuffer]; count is its length in code points. It is
69+ // called after the [Handler.Key] call of that key.
70+ SecretChanged(count int)
53 }71 }
54 72
55 // NopHandler implements every Handler method as a no-op. Embed it in a handler73 // NopHandler implements every Handler method as a no-op. Embed it in a handler
@@ -69,3 +87,8 @@ func (NopHandler) Closed(SurfaceID) {}
69 func (NopHandler) FeedbackDone(SurfaceID) {}87 func (NopHandler) FeedbackDone(SurfaceID) {}
70 func (NopHandler) Locked() {}88 func (NopHandler) Locked() {}
71 func (NopHandler) LockFinished() {}89 func (NopHandler) LockFinished() {}
90+
91+func (NopHandler) Pointer(*PointerEvent) {}
92+func (NopHandler) Key(*KeyEvent) {}
93+func (NopHandler) KeyboardFocus(SurfaceID, bool) {}
94+func (NopHandler) SecretChanged(int) {}
M handler_mock_test.go +166 -0
@@ -296,6 +296,92 @@ func (_c *MockHandler_Frame_Call) RunAndReturn(run func(id SurfaceID)) *MockHand
296296 return _c
297297 }
298298
299+// Key provides a mock function for the type MockHandler
300+func (_mock *MockHandler) Key(ev *KeyEvent) {
301+ _mock.Called(ev)
302+ return
303+}
304+
305+// MockHandler_Key_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Key'
306+type MockHandler_Key_Call struct {
307+ *mock.Call
308+}
309+
310+// Key is a helper method to define mock.On call
311+// - ev *KeyEvent
312+func (_e *MockHandler_Expecter) Key(ev any) *MockHandler_Key_Call {
313+ return &MockHandler_Key_Call{Call: _e.mock.On("Key", ev)}
314+}
315+
316+func (_c *MockHandler_Key_Call) Run(run func(ev *KeyEvent)) *MockHandler_Key_Call {
317+ _c.Call.Run(func(args mock.Arguments) {
318+ var arg0 *KeyEvent
319+ if args[0] != nil {
320+ arg0 = args[0].(*KeyEvent)
321+ }
322+ run(
323+ arg0,
324+ )
325+ })
326+ return _c
327+}
328+
329+func (_c *MockHandler_Key_Call) Return() *MockHandler_Key_Call {
330+ _c.Call.Return()
331+ return _c
332+}
333+
334+func (_c *MockHandler_Key_Call) RunAndReturn(run func(ev *KeyEvent)) *MockHandler_Key_Call {
335+ _c.Run(run)
336+ return _c
337+}
338+
339+// KeyboardFocus provides a mock function for the type MockHandler
340+func (_mock *MockHandler) KeyboardFocus(id SurfaceID, focused bool) {
341+ _mock.Called(id, focused)
342+ return
343+}
344+
345+// MockHandler_KeyboardFocus_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'KeyboardFocus'
346+type MockHandler_KeyboardFocus_Call struct {
347+ *mock.Call
348+}
349+
350+// KeyboardFocus is a helper method to define mock.On call
351+// - id SurfaceID
352+// - focused bool
353+func (_e *MockHandler_Expecter) KeyboardFocus(id any, focused any) *MockHandler_KeyboardFocus_Call {
354+ return &MockHandler_KeyboardFocus_Call{Call: _e.mock.On("KeyboardFocus", id, focused)}
355+}
356+
357+func (_c *MockHandler_KeyboardFocus_Call) Run(run func(id SurfaceID, focused bool)) *MockHandler_KeyboardFocus_Call {
358+ _c.Call.Run(func(args mock.Arguments) {
359+ var arg0 SurfaceID
360+ if args[0] != nil {
361+ arg0 = args[0].(SurfaceID)
362+ }
363+ var arg1 bool
364+ if args[1] != nil {
365+ arg1 = args[1].(bool)
366+ }
367+ run(
368+ arg0,
369+ arg1,
370+ )
371+ })
372+ return _c
373+}
374+
375+func (_c *MockHandler_KeyboardFocus_Call) Return() *MockHandler_KeyboardFocus_Call {
376+ _c.Call.Return()
377+ return _c
378+}
379+
380+func (_c *MockHandler_KeyboardFocus_Call) RunAndReturn(run func(id SurfaceID, focused bool)) *MockHandler_KeyboardFocus_Call {
381+ _c.Run(run)
382+ return _c
383+}
384+
299385 // LockFinished provides a mock function for the type MockHandler
300386 func (_mock *MockHandler) LockFinished() {
301387 _mock.Called()
@@ -442,6 +528,46 @@ func (_c *MockHandler_OutputRemoved_Call) RunAndReturn(run func(global uint32))
442528 return _c
443529 }
444530
531+// Pointer provides a mock function for the type MockHandler
532+func (_mock *MockHandler) Pointer(ev *PointerEvent) {
533+ _mock.Called(ev)
534+ return
535+}
536+
537+// MockHandler_Pointer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Pointer'
538+type MockHandler_Pointer_Call struct {
539+ *mock.Call
540+}
541+
542+// Pointer is a helper method to define mock.On call
543+// - ev *PointerEvent
544+func (_e *MockHandler_Expecter) Pointer(ev any) *MockHandler_Pointer_Call {
545+ return &MockHandler_Pointer_Call{Call: _e.mock.On("Pointer", ev)}
546+}
547+
548+func (_c *MockHandler_Pointer_Call) Run(run func(ev *PointerEvent)) *MockHandler_Pointer_Call {
549+ _c.Call.Run(func(args mock.Arguments) {
550+ var arg0 *PointerEvent
551+ if args[0] != nil {
552+ arg0 = args[0].(*PointerEvent)
553+ }
554+ run(
555+ arg0,
556+ )
557+ })
558+ return _c
559+}
560+
561+func (_c *MockHandler_Pointer_Call) Return() *MockHandler_Pointer_Call {
562+ _c.Call.Return()
563+ return _c
564+}
565+
566+func (_c *MockHandler_Pointer_Call) RunAndReturn(run func(ev *PointerEvent)) *MockHandler_Pointer_Call {
567+ _c.Run(run)
568+ return _c
569+}
570+
445571 // Scale provides a mock function for the type MockHandler
446572 func (_mock *MockHandler) Scale(id SurfaceID, scale float64) {
447573 _mock.Called(id, scale)
@@ -487,3 +613,43 @@ func (_c *MockHandler_Scale_Call) RunAndReturn(run func(id SurfaceID, scale floa
487613 _c.Run(run)
488614 return _c
489615 }
616+
617+// SecretChanged provides a mock function for the type MockHandler
618+func (_mock *MockHandler) SecretChanged(count int) {
619+ _mock.Called(count)
620+ return
621+}
622+
623+// MockHandler_SecretChanged_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SecretChanged'
624+type MockHandler_SecretChanged_Call struct {
625+ *mock.Call
626+}
627+
628+// SecretChanged is a helper method to define mock.On call
629+// - count int
630+func (_e *MockHandler_Expecter) SecretChanged(count any) *MockHandler_SecretChanged_Call {
631+ return &MockHandler_SecretChanged_Call{Call: _e.mock.On("SecretChanged", count)}
632+}
633+
634+func (_c *MockHandler_SecretChanged_Call) Run(run func(count int)) *MockHandler_SecretChanged_Call {
635+ _c.Call.Run(func(args mock.Arguments) {
636+ var arg0 int
637+ if args[0] != nil {
638+ arg0 = args[0].(int)
639+ }
640+ run(
641+ arg0,
642+ )
643+ })
644+ return _c
645+}
646+
647+func (_c *MockHandler_SecretChanged_Call) Return() *MockHandler_SecretChanged_Call {
648+ _c.Call.Return()
649+ return _c
650+}
651+
652+func (_c *MockHandler_SecretChanged_Call) RunAndReturn(run func(count int)) *MockHandler_SecretChanged_Call {
653+ _c.Run(run)
654+ return _c
655+}
@@ -296,6 +296,92 @@ func (_c *MockHandler_Frame_Call) RunAndReturn(run func(id SurfaceID)) *MockHand
296 return _c296 return _c
297 }297 }
298 298
299+// Key provides a mock function for the type MockHandler
300+func (_mock *MockHandler) Key(ev *KeyEvent) {
301+ _mock.Called(ev)
302+ return
303+}
304+
305+// MockHandler_Key_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Key'
306+type MockHandler_Key_Call struct {
307+ *mock.Call
308+}
309+
310+// Key is a helper method to define mock.On call
311+// - ev *KeyEvent
312+func (_e *MockHandler_Expecter) Key(ev any) *MockHandler_Key_Call {
313+ return &MockHandler_Key_Call{Call: _e.mock.On("Key", ev)}
314+}
315+
316+func (_c *MockHandler_Key_Call) Run(run func(ev *KeyEvent)) *MockHandler_Key_Call {
317+ _c.Call.Run(func(args mock.Arguments) {
318+ var arg0 *KeyEvent
319+ if args[0] != nil {
320+ arg0 = args[0].(*KeyEvent)
321+ }
322+ run(
323+ arg0,
324+ )
325+ })
326+ return _c
327+}
328+
329+func (_c *MockHandler_Key_Call) Return() *MockHandler_Key_Call {
330+ _c.Call.Return()
331+ return _c
332+}
333+
334+func (_c *MockHandler_Key_Call) RunAndReturn(run func(ev *KeyEvent)) *MockHandler_Key_Call {
335+ _c.Run(run)
336+ return _c
337+}
338+
339+// KeyboardFocus provides a mock function for the type MockHandler
340+func (_mock *MockHandler) KeyboardFocus(id SurfaceID, focused bool) {
341+ _mock.Called(id, focused)
342+ return
343+}
344+
345+// MockHandler_KeyboardFocus_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'KeyboardFocus'
346+type MockHandler_KeyboardFocus_Call struct {
347+ *mock.Call
348+}
349+
350+// KeyboardFocus is a helper method to define mock.On call
351+// - id SurfaceID
352+// - focused bool
353+func (_e *MockHandler_Expecter) KeyboardFocus(id any, focused any) *MockHandler_KeyboardFocus_Call {
354+ return &MockHandler_KeyboardFocus_Call{Call: _e.mock.On("KeyboardFocus", id, focused)}
355+}
356+
357+func (_c *MockHandler_KeyboardFocus_Call) Run(run func(id SurfaceID, focused bool)) *MockHandler_KeyboardFocus_Call {
358+ _c.Call.Run(func(args mock.Arguments) {
359+ var arg0 SurfaceID
360+ if args[0] != nil {
361+ arg0 = args[0].(SurfaceID)
362+ }
363+ var arg1 bool
364+ if args[1] != nil {
365+ arg1 = args[1].(bool)
366+ }
367+ run(
368+ arg0,
369+ arg1,
370+ )
371+ })
372+ return _c
373+}
374+
375+func (_c *MockHandler_KeyboardFocus_Call) Return() *MockHandler_KeyboardFocus_Call {
376+ _c.Call.Return()
377+ return _c
378+}
379+
380+func (_c *MockHandler_KeyboardFocus_Call) RunAndReturn(run func(id SurfaceID, focused bool)) *MockHandler_KeyboardFocus_Call {
381+ _c.Run(run)
382+ return _c
383+}
384+
299 // LockFinished provides a mock function for the type MockHandler385 // LockFinished provides a mock function for the type MockHandler
300 func (_mock *MockHandler) LockFinished() {386 func (_mock *MockHandler) LockFinished() {
301 _mock.Called()387 _mock.Called()
@@ -442,6 +528,46 @@ func (_c *MockHandler_OutputRemoved_Call) RunAndReturn(run func(global uint32))
442 return _c528 return _c
443 }529 }
444 530
531+// Pointer provides a mock function for the type MockHandler
532+func (_mock *MockHandler) Pointer(ev *PointerEvent) {
533+ _mock.Called(ev)
534+ return
535+}
536+
537+// MockHandler_Pointer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Pointer'
538+type MockHandler_Pointer_Call struct {
539+ *mock.Call
540+}
541+
542+// Pointer is a helper method to define mock.On call
543+// - ev *PointerEvent
544+func (_e *MockHandler_Expecter) Pointer(ev any) *MockHandler_Pointer_Call {
545+ return &MockHandler_Pointer_Call{Call: _e.mock.On("Pointer", ev)}
546+}
547+
548+func (_c *MockHandler_Pointer_Call) Run(run func(ev *PointerEvent)) *MockHandler_Pointer_Call {
549+ _c.Call.Run(func(args mock.Arguments) {
550+ var arg0 *PointerEvent
551+ if args[0] != nil {
552+ arg0 = args[0].(*PointerEvent)
553+ }
554+ run(
555+ arg0,
556+ )
557+ })
558+ return _c
559+}
560+
561+func (_c *MockHandler_Pointer_Call) Return() *MockHandler_Pointer_Call {
562+ _c.Call.Return()
563+ return _c
564+}
565+
566+func (_c *MockHandler_Pointer_Call) RunAndReturn(run func(ev *PointerEvent)) *MockHandler_Pointer_Call {
567+ _c.Run(run)
568+ return _c
569+}
570+
445 // Scale provides a mock function for the type MockHandler571 // Scale provides a mock function for the type MockHandler
446 func (_mock *MockHandler) Scale(id SurfaceID, scale float64) {572 func (_mock *MockHandler) Scale(id SurfaceID, scale float64) {
447 _mock.Called(id, scale)573 _mock.Called(id, scale)
@@ -487,3 +613,43 @@ func (_c *MockHandler_Scale_Call) RunAndReturn(run func(id SurfaceID, scale floa
487 _c.Run(run)613 _c.Run(run)
488 return _c614 return _c
489 }615 }
616+
617+// SecretChanged provides a mock function for the type MockHandler
618+func (_mock *MockHandler) SecretChanged(count int) {
619+ _mock.Called(count)
620+ return
621+}
622+
623+// MockHandler_SecretChanged_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SecretChanged'
624+type MockHandler_SecretChanged_Call struct {
625+ *mock.Call
626+}
627+
628+// SecretChanged is a helper method to define mock.On call
629+// - count int
630+func (_e *MockHandler_Expecter) SecretChanged(count any) *MockHandler_SecretChanged_Call {
631+ return &MockHandler_SecretChanged_Call{Call: _e.mock.On("SecretChanged", count)}
632+}
633+
634+func (_c *MockHandler_SecretChanged_Call) Run(run func(count int)) *MockHandler_SecretChanged_Call {
635+ _c.Call.Run(func(args mock.Arguments) {
636+ var arg0 int
637+ if args[0] != nil {
638+ arg0 = args[0].(int)
639+ }
640+ run(
641+ arg0,
642+ )
643+ })
644+ return _c
645+}
646+
647+func (_c *MockHandler_SecretChanged_Call) Return() *MockHandler_SecretChanged_Call {
648+ _c.Call.Return()
649+ return _c
650+}
651+
652+func (_c *MockHandler_SecretChanged_Call) RunAndReturn(run func(count int)) *MockHandler_SecretChanged_Call {
653+ _c.Run(run)
654+ return _c
655+}
A keyboard.go +463 -0
@@ -0,0 +1,463 @@
1+package neferclient
2+
3+import (
4+ "errors"
5+ "io"
6+ "os"
7+ "time"
8+
9+ xkb "github.com/bnema/purego-xkbcommon"
10+ "github.com/bnema/purego-xkbcommon/raw"
11+ "golang.org/x/sys/unix"
12+
13+ "github.com/bnema/neferclient/internal/secret"
14+)
15+
16+// Modifiers is the set of active keyboard modifiers.
17+type Modifiers uint8
18+
19+const (
20+ ModShift Modifiers = 1 << iota
21+ ModCtrl
22+ ModAlt
23+ ModSuper
24+ ModCapsLock
25+ ModNumLock
26+)
27+
28+// modNames are the xkb modifier names behind each Modifiers bit, in order.
29+var modNames = [...]string{"Shift", "Control", "Mod1", "Mod4", "Lock", "Mod2"}
30+
31+const (
32+ maxHeldKeys = 32
33+ scratchSize = 64 // longest key or compose text kept; longer yields no text
34+ keymapMax = 16 << 20
35+)
36+
37+type heldKey struct{ evdev, sym uint32 }
38+
39+type textKind uint8
40+
41+const (
42+ kindNone textKind = iota
43+ kindText
44+ kindBackspace
45+)
46+
47+// keyboard interprets wl_keyboard events with xkbcommon. It runs only on the
48+// owner goroutine. It never builds a string from key text: translations go
49+// through the fixed scratch array, which is wiped after every use.
50+type keyboard struct {
51+ ctx *xkb.Context
52+ keymap *xkb.Keymap
53+ state *xkb.State
54+ compose *xkb.ComposeState
55+
56+ modBits [len(modNames)]uint32 // xkb mask per Modifiers bit; 0 when absent
57+ lastMask [6]uint32
58+ haveMask bool
59+
60+ held []heldKey
61+ focus bool
62+ rate int32 // repeats per second, 0 disables
63+ delay int32 // milliseconds before the first repeat
64+ repeating uint32
65+ composePending bool
66+
67+ tfd int // repeat timerfd
68+ tbuf [8]byte
69+
70+ secret *SecretBuffer
71+ scratch [scratchSize]byte
72+
73+ // Work area of doSecret, which secret.Do runs without arguments.
74+ secretFn func()
75+ w struct {
76+ evdev, sym uint32
77+ mods Modifiers
78+ repeat bool
79+ kind textKind
80+ changed bool
81+ err error
82+ }
83+ changed bool // the last translation edited the SecretBuffer
84+}
85+
86+func newKeyboard(locale string) (*keyboard, error) {
87+ c, err := xkb.NewContext()
88+ if err != nil {
89+ return nil, err
90+ }
91+ k := &keyboard{ctx: c, held: make([]heldKey, 0, maxHeldKeys), tfd: -1}
92+ k.secretFn = k.doSecret
93+ if t, e := c.NewComposeTable(locale); e == nil {
94+ k.compose, _ = t.NewState() // compose is optional: without it, dead keys still come from xkb
95+ _ = t.Close()
96+ }
97+ if k.tfd, err = unix.TimerfdCreate(unix.CLOCK_MONOTONIC, unix.TFD_NONBLOCK|unix.TFD_CLOEXEC); err != nil {
98+ _ = c.Close()
99+ return nil, err
100+ }
101+ return k, nil
102+}
103+
104+// composeLocale picks the locale for the compose table the way libc does.
105+func composeLocale() string {
106+ for _, name := range []string{"LC_ALL", "LC_CTYPE", "LANG"} {
107+ if v := os.Getenv(name); v != "" {
108+ return v
109+ }
110+ }
111+ return "C"
112+}
113+
114+func (k *keyboard) close() {
115+ k.disarm()
116+ if k.tfd >= 0 {
117+ _ = unix.Close(k.tfd)
118+ k.tfd = -1
119+ }
120+ if k.compose != nil {
121+ _ = k.compose.Close()
122+ k.compose = nil
123+ }
124+ if k.state != nil {
125+ _ = k.state.Close()
126+ k.state = nil
127+ }
128+ if k.keymap != nil {
129+ _ = k.keymap.Close()
130+ k.keymap = nil
131+ }
132+ if k.ctx != nil {
133+ _ = k.ctx.Close()
134+ k.ctx = nil
135+ }
136+}
137+
138+// replaceFD installs the keymap in fd. It consumes fd even on failure; the
139+// previous keymap stays valid on failure.
140+func (k *keyboard) replaceFD(fd, size int) error {
141+ f := os.NewFile(uintptr(fd), "keymap")
142+ if f == nil {
143+ return errors.New("neferclient: invalid keymap descriptor")
144+ }
145+ defer f.Close()
146+ km, err := k.ctx.NewKeymapFD(fd, size)
147+ if err != nil {
148+ return err
149+ }
150+ return k.replace(km)
151+}
152+
153+func (k *keyboard) replace(km *xkb.Keymap) error {
154+ s, err := km.NewState()
155+ if err != nil {
156+ _ = km.Close()
157+ return err
158+ }
159+ k.reset()
160+ if k.state != nil {
161+ _ = k.state.Close()
162+ }
163+ if k.keymap != nil {
164+ _ = k.keymap.Close()
165+ }
166+ k.keymap, k.state = km, s
167+ for i, name := range modNames {
168+ k.modBits[i] = 0
169+ if idx, e := km.ModIndex(name); e == nil && idx < 32 {
170+ k.modBits[i] = 1 << idx
171+ }
172+ }
173+ if k.haveMask { // the compositor's modifiers survive a keymap change
174+ _, _ = s.UpdateMask(k.lastMask[0], k.lastMask[1], k.lastMask[2], k.lastMask[3], k.lastMask[4], k.lastMask[5])
175+ }
176+ return nil
177+}
178+
179+func (k *keyboard) setMask(depressed, latched, locked, group uint32) error {
180+ k.lastMask = [6]uint32{depressed, latched, locked, 0, 0, group}
181+ k.haveMask = true
182+ if k.state == nil {
183+ return nil
184+ }
185+ _, err := k.state.UpdateMask(depressed, latched, locked, 0, 0, group)
186+ return err
187+}
188+
189+// reset drops held keys, repeat and compose state. It keeps the keymap, the
190+// modifier mask and the focus flag.
191+func (k *keyboard) reset() {
192+ k.held = k.held[:0]
193+ k.repeating = 0
194+ k.disarm()
195+ k.composePending = false
196+ if k.compose != nil {
197+ _ = k.compose.Reset()
198+ }
199+}
200+
201+func (k *keyboard) setFocus(on bool) {
202+ k.focus = on
203+ k.reset()
204+}
205+
206+func (k *keyboard) setSecret(b *SecretBuffer) {
207+ k.secret = b
208+ k.reset() // switching paths cancels held keys, repeat and compose
209+}
210+
211+func (k *keyboard) setRepeat(rate, delay int32) {
212+ k.rate, k.delay = max(rate, 0), max(delay, 0)
213+ if k.rate == 0 {
214+ k.repeating = 0
215+ k.disarm()
216+ }
217+}
218+
219+// arm starts the repeat timer: first expiry after the delay, then at the rate.
220+func (k *keyboard) arm() {
221+ spec := unix.ItimerSpec{
222+ Interval: unix.NsecToTimespec(int64(time.Second) / int64(k.rate)),
223+ Value: unix.NsecToTimespec(max(int64(k.delay)*int64(time.Millisecond), 1)), // zero would disarm
224+ }
225+ _ = unix.TimerfdSettime(k.tfd, 0, &spec, nil)
226+}
227+
228+func (k *keyboard) disarm() {
229+ if k.tfd >= 0 {
230+ var spec unix.ItimerSpec
231+ _ = unix.TimerfdSettime(k.tfd, 0, &spec, nil)
232+ }
233+}
234+
235+// expired consumes a timer expiration. Missed ticks are not accumulated: one
236+// call yields at most one repeat.
237+func (k *keyboard) expired() bool {
238+ n, err := unix.Read(k.tfd, k.tbuf[:])
239+ return err == nil && n == 8
240+}
241+
242+func (k *keyboard) modifiers() Modifiers {
243+ mods, err := k.state.Mods()
244+ if err != nil {
245+ return 0
246+ }
247+ var m Modifiers
248+ for i, bit := range k.modBits {
249+ if bit != 0 && mods&bit != 0 {
250+ m |= 1 << i
251+ }
252+ }
253+ return m
254+}
255+
256+func (k *keyboard) find(evdev uint32) int {
257+ for i := range k.held {
258+ if k.held[i].evdev == evdev {
259+ return i
260+ }
261+ }
262+ return -1
263+}
264+
265+func (k *keyboard) drop(i int) { k.held = append(k.held[:i], k.held[i+1:]...) }
266+
267+// press translates a key press into ev. It reports false when the press must
268+// not be delivered (no focus or keymap).
269+func (k *keyboard) press(evdev uint32, ev *KeyEvent) (bool, error) {
270+ if !k.focus || k.state == nil {
271+ return false, nil
272+ }
273+ if i := k.find(evdev); i >= 0 {
274+ k.drop(i)
275+ }
276+ if len(k.held) == cap(k.held) {
277+ return false, nil
278+ }
279+ sym, err := k.state.KeySym(xkb.WaylandKeycode(evdev))
280+ if err != nil {
281+ return false, err
282+ }
283+ kind, err := k.translate(evdev, sym, false, ev)
284+ if err != nil {
285+ return false, err
286+ }
287+ k.held = append(k.held, heldKey{evdev, sym})
288+ if k.secret == nil && repeatable(sym) || k.secret != nil && (kind == kindBackspace || kind == kindText && repeatable(sym)) {
289+ if k.rate > 0 {
290+ k.repeating = evdev
291+ k.arm()
292+ }
293+ } else if k.secret != nil && k.repeating != 0 && repeatable(sym) {
294+ // A control or rejected key stops a previous printable repeat;
295+ // a modifier does not.
296+ k.repeating = 0
297+ k.disarm()
298+ }
299+ return true, nil
300+}
301+
302+// release fills ev for a key released after a delivered press.
303+func (k *keyboard) release(evdev uint32, ev *KeyEvent) bool {
304+ i := k.find(evdev)
305+ if i < 0 {
306+ return false
307+ }
308+ h := k.held[i]
309+ k.drop(i)
310+ if k.repeating == evdev {
311+ k.repeating = 0
312+ k.disarm()
313+ }
314+ ev.Keycode, ev.Keysym, ev.Pressed = evdev, h.sym, false
315+ if k.state != nil {
316+ ev.Modifiers = k.modifiers()
317+ ev.Group, _ = k.state.Layout()
318+ }
319+ return true
320+}
321+
322+// repeat produces one repeat of the held key whose timer fired.
323+func (k *keyboard) repeat(ev *KeyEvent) (bool, error) {
324+ if !k.focus || k.state == nil || k.rate <= 0 || k.repeating == 0 || k.find(k.repeating) < 0 {
325+ return false, nil
326+ }
327+ evdev := k.repeating
328+ stop := func() (bool, error) {
329+ k.repeating = 0
330+ k.disarm()
331+ return false, nil
332+ }
333+ sym, err := k.state.KeySym(xkb.WaylandKeycode(evdev))
334+ if err != nil {
335+ _, _ = stop()
336+ return false, err
337+ }
338+ if k.secret == nil && !repeatable(sym) {
339+ return stop()
340+ }
341+ kind, err := k.translate(evdev, sym, true, ev)
342+ if err != nil {
343+ _, _ = stop()
344+ return false, err
345+ }
346+ if k.secret != nil && kind != kindBackspace && !(kind == kindText && repeatable(sym)) {
347+ return stop()
348+ }
349+ return true, nil
350+}
351+
352+// translate fills ev for a press or repeat and returns what the key meant to
353+// the SecretBuffer, if one is set. In secret mode ev.Text stays nil.
354+func (k *keyboard) translate(evdev, sym uint32, repeat bool, ev *KeyEvent) (textKind, error) {
355+ ev.Keycode, ev.Keysym, ev.Pressed, ev.Repeat = evdev, sym, true, repeat
356+ ev.Modifiers = k.modifiers()
357+ ev.Group, _ = k.state.Layout()
358+ k.changed = false
359+ if k.secret != nil {
360+ w := &k.w
361+ w.evdev, w.sym, w.mods, w.repeat = evdev, sym, ev.Modifiers, repeat
362+ secret.Do(k.secretFn)
363+ k.changed = w.changed
364+ return w.kind, w.err
365+ }
366+ n, err := k.text(evdev, sym, repeat)
367+ if err != nil {
368+ return kindNone, err
369+ }
370+ if n > 0 {
371+ ev.Text = k.scratch[:n:n]
372+ }
373+ return kindNone, nil
374+}
375+
376+// doSecret translates one key into the SecretBuffer. It is the only code that
377+// handles secret text, so it runs under runtime/secret when available.
378+func (k *keyboard) doSecret() {
379+ w := &k.w
380+ w.kind, w.changed, w.err = kindNone, false, nil
381+ defer clear(k.scratch[:])
382+ switch {
383+ case w.sym == raw.XKB_KEY_BackSpace:
384+ w.kind = kindBackspace
385+ k.resetCompose()
386+ w.changed = k.secret.backspace()
387+ case w.sym == raw.XKB_KEY_Return || w.sym == raw.XKB_KEY_KP_Enter || w.sym == raw.XKB_KEY_Escape:
388+ k.resetCompose() // controls are delivered as keys only
389+ case w.mods&ModCtrl != 0:
390+ // Other Control combinations are neither secret text nor ours to handle.
391+ default:
392+ n, err := k.text(w.evdev, w.sym, w.repeat)
393+ if err != nil {
394+ w.err = err
395+ return
396+ }
397+ if classifySecretText(k.scratch[:n]) {
398+ w.kind = kindText
399+ w.changed = k.secret.appendText(k.scratch[:n])
400+ }
401+ }
402+}
403+
404+func (k *keyboard) resetCompose() {
405+ if k.compose != nil {
406+ _ = k.compose.Reset()
407+ }
408+ k.composePending = false
409+}
410+
411+// text writes the text of a key into scratch and returns its length. Compose
412+// is fed only by physical presses: a repeat neither advances a sequence nor
413+// replays composed text.
414+func (k *keyboard) text(evdev, sym uint32, repeat bool) (int, error) {
415+ if k.compose != nil && !repeat {
416+ if _, err := k.compose.Feed(sym); err != nil {
417+ return 0, err
418+ }
419+ status, err := k.compose.Status()
420+ if err != nil {
421+ return 0, err
422+ }
423+ switch status {
424+ case raw.XKB_COMPOSE_COMPOSING:
425+ k.composePending = true
426+ return 0, nil
427+ case raw.XKB_COMPOSE_CANCELLED:
428+ k.resetCompose()
429+ return 0, nil
430+ case raw.XKB_COMPOSE_COMPOSED:
431+ n, err := k.compose.UTF8Into(k.scratch[:])
432+ k.resetCompose()
433+ return shortAsEmpty(n, err)
434+ default:
435+ k.composePending = false
436+ }
437+ }
438+ if k.composePending {
439+ return 0, nil
440+ }
441+ n, err := k.state.UTF8Into(xkb.WaylandKeycode(evdev), k.scratch[:])
442+ return shortAsEmpty(n, err)
443+}
444+
445+// shortAsEmpty maps a too-long text to no text; xkb already wiped the buffer.
446+func shortAsEmpty(n int, err error) (int, error) {
447+ if errors.Is(err, io.ErrShortBuffer) {
448+ return 0, nil
449+ }
450+ return n, err
451+}
452+
453+// Modifier, dead and compose keys never repeat. The compositor provides rate
454+// and delay; its keymap is authoritative for text and layout.
455+func repeatable(sym uint32) bool {
456+ switch sym {
457+ case raw.XKB_KEY_Shift_L, raw.XKB_KEY_Shift_R, raw.XKB_KEY_Control_L, raw.XKB_KEY_Control_R,
458+ raw.XKB_KEY_Alt_L, raw.XKB_KEY_Alt_R, raw.XKB_KEY_Super_L, raw.XKB_KEY_Super_R,
459+ raw.XKB_KEY_Caps_Lock, raw.XKB_KEY_Num_Lock, raw.XKB_KEY_Multi_key:
460+ return false
461+ }
462+ return sym < raw.XKB_KEY_dead_grave || sym > raw.XKB_KEY_dead_currency
463+}
@@ -0,0 +1,463 @@
1+package neferclient
2+
3+import (
4+ "errors"
5+ "io"
6+ "os"
7+ "time"
8+
9+ xkb "github.com/bnema/purego-xkbcommon"
10+ "github.com/bnema/purego-xkbcommon/raw"
11+ "golang.org/x/sys/unix"
12+
13+ "github.com/bnema/neferclient/internal/secret"
14+)
15+
16+// Modifiers is the set of active keyboard modifiers.
17+type Modifiers uint8
18+
19+const (
20+ ModShift Modifiers = 1 << iota
21+ ModCtrl
22+ ModAlt
23+ ModSuper
24+ ModCapsLock
25+ ModNumLock
26+)
27+
28+// modNames are the xkb modifier names behind each Modifiers bit, in order.
29+var modNames = [...]string{"Shift", "Control", "Mod1", "Mod4", "Lock", "Mod2"}
30+
31+const (
32+ maxHeldKeys = 32
33+ scratchSize = 64 // longest key or compose text kept; longer yields no text
34+ keymapMax = 16 << 20
35+)
36+
37+type heldKey struct{ evdev, sym uint32 }
38+
39+type textKind uint8
40+
41+const (
42+ kindNone textKind = iota
43+ kindText
44+ kindBackspace
45+)
46+
47+// keyboard interprets wl_keyboard events with xkbcommon. It runs only on the
48+// owner goroutine. It never builds a string from key text: translations go
49+// through the fixed scratch array, which is wiped after every use.
50+type keyboard struct {
51+ ctx *xkb.Context
52+ keymap *xkb.Keymap
53+ state *xkb.State
54+ compose *xkb.ComposeState
55+
56+ modBits [len(modNames)]uint32 // xkb mask per Modifiers bit; 0 when absent
57+ lastMask [6]uint32
58+ haveMask bool
59+
60+ held []heldKey
61+ focus bool
62+ rate int32 // repeats per second, 0 disables
63+ delay int32 // milliseconds before the first repeat
64+ repeating uint32
65+ composePending bool
66+
67+ tfd int // repeat timerfd
68+ tbuf [8]byte
69+
70+ secret *SecretBuffer
71+ scratch [scratchSize]byte
72+
73+ // Work area of doSecret, which secret.Do runs without arguments.
74+ secretFn func()
75+ w struct {
76+ evdev, sym uint32
77+ mods Modifiers
78+ repeat bool
79+ kind textKind
80+ changed bool
81+ err error
82+ }
83+ changed bool // the last translation edited the SecretBuffer
84+}
85+
86+func newKeyboard(locale string) (*keyboard, error) {
87+ c, err := xkb.NewContext()
88+ if err != nil {
89+ return nil, err
90+ }
91+ k := &keyboard{ctx: c, held: make([]heldKey, 0, maxHeldKeys), tfd: -1}
92+ k.secretFn = k.doSecret
93+ if t, e := c.NewComposeTable(locale); e == nil {
94+ k.compose, _ = t.NewState() // compose is optional: without it, dead keys still come from xkb
95+ _ = t.Close()
96+ }
97+ if k.tfd, err = unix.TimerfdCreate(unix.CLOCK_MONOTONIC, unix.TFD_NONBLOCK|unix.TFD_CLOEXEC); err != nil {
98+ _ = c.Close()
99+ return nil, err
100+ }
101+ return k, nil
102+}
103+
104+// composeLocale picks the locale for the compose table the way libc does.
105+func composeLocale() string {
106+ for _, name := range []string{"LC_ALL", "LC_CTYPE", "LANG"} {
107+ if v := os.Getenv(name); v != "" {
108+ return v
109+ }
110+ }
111+ return "C"
112+}
113+
114+func (k *keyboard) close() {
115+ k.disarm()
116+ if k.tfd >= 0 {
117+ _ = unix.Close(k.tfd)
118+ k.tfd = -1
119+ }
120+ if k.compose != nil {
121+ _ = k.compose.Close()
122+ k.compose = nil
123+ }
124+ if k.state != nil {
125+ _ = k.state.Close()
126+ k.state = nil
127+ }
128+ if k.keymap != nil {
129+ _ = k.keymap.Close()
130+ k.keymap = nil
131+ }
132+ if k.ctx != nil {
133+ _ = k.ctx.Close()
134+ k.ctx = nil
135+ }
136+}
137+
138+// replaceFD installs the keymap in fd. It consumes fd even on failure; the
139+// previous keymap stays valid on failure.
140+func (k *keyboard) replaceFD(fd, size int) error {
141+ f := os.NewFile(uintptr(fd), "keymap")
142+ if f == nil {
143+ return errors.New("neferclient: invalid keymap descriptor")
144+ }
145+ defer f.Close()
146+ km, err := k.ctx.NewKeymapFD(fd, size)
147+ if err != nil {
148+ return err
149+ }
150+ return k.replace(km)
151+}
152+
153+func (k *keyboard) replace(km *xkb.Keymap) error {
154+ s, err := km.NewState()
155+ if err != nil {
156+ _ = km.Close()
157+ return err
158+ }
159+ k.reset()
160+ if k.state != nil {
161+ _ = k.state.Close()
162+ }
163+ if k.keymap != nil {
164+ _ = k.keymap.Close()
165+ }
166+ k.keymap, k.state = km, s
167+ for i, name := range modNames {
168+ k.modBits[i] = 0
169+ if idx, e := km.ModIndex(name); e == nil && idx < 32 {
170+ k.modBits[i] = 1 << idx
171+ }
172+ }
173+ if k.haveMask { // the compositor's modifiers survive a keymap change
174+ _, _ = s.UpdateMask(k.lastMask[0], k.lastMask[1], k.lastMask[2], k.lastMask[3], k.lastMask[4], k.lastMask[5])
175+ }
176+ return nil
177+}
178+
179+func (k *keyboard) setMask(depressed, latched, locked, group uint32) error {
180+ k.lastMask = [6]uint32{depressed, latched, locked, 0, 0, group}
181+ k.haveMask = true
182+ if k.state == nil {
183+ return nil
184+ }
185+ _, err := k.state.UpdateMask(depressed, latched, locked, 0, 0, group)
186+ return err
187+}
188+
189+// reset drops held keys, repeat and compose state. It keeps the keymap, the
190+// modifier mask and the focus flag.
191+func (k *keyboard) reset() {
192+ k.held = k.held[:0]
193+ k.repeating = 0
194+ k.disarm()
195+ k.composePending = false
196+ if k.compose != nil {
197+ _ = k.compose.Reset()
198+ }
199+}
200+
201+func (k *keyboard) setFocus(on bool) {
202+ k.focus = on
203+ k.reset()
204+}
205+
206+func (k *keyboard) setSecret(b *SecretBuffer) {
207+ k.secret = b
208+ k.reset() // switching paths cancels held keys, repeat and compose
209+}
210+
211+func (k *keyboard) setRepeat(rate, delay int32) {
212+ k.rate, k.delay = max(rate, 0), max(delay, 0)
213+ if k.rate == 0 {
214+ k.repeating = 0
215+ k.disarm()
216+ }
217+}
218+
219+// arm starts the repeat timer: first expiry after the delay, then at the rate.
220+func (k *keyboard) arm() {
221+ spec := unix.ItimerSpec{
222+ Interval: unix.NsecToTimespec(int64(time.Second) / int64(k.rate)),
223+ Value: unix.NsecToTimespec(max(int64(k.delay)*int64(time.Millisecond), 1)), // zero would disarm
224+ }
225+ _ = unix.TimerfdSettime(k.tfd, 0, &spec, nil)
226+}
227+
228+func (k *keyboard) disarm() {
229+ if k.tfd >= 0 {
230+ var spec unix.ItimerSpec
231+ _ = unix.TimerfdSettime(k.tfd, 0, &spec, nil)
232+ }
233+}
234+
235+// expired consumes a timer expiration. Missed ticks are not accumulated: one
236+// call yields at most one repeat.
237+func (k *keyboard) expired() bool {
238+ n, err := unix.Read(k.tfd, k.tbuf[:])
239+ return err == nil && n == 8
240+}
241+
242+func (k *keyboard) modifiers() Modifiers {
243+ mods, err := k.state.Mods()
244+ if err != nil {
245+ return 0
246+ }
247+ var m Modifiers
248+ for i, bit := range k.modBits {
249+ if bit != 0 && mods&bit != 0 {
250+ m |= 1 << i
251+ }
252+ }
253+ return m
254+}
255+
256+func (k *keyboard) find(evdev uint32) int {
257+ for i := range k.held {
258+ if k.held[i].evdev == evdev {
259+ return i
260+ }
261+ }
262+ return -1
263+}
264+
265+func (k *keyboard) drop(i int) { k.held = append(k.held[:i], k.held[i+1:]...) }
266+
267+// press translates a key press into ev. It reports false when the press must
268+// not be delivered (no focus or keymap).
269+func (k *keyboard) press(evdev uint32, ev *KeyEvent) (bool, error) {
270+ if !k.focus || k.state == nil {
271+ return false, nil
272+ }
273+ if i := k.find(evdev); i >= 0 {
274+ k.drop(i)
275+ }
276+ if len(k.held) == cap(k.held) {
277+ return false, nil
278+ }
279+ sym, err := k.state.KeySym(xkb.WaylandKeycode(evdev))
280+ if err != nil {
281+ return false, err
282+ }
283+ kind, err := k.translate(evdev, sym, false, ev)
284+ if err != nil {
285+ return false, err
286+ }
287+ k.held = append(k.held, heldKey{evdev, sym})
288+ if k.secret == nil && repeatable(sym) || k.secret != nil && (kind == kindBackspace || kind == kindText && repeatable(sym)) {
289+ if k.rate > 0 {
290+ k.repeating = evdev
291+ k.arm()
292+ }
293+ } else if k.secret != nil && k.repeating != 0 && repeatable(sym) {
294+ // A control or rejected key stops a previous printable repeat;
295+ // a modifier does not.
296+ k.repeating = 0
297+ k.disarm()
298+ }
299+ return true, nil
300+}
301+
302+// release fills ev for a key released after a delivered press.
303+func (k *keyboard) release(evdev uint32, ev *KeyEvent) bool {
304+ i := k.find(evdev)
305+ if i < 0 {
306+ return false
307+ }
308+ h := k.held[i]
309+ k.drop(i)
310+ if k.repeating == evdev {
311+ k.repeating = 0
312+ k.disarm()
313+ }
314+ ev.Keycode, ev.Keysym, ev.Pressed = evdev, h.sym, false
315+ if k.state != nil {
316+ ev.Modifiers = k.modifiers()
317+ ev.Group, _ = k.state.Layout()
318+ }
319+ return true
320+}
321+
322+// repeat produces one repeat of the held key whose timer fired.
323+func (k *keyboard) repeat(ev *KeyEvent) (bool, error) {
324+ if !k.focus || k.state == nil || k.rate <= 0 || k.repeating == 0 || k.find(k.repeating) < 0 {
325+ return false, nil
326+ }
327+ evdev := k.repeating
328+ stop := func() (bool, error) {
329+ k.repeating = 0
330+ k.disarm()
331+ return false, nil
332+ }
333+ sym, err := k.state.KeySym(xkb.WaylandKeycode(evdev))
334+ if err != nil {
335+ _, _ = stop()
336+ return false, err
337+ }
338+ if k.secret == nil && !repeatable(sym) {
339+ return stop()
340+ }
341+ kind, err := k.translate(evdev, sym, true, ev)
342+ if err != nil {
343+ _, _ = stop()
344+ return false, err
345+ }
346+ if k.secret != nil && kind != kindBackspace && !(kind == kindText && repeatable(sym)) {
347+ return stop()
348+ }
349+ return true, nil
350+}
351+
352+// translate fills ev for a press or repeat and returns what the key meant to
353+// the SecretBuffer, if one is set. In secret mode ev.Text stays nil.
354+func (k *keyboard) translate(evdev, sym uint32, repeat bool, ev *KeyEvent) (textKind, error) {
355+ ev.Keycode, ev.Keysym, ev.Pressed, ev.Repeat = evdev, sym, true, repeat
356+ ev.Modifiers = k.modifiers()
357+ ev.Group, _ = k.state.Layout()
358+ k.changed = false
359+ if k.secret != nil {
360+ w := &k.w
361+ w.evdev, w.sym, w.mods, w.repeat = evdev, sym, ev.Modifiers, repeat
362+ secret.Do(k.secretFn)
363+ k.changed = w.changed
364+ return w.kind, w.err
365+ }
366+ n, err := k.text(evdev, sym, repeat)
367+ if err != nil {
368+ return kindNone, err
369+ }
370+ if n > 0 {
371+ ev.Text = k.scratch[:n:n]
372+ }
373+ return kindNone, nil
374+}
375+
376+// doSecret translates one key into the SecretBuffer. It is the only code that
377+// handles secret text, so it runs under runtime/secret when available.
378+func (k *keyboard) doSecret() {
379+ w := &k.w
380+ w.kind, w.changed, w.err = kindNone, false, nil
381+ defer clear(k.scratch[:])
382+ switch {
383+ case w.sym == raw.XKB_KEY_BackSpace:
384+ w.kind = kindBackspace
385+ k.resetCompose()
386+ w.changed = k.secret.backspace()
387+ case w.sym == raw.XKB_KEY_Return || w.sym == raw.XKB_KEY_KP_Enter || w.sym == raw.XKB_KEY_Escape:
388+ k.resetCompose() // controls are delivered as keys only
389+ case w.mods&ModCtrl != 0:
390+ // Other Control combinations are neither secret text nor ours to handle.
391+ default:
392+ n, err := k.text(w.evdev, w.sym, w.repeat)
393+ if err != nil {
394+ w.err = err
395+ return
396+ }
397+ if classifySecretText(k.scratch[:n]) {
398+ w.kind = kindText
399+ w.changed = k.secret.appendText(k.scratch[:n])
400+ }
401+ }
402+}
403+
404+func (k *keyboard) resetCompose() {
405+ if k.compose != nil {
406+ _ = k.compose.Reset()
407+ }
408+ k.composePending = false
409+}
410+
411+// text writes the text of a key into scratch and returns its length. Compose
412+// is fed only by physical presses: a repeat neither advances a sequence nor
413+// replays composed text.
414+func (k *keyboard) text(evdev, sym uint32, repeat bool) (int, error) {
415+ if k.compose != nil && !repeat {
416+ if _, err := k.compose.Feed(sym); err != nil {
417+ return 0, err
418+ }
419+ status, err := k.compose.Status()
420+ if err != nil {
421+ return 0, err
422+ }
423+ switch status {
424+ case raw.XKB_COMPOSE_COMPOSING:
425+ k.composePending = true
426+ return 0, nil
427+ case raw.XKB_COMPOSE_CANCELLED:
428+ k.resetCompose()
429+ return 0, nil
430+ case raw.XKB_COMPOSE_COMPOSED:
431+ n, err := k.compose.UTF8Into(k.scratch[:])
432+ k.resetCompose()
433+ return shortAsEmpty(n, err)
434+ default:
435+ k.composePending = false
436+ }
437+ }
438+ if k.composePending {
439+ return 0, nil
440+ }
441+ n, err := k.state.UTF8Into(xkb.WaylandKeycode(evdev), k.scratch[:])
442+ return shortAsEmpty(n, err)
443+}
444+
445+// shortAsEmpty maps a too-long text to no text; xkb already wiped the buffer.
446+func shortAsEmpty(n int, err error) (int, error) {
447+ if errors.Is(err, io.ErrShortBuffer) {
448+ return 0, nil
449+ }
450+ return n, err
451+}
452+
453+// Modifier, dead and compose keys never repeat. The compositor provides rate
454+// and delay; its keymap is authoritative for text and layout.
455+func repeatable(sym uint32) bool {
456+ switch sym {
457+ case raw.XKB_KEY_Shift_L, raw.XKB_KEY_Shift_R, raw.XKB_KEY_Control_L, raw.XKB_KEY_Control_R,
458+ raw.XKB_KEY_Alt_L, raw.XKB_KEY_Alt_R, raw.XKB_KEY_Super_L, raw.XKB_KEY_Super_R,
459+ raw.XKB_KEY_Caps_Lock, raw.XKB_KEY_Num_Lock, raw.XKB_KEY_Multi_key:
460+ return false
461+ }
462+ return sym < raw.XKB_KEY_dead_grave || sym > raw.XKB_KEY_dead_currency
463+}
A keyboard_test.go +283 -0
@@ -0,0 +1,283 @@
1+package neferclient
2+
3+import (
4+ "os"
5+ "testing"
6+
7+ "github.com/stretchr/testify/require"
8+ "golang.org/x/sys/unix"
9+
10+ "github.com/bnema/purego-xkbcommon/raw"
11+)
12+
13+// Evdev codes used below (US QWERTY positions).
14+const (
15+ keyQ = 16
16+ keyE = 18
17+ keyBackspace = 14
18+ keyEnter = 28
19+ keyU = 22
20+ keyLeftShift = 42
21+ keyCircum = 41 // de: dead_circumflex
22+)
23+
24+// testKeyboard is a keyboard on a real xkb keymap compiled from rules.
25+func testKeyboard(t testing.TB, locale, layout string) *keyboard {
26+ t.Helper()
27+ k, err := newKeyboard(locale)
28+ require.NoError(t, err)
29+ t.Cleanup(k.close)
30+ km, err := k.ctx.NewKeymapRules("evdev", "pc105", layout, "", "")
31+ require.NoError(t, err)
32+ require.NoError(t, k.replace(km))
33+ k.setFocus(true)
34+ return k
35+}
36+
37+func pressKey(t testing.TB, k *keyboard, code uint32) (KeyEvent, bool) {
38+ t.Helper()
39+ var ev KeyEvent
40+ ok, err := k.press(code, &ev)
41+ require.NoError(t, err)
42+ return ev, ok
43+}
44+
45+func releaseKey(k *keyboard, code uint32) (KeyEvent, bool) {
46+ var ev KeyEvent
47+ ok := k.release(code, &ev)
48+ return ev, ok
49+}
50+
51+func TestKeyboardLayoutsAndModifiers(t *testing.T) {
52+ for _, tc := range []struct {
53+ layout string
54+ code uint32
55+ want string
56+ }{{"us", keyQ, "q"}, {"fr", keyQ, "a"}, {"de", 21, "z"}} {
57+ k := testKeyboard(t, "en_US.UTF-8", tc.layout)
58+ ev, ok := pressKey(t, k, tc.code)
59+ require.True(t, ok)
60+ require.Equal(t, tc.want, string(ev.Text), tc.layout)
61+ require.True(t, ev.Pressed)
62+ require.NotZero(t, ev.Keysym)
63+ require.Equal(t, tc.code, ev.Keycode)
64+ rel, ok := releaseKey(k, tc.code)
65+ require.True(t, ok)
66+ require.False(t, rel.Pressed)
67+ require.Nil(t, rel.Text)
68+ require.Equal(t, ev.Keysym, rel.Keysym)
69+ }
70+
71+ k := testKeyboard(t, "en_US.UTF-8", "us")
72+ idx, err := k.keymap.ModIndex("Shift")
73+ require.NoError(t, err)
74+ require.NoError(t, k.setMask(1<<idx, 0, 0, 0))
75+ ev, _ := pressKey(t, k, keyQ)
76+ require.Equal(t, "Q", string(ev.Text))
77+ require.Equal(t, ModShift, ev.Modifiers)
78+
79+ // The compositor's mask survives a keymap change.
80+ km, err := k.ctx.NewKeymapRules("evdev", "pc105", "fr", "", "")
81+ require.NoError(t, err)
82+ require.NoError(t, k.replace(km))
83+ k.setFocus(true)
84+ ev, _ = pressKey(t, k, keyQ)
85+ require.Equal(t, "A", string(ev.Text))
86+}
87+
88+func TestKeyboardKeymapFD(t *testing.T) {
89+ data, err := os.ReadFile("testdata/fr.xkb")
90+ require.NoError(t, err)
91+ f, err := os.CreateTemp(t.TempDir(), "keymap")
92+ require.NoError(t, err)
93+ defer f.Close()
94+ _, err = f.Write(append(data, 0))
95+ require.NoError(t, err)
96+
97+ k := testKeyboard(t, "", "us")
98+ fd, err := unix.Dup(int(f.Fd()))
99+ require.NoError(t, err)
100+ require.NoError(t, k.replaceFD(fd, len(data)+1))
101+ _, err = unix.FcntlInt(uintptr(fd), unix.F_GETFD, 0)
102+ require.ErrorIs(t, err, unix.EBADF, "replaceFD consumes the descriptor")
103+ k.setFocus(true)
104+ ev, _ := pressKey(t, k, keyQ)
105+ require.Equal(t, "a", string(ev.Text))
106+
107+ // A failing map keeps the previous one and still consumes its fd.
108+ bad, err := unix.Dup(int(f.Fd()))
109+ require.NoError(t, err)
110+ require.Error(t, k.replaceFD(bad, 5))
111+ _, err = unix.FcntlInt(uintptr(bad), unix.F_GETFD, 0)
112+ require.ErrorIs(t, err, unix.EBADF)
113+ ev, _ = pressKey(t, k, keyQ)
114+ require.Equal(t, "a", string(ev.Text))
115+}
116+
117+func TestKeyboardComposeAndFocus(t *testing.T) {
118+ k := testKeyboard(t, "en_US.UTF-8", "de")
119+ dead, _ := pressKey(t, k, keyCircum)
120+ require.Equal(t, uint32(raw.XKB_KEY_dead_circumflex), dead.Keysym)
121+ require.Nil(t, dead.Text)
122+ releaseKey(k, keyCircum)
123+ composed, _ := pressKey(t, k, keyE)
124+ require.Equal(t, "ê", string(composed.Text))
125+ releaseKey(k, keyE)
126+
127+ pressKey(t, k, keyCircum)
128+ k.setFocus(false)
129+ _, ok := pressKey2(k, keyE)
130+ require.False(t, ok, "no key without focus")
131+ k.setFocus(true)
132+ ev, _ := pressKey(t, k, keyE)
133+ require.Equal(t, "e", string(ev.Text), "focus loss resets compose")
134+}
135+
136+func pressKey2(k *keyboard, code uint32) (KeyEvent, bool) {
137+ var ev KeyEvent
138+ ok, _ := k.press(code, &ev)
139+ return ev, ok
140+}
141+
142+func TestKeyboardRepeatTimer(t *testing.T) {
143+ k := testKeyboard(t, "", "us")
144+ k.setRepeat(20, 50)
145+ _, ok := pressKey(t, k, keyQ)
146+ require.True(t, ok)
147+ require.Equal(t, uint32(keyQ), k.repeating)
148+ var ev KeyEvent
149+ require.Eventually(t, k.expired, 2e9, 5e6)
150+ ok, err := k.repeat(&ev)
151+ require.NoError(t, err)
152+ require.True(t, ok)
153+ require.True(t, ev.Repeat)
154+ require.Equal(t, "q", string(ev.Text))
155+
156+ releaseKey(k, keyQ)
157+ require.Zero(t, k.repeating)
158+ require.False(t, k.expired(), "timer disarmed on release")
159+
160+ // Modifiers never repeat.
161+ pressKey(t, k, keyLeftShift)
162+ require.Zero(t, k.repeating)
163+ // A rate of 0 disables repeat.
164+ k.setRepeat(0, 0)
165+ pressKey(t, k, keyQ)
166+ require.Zero(t, k.repeating)
167+}
168+
169+func TestKeyboardRepeatTracksCurrentMask(t *testing.T) {
170+ k := testKeyboard(t, "", "us")
171+ k.setRepeat(100, 1)
172+ pressKey(t, k, keyQ)
173+ idx, err := k.keymap.ModIndex("Shift")
174+ require.NoError(t, err)
175+ require.NoError(t, k.setMask(1<<idx, 0, 0, 0))
176+ require.Eventually(t, k.expired, 2e9, 1e6)
177+ var ev KeyEvent
178+ ok, err := k.repeat(&ev)
179+ require.NoError(t, err)
180+ require.True(t, ok)
181+ require.Equal(t, "Q", string(ev.Text))
182+}
183+
184+// TestSecretKeysNeverReachText covers the secret rules end to end on the
185+// keyboard: printable text only into the buffer, BackSpace by code point,
186+// every other key delivered without text.
187+func TestSecretKeysNeverReachText(t *testing.T) {
188+ k := testKeyboard(t, "en_US.UTF-8", "de")
189+ buf := NewSecretBuffer(8)
190+ k.setSecret(buf)
191+
192+ press := func(code uint32) KeyEvent {
193+ ev, ok := pressKey(t, k, code)
194+ require.True(t, ok)
195+ require.Nil(t, ev.Text, "secret mode never fills KeyEvent.Text")
196+ releaseKey(k, code)
197+ return ev
198+ }
199+ press(keyQ)
200+ press(keyCircum) // dead key
201+ press(keyE) // composes ê
202+ require.Equal(t, "qê", string(buf.Bytes()))
203+ require.Equal(t, 2, buf.Len())
204+
205+ press(keyBackspace)
206+ require.Equal(t, 1, buf.Len(), "backspace removes one code point")
207+ press(keyBackspace)
208+ press(keyBackspace) // empty: nothing to remove
209+ require.Zero(t, buf.Len())
210+
211+ press(keyQ)
212+ enter := press(keyEnter)
213+ require.Equal(t, uint32(raw.XKB_KEY_Return), enter.Keysym)
214+ require.Equal(t, 1, buf.Len(), "Enter is delivered, not typed")
215+
216+ // Control combinations are keys, not text.
217+ idx, err := k.keymap.ModIndex("Control")
218+ require.NoError(t, err)
219+ require.NoError(t, k.setMask(1<<idx, 0, 0, 0))
220+ ev := press(keyU)
221+ require.Equal(t, ModCtrl, ev.Modifiers)
222+ require.Equal(t, 1, buf.Len())
223+ require.NoError(t, k.setMask(0, 0, 0, 0))
224+
225+ // Capacity: extra text is dropped, the key is still delivered.
226+ for range 10 {
227+ press(keyQ)
228+ }
229+ require.Equal(t, 8, buf.Len())
230+
231+ // Scratch is wiped after use.
232+ require.Equal(t, make([]byte, scratchSize), k.scratch[:])
233+
234+ k.setSecret(nil)
235+ ev, _ = pressKey(t, k, keyQ)
236+ require.Equal(t, "q", string(ev.Text), "ordinary text again once the buffer is removed")
237+}
238+
239+func TestSecretChangedFlag(t *testing.T) {
240+ k := testKeyboard(t, "", "us")
241+ buf := NewSecretBuffer(2)
242+ k.setSecret(buf)
243+ pressKey(t, k, keyQ)
244+ require.True(t, k.changed)
245+ pressKey(t, k, keyEnter)
246+ require.False(t, k.changed)
247+ pressKey(t, k, keyBackspace)
248+ require.True(t, k.changed)
249+ pressKey(t, k, keyBackspace)
250+ require.False(t, k.changed, "nothing left to remove")
251+}
252+
253+func TestSecretRepeat(t *testing.T) {
254+ k := testKeyboard(t, "", "us")
255+ buf := NewSecretBuffer(16)
256+ k.setSecret(buf)
257+ k.setRepeat(100, 1)
258+ var ev KeyEvent
259+ pressKey(t, k, keyQ)
260+ for range 2 {
261+ require.Eventually(t, k.expired, 2e9, 1e6)
262+ ok, err := k.repeat(&ev)
263+ require.NoError(t, err)
264+ require.True(t, ok)
265+ require.Nil(t, ev.Text)
266+ }
267+ require.Equal(t, "qqq", string(buf.Bytes()))
268+
269+ // Enter cancels a previous printable repeat.
270+ pressKey(t, k, keyEnter)
271+ require.Zero(t, k.repeating)
272+ releaseKey(k, keyQ)
273+ releaseKey(k, keyEnter)
274+
275+ // Held backspace repeats.
276+ pressKey(t, k, keyBackspace)
277+ require.Equal(t, uint32(keyBackspace), k.repeating)
278+ require.Eventually(t, k.expired, 2e9, 1e6)
279+ ok, err := k.repeat(&ev)
280+ require.NoError(t, err)
281+ require.True(t, ok)
282+ require.Equal(t, 1, buf.Len())
283+}
@@ -0,0 +1,283 @@
1+package neferclient
2+
3+import (
4+ "os"
5+ "testing"
6+
7+ "github.com/stretchr/testify/require"
8+ "golang.org/x/sys/unix"
9+
10+ "github.com/bnema/purego-xkbcommon/raw"
11+)
12+
13+// Evdev codes used below (US QWERTY positions).
14+const (
15+ keyQ = 16
16+ keyE = 18
17+ keyBackspace = 14
18+ keyEnter = 28
19+ keyU = 22
20+ keyLeftShift = 42
21+ keyCircum = 41 // de: dead_circumflex
22+)
23+
24+// testKeyboard is a keyboard on a real xkb keymap compiled from rules.
25+func testKeyboard(t testing.TB, locale, layout string) *keyboard {
26+ t.Helper()
27+ k, err := newKeyboard(locale)
28+ require.NoError(t, err)
29+ t.Cleanup(k.close)
30+ km, err := k.ctx.NewKeymapRules("evdev", "pc105", layout, "", "")
31+ require.NoError(t, err)
32+ require.NoError(t, k.replace(km))
33+ k.setFocus(true)
34+ return k
35+}
36+
37+func pressKey(t testing.TB, k *keyboard, code uint32) (KeyEvent, bool) {
38+ t.Helper()
39+ var ev KeyEvent
40+ ok, err := k.press(code, &ev)
41+ require.NoError(t, err)
42+ return ev, ok
43+}
44+
45+func releaseKey(k *keyboard, code uint32) (KeyEvent, bool) {
46+ var ev KeyEvent
47+ ok := k.release(code, &ev)
48+ return ev, ok
49+}
50+
51+func TestKeyboardLayoutsAndModifiers(t *testing.T) {
52+ for _, tc := range []struct {
53+ layout string
54+ code uint32
55+ want string
56+ }{{"us", keyQ, "q"}, {"fr", keyQ, "a"}, {"de", 21, "z"}} {
57+ k := testKeyboard(t, "en_US.UTF-8", tc.layout)
58+ ev, ok := pressKey(t, k, tc.code)
59+ require.True(t, ok)
60+ require.Equal(t, tc.want, string(ev.Text), tc.layout)
61+ require.True(t, ev.Pressed)
62+ require.NotZero(t, ev.Keysym)
63+ require.Equal(t, tc.code, ev.Keycode)
64+ rel, ok := releaseKey(k, tc.code)
65+ require.True(t, ok)
66+ require.False(t, rel.Pressed)
67+ require.Nil(t, rel.Text)
68+ require.Equal(t, ev.Keysym, rel.Keysym)
69+ }
70+
71+ k := testKeyboard(t, "en_US.UTF-8", "us")
72+ idx, err := k.keymap.ModIndex("Shift")
73+ require.NoError(t, err)
74+ require.NoError(t, k.setMask(1<<idx, 0, 0, 0))
75+ ev, _ := pressKey(t, k, keyQ)
76+ require.Equal(t, "Q", string(ev.Text))
77+ require.Equal(t, ModShift, ev.Modifiers)
78+
79+ // The compositor's mask survives a keymap change.
80+ km, err := k.ctx.NewKeymapRules("evdev", "pc105", "fr", "", "")
81+ require.NoError(t, err)
82+ require.NoError(t, k.replace(km))
83+ k.setFocus(true)
84+ ev, _ = pressKey(t, k, keyQ)
85+ require.Equal(t, "A", string(ev.Text))
86+}
87+
88+func TestKeyboardKeymapFD(t *testing.T) {
89+ data, err := os.ReadFile("testdata/fr.xkb")
90+ require.NoError(t, err)
91+ f, err := os.CreateTemp(t.TempDir(), "keymap")
92+ require.NoError(t, err)
93+ defer f.Close()
94+ _, err = f.Write(append(data, 0))
95+ require.NoError(t, err)
96+
97+ k := testKeyboard(t, "", "us")
98+ fd, err := unix.Dup(int(f.Fd()))
99+ require.NoError(t, err)
100+ require.NoError(t, k.replaceFD(fd, len(data)+1))
101+ _, err = unix.FcntlInt(uintptr(fd), unix.F_GETFD, 0)
102+ require.ErrorIs(t, err, unix.EBADF, "replaceFD consumes the descriptor")
103+ k.setFocus(true)
104+ ev, _ := pressKey(t, k, keyQ)
105+ require.Equal(t, "a", string(ev.Text))
106+
107+ // A failing map keeps the previous one and still consumes its fd.
108+ bad, err := unix.Dup(int(f.Fd()))
109+ require.NoError(t, err)
110+ require.Error(t, k.replaceFD(bad, 5))
111+ _, err = unix.FcntlInt(uintptr(bad), unix.F_GETFD, 0)
112+ require.ErrorIs(t, err, unix.EBADF)
113+ ev, _ = pressKey(t, k, keyQ)
114+ require.Equal(t, "a", string(ev.Text))
115+}
116+
117+func TestKeyboardComposeAndFocus(t *testing.T) {
118+ k := testKeyboard(t, "en_US.UTF-8", "de")
119+ dead, _ := pressKey(t, k, keyCircum)
120+ require.Equal(t, uint32(raw.XKB_KEY_dead_circumflex), dead.Keysym)
121+ require.Nil(t, dead.Text)
122+ releaseKey(k, keyCircum)
123+ composed, _ := pressKey(t, k, keyE)
124+ require.Equal(t, "ê", string(composed.Text))
125+ releaseKey(k, keyE)
126+
127+ pressKey(t, k, keyCircum)
128+ k.setFocus(false)
129+ _, ok := pressKey2(k, keyE)
130+ require.False(t, ok, "no key without focus")
131+ k.setFocus(true)
132+ ev, _ := pressKey(t, k, keyE)
133+ require.Equal(t, "e", string(ev.Text), "focus loss resets compose")
134+}
135+
136+func pressKey2(k *keyboard, code uint32) (KeyEvent, bool) {
137+ var ev KeyEvent
138+ ok, _ := k.press(code, &ev)
139+ return ev, ok
140+}
141+
142+func TestKeyboardRepeatTimer(t *testing.T) {
143+ k := testKeyboard(t, "", "us")
144+ k.setRepeat(20, 50)
145+ _, ok := pressKey(t, k, keyQ)
146+ require.True(t, ok)
147+ require.Equal(t, uint32(keyQ), k.repeating)
148+ var ev KeyEvent
149+ require.Eventually(t, k.expired, 2e9, 5e6)
150+ ok, err := k.repeat(&ev)
151+ require.NoError(t, err)
152+ require.True(t, ok)
153+ require.True(t, ev.Repeat)
154+ require.Equal(t, "q", string(ev.Text))
155+
156+ releaseKey(k, keyQ)
157+ require.Zero(t, k.repeating)
158+ require.False(t, k.expired(), "timer disarmed on release")
159+
160+ // Modifiers never repeat.
161+ pressKey(t, k, keyLeftShift)
162+ require.Zero(t, k.repeating)
163+ // A rate of 0 disables repeat.
164+ k.setRepeat(0, 0)
165+ pressKey(t, k, keyQ)
166+ require.Zero(t, k.repeating)
167+}
168+
169+func TestKeyboardRepeatTracksCurrentMask(t *testing.T) {
170+ k := testKeyboard(t, "", "us")
171+ k.setRepeat(100, 1)
172+ pressKey(t, k, keyQ)
173+ idx, err := k.keymap.ModIndex("Shift")
174+ require.NoError(t, err)
175+ require.NoError(t, k.setMask(1<<idx, 0, 0, 0))
176+ require.Eventually(t, k.expired, 2e9, 1e6)
177+ var ev KeyEvent
178+ ok, err := k.repeat(&ev)
179+ require.NoError(t, err)
180+ require.True(t, ok)
181+ require.Equal(t, "Q", string(ev.Text))
182+}
183+
184+// TestSecretKeysNeverReachText covers the secret rules end to end on the
185+// keyboard: printable text only into the buffer, BackSpace by code point,
186+// every other key delivered without text.
187+func TestSecretKeysNeverReachText(t *testing.T) {
188+ k := testKeyboard(t, "en_US.UTF-8", "de")
189+ buf := NewSecretBuffer(8)
190+ k.setSecret(buf)
191+
192+ press := func(code uint32) KeyEvent {
193+ ev, ok := pressKey(t, k, code)
194+ require.True(t, ok)
195+ require.Nil(t, ev.Text, "secret mode never fills KeyEvent.Text")
196+ releaseKey(k, code)
197+ return ev
198+ }
199+ press(keyQ)
200+ press(keyCircum) // dead key
201+ press(keyE) // composes ê
202+ require.Equal(t, "qê", string(buf.Bytes()))
203+ require.Equal(t, 2, buf.Len())
204+
205+ press(keyBackspace)
206+ require.Equal(t, 1, buf.Len(), "backspace removes one code point")
207+ press(keyBackspace)
208+ press(keyBackspace) // empty: nothing to remove
209+ require.Zero(t, buf.Len())
210+
211+ press(keyQ)
212+ enter := press(keyEnter)
213+ require.Equal(t, uint32(raw.XKB_KEY_Return), enter.Keysym)
214+ require.Equal(t, 1, buf.Len(), "Enter is delivered, not typed")
215+
216+ // Control combinations are keys, not text.
217+ idx, err := k.keymap.ModIndex("Control")
218+ require.NoError(t, err)
219+ require.NoError(t, k.setMask(1<<idx, 0, 0, 0))
220+ ev := press(keyU)
221+ require.Equal(t, ModCtrl, ev.Modifiers)
222+ require.Equal(t, 1, buf.Len())
223+ require.NoError(t, k.setMask(0, 0, 0, 0))
224+
225+ // Capacity: extra text is dropped, the key is still delivered.
226+ for range 10 {
227+ press(keyQ)
228+ }
229+ require.Equal(t, 8, buf.Len())
230+
231+ // Scratch is wiped after use.
232+ require.Equal(t, make([]byte, scratchSize), k.scratch[:])
233+
234+ k.setSecret(nil)
235+ ev, _ = pressKey(t, k, keyQ)
236+ require.Equal(t, "q", string(ev.Text), "ordinary text again once the buffer is removed")
237+}
238+
239+func TestSecretChangedFlag(t *testing.T) {
240+ k := testKeyboard(t, "", "us")
241+ buf := NewSecretBuffer(2)
242+ k.setSecret(buf)
243+ pressKey(t, k, keyQ)
244+ require.True(t, k.changed)
245+ pressKey(t, k, keyEnter)
246+ require.False(t, k.changed)
247+ pressKey(t, k, keyBackspace)
248+ require.True(t, k.changed)
249+ pressKey(t, k, keyBackspace)
250+ require.False(t, k.changed, "nothing left to remove")
251+}
252+
253+func TestSecretRepeat(t *testing.T) {
254+ k := testKeyboard(t, "", "us")
255+ buf := NewSecretBuffer(16)
256+ k.setSecret(buf)
257+ k.setRepeat(100, 1)
258+ var ev KeyEvent
259+ pressKey(t, k, keyQ)
260+ for range 2 {
261+ require.Eventually(t, k.expired, 2e9, 1e6)
262+ ok, err := k.repeat(&ev)
263+ require.NoError(t, err)
264+ require.True(t, ok)
265+ require.Nil(t, ev.Text)
266+ }
267+ require.Equal(t, "qqq", string(buf.Bytes()))
268+
269+ // Enter cancels a previous printable repeat.
270+ pressKey(t, k, keyEnter)
271+ require.Zero(t, k.repeating)
272+ releaseKey(k, keyQ)
273+ releaseKey(k, keyEnter)
274+
275+ // Held backspace repeats.
276+ pressKey(t, k, keyBackspace)
277+ require.Equal(t, uint32(keyBackspace), k.repeating)
278+ require.Eventually(t, k.expired, 2e9, 1e6)
279+ ok, err := k.repeat(&ev)
280+ require.NoError(t, err)
281+ require.True(t, ok)
282+ require.Equal(t, 1, buf.Len())
283+}
M mocks/handler_mock.go +166 -0
@@ -297,6 +297,92 @@ func (_c *MockHandler_Frame_Call) RunAndReturn(run func(id neferclient.SurfaceID
297297 return _c
298298 }
299299
300+// Key provides a mock function for the type MockHandler
301+func (_mock *MockHandler) Key(ev *neferclient.KeyEvent) {
302+ _mock.Called(ev)
303+ return
304+}
305+
306+// MockHandler_Key_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Key'
307+type MockHandler_Key_Call struct {
308+ *mock.Call
309+}
310+
311+// Key is a helper method to define mock.On call
312+// - ev *neferclient.KeyEvent
313+func (_e *MockHandler_Expecter) Key(ev any) *MockHandler_Key_Call {
314+ return &MockHandler_Key_Call{Call: _e.mock.On("Key", ev)}
315+}
316+
317+func (_c *MockHandler_Key_Call) Run(run func(ev *neferclient.KeyEvent)) *MockHandler_Key_Call {
318+ _c.Call.Run(func(args mock.Arguments) {
319+ var arg0 *neferclient.KeyEvent
320+ if args[0] != nil {
321+ arg0 = args[0].(*neferclient.KeyEvent)
322+ }
323+ run(
324+ arg0,
325+ )
326+ })
327+ return _c
328+}
329+
330+func (_c *MockHandler_Key_Call) Return() *MockHandler_Key_Call {
331+ _c.Call.Return()
332+ return _c
333+}
334+
335+func (_c *MockHandler_Key_Call) RunAndReturn(run func(ev *neferclient.KeyEvent)) *MockHandler_Key_Call {
336+ _c.Run(run)
337+ return _c
338+}
339+
340+// KeyboardFocus provides a mock function for the type MockHandler
341+func (_mock *MockHandler) KeyboardFocus(id neferclient.SurfaceID, focused bool) {
342+ _mock.Called(id, focused)
343+ return
344+}
345+
346+// MockHandler_KeyboardFocus_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'KeyboardFocus'
347+type MockHandler_KeyboardFocus_Call struct {
348+ *mock.Call
349+}
350+
351+// KeyboardFocus is a helper method to define mock.On call
352+// - id neferclient.SurfaceID
353+// - focused bool
354+func (_e *MockHandler_Expecter) KeyboardFocus(id any, focused any) *MockHandler_KeyboardFocus_Call {
355+ return &MockHandler_KeyboardFocus_Call{Call: _e.mock.On("KeyboardFocus", id, focused)}
356+}
357+
358+func (_c *MockHandler_KeyboardFocus_Call) Run(run func(id neferclient.SurfaceID, focused bool)) *MockHandler_KeyboardFocus_Call {
359+ _c.Call.Run(func(args mock.Arguments) {
360+ var arg0 neferclient.SurfaceID
361+ if args[0] != nil {
362+ arg0 = args[0].(neferclient.SurfaceID)
363+ }
364+ var arg1 bool
365+ if args[1] != nil {
366+ arg1 = args[1].(bool)
367+ }
368+ run(
369+ arg0,
370+ arg1,
371+ )
372+ })
373+ return _c
374+}
375+
376+func (_c *MockHandler_KeyboardFocus_Call) Return() *MockHandler_KeyboardFocus_Call {
377+ _c.Call.Return()
378+ return _c
379+}
380+
381+func (_c *MockHandler_KeyboardFocus_Call) RunAndReturn(run func(id neferclient.SurfaceID, focused bool)) *MockHandler_KeyboardFocus_Call {
382+ _c.Run(run)
383+ return _c
384+}
385+
300386 // LockFinished provides a mock function for the type MockHandler
301387 func (_mock *MockHandler) LockFinished() {
302388 _mock.Called()
@@ -443,6 +529,46 @@ func (_c *MockHandler_OutputRemoved_Call) RunAndReturn(run func(global uint32))
443529 return _c
444530 }
445531
532+// Pointer provides a mock function for the type MockHandler
533+func (_mock *MockHandler) Pointer(ev *neferclient.PointerEvent) {
534+ _mock.Called(ev)
535+ return
536+}
537+
538+// MockHandler_Pointer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Pointer'
539+type MockHandler_Pointer_Call struct {
540+ *mock.Call
541+}
542+
543+// Pointer is a helper method to define mock.On call
544+// - ev *neferclient.PointerEvent
545+func (_e *MockHandler_Expecter) Pointer(ev any) *MockHandler_Pointer_Call {
546+ return &MockHandler_Pointer_Call{Call: _e.mock.On("Pointer", ev)}
547+}
548+
549+func (_c *MockHandler_Pointer_Call) Run(run func(ev *neferclient.PointerEvent)) *MockHandler_Pointer_Call {
550+ _c.Call.Run(func(args mock.Arguments) {
551+ var arg0 *neferclient.PointerEvent
552+ if args[0] != nil {
553+ arg0 = args[0].(*neferclient.PointerEvent)
554+ }
555+ run(
556+ arg0,
557+ )
558+ })
559+ return _c
560+}
561+
562+func (_c *MockHandler_Pointer_Call) Return() *MockHandler_Pointer_Call {
563+ _c.Call.Return()
564+ return _c
565+}
566+
567+func (_c *MockHandler_Pointer_Call) RunAndReturn(run func(ev *neferclient.PointerEvent)) *MockHandler_Pointer_Call {
568+ _c.Run(run)
569+ return _c
570+}
571+
446572 // Scale provides a mock function for the type MockHandler
447573 func (_mock *MockHandler) Scale(id neferclient.SurfaceID, scale float64) {
448574 _mock.Called(id, scale)
@@ -488,3 +614,43 @@ func (_c *MockHandler_Scale_Call) RunAndReturn(run func(id neferclient.SurfaceID
488614 _c.Run(run)
489615 return _c
490616 }
617+
618+// SecretChanged provides a mock function for the type MockHandler
619+func (_mock *MockHandler) SecretChanged(count int) {
620+ _mock.Called(count)
621+ return
622+}
623+
624+// MockHandler_SecretChanged_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SecretChanged'
625+type MockHandler_SecretChanged_Call struct {
626+ *mock.Call
627+}
628+
629+// SecretChanged is a helper method to define mock.On call
630+// - count int
631+func (_e *MockHandler_Expecter) SecretChanged(count any) *MockHandler_SecretChanged_Call {
632+ return &MockHandler_SecretChanged_Call{Call: _e.mock.On("SecretChanged", count)}
633+}
634+
635+func (_c *MockHandler_SecretChanged_Call) Run(run func(count int)) *MockHandler_SecretChanged_Call {
636+ _c.Call.Run(func(args mock.Arguments) {
637+ var arg0 int
638+ if args[0] != nil {
639+ arg0 = args[0].(int)
640+ }
641+ run(
642+ arg0,
643+ )
644+ })
645+ return _c
646+}
647+
648+func (_c *MockHandler_SecretChanged_Call) Return() *MockHandler_SecretChanged_Call {
649+ _c.Call.Return()
650+ return _c
651+}
652+
653+func (_c *MockHandler_SecretChanged_Call) RunAndReturn(run func(count int)) *MockHandler_SecretChanged_Call {
654+ _c.Run(run)
655+ return _c
656+}
@@ -297,6 +297,92 @@ func (_c *MockHandler_Frame_Call) RunAndReturn(run func(id neferclient.SurfaceID
297 return _c297 return _c
298 }298 }
299 299
300+// Key provides a mock function for the type MockHandler
301+func (_mock *MockHandler) Key(ev *neferclient.KeyEvent) {
302+ _mock.Called(ev)
303+ return
304+}
305+
306+// MockHandler_Key_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Key'
307+type MockHandler_Key_Call struct {
308+ *mock.Call
309+}
310+
311+// Key is a helper method to define mock.On call
312+// - ev *neferclient.KeyEvent
313+func (_e *MockHandler_Expecter) Key(ev any) *MockHandler_Key_Call {
314+ return &MockHandler_Key_Call{Call: _e.mock.On("Key", ev)}
315+}
316+
317+func (_c *MockHandler_Key_Call) Run(run func(ev *neferclient.KeyEvent)) *MockHandler_Key_Call {
318+ _c.Call.Run(func(args mock.Arguments) {
319+ var arg0 *neferclient.KeyEvent
320+ if args[0] != nil {
321+ arg0 = args[0].(*neferclient.KeyEvent)
322+ }
323+ run(
324+ arg0,
325+ )
326+ })
327+ return _c
328+}
329+
330+func (_c *MockHandler_Key_Call) Return() *MockHandler_Key_Call {
331+ _c.Call.Return()
332+ return _c
333+}
334+
335+func (_c *MockHandler_Key_Call) RunAndReturn(run func(ev *neferclient.KeyEvent)) *MockHandler_Key_Call {
336+ _c.Run(run)
337+ return _c
338+}
339+
340+// KeyboardFocus provides a mock function for the type MockHandler
341+func (_mock *MockHandler) KeyboardFocus(id neferclient.SurfaceID, focused bool) {
342+ _mock.Called(id, focused)
343+ return
344+}
345+
346+// MockHandler_KeyboardFocus_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'KeyboardFocus'
347+type MockHandler_KeyboardFocus_Call struct {
348+ *mock.Call
349+}
350+
351+// KeyboardFocus is a helper method to define mock.On call
352+// - id neferclient.SurfaceID
353+// - focused bool
354+func (_e *MockHandler_Expecter) KeyboardFocus(id any, focused any) *MockHandler_KeyboardFocus_Call {
355+ return &MockHandler_KeyboardFocus_Call{Call: _e.mock.On("KeyboardFocus", id, focused)}
356+}
357+
358+func (_c *MockHandler_KeyboardFocus_Call) Run(run func(id neferclient.SurfaceID, focused bool)) *MockHandler_KeyboardFocus_Call {
359+ _c.Call.Run(func(args mock.Arguments) {
360+ var arg0 neferclient.SurfaceID
361+ if args[0] != nil {
362+ arg0 = args[0].(neferclient.SurfaceID)
363+ }
364+ var arg1 bool
365+ if args[1] != nil {
366+ arg1 = args[1].(bool)
367+ }
368+ run(
369+ arg0,
370+ arg1,
371+ )
372+ })
373+ return _c
374+}
375+
376+func (_c *MockHandler_KeyboardFocus_Call) Return() *MockHandler_KeyboardFocus_Call {
377+ _c.Call.Return()
378+ return _c
379+}
380+
381+func (_c *MockHandler_KeyboardFocus_Call) RunAndReturn(run func(id neferclient.SurfaceID, focused bool)) *MockHandler_KeyboardFocus_Call {
382+ _c.Run(run)
383+ return _c
384+}
385+
300 // LockFinished provides a mock function for the type MockHandler386 // LockFinished provides a mock function for the type MockHandler
301 func (_mock *MockHandler) LockFinished() {387 func (_mock *MockHandler) LockFinished() {
302 _mock.Called()388 _mock.Called()
@@ -443,6 +529,46 @@ func (_c *MockHandler_OutputRemoved_Call) RunAndReturn(run func(global uint32))
443 return _c529 return _c
444 }530 }
445 531
532+// Pointer provides a mock function for the type MockHandler
533+func (_mock *MockHandler) Pointer(ev *neferclient.PointerEvent) {
534+ _mock.Called(ev)
535+ return
536+}
537+
538+// MockHandler_Pointer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Pointer'
539+type MockHandler_Pointer_Call struct {
540+ *mock.Call
541+}
542+
543+// Pointer is a helper method to define mock.On call
544+// - ev *neferclient.PointerEvent
545+func (_e *MockHandler_Expecter) Pointer(ev any) *MockHandler_Pointer_Call {
546+ return &MockHandler_Pointer_Call{Call: _e.mock.On("Pointer", ev)}
547+}
548+
549+func (_c *MockHandler_Pointer_Call) Run(run func(ev *neferclient.PointerEvent)) *MockHandler_Pointer_Call {
550+ _c.Call.Run(func(args mock.Arguments) {
551+ var arg0 *neferclient.PointerEvent
552+ if args[0] != nil {
553+ arg0 = args[0].(*neferclient.PointerEvent)
554+ }
555+ run(
556+ arg0,
557+ )
558+ })
559+ return _c
560+}
561+
562+func (_c *MockHandler_Pointer_Call) Return() *MockHandler_Pointer_Call {
563+ _c.Call.Return()
564+ return _c
565+}
566+
567+func (_c *MockHandler_Pointer_Call) RunAndReturn(run func(ev *neferclient.PointerEvent)) *MockHandler_Pointer_Call {
568+ _c.Run(run)
569+ return _c
570+}
571+
446 // Scale provides a mock function for the type MockHandler572 // Scale provides a mock function for the type MockHandler
447 func (_mock *MockHandler) Scale(id neferclient.SurfaceID, scale float64) {573 func (_mock *MockHandler) Scale(id neferclient.SurfaceID, scale float64) {
448 _mock.Called(id, scale)574 _mock.Called(id, scale)
@@ -488,3 +614,43 @@ func (_c *MockHandler_Scale_Call) RunAndReturn(run func(id neferclient.SurfaceID
488 _c.Run(run)614 _c.Run(run)
489 return _c615 return _c
490 }616 }
617+
618+// SecretChanged provides a mock function for the type MockHandler
619+func (_mock *MockHandler) SecretChanged(count int) {
620+ _mock.Called(count)
621+ return
622+}
623+
624+// MockHandler_SecretChanged_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SecretChanged'
625+type MockHandler_SecretChanged_Call struct {
626+ *mock.Call
627+}
628+
629+// SecretChanged is a helper method to define mock.On call
630+// - count int
631+func (_e *MockHandler_Expecter) SecretChanged(count any) *MockHandler_SecretChanged_Call {
632+ return &MockHandler_SecretChanged_Call{Call: _e.mock.On("SecretChanged", count)}
633+}
634+
635+func (_c *MockHandler_SecretChanged_Call) Run(run func(count int)) *MockHandler_SecretChanged_Call {
636+ _c.Call.Run(func(args mock.Arguments) {
637+ var arg0 int
638+ if args[0] != nil {
639+ arg0 = args[0].(int)
640+ }
641+ run(
642+ arg0,
643+ )
644+ })
645+ return _c
646+}
647+
648+func (_c *MockHandler_SecretChanged_Call) Return() *MockHandler_SecretChanged_Call {
649+ _c.Call.Return()
650+ return _c
651+}
652+
653+func (_c *MockHandler_SecretChanged_Call) RunAndReturn(run func(count int)) *MockHandler_SecretChanged_Call {
654+ _c.Run(run)
655+ return _c
656+}
M queue.go +21 -1
@@ -39,6 +39,26 @@ const (
3939 evLocked // id = lock generation
4040 evLockFinished // id = lock generation
4141 evBadEvent // id, a = badEvent code: the reader met a malformed event
42+
43+ // Seat events (kind >= evSeatCaps). Pointer and keyboard events carry the
44+ // generation of the wl_pointer/wl_keyboard in version, so events of a
45+ // released device that are still queued are ignored. global is a wl_surface
46+ // object id where a surface is named.
47+ evSeatCaps // a = capabilities
48+ evSeatBad // a = bad code: a seat device event was malformed
49+ evPtrEnter // global = surface, serial, a, b = fixed x, y
50+ evPtrLeave // global = surface
51+ evPtrMotion // a, b = fixed x, y
52+ evPtrButton // flags = button, a = state
53+ evPtrAxis // flags = axis, a = fixed value
54+ evPtrAxisValue // flags = axis, a = value120
55+ evPtrAxisStop // flags = axis
56+ evKbKeymap // fd = owned descriptor, flags = size, a = format
57+ evKbEnter // global = surface, serial
58+ evKbLeave // global = surface
59+ evKbKey // flags = evdev code, a = state
60+ evKbModifiers // flags = depressed, dev = latched | locked<<32, a = group
61+ evKbRepeat // a = rate, b = delay
4262 )
4363
4464 // event is the only thing the reader and the epoll goroutine hand to the
@@ -60,7 +80,7 @@ type event struct {
6080
6181 // hasFD reports whether the event owns a received descriptor that must be
6282 // closed if the event is dropped.
63-func (e *event) hasFD() bool { return e.kind == evFeedbackTable && e.fd >= 0 }
83+func (e *event) hasFD() bool { return (e.kind == evFeedbackTable || e.kind == evKbKeymap) && e.fd >= 0 }
6484
6585 func (e *event) closeFD() {
6686 if e.hasFD() {
@@ -39,6 +39,26 @@ const (
39 evLocked // id = lock generation39 evLocked // id = lock generation
40 evLockFinished // id = lock generation40 evLockFinished // id = lock generation
41 evBadEvent // id, a = badEvent code: the reader met a malformed event41 evBadEvent // id, a = badEvent code: the reader met a malformed event
42+
43+ // Seat events (kind >= evSeatCaps). Pointer and keyboard events carry the
44+ // generation of the wl_pointer/wl_keyboard in version, so events of a
45+ // released device that are still queued are ignored. global is a wl_surface
46+ // object id where a surface is named.
47+ evSeatCaps // a = capabilities
48+ evSeatBad // a = bad code: a seat device event was malformed
49+ evPtrEnter // global = surface, serial, a, b = fixed x, y
50+ evPtrLeave // global = surface
51+ evPtrMotion // a, b = fixed x, y
52+ evPtrButton // flags = button, a = state
53+ evPtrAxis // flags = axis, a = fixed value
54+ evPtrAxisValue // flags = axis, a = value120
55+ evPtrAxisStop // flags = axis
56+ evKbKeymap // fd = owned descriptor, flags = size, a = format
57+ evKbEnter // global = surface, serial
58+ evKbLeave // global = surface
59+ evKbKey // flags = evdev code, a = state
60+ evKbModifiers // flags = depressed, dev = latched | locked<<32, a = group
61+ evKbRepeat // a = rate, b = delay
42 )62 )
43 63
44 // event is the only thing the reader and the epoll goroutine hand to the64 // event is the only thing the reader and the epoll goroutine hand to the
@@ -60,7 +80,7 @@ type event struct {
60 80
61 // hasFD reports whether the event owns a received descriptor that must be81 // hasFD reports whether the event owns a received descriptor that must be
62 // closed if the event is dropped.82 // closed if the event is dropped.
63-func (e *event) hasFD() bool { return e.kind == evFeedbackTable && e.fd >= 0 }83+func (e *event) hasFD() bool { return (e.kind == evFeedbackTable || e.kind == evKbKeymap) && e.fd >= 0 }
64 84
65 func (e *event) closeFD() {85 func (e *event) closeFD() {
66 if e.hasFD() {86 if e.hasFD() {
A seat.go +591 -0
@@ -0,0 +1,591 @@
1+package neferclient
2+
3+import (
4+ "errors"
5+ "fmt"
6+
7+ "github.com/bnema/go-wayland-bindings/client/cursorshape"
8+ "github.com/bnema/go-wayland-bindings/client/wayland"
9+ "github.com/bnema/wlturbo/wl"
10+ "golang.org/x/sys/unix"
11+)
12+
13+// maxSeatVersion is the wl_seat version bound: 9 adds axis_value120 users and
14+// the release requests.
15+const maxSeatVersion = 9
16+
17+// CursorShape is a wp_cursor_shape_v1 shape. The values are the protocol's.
18+type CursorShape uint32
19+
20+const (
21+ CursorDefault CursorShape = iota + 1
22+ CursorContextMenu
23+ CursorHelp
24+ CursorPointer
25+ CursorProgress
26+ CursorWait
27+ CursorCell
28+ CursorCrosshair
29+ CursorText
30+ CursorVerticalText
31+ CursorAlias
32+ CursorCopy
33+ CursorMove
34+ CursorNoDrop
35+ CursorNotAllowed
36+ CursorGrab
37+ CursorGrabbing
38+ CursorEResize
39+ CursorNResize
40+ CursorNEResize
41+ CursorNWResize
42+ CursorSResize
43+ CursorSEResize
44+ CursorSWResize
45+ CursorWResize
46+ CursorEWResize
47+ CursorNSResize
48+ CursorNESWResize
49+ CursorNWSEResize
50+ CursorColResize
51+ CursorRowResize
52+ CursorAllScroll
53+ CursorZoomIn
54+ CursorZoomOut
55+ CursorDndAsk // needs cursor-shape version 2
56+ CursorAllResize // needs cursor-shape version 2
57+)
58+
59+// PointerKind tells which pointer event a [PointerEvent] is.
60+type PointerKind uint8
61+
62+const (
63+ PointerEnter PointerKind = iota + 1
64+ PointerLeave
65+ PointerMotion
66+ PointerButton
67+ // PointerAxis is a scroll step on Axis. DX or DY carry the continuous
68+ // value in logical pixels; Value120 carries the wheel value in 1/120 of a
69+ // notch. A compositor can send both for one physical step: use one.
70+ PointerAxis
71+ // PointerAxisStop ends a scroll sequence on Axis.
72+ PointerAxisStop
73+)
74+
75+// Scroll axes of [PointerEvent.Axis].
76+const (
77+ AxisVertical = 0
78+ AxisHorizontal = 1
79+)
80+
81+// PointerEvent is one pointer event over a surface of the connection. X and Y
82+// are surface-local logical pixels (already logical: never divide by scale)
83+// and hold the latest position for every kind.
84+type PointerEvent struct {
85+ Surface SurfaceID
86+ Kind PointerKind
87+ X, Y float64
88+ DX, DY float64 // PointerAxis: continuous scroll value
89+ Button uint32 // PointerButton: evdev button code
90+ Pressed bool // PointerButton
91+ Axis uint32 // PointerAxis, PointerAxisStop: AxisVertical or AxisHorizontal
92+ Value120 int32 // PointerAxis: wheel value in 1/120 notches
93+}
94+
95+// KeyEvent is one key press, repeat or release.
96+type KeyEvent struct {
97+ Surface SurfaceID
98+ Keycode uint32 // evdev key code
99+ Keysym uint32 // xkb keysym in the current layout and modifier state
100+ Modifiers Modifiers
101+ Group uint32 // effective layout index
102+ Pressed bool
103+ Repeat bool
104+ // Text is the UTF-8 text of the key, nil for releases and keys without
105+ // text. It aliases library storage that is wiped when Handler.Key
106+ // returns. It is always nil while a [SecretBuffer] is installed.
107+ Text []byte
108+}
109+
110+// Seat is the connection's first wl_seat: pointer, keyboard and cursor. It
111+// belongs to the owner goroutine. Without a seat global every method is a
112+// no-op.
113+type Seat struct {
114+ c *Conn
115+ proxy *wayland.Seat
116+ name uint32 // registry name of the global
117+ ver uint32
118+
119+ pointer *wayland.Pointer
120+ ptrGen uint32 // generation of pointer; bumped on every create and drop
121+ ptrSurf SurfaceID
122+ px, py float64
123+ pev PointerEvent
124+
125+ keyboard *wayland.Keyboard
126+ kbGen uint32
127+ kbSurf SurfaceID
128+ kb *keyboard
129+ kev KeyEvent
130+
131+ secret *SecretBuffer
132+
133+ shapes *cursorshape.WpCursorShapeManager
134+ shapesVer uint32
135+ shapeDev *cursorshape.WpCursorShapeDevice
136+ enterSerial uint32 // latest pointer enter serial, 0 while outside
137+ shape CursorShape
138+}
139+
140+// Seat returns the connection's seat, binding wl_seat on first use. The seat
141+// is also bound when the first surface is created. Input starts flowing to the
142+// Handler once the compositor announces the capabilities.
143+func (c *Conn) Seat() *Seat {
144+ c.ensureSeat()
145+ return c.seat
146+}
147+
148+// ensureSeat binds wl_seat and the optional cursor-shape manager once. A
149+// failure is reported by the next Dispatch through Handler.Error.
150+func (c *Conn) ensureSeat() {
151+ if c.seat != nil || c.closed {
152+ return
153+ }
154+ s := &Seat{c: c}
155+ c.seat = s
156+ g, ok := c.display.Registry().FindGlobal(wayland.SeatInterface)
157+ if !ok {
158+ return
159+ }
160+ q := c.q
161+ proxy, v, err := c.Bind(wayland.SeatInterface, maxSeatVersion, func(ctx *wl.Context) *wayland.Seat {
162+ p := wayland.NewSeat(ctx)
163+ p.OnCapabilities(func(caps uint32) {
164+ e := event{kind: evSeatCaps, a: int32(caps)}
165+ q.post(&e)
166+ })
167+ return p
168+ })
169+ if err != nil {
170+ c.seatErr = fmt.Errorf("neferclient: bind wl_seat: %w", err)
171+ return
172+ }
173+ s.proxy, s.name, s.ver = proxy, g.Name, v
174+ m, mv, err := c.Bind(cursorshape.WpCursorShapeManagerInterface, 2, cursorshape.NewWpCursorShapeManager)
175+ if err != nil {
176+ if !errors.Is(err, ErrGlobalNotFound) {
177+ c.seatErr = fmt.Errorf("neferclient: bind cursor shape manager: %w", err)
178+ }
179+ return
180+ }
181+ s.shapes, s.shapesVer = m, mv
182+}
183+
184+// SetSecret installs b to receive typed text, or removes it with nil. While
185+// installed, printable text goes only into b and never into KeyEvent.Text;
186+// BackSpace removes one code point; every other key is still delivered as a
187+// KeyEvent without text. Installing or removing cancels held keys and repeat.
188+// The previous buffer is not wiped: that is the caller's call.
189+func (s *Seat) SetSecret(b *SecretBuffer) {
190+ s.secret = b
191+ if s.kb != nil {
192+ s.kb.setSecret(b)
193+ }
194+}
195+
196+// SetCursor asks the compositor to show shape for the pointer. It is a no-op
197+// when the compositor has no cursor-shape support, the pointer is outside the
198+// connection's surfaces, or shape is unchanged since the last enter.
199+func (s *Seat) SetCursor(shape CursorShape) error {
200+ if s.c.closed {
201+ return ErrClosed
202+ }
203+ limit := CursorZoomOut
204+ if s.shapesVer >= 2 {
205+ limit = CursorAllResize
206+ }
207+ if shape < CursorDefault || shape > CursorAllResize {
208+ return fmt.Errorf("neferclient: invalid cursor shape %d", shape)
209+ }
210+ if s.shapes == nil || s.pointer == nil || s.enterSerial == 0 || shape == s.shape {
211+ return nil
212+ }
213+ if shape > limit {
214+ return &CapabilityError{Name: cursorshape.WpCursorShapeManagerInterface, Cause: fmt.Errorf("shape %d requires version 2", shape)}
215+ }
216+ if s.shapeDev == nil {
217+ dev, err := s.shapes.GetPointer(s.pointer)
218+ if err != nil {
219+ return err
220+ }
221+ s.shapeDev = dev
222+ }
223+ if err := s.shapeDev.SetShape(s.enterSerial, uint32(shape)); err != nil {
224+ return err
225+ }
226+ s.shape = shape
227+ return nil
228+}
229+
230+// surfaceByObject finds the surface whose wl_surface has object id obj.
231+func (c *Conn) surfaceByObject(obj uint32) *Surface {
232+ for _, s := range c.surfaces {
233+ if !s.closed && s.surf != nil && s.surf.ID() == obj {
234+ return s
235+ }
236+ }
237+ return nil
238+}
239+
240+func (c *Conn) seatTimer(fd int32) bool {
241+ return c.seat != nil && c.seat.kb != nil && int(fd) == c.seat.kb.tfd
242+}
243+
244+// seatRepeat handles the repeat timer: at most one repeat per expiration.
245+func (c *Conn) seatRepeat(h Handler) {
246+ s := c.seat
247+ if s.kb.expired() {
248+ ke := &s.kev
249+ *ke = KeyEvent{Surface: s.kbSurf}
250+ ok, err := s.kb.repeat(ke)
251+ switch {
252+ case err != nil:
253+ h.Error(err)
254+ case ok:
255+ s.deliverKey(ke, h)
256+ }
257+ }
258+ if !c.closed {
259+ if err := c.armFD(s.kb.tfd, unix.EPOLL_CTL_MOD); err != nil {
260+ h.Error(err)
261+ }
262+ }
263+}
264+
265+func (s *Seat) deliverKey(ke *KeyEvent, h Handler) {
266+ h.Key(ke)
267+ clear(s.kb.scratch[:]) // ordinary text must not outlive the call
268+ ke.Text = nil
269+ if s.kb.changed {
270+ h.SecretChanged(s.secret.Len())
271+ }
272+}
273+
274+// seatSurfaceGone forgets focus on a closing surface.
275+func (c *Conn) seatSurfaceGone(sf *Surface) {
276+ s := c.seat
277+ if s == nil {
278+ return
279+ }
280+ if s.ptrSurf == sf.id {
281+ s.ptrSurf = 0
282+ s.enterSerial, s.shape = 0, 0
283+ }
284+ if s.kbSurf == sf.id {
285+ s.kbSurf = 0
286+ if s.kb != nil {
287+ s.kb.setFocus(false)
288+ }
289+ }
290+}
291+
292+func (c *Conn) seatGlobalRemoved(global uint32, h Handler) {
293+ if s := c.seat; s != nil && s.proxy != nil && s.name == global {
294+ s.release(h)
295+ }
296+}
297+
298+// release drops the devices and the seat proxy.
299+func (s *Seat) release(h Handler) {
300+ s.dropPointer(h)
301+ s.dropKeyboard(h)
302+ if s.ver >= 5 {
303+ _ = s.proxy.Release()
304+ } else {
305+ s.c.wlctx.Unregister(s.proxy)
306+ }
307+ s.proxy = nil
308+}
309+
310+func releaseDevice(ver uint32, c *wl.Context, p interface {
311+ wl.Proxy
312+ Release() error
313+}) {
314+ if ver >= 3 {
315+ _ = p.Release()
316+ } else {
317+ c.Unregister(p)
318+ }
319+}
320+
321+func (s *Seat) dropPointer(h Handler) {
322+ if s.pointer == nil {
323+ return
324+ }
325+ if s.shapeDev != nil {
326+ _ = s.shapeDev.Destroy()
327+ s.shapeDev = nil
328+ }
329+ s.enterSerial, s.shape = 0, 0
330+ releaseDevice(s.ver, s.c.wlctx, s.pointer)
331+ s.pointer = nil
332+ s.ptrGen++
333+ if id := s.ptrSurf; id != 0 {
334+ s.ptrSurf = 0
335+ pe := &s.pev
336+ *pe = PointerEvent{Surface: id, Kind: PointerLeave, X: s.px, Y: s.py}
337+ h.Pointer(pe)
338+ }
339+}
340+
341+func (s *Seat) dropKeyboard(h Handler) {
342+ if s.keyboard == nil {
343+ return
344+ }
345+ releaseDevice(s.ver, s.c.wlctx, s.keyboard)
346+ s.keyboard = nil
347+ s.kbGen++
348+ if id := s.kbSurf; id != 0 {
349+ s.kbSurf = 0
350+ s.kb.setFocus(false)
351+ h.KeyboardFocus(id, false)
352+ } else if s.kb != nil {
353+ s.kb.setFocus(false)
354+ }
355+}
356+
357+func (s *Seat) newPointer() error {
358+ c := s.c
359+ c.pause() // handlers go on after the request, before any event is read
360+ defer c.resume()
361+ p, err := s.proxy.GetPointer()
362+ if err != nil {
363+ return err
364+ }
365+ s.pointer = p
366+ s.ptrGen++
367+ gen, q := s.ptrGen, c.q
368+ post := func(e *event) {
369+ e.version = gen
370+ q.post(e)
371+ }
372+ p.OnEnter(func(serial, surf uint32, x, y wl.Fixed) {
373+ post(&event{kind: evPtrEnter, global: surf, serial: serial, a: int32(x), b: int32(y)})
374+ })
375+ p.OnLeave(func(_, surf uint32) { post(&event{kind: evPtrLeave, global: surf}) })
376+ p.OnMotion(func(_ uint32, x, y wl.Fixed) { post(&event{kind: evPtrMotion, a: int32(x), b: int32(y)}) })
377+ p.OnButton(func(serial, _, button, state uint32) {
378+ post(&event{kind: evPtrButton, serial: serial, flags: button, a: int32(state)})
379+ })
380+ p.OnAxis(func(_, axis uint32, v wl.Fixed) { post(&event{kind: evPtrAxis, flags: axis, a: int32(v)}) })
381+ p.OnAxisValue120(func(axis uint32, v int32) { post(&event{kind: evPtrAxisValue, flags: axis, a: v}) })
382+ p.OnAxisStop(func(_, axis uint32) { post(&event{kind: evPtrAxisStop, flags: axis}) })
383+ return nil
384+}
385+
386+func (s *Seat) newKeyboard() error {
387+ c := s.c
388+ if s.kb == nil {
389+ kb, err := newKeyboard(composeLocale())
390+ if err != nil {
391+ return err
392+ }
393+ if err = c.armFD(kb.tfd, unix.EPOLL_CTL_ADD); err != nil {
394+ kb.close()
395+ return err
396+ }
397+ kb.secret = s.secret
398+ s.kb = kb
399+ }
400+ c.pause()
401+ defer c.resume()
402+ k, err := s.proxy.GetKeyboard()
403+ if err != nil {
404+ return err
405+ }
406+ s.keyboard = k
407+ s.kbGen++
408+ gen, q := s.kbGen, c.q
409+ post := func(e *event) {
410+ e.version = gen
411+ q.post(e)
412+ }
413+ k.OnKeymap(func(format uint32, fd *wl.OwnedFD, size uint32) {
414+ n, err := fd.Take()
415+ if err != nil {
416+ post(&event{kind: evSeatBad, a: badKeymapFD})
417+ return
418+ }
419+ post(&event{kind: evKbKeymap, fd: int32(n), flags: size, a: int32(format)})
420+ })
421+ k.OnEnter(func(serial, surf uint32, _ []byte) { post(&event{kind: evKbEnter, global: surf, serial: serial}) })
422+ k.OnLeave(func(_, surf uint32) { post(&event{kind: evKbLeave, global: surf}) })
423+ k.OnKey(func(serial, _, key, state uint32) {
424+ post(&event{kind: evKbKey, serial: serial, flags: key, a: int32(state)})
425+ })
426+ k.OnModifiers(func(_, depressed, latched, locked, group uint32) {
427+ post(&event{kind: evKbModifiers, flags: depressed, dev: uint64(latched) | uint64(locked)<<32, a: int32(group)})
428+ })
429+ k.OnRepeatInfo(func(rate, delay int32) { post(&event{kind: evKbRepeat, a: rate, b: delay}) })
430+ return nil
431+}
432+
433+// Codes of evSeatBad.
434+const badKeymapFD int32 = 100
435+
436+// applySeat handles the seat events on the owner.
437+func (c *Conn) applySeat(ev *event, h Handler) {
438+ defer ev.closeFD()
439+ s := c.seat
440+ if s == nil {
441+ return
442+ }
443+ switch ev.kind {
444+ case evSeatBad:
445+ h.Error(errors.New("neferclient: keymap descriptor unavailable"))
446+ case evSeatCaps:
447+ s.applyCaps(uint32(ev.a), h)
448+ case evPtrEnter, evPtrLeave, evPtrMotion, evPtrButton, evPtrAxis, evPtrAxisValue, evPtrAxisStop:
449+ if s.pointer != nil && ev.version == s.ptrGen {
450+ s.applyPointer(ev, h)
451+ }
452+ default:
453+ if s.keyboard != nil && ev.version == s.kbGen {
454+ s.applyKeyboard(ev, h)
455+ }
456+ }
457+}
458+
459+func (s *Seat) applyCaps(caps uint32, h Handler) {
460+ if s.proxy == nil {
461+ return
462+ }
463+ if caps&1 == 0 {
464+ s.dropPointer(h)
465+ }
466+ if caps&2 == 0 {
467+ s.dropKeyboard(h)
468+ }
469+ if caps&1 != 0 && s.pointer == nil {
470+ if err := s.newPointer(); err != nil {
471+ h.Error(err)
472+ }
473+ }
474+ if caps&2 != 0 && s.keyboard == nil {
475+ if err := s.newKeyboard(); err != nil {
476+ h.Error(err)
477+ }
478+ }
479+}
480+
481+func (s *Seat) applyPointer(ev *event, h Handler) {
482+ pe := &s.pev
483+ *pe = PointerEvent{}
484+ fixed := func(v int32) float64 { return wl.Fixed(v).Float64() }
485+ switch ev.kind {
486+ case evPtrEnter:
487+ sf := s.c.surfaceByObject(ev.global)
488+ if sf == nil {
489+ return
490+ }
491+ s.ptrSurf = sf.id
492+ s.px, s.py = fixed(ev.a), fixed(ev.b)
493+ s.enterSerial, s.shape = ev.serial, 0 // the compositor forgets the cursor on leave
494+ pe.Kind = PointerEnter
495+ case evPtrLeave:
496+ if sf := s.c.surfaceByObject(ev.global); s.ptrSurf == 0 || sf == nil || sf.id != s.ptrSurf {
497+ return
498+ }
499+ pe.Kind = PointerLeave
500+ pe.Surface = s.ptrSurf
501+ pe.X, pe.Y = s.px, s.py
502+ s.ptrSurf = 0
503+ s.enterSerial, s.shape = 0, 0
504+ h.Pointer(pe)
505+ return
506+ default:
507+ if s.ptrSurf == 0 {
508+ return
509+ }
510+ switch ev.kind {
511+ case evPtrMotion:
512+ s.px, s.py = fixed(ev.a), fixed(ev.b)
513+ pe.Kind = PointerMotion
514+ case evPtrButton:
515+ pe.Kind, pe.Button, pe.Pressed = PointerButton, ev.flags, ev.a == 1
516+ case evPtrAxis:
517+ pe.Kind, pe.Axis = PointerAxis, ev.flags
518+ if ev.flags == AxisVertical {
519+ pe.DY = fixed(ev.a)
520+ } else {
521+ pe.DX = fixed(ev.a)
522+ }
523+ case evPtrAxisValue:
524+ pe.Kind, pe.Axis, pe.Value120 = PointerAxis, ev.flags, ev.a
525+ case evPtrAxisStop:
526+ pe.Kind, pe.Axis = PointerAxisStop, ev.flags
527+ }
528+ }
529+ pe.Surface, pe.X, pe.Y = s.ptrSurf, s.px, s.py
530+ h.Pointer(pe)
531+}
532+
533+func (s *Seat) applyKeyboard(ev *event, h Handler) {
534+ kb := s.kb
535+ switch ev.kind {
536+ case evKbKeymap:
537+ fd := int(ev.fd)
538+ ev.fd = -1 // replaceFD consumes fd; the deferred closeFD must not touch the number again
539+ if ev.a != 1 || ev.flags == 0 || ev.flags > keymapMax {
540+ _ = unix.Close(fd)
541+ h.Error(errors.New("neferclient: unsupported keymap format or size"))
542+ return
543+ }
544+ if err := kb.replaceFD(fd, int(ev.flags)); err != nil {
545+ h.Error(fmt.Errorf("neferclient: keymap: %w", err))
546+ }
547+ case evKbEnter:
548+ sf := s.c.surfaceByObject(ev.global)
549+ if sf == nil {
550+ return
551+ }
552+ s.kbSurf = sf.id
553+ kb.setFocus(true)
554+ h.KeyboardFocus(sf.id, true)
555+ case evKbLeave:
556+ sf := s.c.surfaceByObject(ev.global)
557+ if sf == nil || s.kbSurf != sf.id {
558+ return
559+ }
560+ s.kbSurf = 0
561+ kb.setFocus(false)
562+ h.KeyboardFocus(sf.id, false)
563+ case evKbKey:
564+ ke := &s.kev
565+ *ke = KeyEvent{Surface: s.kbSurf}
566+ if ev.a == 1 {
567+ ok, err := kb.press(ev.flags, ke)
568+ switch {
569+ case err != nil:
570+ h.Error(err)
571+ case ok:
572+ s.deliverKey(ke, h)
573+ }
574+ } else if kb.release(ev.flags, ke) {
575+ s.deliverKey(ke, h)
576+ }
577+ case evKbModifiers:
578+ if err := kb.setMask(ev.flags, uint32(ev.dev), uint32(ev.dev>>32), uint32(ev.a)); err != nil {
579+ h.Error(err)
580+ }
581+ case evKbRepeat:
582+ kb.setRepeat(ev.a, ev.b)
583+ }
584+}
585+
586+func (c *Conn) closeSeat() {
587+ if s := c.seat; s != nil && s.kb != nil {
588+ s.kb.close()
589+ s.kb = nil
590+ }
591+}
@@ -0,0 +1,591 @@
1+package neferclient
2+
3+import (
4+ "errors"
5+ "fmt"
6+
7+ "github.com/bnema/go-wayland-bindings/client/cursorshape"
8+ "github.com/bnema/go-wayland-bindings/client/wayland"
9+ "github.com/bnema/wlturbo/wl"
10+ "golang.org/x/sys/unix"
11+)
12+
13+// maxSeatVersion is the wl_seat version bound: 9 adds axis_value120 users and
14+// the release requests.
15+const maxSeatVersion = 9
16+
17+// CursorShape is a wp_cursor_shape_v1 shape. The values are the protocol's.
18+type CursorShape uint32
19+
20+const (
21+ CursorDefault CursorShape = iota + 1
22+ CursorContextMenu
23+ CursorHelp
24+ CursorPointer
25+ CursorProgress
26+ CursorWait
27+ CursorCell
28+ CursorCrosshair
29+ CursorText
30+ CursorVerticalText
31+ CursorAlias
32+ CursorCopy
33+ CursorMove
34+ CursorNoDrop
35+ CursorNotAllowed
36+ CursorGrab
37+ CursorGrabbing
38+ CursorEResize
39+ CursorNResize
40+ CursorNEResize
41+ CursorNWResize
42+ CursorSResize
43+ CursorSEResize
44+ CursorSWResize
45+ CursorWResize
46+ CursorEWResize
47+ CursorNSResize
48+ CursorNESWResize
49+ CursorNWSEResize
50+ CursorColResize
51+ CursorRowResize
52+ CursorAllScroll
53+ CursorZoomIn
54+ CursorZoomOut
55+ CursorDndAsk // needs cursor-shape version 2
56+ CursorAllResize // needs cursor-shape version 2
57+)
58+
59+// PointerKind tells which pointer event a [PointerEvent] is.
60+type PointerKind uint8
61+
62+const (
63+ PointerEnter PointerKind = iota + 1
64+ PointerLeave
65+ PointerMotion
66+ PointerButton
67+ // PointerAxis is a scroll step on Axis. DX or DY carry the continuous
68+ // value in logical pixels; Value120 carries the wheel value in 1/120 of a
69+ // notch. A compositor can send both for one physical step: use one.
70+ PointerAxis
71+ // PointerAxisStop ends a scroll sequence on Axis.
72+ PointerAxisStop
73+)
74+
75+// Scroll axes of [PointerEvent.Axis].
76+const (
77+ AxisVertical = 0
78+ AxisHorizontal = 1
79+)
80+
81+// PointerEvent is one pointer event over a surface of the connection. X and Y
82+// are surface-local logical pixels (already logical: never divide by scale)
83+// and hold the latest position for every kind.
84+type PointerEvent struct {
85+ Surface SurfaceID
86+ Kind PointerKind
87+ X, Y float64
88+ DX, DY float64 // PointerAxis: continuous scroll value
89+ Button uint32 // PointerButton: evdev button code
90+ Pressed bool // PointerButton
91+ Axis uint32 // PointerAxis, PointerAxisStop: AxisVertical or AxisHorizontal
92+ Value120 int32 // PointerAxis: wheel value in 1/120 notches
93+}
94+
95+// KeyEvent is one key press, repeat or release.
96+type KeyEvent struct {
97+ Surface SurfaceID
98+ Keycode uint32 // evdev key code
99+ Keysym uint32 // xkb keysym in the current layout and modifier state
100+ Modifiers Modifiers
101+ Group uint32 // effective layout index
102+ Pressed bool
103+ Repeat bool
104+ // Text is the UTF-8 text of the key, nil for releases and keys without
105+ // text. It aliases library storage that is wiped when Handler.Key
106+ // returns. It is always nil while a [SecretBuffer] is installed.
107+ Text []byte
108+}
109+
110+// Seat is the connection's first wl_seat: pointer, keyboard and cursor. It
111+// belongs to the owner goroutine. Without a seat global every method is a
112+// no-op.
113+type Seat struct {
114+ c *Conn
115+ proxy *wayland.Seat
116+ name uint32 // registry name of the global
117+ ver uint32
118+
119+ pointer *wayland.Pointer
120+ ptrGen uint32 // generation of pointer; bumped on every create and drop
121+ ptrSurf SurfaceID
122+ px, py float64
123+ pev PointerEvent
124+
125+ keyboard *wayland.Keyboard
126+ kbGen uint32
127+ kbSurf SurfaceID
128+ kb *keyboard
129+ kev KeyEvent
130+
131+ secret *SecretBuffer
132+
133+ shapes *cursorshape.WpCursorShapeManager
134+ shapesVer uint32
135+ shapeDev *cursorshape.WpCursorShapeDevice
136+ enterSerial uint32 // latest pointer enter serial, 0 while outside
137+ shape CursorShape
138+}
139+
140+// Seat returns the connection's seat, binding wl_seat on first use. The seat
141+// is also bound when the first surface is created. Input starts flowing to the
142+// Handler once the compositor announces the capabilities.
143+func (c *Conn) Seat() *Seat {
144+ c.ensureSeat()
145+ return c.seat
146+}
147+
148+// ensureSeat binds wl_seat and the optional cursor-shape manager once. A
149+// failure is reported by the next Dispatch through Handler.Error.
150+func (c *Conn) ensureSeat() {
151+ if c.seat != nil || c.closed {
152+ return
153+ }
154+ s := &Seat{c: c}
155+ c.seat = s
156+ g, ok := c.display.Registry().FindGlobal(wayland.SeatInterface)
157+ if !ok {
158+ return
159+ }
160+ q := c.q
161+ proxy, v, err := c.Bind(wayland.SeatInterface, maxSeatVersion, func(ctx *wl.Context) *wayland.Seat {
162+ p := wayland.NewSeat(ctx)
163+ p.OnCapabilities(func(caps uint32) {
164+ e := event{kind: evSeatCaps, a: int32(caps)}
165+ q.post(&e)
166+ })
167+ return p
168+ })
169+ if err != nil {
170+ c.seatErr = fmt.Errorf("neferclient: bind wl_seat: %w", err)
171+ return
172+ }
173+ s.proxy, s.name, s.ver = proxy, g.Name, v
174+ m, mv, err := c.Bind(cursorshape.WpCursorShapeManagerInterface, 2, cursorshape.NewWpCursorShapeManager)
175+ if err != nil {
176+ if !errors.Is(err, ErrGlobalNotFound) {
177+ c.seatErr = fmt.Errorf("neferclient: bind cursor shape manager: %w", err)
178+ }
179+ return
180+ }
181+ s.shapes, s.shapesVer = m, mv
182+}
183+
184+// SetSecret installs b to receive typed text, or removes it with nil. While
185+// installed, printable text goes only into b and never into KeyEvent.Text;
186+// BackSpace removes one code point; every other key is still delivered as a
187+// KeyEvent without text. Installing or removing cancels held keys and repeat.
188+// The previous buffer is not wiped: that is the caller's call.
189+func (s *Seat) SetSecret(b *SecretBuffer) {
190+ s.secret = b
191+ if s.kb != nil {
192+ s.kb.setSecret(b)
193+ }
194+}
195+
196+// SetCursor asks the compositor to show shape for the pointer. It is a no-op
197+// when the compositor has no cursor-shape support, the pointer is outside the
198+// connection's surfaces, or shape is unchanged since the last enter.
199+func (s *Seat) SetCursor(shape CursorShape) error {
200+ if s.c.closed {
201+ return ErrClosed
202+ }
203+ limit := CursorZoomOut
204+ if s.shapesVer >= 2 {
205+ limit = CursorAllResize
206+ }
207+ if shape < CursorDefault || shape > CursorAllResize {
208+ return fmt.Errorf("neferclient: invalid cursor shape %d", shape)
209+ }
210+ if s.shapes == nil || s.pointer == nil || s.enterSerial == 0 || shape == s.shape {
211+ return nil
212+ }
213+ if shape > limit {
214+ return &CapabilityError{Name: cursorshape.WpCursorShapeManagerInterface, Cause: fmt.Errorf("shape %d requires version 2", shape)}
215+ }
216+ if s.shapeDev == nil {
217+ dev, err := s.shapes.GetPointer(s.pointer)
218+ if err != nil {
219+ return err
220+ }
221+ s.shapeDev = dev
222+ }
223+ if err := s.shapeDev.SetShape(s.enterSerial, uint32(shape)); err != nil {
224+ return err
225+ }
226+ s.shape = shape
227+ return nil
228+}
229+
230+// surfaceByObject finds the surface whose wl_surface has object id obj.
231+func (c *Conn) surfaceByObject(obj uint32) *Surface {
232+ for _, s := range c.surfaces {
233+ if !s.closed && s.surf != nil && s.surf.ID() == obj {
234+ return s
235+ }
236+ }
237+ return nil
238+}
239+
240+func (c *Conn) seatTimer(fd int32) bool {
241+ return c.seat != nil && c.seat.kb != nil && int(fd) == c.seat.kb.tfd
242+}
243+
244+// seatRepeat handles the repeat timer: at most one repeat per expiration.
245+func (c *Conn) seatRepeat(h Handler) {
246+ s := c.seat
247+ if s.kb.expired() {
248+ ke := &s.kev
249+ *ke = KeyEvent{Surface: s.kbSurf}
250+ ok, err := s.kb.repeat(ke)
251+ switch {
252+ case err != nil:
253+ h.Error(err)
254+ case ok:
255+ s.deliverKey(ke, h)
256+ }
257+ }
258+ if !c.closed {
259+ if err := c.armFD(s.kb.tfd, unix.EPOLL_CTL_MOD); err != nil {
260+ h.Error(err)
261+ }
262+ }
263+}
264+
265+func (s *Seat) deliverKey(ke *KeyEvent, h Handler) {
266+ h.Key(ke)
267+ clear(s.kb.scratch[:]) // ordinary text must not outlive the call
268+ ke.Text = nil
269+ if s.kb.changed {
270+ h.SecretChanged(s.secret.Len())
271+ }
272+}
273+
274+// seatSurfaceGone forgets focus on a closing surface.
275+func (c *Conn) seatSurfaceGone(sf *Surface) {
276+ s := c.seat
277+ if s == nil {
278+ return
279+ }
280+ if s.ptrSurf == sf.id {
281+ s.ptrSurf = 0
282+ s.enterSerial, s.shape = 0, 0
283+ }
284+ if s.kbSurf == sf.id {
285+ s.kbSurf = 0
286+ if s.kb != nil {
287+ s.kb.setFocus(false)
288+ }
289+ }
290+}
291+
292+func (c *Conn) seatGlobalRemoved(global uint32, h Handler) {
293+ if s := c.seat; s != nil && s.proxy != nil && s.name == global {
294+ s.release(h)
295+ }
296+}
297+
298+// release drops the devices and the seat proxy.
299+func (s *Seat) release(h Handler) {
300+ s.dropPointer(h)
301+ s.dropKeyboard(h)
302+ if s.ver >= 5 {
303+ _ = s.proxy.Release()
304+ } else {
305+ s.c.wlctx.Unregister(s.proxy)
306+ }
307+ s.proxy = nil
308+}
309+
310+func releaseDevice(ver uint32, c *wl.Context, p interface {
311+ wl.Proxy
312+ Release() error
313+}) {
314+ if ver >= 3 {
315+ _ = p.Release()
316+ } else {
317+ c.Unregister(p)
318+ }
319+}
320+
321+func (s *Seat) dropPointer(h Handler) {
322+ if s.pointer == nil {
323+ return
324+ }
325+ if s.shapeDev != nil {
326+ _ = s.shapeDev.Destroy()
327+ s.shapeDev = nil
328+ }
329+ s.enterSerial, s.shape = 0, 0
330+ releaseDevice(s.ver, s.c.wlctx, s.pointer)
331+ s.pointer = nil
332+ s.ptrGen++
333+ if id := s.ptrSurf; id != 0 {
334+ s.ptrSurf = 0
335+ pe := &s.pev
336+ *pe = PointerEvent{Surface: id, Kind: PointerLeave, X: s.px, Y: s.py}
337+ h.Pointer(pe)
338+ }
339+}
340+
341+func (s *Seat) dropKeyboard(h Handler) {
342+ if s.keyboard == nil {
343+ return
344+ }
345+ releaseDevice(s.ver, s.c.wlctx, s.keyboard)
346+ s.keyboard = nil
347+ s.kbGen++
348+ if id := s.kbSurf; id != 0 {
349+ s.kbSurf = 0
350+ s.kb.setFocus(false)
351+ h.KeyboardFocus(id, false)
352+ } else if s.kb != nil {
353+ s.kb.setFocus(false)
354+ }
355+}
356+
357+func (s *Seat) newPointer() error {
358+ c := s.c
359+ c.pause() // handlers go on after the request, before any event is read
360+ defer c.resume()
361+ p, err := s.proxy.GetPointer()
362+ if err != nil {
363+ return err
364+ }
365+ s.pointer = p
366+ s.ptrGen++
367+ gen, q := s.ptrGen, c.q
368+ post := func(e *event) {
369+ e.version = gen
370+ q.post(e)
371+ }
372+ p.OnEnter(func(serial, surf uint32, x, y wl.Fixed) {
373+ post(&event{kind: evPtrEnter, global: surf, serial: serial, a: int32(x), b: int32(y)})
374+ })
375+ p.OnLeave(func(_, surf uint32) { post(&event{kind: evPtrLeave, global: surf}) })
376+ p.OnMotion(func(_ uint32, x, y wl.Fixed) { post(&event{kind: evPtrMotion, a: int32(x), b: int32(y)}) })
377+ p.OnButton(func(serial, _, button, state uint32) {
378+ post(&event{kind: evPtrButton, serial: serial, flags: button, a: int32(state)})
379+ })
380+ p.OnAxis(func(_, axis uint32, v wl.Fixed) { post(&event{kind: evPtrAxis, flags: axis, a: int32(v)}) })
381+ p.OnAxisValue120(func(axis uint32, v int32) { post(&event{kind: evPtrAxisValue, flags: axis, a: v}) })
382+ p.OnAxisStop(func(_, axis uint32) { post(&event{kind: evPtrAxisStop, flags: axis}) })
383+ return nil
384+}
385+
386+func (s *Seat) newKeyboard() error {
387+ c := s.c
388+ if s.kb == nil {
389+ kb, err := newKeyboard(composeLocale())
390+ if err != nil {
391+ return err
392+ }
393+ if err = c.armFD(kb.tfd, unix.EPOLL_CTL_ADD); err != nil {
394+ kb.close()
395+ return err
396+ }
397+ kb.secret = s.secret
398+ s.kb = kb
399+ }
400+ c.pause()
401+ defer c.resume()
402+ k, err := s.proxy.GetKeyboard()
403+ if err != nil {
404+ return err
405+ }
406+ s.keyboard = k
407+ s.kbGen++
408+ gen, q := s.kbGen, c.q
409+ post := func(e *event) {
410+ e.version = gen
411+ q.post(e)
412+ }
413+ k.OnKeymap(func(format uint32, fd *wl.OwnedFD, size uint32) {
414+ n, err := fd.Take()
415+ if err != nil {
416+ post(&event{kind: evSeatBad, a: badKeymapFD})
417+ return
418+ }
419+ post(&event{kind: evKbKeymap, fd: int32(n), flags: size, a: int32(format)})
420+ })
421+ k.OnEnter(func(serial, surf uint32, _ []byte) { post(&event{kind: evKbEnter, global: surf, serial: serial}) })
422+ k.OnLeave(func(_, surf uint32) { post(&event{kind: evKbLeave, global: surf}) })
423+ k.OnKey(func(serial, _, key, state uint32) {
424+ post(&event{kind: evKbKey, serial: serial, flags: key, a: int32(state)})
425+ })
426+ k.OnModifiers(func(_, depressed, latched, locked, group uint32) {
427+ post(&event{kind: evKbModifiers, flags: depressed, dev: uint64(latched) | uint64(locked)<<32, a: int32(group)})
428+ })
429+ k.OnRepeatInfo(func(rate, delay int32) { post(&event{kind: evKbRepeat, a: rate, b: delay}) })
430+ return nil
431+}
432+
433+// Codes of evSeatBad.
434+const badKeymapFD int32 = 100
435+
436+// applySeat handles the seat events on the owner.
437+func (c *Conn) applySeat(ev *event, h Handler) {
438+ defer ev.closeFD()
439+ s := c.seat
440+ if s == nil {
441+ return
442+ }
443+ switch ev.kind {
444+ case evSeatBad:
445+ h.Error(errors.New("neferclient: keymap descriptor unavailable"))
446+ case evSeatCaps:
447+ s.applyCaps(uint32(ev.a), h)
448+ case evPtrEnter, evPtrLeave, evPtrMotion, evPtrButton, evPtrAxis, evPtrAxisValue, evPtrAxisStop:
449+ if s.pointer != nil && ev.version == s.ptrGen {
450+ s.applyPointer(ev, h)
451+ }
452+ default:
453+ if s.keyboard != nil && ev.version == s.kbGen {
454+ s.applyKeyboard(ev, h)
455+ }
456+ }
457+}
458+
459+func (s *Seat) applyCaps(caps uint32, h Handler) {
460+ if s.proxy == nil {
461+ return
462+ }
463+ if caps&1 == 0 {
464+ s.dropPointer(h)
465+ }
466+ if caps&2 == 0 {
467+ s.dropKeyboard(h)
468+ }
469+ if caps&1 != 0 && s.pointer == nil {
470+ if err := s.newPointer(); err != nil {
471+ h.Error(err)
472+ }
473+ }
474+ if caps&2 != 0 && s.keyboard == nil {
475+ if err := s.newKeyboard(); err != nil {
476+ h.Error(err)
477+ }
478+ }
479+}
480+
481+func (s *Seat) applyPointer(ev *event, h Handler) {
482+ pe := &s.pev
483+ *pe = PointerEvent{}
484+ fixed := func(v int32) float64 { return wl.Fixed(v).Float64() }
485+ switch ev.kind {
486+ case evPtrEnter:
487+ sf := s.c.surfaceByObject(ev.global)
488+ if sf == nil {
489+ return
490+ }
491+ s.ptrSurf = sf.id
492+ s.px, s.py = fixed(ev.a), fixed(ev.b)
493+ s.enterSerial, s.shape = ev.serial, 0 // the compositor forgets the cursor on leave
494+ pe.Kind = PointerEnter
495+ case evPtrLeave:
496+ if sf := s.c.surfaceByObject(ev.global); s.ptrSurf == 0 || sf == nil || sf.id != s.ptrSurf {
497+ return
498+ }
499+ pe.Kind = PointerLeave
500+ pe.Surface = s.ptrSurf
501+ pe.X, pe.Y = s.px, s.py
502+ s.ptrSurf = 0
503+ s.enterSerial, s.shape = 0, 0
504+ h.Pointer(pe)
505+ return
506+ default:
507+ if s.ptrSurf == 0 {
508+ return
509+ }
510+ switch ev.kind {
511+ case evPtrMotion:
512+ s.px, s.py = fixed(ev.a), fixed(ev.b)
513+ pe.Kind = PointerMotion
514+ case evPtrButton:
515+ pe.Kind, pe.Button, pe.Pressed = PointerButton, ev.flags, ev.a == 1
516+ case evPtrAxis:
517+ pe.Kind, pe.Axis = PointerAxis, ev.flags
518+ if ev.flags == AxisVertical {
519+ pe.DY = fixed(ev.a)
520+ } else {
521+ pe.DX = fixed(ev.a)
522+ }
523+ case evPtrAxisValue:
524+ pe.Kind, pe.Axis, pe.Value120 = PointerAxis, ev.flags, ev.a
525+ case evPtrAxisStop:
526+ pe.Kind, pe.Axis = PointerAxisStop, ev.flags
527+ }
528+ }
529+ pe.Surface, pe.X, pe.Y = s.ptrSurf, s.px, s.py
530+ h.Pointer(pe)
531+}
532+
533+func (s *Seat) applyKeyboard(ev *event, h Handler) {
534+ kb := s.kb
535+ switch ev.kind {
536+ case evKbKeymap:
537+ fd := int(ev.fd)
538+ ev.fd = -1 // replaceFD consumes fd; the deferred closeFD must not touch the number again
539+ if ev.a != 1 || ev.flags == 0 || ev.flags > keymapMax {
540+ _ = unix.Close(fd)
541+ h.Error(errors.New("neferclient: unsupported keymap format or size"))
542+ return
543+ }
544+ if err := kb.replaceFD(fd, int(ev.flags)); err != nil {
545+ h.Error(fmt.Errorf("neferclient: keymap: %w", err))
546+ }
547+ case evKbEnter:
548+ sf := s.c.surfaceByObject(ev.global)
549+ if sf == nil {
550+ return
551+ }
552+ s.kbSurf = sf.id
553+ kb.setFocus(true)
554+ h.KeyboardFocus(sf.id, true)
555+ case evKbLeave:
556+ sf := s.c.surfaceByObject(ev.global)
557+ if sf == nil || s.kbSurf != sf.id {
558+ return
559+ }
560+ s.kbSurf = 0
561+ kb.setFocus(false)
562+ h.KeyboardFocus(sf.id, false)
563+ case evKbKey:
564+ ke := &s.kev
565+ *ke = KeyEvent{Surface: s.kbSurf}
566+ if ev.a == 1 {
567+ ok, err := kb.press(ev.flags, ke)
568+ switch {
569+ case err != nil:
570+ h.Error(err)
571+ case ok:
572+ s.deliverKey(ke, h)
573+ }
574+ } else if kb.release(ev.flags, ke) {
575+ s.deliverKey(ke, h)
576+ }
577+ case evKbModifiers:
578+ if err := kb.setMask(ev.flags, uint32(ev.dev), uint32(ev.dev>>32), uint32(ev.a)); err != nil {
579+ h.Error(err)
580+ }
581+ case evKbRepeat:
582+ kb.setRepeat(ev.a, ev.b)
583+ }
584+}
585+
586+func (c *Conn) closeSeat() {
587+ if s := c.seat; s != nil && s.kb != nil {
588+ s.kb.close()
589+ s.kb = nil
590+ }
591+}
M surface.go +2 -0
@@ -236,6 +236,7 @@ func (c *Conn) newSurface(role surfaceRole, w, h int32) (*Surface, error) {
236236 if err := c.ensureCore(); err != nil {
237237 return nil, err
238238 }
239+ c.ensureSeat() // optional: input flows to the Handler once the seat is bound
239240 g := &c.g
240241 c.nextSurf++
241242 s := &Surface{c: c, id: c.nextSurf, role: role, width: w, height: h, scale: 1, sentBufScale: 1,
@@ -728,6 +729,7 @@ func (s *Surface) destroy() error {
728729 // server-side delete_id handling in wlturbo (see TestCloseWithPendingFrame).
729730 s.closed = true
730731 delete(s.c.surfaces, s.id)
732+ s.c.seatSurfaceGone(s)
731733 var errs []error
732734 add := func(err error) {
733735 if err != nil {
@@ -236,6 +236,7 @@ func (c *Conn) newSurface(role surfaceRole, w, h int32) (*Surface, error) {
236 if err := c.ensureCore(); err != nil {236 if err := c.ensureCore(); err != nil {
237 return nil, err237 return nil, err
238 }238 }
239+ c.ensureSeat() // optional: input flows to the Handler once the seat is bound
239 g := &c.g240 g := &c.g
240 c.nextSurf++241 c.nextSurf++
241 s := &Surface{c: c, id: c.nextSurf, role: role, width: w, height: h, scale: 1, sentBufScale: 1,242 s := &Surface{c: c, id: c.nextSurf, role: role, width: w, height: h, scale: 1, sentBufScale: 1,
@@ -728,6 +729,7 @@ func (s *Surface) destroy() error {
728 // server-side delete_id handling in wlturbo (see TestCloseWithPendingFrame).729 // server-side delete_id handling in wlturbo (see TestCloseWithPendingFrame).
729 s.closed = true730 s.closed = true
730 delete(s.c.surfaces, s.id)731 delete(s.c.surfaces, s.id)
732+ s.c.seatSurfaceGone(s)
731 var errs []error733 var errs []error
732 add := func(err error) {734 add := func(err error) {
733 if err != nil {735 if err != nil {
A testdata/fr.xkb +2084 -0
@@ -0,0 +1,2084 @@
1+xkb_keymap {
2+xkb_keycodes "evdev_aliases(azerty)" {
3+ minimum = 8;
4+ maximum = 709;
5+ <ESC> = 9;
6+ <AE01> = 10;
7+ <AE02> = 11;
8+ <AE03> = 12;
9+ <AE04> = 13;
10+ <AE05> = 14;
11+ <AE06> = 15;
12+ <AE07> = 16;
13+ <AE08> = 17;
14+ <AE09> = 18;
15+ <AE10> = 19;
16+ <AE11> = 20;
17+ <AE12> = 21;
18+ <BKSP> = 22;
19+ <TAB> = 23;
20+ <AD01> = 24;
21+ <AD02> = 25;
22+ <AD03> = 26;
23+ <AD04> = 27;
24+ <AD05> = 28;
25+ <AD06> = 29;
26+ <AD07> = 30;
27+ <AD08> = 31;
28+ <AD09> = 32;
29+ <AD10> = 33;
30+ <AD11> = 34;
31+ <AD12> = 35;
32+ <RTRN> = 36;
33+ <LCTL> = 37;
34+ <AC01> = 38;
35+ <AC02> = 39;
36+ <AC03> = 40;
37+ <AC04> = 41;
38+ <AC05> = 42;
39+ <AC06> = 43;
40+ <AC07> = 44;
41+ <AC08> = 45;
42+ <AC09> = 46;
43+ <AC10> = 47;
44+ <AC11> = 48;
45+ <TLDE> = 49;
46+ <LFSH> = 50;
47+ <BKSL> = 51;
48+ <AB01> = 52;
49+ <AB02> = 53;
50+ <AB03> = 54;
51+ <AB04> = 55;
52+ <AB05> = 56;
53+ <AB06> = 57;
54+ <AB07> = 58;
55+ <AB08> = 59;
56+ <AB09> = 60;
57+ <AB10> = 61;
58+ <RTSH> = 62;
59+ <KPMU> = 63;
60+ <LALT> = 64;
61+ <SPCE> = 65;
62+ <CAPS> = 66;
63+ <FK01> = 67;
64+ <FK02> = 68;
65+ <FK03> = 69;
66+ <FK04> = 70;
67+ <FK05> = 71;
68+ <FK06> = 72;
69+ <FK07> = 73;
70+ <FK08> = 74;
71+ <FK09> = 75;
72+ <FK10> = 76;
73+ <NMLK> = 77;
74+ <SCLK> = 78;
75+ <KP7> = 79;
76+ <KP8> = 80;
77+ <KP9> = 81;
78+ <KPSU> = 82;
79+ <KP4> = 83;
80+ <KP5> = 84;
81+ <KP6> = 85;
82+ <KPAD> = 86;
83+ <KP1> = 87;
84+ <KP2> = 88;
85+ <KP3> = 89;
86+ <KP0> = 90;
87+ <KPDL> = 91;
88+ <LVL3> = 92;
89+ <ZEHA> = 93;
90+ <LSGT> = 94;
91+ <FK11> = 95;
92+ <FK12> = 96;
93+ <AB11> = 97;
94+ <KATA> = 98;
95+ <HIRA> = 99;
96+ <HENK> = 100;
97+ <HKTG> = 101;
98+ <MUHE> = 102;
99+ <JPCM> = 103;
100+ <KPEN> = 104;
101+ <RCTL> = 105;
102+ <KPDV> = 106;
103+ <PRSC> = 107;
104+ <RALT> = 108;
105+ <LNFD> = 109;
106+ <HOME> = 110;
107+ <UP> = 111;
108+ <PGUP> = 112;
109+ <LEFT> = 113;
110+ <RGHT> = 114;
111+ <END> = 115;
112+ <DOWN> = 116;
113+ <PGDN> = 117;
114+ <INS> = 118;
115+ <DELE> = 119;
116+ <I120> = 120;
117+ <MUTE> = 121;
118+ <VOL-> = 122;
119+ <VOL+> = 123;
120+ <POWR> = 124;
121+ <KPEQ> = 125;
122+ <I126> = 126;
123+ <PAUS> = 127;
124+ <I128> = 128;
125+ <I129> = 129;
126+ <HNGL> = 130;
127+ <HJCV> = 131;
128+ <AE13> = 132;
129+ <LWIN> = 133;
130+ <RWIN> = 134;
131+ <COMP> = 135;
132+ <STOP> = 136;
133+ <AGAI> = 137;
134+ <PROP> = 138;
135+ <UNDO> = 139;
136+ <FRNT> = 140;
137+ <COPY> = 141;
138+ <OPEN> = 142;
139+ <PAST> = 143;
140+ <FIND> = 144;
141+ <CUT> = 145;
142+ <HELP> = 146;
143+ <I147> = 147;
144+ <I148> = 148;
145+ <I149> = 149;
146+ <I150> = 150;
147+ <I151> = 151;
148+ <I152> = 152;
149+ <I153> = 153;
150+ <I154> = 154;
151+ <I155> = 155;
152+ <I156> = 156;
153+ <I157> = 157;
154+ <I158> = 158;
155+ <I159> = 159;
156+ <I160> = 160;
157+ <I161> = 161;
158+ <I162> = 162;
159+ <I163> = 163;
160+ <I164> = 164;
161+ <I165> = 165;
162+ <I166> = 166;
163+ <I167> = 167;
164+ <I168> = 168;
165+ <I169> = 169;
166+ <I170> = 170;
167+ <I171> = 171;
168+ <I172> = 172;
169+ <I173> = 173;
170+ <I174> = 174;
171+ <I175> = 175;
172+ <I176> = 176;
173+ <I177> = 177;
174+ <I178> = 178;
175+ <I179> = 179;
176+ <I180> = 180;
177+ <I181> = 181;
178+ <I182> = 182;
179+ <I183> = 183;
180+ <I184> = 184;
181+ <I185> = 185;
182+ <I186> = 186;
183+ <I187> = 187;
184+ <I188> = 188;
185+ <I189> = 189;
186+ <I190> = 190;
187+ <FK13> = 191;
188+ <FK14> = 192;
189+ <FK15> = 193;
190+ <FK16> = 194;
191+ <FK17> = 195;
192+ <FK18> = 196;
193+ <FK19> = 197;
194+ <FK20> = 198;
195+ <FK21> = 199;
196+ <FK22> = 200;
197+ <FK23> = 201;
198+ <FK24> = 202;
199+ <LVL5> = 203;
200+ <ALT> = 204;
201+ <META> = 205;
202+ <SUPR> = 206;
203+ <HYPR> = 207;
204+ <I208> = 208;
205+ <I209> = 209;
206+ <I210> = 210;
207+ <I211> = 211;
208+ <I212> = 212;
209+ <I213> = 213;
210+ <I214> = 214;
211+ <I215> = 215;
212+ <I216> = 216;
213+ <I217> = 217;
214+ <I218> = 218;
215+ <I219> = 219;
216+ <I220> = 220;
217+ <I221> = 221;
218+ <I222> = 222;
219+ <I223> = 223;
220+ <I224> = 224;
221+ <I225> = 225;
222+ <I226> = 226;
223+ <I227> = 227;
224+ <I228> = 228;
225+ <I229> = 229;
226+ <I230> = 230;
227+ <I231> = 231;
228+ <I232> = 232;
229+ <I233> = 233;
230+ <I234> = 234;
231+ <I235> = 235;
232+ <I236> = 236;
233+ <I237> = 237;
234+ <I238> = 238;
235+ <I239> = 239;
236+ <I240> = 240;
237+ <I241> = 241;
238+ <I242> = 242;
239+ <I243> = 243;
240+ <I244> = 244;
241+ <I245> = 245;
242+ <I246> = 246;
243+ <I247> = 247;
244+ <I248> = 248;
245+ <I249> = 249;
246+ <I250> = 250;
247+ <I251> = 251;
248+ <I252> = 252;
249+ <I253> = 253;
250+ <I254> = 254;
251+ <I255> = 255;
252+ <I256> = 256;
253+ <I360> = 360;
254+ <I361> = 361;
255+ <I362> = 362;
256+ <I363> = 363;
257+ <I364> = 364;
258+ <I365> = 365;
259+ <I366> = 366;
260+ <I367> = 367;
261+ <I368> = 368;
262+ <I369> = 369;
263+ <I370> = 370;
264+ <I371> = 371;
265+ <I372> = 372;
266+ <I373> = 373;
267+ <I374> = 374;
268+ <I375> = 375;
269+ <I376> = 376;
270+ <I377> = 377;
271+ <I378> = 378;
272+ <I379> = 379;
273+ <I380> = 380;
274+ <I381> = 381;
275+ <I382> = 382;
276+ <I383> = 383;
277+ <I384> = 384;
278+ <I385> = 385;
279+ <I386> = 386;
280+ <I387> = 387;
281+ <I388> = 388;
282+ <I389> = 389;
283+ <I390> = 390;
284+ <I391> = 391;
285+ <I392> = 392;
286+ <I393> = 393;
287+ <I394> = 394;
288+ <I395> = 395;
289+ <I396> = 396;
290+ <I397> = 397;
291+ <I398> = 398;
292+ <I399> = 399;
293+ <I400> = 400;
294+ <I401> = 401;
295+ <I402> = 402;
296+ <I403> = 403;
297+ <I404> = 404;
298+ <I405> = 405;
299+ <I406> = 406;
300+ <I407> = 407;
301+ <I408> = 408;
302+ <I409> = 409;
303+ <I410> = 410;
304+ <I411> = 411;
305+ <I412> = 412;
306+ <I413> = 413;
307+ <I414> = 414;
308+ <I415> = 415;
309+ <I416> = 416;
310+ <I417> = 417;
311+ <I418> = 418;
312+ <I419> = 419;
313+ <I420> = 420;
314+ <I421> = 421;
315+ <I422> = 422;
316+ <I423> = 423;
317+ <I424> = 424;
318+ <I425> = 425;
319+ <I426> = 426;
320+ <I427> = 427;
321+ <I428> = 428;
322+ <I429> = 429;
323+ <I430> = 430;
324+ <I431> = 431;
325+ <I432> = 432;
326+ <I433> = 433;
327+ <I434> = 434;
328+ <I435> = 435;
329+ <I436> = 436;
330+ <I437> = 437;
331+ <I438> = 438;
332+ <I439> = 439;
333+ <I440> = 440;
334+ <I441> = 441;
335+ <I442> = 442;
336+ <I443> = 443;
337+ <I444> = 444;
338+ <I445> = 445;
339+ <I446> = 446;
340+ <I447> = 447;
341+ <I448> = 448;
342+ <I449> = 449;
343+ <I450> = 450;
344+ <I452> = 452;
345+ <I453> = 453;
346+ <I454> = 454;
347+ <I455> = 455;
348+ <I456> = 456;
349+ <I457> = 457;
350+ <I458> = 458;
351+ <I459> = 459;
352+ <I472> = 472;
353+ <I473> = 473;
354+ <I474> = 474;
355+ <I475> = 475;
356+ <I476> = 476;
357+ <I477> = 477;
358+ <I478> = 478;
359+ <I479> = 479;
360+ <I480> = 480;
361+ <I481> = 481;
362+ <I482> = 482;
363+ <I483> = 483;
364+ <I484> = 484;
365+ <I485> = 485;
366+ <I486> = 486;
367+ <I487> = 487;
368+ <I488> = 488;
369+ <I489> = 489;
370+ <I490> = 490;
371+ <I491> = 491;
372+ <I492> = 492;
373+ <I493> = 493;
374+ <I505> = 505;
375+ <I506> = 506;
376+ <I507> = 507;
377+ <I508> = 508;
378+ <I509> = 509;
379+ <I510> = 510;
380+ <I511> = 511;
381+ <I512> = 512;
382+ <I513> = 513;
383+ <I514> = 514;
384+ <I520> = 520;
385+ <I521> = 521;
386+ <I522> = 522;
387+ <I523> = 523;
388+ <I524> = 524;
389+ <I525> = 525;
390+ <I526> = 526;
391+ <I527> = 527;
392+ <I528> = 528;
393+ <I529> = 529;
394+ <I530> = 530;
395+ <I531> = 531;
396+ <I532> = 532;
397+ <I533> = 533;
398+ <I534> = 534;
399+ <I535> = 535;
400+ <I536> = 536;
401+ <I537> = 537;
402+ <I538> = 538;
403+ <I539> = 539;
404+ <I540> = 540;
405+ <I541> = 541;
406+ <I542> = 542;
407+ <I543> = 543;
408+ <I544> = 544;
409+ <I545> = 545;
410+ <I546> = 546;
411+ <I547> = 547;
412+ <I548> = 548;
413+ <I549> = 549;
414+ <I550> = 550;
415+ <I568> = 568;
416+ <I569> = 569;
417+ <I570> = 570;
418+ <I584> = 584;
419+ <I585> = 585;
420+ <I586> = 586;
421+ <I587> = 587;
422+ <I588> = 588;
423+ <I589> = 589;
424+ <I590> = 590;
425+ <I591> = 591;
426+ <I592> = 592;
427+ <I593> = 593;
428+ <I594> = 594;
429+ <I595> = 595;
430+ <I596> = 596;
431+ <I597> = 597;
432+ <I598> = 598;
433+ <I599> = 599;
434+ <I600> = 600;
435+ <I601> = 601;
436+ <I602> = 602;
437+ <I603> = 603;
438+ <I604> = 604;
439+ <I605> = 605;
440+ <I606> = 606;
441+ <I616> = 616;
442+ <I617> = 617;
443+ <I618> = 618;
444+ <I619> = 619;
445+ <I620> = 620;
446+ <I621> = 621;
447+ <I622> = 622;
448+ <I623> = 623;
449+ <I624> = 624;
450+ <I625> = 625;
451+ <I626> = 626;
452+ <I627> = 627;
453+ <I628> = 628;
454+ <I629> = 629;
455+ <I630> = 630;
456+ <I631> = 631;
457+ <I632> = 632;
458+ <I633> = 633;
459+ <I634> = 634;
460+ <I635> = 635;
461+ <I636> = 636;
462+ <I637> = 637;
463+ <I638> = 638;
464+ <I639> = 639;
465+ <I640> = 640;
466+ <I641> = 641;
467+ <I642> = 642;
468+ <I643> = 643;
469+ <I644> = 644;
470+ <I645> = 645;
471+ <I646> = 646;
472+ <I647> = 647;
473+ <I648> = 648;
474+ <I649> = 649;
475+ <I650> = 650;
476+ <I651> = 651;
477+ <I652> = 652;
478+ <I653> = 653;
479+ <I654> = 654;
480+ <I655> = 655;
481+ <I656> = 656;
482+ <I657> = 657;
483+ <I664> = 664;
484+ <I665> = 665;
485+ <I666> = 666;
486+ <I667> = 667;
487+ <I668> = 668;
488+ <I669> = 669;
489+ <I670> = 670;
490+ <I671> = 671;
491+ <I672> = 672;
492+ <I673> = 673;
493+ <I674> = 674;
494+ <I675> = 675;
495+ <I676> = 676;
496+ <I677> = 677;
497+ <I678> = 678;
498+ <I679> = 679;
499+ <I680> = 680;
500+ <I681> = 681;
501+ <I682> = 682;
502+ <I683> = 683;
503+ <I684> = 684;
504+ <I685> = 685;
505+ <I686> = 686;
506+ <I687> = 687;
507+ <I688> = 688;
508+ <I689> = 689;
509+ <I690> = 690;
510+ <I691> = 691;
511+ <I692> = 692;
512+ <I693> = 693;
513+ <I696> = 696;
514+ <I697> = 697;
515+ <I698> = 698;
516+ <I699> = 699;
517+ <I700> = 700;
518+ <I701> = 701;
519+ <I704> = 704;
520+ <I705> = 705;
521+ <I706> = 706;
522+ <I707> = 707;
523+ <I708> = 708;
524+ <I709> = 709;
525+ indicator 1 = "Caps Lock";
526+ indicator 2 = "Num Lock";
527+ indicator 3 = "Scroll Lock";
528+ indicator 4 = "Compose";
529+ indicator 5 = "Kana";
530+ indicator 6 = "Sleep";
531+ indicator 7 = "Suspend";
532+ indicator 8 = "Mute";
533+ indicator 9 = "Misc";
534+ indicator 10 = "Mail";
535+ indicator 11 = "Charging";
536+ indicator 12 = "Shift Lock";
537+ indicator 13 = "Group 2";
538+ indicator 14 = "Mouse Keys";
539+ alias <AC12> = <BKSL>;
540+ alias <ALGR> = <RALT>;
541+ alias <MENU> = <COMP>;
542+ alias <HZTG> = <TLDE>;
543+ alias <LMTA> = <LWIN>;
544+ alias <RMTA> = <RWIN>;
545+ alias <OUTP> = <I235>;
546+ alias <KITG> = <I236>;
547+ alias <KIDN> = <I237>;
548+ alias <KIUP> = <I238>;
549+ alias <I121> = <MUTE>;
550+ alias <I122> = <VOL->;
551+ alias <I123> = <VOL+>;
552+ alias <I124> = <POWR>;
553+ alias <I125> = <KPEQ>;
554+ alias <I127> = <PAUS>;
555+ alias <I130> = <HNGL>;
556+ alias <I131> = <HJCV>;
557+ alias <I132> = <AE13>;
558+ alias <I133> = <LWIN>;
559+ alias <I134> = <RWIN>;
560+ alias <I135> = <COMP>;
561+ alias <I136> = <STOP>;
562+ alias <I137> = <AGAI>;
563+ alias <I138> = <PROP>;
564+ alias <I139> = <UNDO>;
565+ alias <I140> = <FRNT>;
566+ alias <I141> = <COPY>;
567+ alias <I142> = <OPEN>;
568+ alias <I143> = <PAST>;
569+ alias <I144> = <FIND>;
570+ alias <I145> = <CUT>;
571+ alias <I146> = <HELP>;
572+ alias <I191> = <FK13>;
573+ alias <I192> = <FK14>;
574+ alias <I193> = <FK15>;
575+ alias <I194> = <FK16>;
576+ alias <I195> = <FK17>;
577+ alias <I196> = <FK18>;
578+ alias <I197> = <FK19>;
579+ alias <I198> = <FK20>;
580+ alias <I199> = <FK21>;
581+ alias <I200> = <FK22>;
582+ alias <I201> = <FK23>;
583+ alias <I202> = <FK24>;
584+ alias <MDSW> = <LVL5>;
585+ alias <KPPT> = <I129>;
586+ alias <LatQ> = <AC01>;
587+ alias <LatW> = <AB01>;
588+ alias <LatE> = <AD03>;
589+ alias <LatR> = <AD04>;
590+ alias <LatT> = <AD05>;
591+ alias <LatY> = <AD06>;
592+ alias <LatU> = <AD07>;
593+ alias <LatI> = <AD08>;
594+ alias <LatO> = <AD09>;
595+ alias <LatP> = <AD10>;
596+ alias <LatA> = <AD01>;
597+ alias <LatS> = <AC02>;
598+ alias <LatD> = <AC03>;
599+ alias <LatF> = <AC04>;
600+ alias <LatG> = <AC05>;
601+ alias <LatH> = <AC06>;
602+ alias <LatJ> = <AC07>;
603+ alias <LatK> = <AC08>;
604+ alias <LatL> = <AC09>;
605+ alias <LatZ> = <AD02>;
606+ alias <LatX> = <AB02>;
607+ alias <LatC> = <AB03>;
608+ alias <LatV> = <AB04>;
609+ alias <LatB> = <AB05>;
610+ alias <LatN> = <AB06>;
611+ alias <LatM> = <AC10>;
612+};
613+
614+xkb_types "complete" {
615+ virtual_modifiers NumLock,Alt,LevelThree,Super,LevelFive,Meta,Hyper=0x4000,ScrollLock=0x8000;
616+
617+ type "ONE_LEVEL" {
618+ modifiers= none;
619+ level_name[1]= "Any";
620+ };
621+ type "TWO_LEVEL" {
622+ modifiers= Shift;
623+ map[Shift]= 2;
624+ level_name[1]= "Base";
625+ level_name[2]= "Shift";
626+ };
627+ type "ALPHABETIC" {
628+ modifiers= Shift+Lock;
629+ map[Shift]= 2;
630+ map[Lock]= 2;
631+ level_name[1]= "Base";
632+ level_name[2]= "Caps";
633+ };
634+ type "PC_ALT_LEVEL2" {
635+ modifiers= Alt;
636+ map[Alt]= 2;
637+ level_name[1]= "Base";
638+ level_name[2]= "Alt";
639+ };
640+ type "PC_SUPER_LEVEL2" {
641+ modifiers= Super;
642+ map[Super]= 2;
643+ level_name[1]= "Base";
644+ level_name[2]= "Super";
645+ };
646+ type "PC_SHIFT_SUPER_LEVEL2" {
647+ modifiers= Shift+Super;
648+ map[Shift+Super]= 2;
649+ map[Shift]= 1;
650+ preserve[Shift]= Shift;
651+ map[Super]= 1;
652+ preserve[Super]= Super;
653+ level_name[1]= "Base";
654+ level_name[2]= "Super";
655+ };
656+ type "PC_CONTROL_LEVEL2" {
657+ modifiers= Control;
658+ map[Control]= 2;
659+ level_name[1]= "Base";
660+ level_name[2]= "Control";
661+ };
662+ type "PC_CONTROL_SUPER_LEVEL2" {
663+ modifiers= Control+Super;
664+ map[Control+Super]= 2;
665+ map[Control]= 1;
666+ preserve[Control]= Control;
667+ map[Super]= 1;
668+ preserve[Super]= Super;
669+ level_name[1]= "Base";
670+ level_name[2]= "Control + Super";
671+ };
672+ type "CTRL+ALT" {
673+ modifiers= Shift+Control+Alt+LevelThree;
674+ map[Shift]= 2;
675+ map[LevelThree]= 3;
676+ map[Shift+LevelThree]= 4;
677+ map[Control]= 1;
678+ preserve[Control]= Control;
679+ map[Shift+Control]= 2;
680+ preserve[Shift+Control]= Control;
681+ map[Control+LevelThree]= 3;
682+ preserve[Control+LevelThree]= Control;
683+ map[Shift+Control+LevelThree]= 4;
684+ preserve[Shift+Control+LevelThree]= Control;
685+ map[Alt]= 1;
686+ preserve[Alt]= Alt;
687+ map[Shift+Alt]= 2;
688+ preserve[Shift+Alt]= Alt;
689+ map[Alt+LevelThree]= 3;
690+ preserve[Alt+LevelThree]= Alt;
691+ map[Shift+Alt+LevelThree]= 4;
692+ preserve[Shift+Alt+LevelThree]= Alt;
693+ map[Control+Alt]= 5;
694+ map[Shift+Control+Alt]= 2;
695+ preserve[Shift+Control+Alt]= Control+Alt;
696+ map[Control+Alt+LevelThree]= 3;
697+ preserve[Control+Alt+LevelThree]= Control+Alt;
698+ map[Shift+Control+Alt+LevelThree]= 4;
699+ preserve[Shift+Control+Alt+LevelThree]= Control+Alt;
700+ level_name[1]= "Base";
701+ level_name[2]= "Shift";
702+ level_name[3]= "AltGr";
703+ level_name[4]= "Shift AltGr";
704+ level_name[5]= "Ctrl+Alt";
705+ };
706+ type "THREE_LEVEL" {
707+ modifiers= Shift+LevelThree;
708+ map[Shift]= 2;
709+ map[LevelThree]= 3;
710+ map[Shift+LevelThree]= 3;
711+ level_name[1]= "Base";
712+ level_name[2]= "Shift";
713+ level_name[3]= "Level3";
714+ };
715+ type "FOUR_LEVEL" {
716+ modifiers= Shift+LevelThree;
717+ map[Shift]= 2;
718+ map[LevelThree]= 3;
719+ map[Shift+LevelThree]= 4;
720+ level_name[1]= "Base";
721+ level_name[2]= "Shift";
722+ level_name[3]= "AltGr";
723+ level_name[4]= "Shift AltGr";
724+ };
725+ type "FOUR_LEVEL_ALPHABETIC" {
726+ modifiers= Shift+Lock+LevelThree;
727+ map[Shift]= 2;
728+ map[Lock]= 2;
729+ map[LevelThree]= 3;
730+ map[Shift+LevelThree]= 4;
731+ map[Lock+LevelThree]= 4;
732+ map[Shift+Lock+LevelThree]= 3;
733+ level_name[1]= "Base";
734+ level_name[2]= "Shift";
735+ level_name[3]= "AltGr";
736+ level_name[4]= "Shift AltGr";
737+ };
738+ type "FOUR_LEVEL_SEMIALPHABETIC" {
739+ modifiers= Shift+Lock+LevelThree;
740+ map[Shift]= 2;
741+ map[Lock]= 2;
742+ map[LevelThree]= 3;
743+ map[Shift+LevelThree]= 4;
744+ map[Lock+LevelThree]= 3;
745+ preserve[Lock+LevelThree]= Lock;
746+ map[Shift+Lock+LevelThree]= 4;
747+ preserve[Shift+Lock+LevelThree]= Lock;
748+ level_name[1]= "Base";
749+ level_name[2]= "Shift";
750+ level_name[3]= "AltGr";
751+ level_name[4]= "Shift AltGr";
752+ };
753+ type "FOUR_LEVEL_KEYPAD" {
754+ modifiers= Shift+NumLock+LevelThree;
755+ map[Shift]= 1;
756+ preserve[Shift]= Shift;
757+ map[NumLock]= 2;
758+ map[LevelThree]= 3;
759+ map[Shift+NumLock]= 2;
760+ preserve[Shift+NumLock]= Shift;
761+ map[Shift+LevelThree]= 4;
762+ map[NumLock+LevelThree]= 3;
763+ map[Shift+NumLock+LevelThree]= 4;
764+ level_name[1]= "Base";
765+ level_name[2]= "NumLock";
766+ level_name[3]= "AltGr";
767+ level_name[4]= "Shift AltGr";
768+ };
769+ type "FOUR_LEVEL_MIXED_KEYPAD" {
770+ modifiers= Shift+NumLock+LevelThree;
771+ map[Shift]= 1;
772+ preserve[Shift]= Shift;
773+ map[NumLock]= 2;
774+ map[LevelThree]= 3;
775+ map[Shift+NumLock]= 2;
776+ preserve[Shift+NumLock]= Shift;
777+ map[Shift+LevelThree]= 4;
778+ map[NumLock+LevelThree]= 3;
779+ map[Shift+NumLock+LevelThree]= 4;
780+ level_name[1]= "Base";
781+ level_name[2]= "NumLock";
782+ level_name[3]= "AltGr";
783+ level_name[4]= "Shift AltGr";
784+ };
785+ type "FOUR_LEVEL_LOCKABLE_LEVEL2" {
786+ modifiers= Shift+LevelThree+LevelFive;
787+ map[Shift]= 2;
788+ map[LevelFive]= 2;
789+ map[LevelThree]= 3;
790+ map[Shift+LevelThree]= 4;
791+ map[LevelThree+LevelFive]= 3;
792+ map[Shift+LevelThree+LevelFive]= 4;
793+ level_name[1]= "Base";
794+ level_name[2]= "Digit";
795+ level_name[3]= "AltGr";
796+ level_name[4]= "Shift AltGr";
797+ };
798+ type "FOUR_LEVEL_X" {
799+ modifiers= Shift+Control+Alt+LevelThree;
800+ map[Shift]= 1;
801+ preserve[Shift]= Shift;
802+ map[LevelThree]= 2;
803+ map[Control]= 1;
804+ preserve[Control]= Control;
805+ map[Alt]= 1;
806+ preserve[Alt]= Alt;
807+ map[Shift+LevelThree]= 3;
808+ map[Shift+Control]= 1;
809+ preserve[Shift+Control]= Shift+Control;
810+ map[Shift+Alt]= 1;
811+ preserve[Shift+Alt]= Shift+Alt;
812+ map[Control+LevelThree]= 2;
813+ preserve[Control+LevelThree]= Control;
814+ map[Alt+LevelThree]= 2;
815+ preserve[Alt+LevelThree]= Alt;
816+ map[Control+Alt]= 4;
817+ map[Shift+Control+LevelThree]= 3;
818+ preserve[Shift+Control+LevelThree]= Control;
819+ map[Shift+Alt+LevelThree]= 3;
820+ preserve[Shift+Alt+LevelThree]= Alt;
821+ map[Shift+Control+Alt]= 4;
822+ preserve[Shift+Control+Alt]= Shift;
823+ map[Control+Alt+LevelThree]= 2;
824+ preserve[Control+Alt+LevelThree]= Control+Alt;
825+ map[Shift+Control+Alt+LevelThree]= 3;
826+ preserve[Shift+Control+Alt+LevelThree]= Control+Alt;
827+ level_name[1]= "Base";
828+ level_name[2]= "AltGr";
829+ level_name[3]= "Shift AltGr";
830+ level_name[4]= "Ctrl+Alt";
831+ };
832+ type "SEPARATE_CAPS_AND_SHIFT_ALPHABETIC" {
833+ modifiers= Shift+Lock+LevelThree;
834+ map[Shift]= 2;
835+ map[Lock]= 4;
836+ preserve[Lock]= Lock;
837+ map[LevelThree]= 3;
838+ map[Shift+LevelThree]= 4;
839+ map[Lock+LevelThree]= 3;
840+ preserve[Lock+LevelThree]= Lock;
841+ map[Shift+Lock+LevelThree]= 3;
842+ level_name[1]= "Base";
843+ level_name[2]= "Shift";
844+ level_name[3]= "AltGr";
845+ level_name[4]= "Caps / Shift AltGr";
846+ };
847+ type "FOUR_LEVEL_PLUS_LOCK" {
848+ modifiers= Shift+Lock+LevelThree;
849+ map[Shift]= 2;
850+ map[LevelThree]= 3;
851+ map[Shift+LevelThree]= 4;
852+ map[Lock]= 5;
853+ map[Shift+Lock]= 2;
854+ map[Lock+LevelThree]= 3;
855+ map[Shift+Lock+LevelThree]= 4;
856+ level_name[1]= "Base";
857+ level_name[2]= "Shift";
858+ level_name[3]= "AltGr";
859+ level_name[4]= "Shift AltGr";
860+ level_name[5]= "Lock";
861+ };
862+ type "EIGHT_LEVEL" {
863+ modifiers= Shift+LevelThree+LevelFive;
864+ map[Shift]= 2;
865+ map[LevelThree]= 3;
866+ map[Shift+LevelThree]= 4;
867+ map[LevelFive]= 5;
868+ map[Shift+LevelFive]= 6;
869+ map[LevelThree+LevelFive]= 7;
870+ map[Shift+LevelThree+LevelFive]= 8;
871+ level_name[1]= "Base";
872+ level_name[2]= "Shift";
873+ level_name[3]= "AltGr";
874+ level_name[4]= "Shift AltGr";
875+ level_name[5]= "X";
876+ level_name[6]= "X Shift";
877+ level_name[7]= "X AltGr";
878+ level_name[8]= "X Shift AltGr";
879+ };
880+ type "EIGHT_LEVEL_ALPHABETIC" {
881+ modifiers= Shift+Lock+LevelThree+LevelFive;
882+ map[Shift]= 2;
883+ map[Lock]= 2;
884+ map[LevelThree]= 3;
885+ map[Shift+LevelThree]= 4;
886+ map[Lock+LevelThree]= 4;
887+ map[Shift+Lock+LevelThree]= 3;
888+ map[LevelFive]= 5;
889+ map[Shift+LevelFive]= 6;
890+ map[Lock+LevelFive]= 6;
891+ map[Shift+Lock+LevelFive]= 5;
892+ map[LevelThree+LevelFive]= 7;
893+ map[Shift+LevelThree+LevelFive]= 8;
894+ map[Lock+LevelThree+LevelFive]= 8;
895+ map[Shift+Lock+LevelThree+LevelFive]= 7;
896+ level_name[1]= "Base";
897+ level_name[2]= "Shift";
898+ level_name[3]= "AltGr";
899+ level_name[4]= "Shift AltGr";
900+ level_name[5]= "X";
901+ level_name[6]= "X Shift";
902+ level_name[7]= "X AltGr";
903+ level_name[8]= "X Shift AltGr";
904+ };
905+ type "EIGHT_LEVEL_SEMIALPHABETIC" {
906+ modifiers= Shift+Lock+LevelThree+LevelFive;
907+ map[Shift]= 2;
908+ map[Lock]= 2;
909+ map[LevelThree]= 3;
910+ map[Shift+LevelThree]= 4;
911+ map[Lock+LevelThree]= 3;
912+ preserve[Lock+LevelThree]= Lock;
913+ map[Shift+Lock+LevelThree]= 4;
914+ preserve[Shift+Lock+LevelThree]= Lock;
915+ map[LevelFive]= 5;
916+ map[Shift+LevelFive]= 6;
917+ map[Lock+LevelFive]= 6;
918+ map[Shift+Lock+LevelFive]= 5;
919+ map[LevelThree+LevelFive]= 7;
920+ map[Shift+LevelThree+LevelFive]= 8;
921+ map[Lock+LevelThree+LevelFive]= 7;
922+ preserve[Lock+LevelThree+LevelFive]= Lock;
923+ map[Shift+Lock+LevelThree+LevelFive]= 8;
924+ preserve[Shift+Lock+LevelThree+LevelFive]= Lock;
925+ level_name[1]= "Base";
926+ level_name[2]= "Shift";
927+ level_name[3]= "AltGr";
928+ level_name[4]= "Shift AltGr";
929+ level_name[5]= "X";
930+ level_name[6]= "X Shift";
931+ level_name[7]= "X AltGr";
932+ level_name[8]= "X Shift AltGr";
933+ };
934+ type "EIGHT_LEVEL_WITH_LEVEL5_LOCK" {
935+ modifiers= Shift+NumLock+LevelThree+LevelFive;
936+ map[Shift]= 2;
937+ map[LevelThree]= 3;
938+ map[Shift+LevelThree]= 4;
939+ map[LevelFive]= 5;
940+ map[Shift+LevelFive]= 6;
941+ preserve[Shift+LevelFive]= Shift;
942+ map[LevelThree+LevelFive]= 7;
943+ map[Shift+LevelThree+LevelFive]= 8;
944+ map[NumLock]= 5;
945+ map[Shift+NumLock]= 6;
946+ preserve[Shift+NumLock]= Shift;
947+ map[NumLock+LevelThree]= 7;
948+ map[Shift+NumLock+LevelThree]= 8;
949+ map[Shift+NumLock+LevelFive]= 2;
950+ map[NumLock+LevelThree+LevelFive]= 3;
951+ map[Shift+NumLock+LevelThree+LevelFive]= 4;
952+ level_name[1]= "Base";
953+ level_name[2]= "Shift";
954+ level_name[3]= "AltGr";
955+ level_name[4]= "Shift AltGr";
956+ level_name[5]= "X";
957+ level_name[6]= "X Shift";
958+ level_name[7]= "X AltGr";
959+ level_name[8]= "X Shift AltGr";
960+ };
961+ type "EIGHT_LEVEL_ALPHABETIC_WITH_LEVEL5_LOCK" {
962+ modifiers= Shift+Lock+NumLock+LevelThree+LevelFive;
963+ map[Shift]= 2;
964+ map[LevelThree]= 3;
965+ map[Shift+LevelThree]= 4;
966+ map[LevelFive]= 5;
967+ map[Shift+LevelFive]= 6;
968+ preserve[Shift+LevelFive]= Shift;
969+ map[LevelThree+LevelFive]= 7;
970+ map[Shift+LevelThree+LevelFive]= 8;
971+ map[NumLock]= 5;
972+ map[Shift+NumLock]= 6;
973+ preserve[Shift+NumLock]= Shift;
974+ map[NumLock+LevelThree]= 7;
975+ map[Shift+NumLock+LevelThree]= 8;
976+ map[Shift+NumLock+LevelFive]= 2;
977+ map[NumLock+LevelThree+LevelFive]= 3;
978+ map[Shift+NumLock+LevelThree+LevelFive]= 4;
979+ map[Lock]= 2;
980+ map[Lock+LevelThree]= 3;
981+ map[Shift+Lock+LevelThree]= 4;
982+ map[Lock+LevelFive]= 5;
983+ map[Shift+Lock+LevelFive]= 6;
984+ map[Lock+LevelThree+LevelFive]= 7;
985+ map[Shift+Lock+LevelThree+LevelFive]= 8;
986+ map[Lock+NumLock]= 5;
987+ map[Shift+Lock+NumLock]= 6;
988+ map[Lock+NumLock+LevelThree]= 7;
989+ map[Shift+Lock+NumLock+LevelThree]= 8;
990+ map[Lock+NumLock+LevelFive]= 2;
991+ map[Lock+NumLock+LevelThree+LevelFive]= 3;
992+ map[Shift+Lock+NumLock+LevelThree+LevelFive]= 4;
993+ level_name[1]= "Base";
994+ level_name[2]= "Shift";
995+ level_name[3]= "AltGr";
996+ level_name[4]= "Shift AltGr";
997+ level_name[5]= "X";
998+ level_name[6]= "X Shift";
999+ level_name[7]= "X AltGr";
1000+ level_name[8]= "X Shift AltGr";
1001+ };
1002+ type "EIGHT_LEVEL_BY_CTRL" {
1003+ modifiers= Shift+Lock+Control+LevelThree;
1004+ map[Shift]= 2;
1005+ map[Lock]= 2;
1006+ map[LevelThree]= 3;
1007+ map[Shift+LevelThree]= 4;
1008+ map[Lock+LevelThree]= 4;
1009+ map[Shift+Lock+LevelThree]= 3;
1010+ map[Control]= 5;
1011+ map[Shift+Control]= 6;
1012+ map[Lock+Control]= 6;
1013+ map[Shift+Lock+Control]= 5;
1014+ map[Control+LevelThree]= 7;
1015+ map[Shift+Control+LevelThree]= 8;
1016+ map[Lock+Control+LevelThree]= 8;
1017+ map[Shift+Lock+Control+LevelThree]= 7;
1018+ level_name[1]= "Base";
1019+ level_name[2]= "Shift";
1020+ level_name[3]= "Level3";
1021+ level_name[4]= "Shift Level3";
1022+ level_name[5]= "Ctrl";
1023+ level_name[6]= "Shift Ctrl";
1024+ level_name[7]= "Level3 Ctrl";
1025+ level_name[8]= "Shift Level3 Ctrl";
1026+ };
1027+ type "KEYPAD" {
1028+ modifiers= NumLock;
1029+ map[NumLock]= 2;
1030+ level_name[1]= "Base";
1031+ level_name[2]= "Number";
1032+ };
1033+ type "SHIFT+ALT" {
1034+ modifiers= Shift+Alt;
1035+ map[Shift+Alt]= 2;
1036+ level_name[1]= "Base";
1037+ level_name[2]= "Shift+Alt";
1038+ };
1039+};
1040+
1041+xkb_compatibility "complete" {
1042+ virtual_modifiers NumLock,Alt,LevelThree,Super,LevelFive,Meta,Hyper=0x4000,ScrollLock=0x8000;
1043+
1044+ interpret.useModMapMods= AnyLevel;
1045+ interpret.repeat= False;
1046+ interpret ISO_Level2_Latch+Exactly(Shift) {
1047+ useModMapMods=level1;
1048+ action= LatchMods(modifiers=Shift,clearLocks,latchToLock);
1049+ };
1050+ interpret Shift_Lock+AnyOf(Shift+Lock) {
1051+ action= LockMods(modifiers=Shift);
1052+ };
1053+ interpret Num_Lock+AnyOf(all) {
1054+ virtualModifier= NumLock;
1055+ action= LockMods(modifiers=NumLock);
1056+ };
1057+ interpret ISO_Level3_Shift+AnyOf(all) {
1058+ virtualModifier= LevelThree;
1059+ useModMapMods=level1;
1060+ action= SetMods(modifiers=LevelThree,clearLocks);
1061+ };
1062+ interpret ISO_Level3_Latch+AnyOf(all) {
1063+ virtualModifier= LevelThree;
1064+ useModMapMods=level1;
1065+ action= LatchMods(modifiers=LevelThree,clearLocks,latchToLock);
1066+ };
1067+ interpret ISO_Level3_Lock+AnyOf(all) {
1068+ virtualModifier= LevelThree;
1069+ useModMapMods=level1;
1070+ action= LockMods(modifiers=LevelThree);
1071+ };
1072+ interpret Alt_L+AnyOf(all) {
1073+ virtualModifier= Alt;
1074+ action= SetMods(modifiers=modMapMods,clearLocks);
1075+ };
1076+ interpret Alt_R+AnyOf(all) {
1077+ virtualModifier= Alt;
1078+ action= SetMods(modifiers=modMapMods,clearLocks);
1079+ };
1080+ interpret Meta_L+AnyOf(all) {
1081+ virtualModifier= Meta;
1082+ action= SetMods(modifiers=modMapMods,clearLocks);
1083+ };
1084+ interpret Meta_R+AnyOf(all) {
1085+ virtualModifier= Meta;
1086+ action= SetMods(modifiers=modMapMods,clearLocks);
1087+ };
1088+ interpret Super_L+AnyOf(all) {
1089+ virtualModifier= Super;
1090+ action= SetMods(modifiers=modMapMods,clearLocks);
1091+ };
1092+ interpret Super_R+AnyOf(all) {
1093+ virtualModifier= Super;
1094+ action= SetMods(modifiers=modMapMods,clearLocks);
1095+ };
1096+ interpret Hyper_L+AnyOf(all) {
1097+ virtualModifier= Hyper;
1098+ action= SetMods(modifiers=modMapMods,clearLocks);
1099+ };
1100+ interpret Hyper_R+AnyOf(all) {
1101+ virtualModifier= Hyper;
1102+ action= SetMods(modifiers=modMapMods,clearLocks);
1103+ };
1104+ interpret Scroll_Lock+AnyOf(all) {
1105+ virtualModifier= ScrollLock;
1106+ action= LockMods(modifiers=modMapMods);
1107+ };
1108+ interpret ISO_Level5_Shift+AnyOf(all) {
1109+ virtualModifier= LevelFive;
1110+ useModMapMods=level1;
1111+ action= SetMods(modifiers=LevelFive,clearLocks);
1112+ };
1113+ interpret ISO_Level5_Latch+AnyOf(all) {
1114+ virtualModifier= LevelFive;
1115+ useModMapMods=level1;
1116+ action= LatchMods(modifiers=LevelFive,clearLocks,latchToLock);
1117+ };
1118+ interpret ISO_Level5_Lock+AnyOf(all) {
1119+ virtualModifier= LevelFive;
1120+ useModMapMods=level1;
1121+ action= LockMods(modifiers=LevelFive);
1122+ };
1123+ interpret ISO_Group_Shift+AnyOfOrNone(all) {
1124+ action= SetGroup(group=+1);
1125+ };
1126+ interpret ISO_Level3_Shift+AnyOfOrNone(all) {
1127+ action= SetMods(modifiers=LevelThree,clearLocks);
1128+ };
1129+ interpret ISO_Level3_Latch+AnyOfOrNone(all) {
1130+ action= LatchMods(modifiers=LevelThree,clearLocks,latchToLock);
1131+ };
1132+ interpret ISO_Level3_Lock+AnyOfOrNone(all) {
1133+ action= LockMods(modifiers=LevelThree);
1134+ };
1135+ interpret ISO_Group_Latch+AnyOfOrNone(all) {
1136+ action= LatchGroup(group=2);
1137+ };
1138+ interpret ISO_Next_Group+AnyOfOrNone(all) {
1139+ action= LockGroup(group=+1);
1140+ };
1141+ interpret ISO_Prev_Group+AnyOfOrNone(all) {
1142+ action= LockGroup(group=-1);
1143+ };
1144+ interpret ISO_First_Group+AnyOfOrNone(all) {
1145+ action= LockGroup(group=1);
1146+ };
1147+ interpret ISO_Last_Group+AnyOfOrNone(all) {
1148+ action= LockGroup(group=2);
1149+ };
1150+ interpret KP_1+AnyOfOrNone(all) {
1151+ repeat= True;
1152+ action= MovePtr(x=-1,y=+1);
1153+ };
1154+ interpret KP_End+AnyOfOrNone(all) {
1155+ repeat= True;
1156+ action= MovePtr(x=-1,y=+1);
1157+ };
1158+ interpret KP_2+AnyOfOrNone(all) {
1159+ repeat= True;
1160+ action= MovePtr(x=+0,y=+1);
1161+ };
1162+ interpret KP_Down+AnyOfOrNone(all) {
1163+ repeat= True;
1164+ action= MovePtr(x=+0,y=+1);
1165+ };
1166+ interpret KP_3+AnyOfOrNone(all) {
1167+ repeat= True;
1168+ action= MovePtr(x=+1,y=+1);
1169+ };
1170+ interpret KP_Next+AnyOfOrNone(all) {
1171+ repeat= True;
1172+ action= MovePtr(x=+1,y=+1);
1173+ };
1174+ interpret KP_4+AnyOfOrNone(all) {
1175+ repeat= True;
1176+ action= MovePtr(x=-1,y=+0);
1177+ };
1178+ interpret KP_Left+AnyOfOrNone(all) {
1179+ repeat= True;
1180+ action= MovePtr(x=-1,y=+0);
1181+ };
1182+ interpret KP_6+AnyOfOrNone(all) {
1183+ repeat= True;
1184+ action= MovePtr(x=+1,y=+0);
1185+ };
1186+ interpret KP_Right+AnyOfOrNone(all) {
1187+ repeat= True;
1188+ action= MovePtr(x=+1,y=+0);
1189+ };
1190+ interpret KP_7+AnyOfOrNone(all) {
1191+ repeat= True;
1192+ action= MovePtr(x=-1,y=-1);
1193+ };
1194+ interpret KP_Home+AnyOfOrNone(all) {
1195+ repeat= True;
1196+ action= MovePtr(x=-1,y=-1);
1197+ };
1198+ interpret KP_8+AnyOfOrNone(all) {
1199+ repeat= True;
1200+ action= MovePtr(x=+0,y=-1);
1201+ };
1202+ interpret KP_Up+AnyOfOrNone(all) {
1203+ repeat= True;
1204+ action= MovePtr(x=+0,y=-1);
1205+ };
1206+ interpret KP_9+AnyOfOrNone(all) {
1207+ repeat= True;
1208+ action= MovePtr(x=+1,y=-1);
1209+ };
1210+ interpret KP_Prior+AnyOfOrNone(all) {
1211+ repeat= True;
1212+ action= MovePtr(x=+1,y=-1);
1213+ };
1214+ interpret KP_5+AnyOfOrNone(all) {
1215+ repeat= True;
1216+ action= PtrBtn(button=default);
1217+ };
1218+ interpret KP_Begin+AnyOfOrNone(all) {
1219+ repeat= True;
1220+ action= PtrBtn(button=default);
1221+ };
1222+ interpret KP_F2+AnyOfOrNone(all) {
1223+ repeat= True;
1224+ action= SetPtrDflt(affect=button,button=1);
1225+ };
1226+ interpret KP_Divide+AnyOfOrNone(all) {
1227+ repeat= True;
1228+ action= SetPtrDflt(affect=button,button=1);
1229+ };
1230+ interpret KP_F3+AnyOfOrNone(all) {
1231+ repeat= True;
1232+ action= SetPtrDflt(affect=button,button=2);
1233+ };
1234+ interpret KP_Multiply+AnyOfOrNone(all) {
1235+ repeat= True;
1236+ action= SetPtrDflt(affect=button,button=2);
1237+ };
1238+ interpret KP_F4+AnyOfOrNone(all) {
1239+ repeat= True;
1240+ action= SetPtrDflt(affect=button,button=3);
1241+ };
1242+ interpret KP_Subtract+AnyOfOrNone(all) {
1243+ repeat= True;
1244+ action= SetPtrDflt(affect=button,button=3);
1245+ };
1246+ interpret KP_Separator+AnyOfOrNone(all) {
1247+ repeat= True;
1248+ action= PtrBtn(button=default,count=2);
1249+ };
1250+ interpret KP_Add+AnyOfOrNone(all) {
1251+ repeat= True;
1252+ action= PtrBtn(button=default,count=2);
1253+ };
1254+ interpret KP_0+AnyOfOrNone(all) {
1255+ repeat= True;
1256+ action= LockPtrBtn(button=default,affect=lock);
1257+ };
1258+ interpret KP_Insert+AnyOfOrNone(all) {
1259+ repeat= True;
1260+ action= LockPtrBtn(button=default,affect=lock);
1261+ };
1262+ interpret KP_Decimal+AnyOfOrNone(all) {
1263+ repeat= True;
1264+ action= LockPtrBtn(button=default,affect=unlock);
1265+ };
1266+ interpret KP_Delete+AnyOfOrNone(all) {
1267+ repeat= True;
1268+ action= LockPtrBtn(button=default,affect=unlock);
1269+ };
1270+ interpret F25+AnyOfOrNone(all) {
1271+ repeat= True;
1272+ action= SetPtrDflt(affect=button,button=1);
1273+ };
1274+ interpret F26+AnyOfOrNone(all) {
1275+ repeat= True;
1276+ action= SetPtrDflt(affect=button,button=2);
1277+ };
1278+ interpret F27+AnyOfOrNone(all) {
1279+ repeat= True;
1280+ action= MovePtr(x=-1,y=-1);
1281+ };
1282+ interpret F29+AnyOfOrNone(all) {
1283+ repeat= True;
1284+ action= MovePtr(x=+1,y=-1);
1285+ };
1286+ interpret F31+AnyOfOrNone(all) {
1287+ repeat= True;
1288+ action= PtrBtn(button=default);
1289+ };
1290+ interpret F33+AnyOfOrNone(all) {
1291+ repeat= True;
1292+ action= MovePtr(x=-1,y=+1);
1293+ };
1294+ interpret F35+AnyOfOrNone(all) {
1295+ repeat= True;
1296+ action= MovePtr(x=+1,y=+1);
1297+ };
1298+ interpret Pointer_Button_Dflt+AnyOfOrNone(all) {
1299+ action= PtrBtn(button=default);
1300+ };
1301+ interpret Pointer_Button1+AnyOfOrNone(all) {
1302+ action= PtrBtn(button=1);
1303+ };
1304+ interpret Pointer_Button2+AnyOfOrNone(all) {
1305+ action= PtrBtn(button=2);
1306+ };
1307+ interpret Pointer_Button3+AnyOfOrNone(all) {
1308+ action= PtrBtn(button=3);
1309+ };
1310+ interpret Pointer_DblClick_Dflt+AnyOfOrNone(all) {
1311+ action= PtrBtn(button=default,count=2);
1312+ };
1313+ interpret Pointer_DblClick1+AnyOfOrNone(all) {
1314+ action= PtrBtn(button=1,count=2);
1315+ };
1316+ interpret Pointer_DblClick2+AnyOfOrNone(all) {
1317+ action= PtrBtn(button=2,count=2);
1318+ };
1319+ interpret Pointer_DblClick3+AnyOfOrNone(all) {
1320+ action= PtrBtn(button=3,count=2);
1321+ };
1322+ interpret Pointer_Drag_Dflt+AnyOfOrNone(all) {
1323+ action= LockPtrBtn(button=default,affect=both);
1324+ };
1325+ interpret Pointer_Drag1+AnyOfOrNone(all) {
1326+ action= LockPtrBtn(button=1,affect=both);
1327+ };
1328+ interpret Pointer_Drag2+AnyOfOrNone(all) {
1329+ action= LockPtrBtn(button=2,affect=both);
1330+ };
1331+ interpret Pointer_Drag3+AnyOfOrNone(all) {
1332+ action= LockPtrBtn(button=3,affect=both);
1333+ };
1334+ interpret Pointer_EnableKeys+AnyOfOrNone(all) {
1335+ action= LockControls(controls=MouseKeys);
1336+ };
1337+ interpret Pointer_Accelerate+AnyOfOrNone(all) {
1338+ action= LockControls(controls=MouseKeysAccel);
1339+ };
1340+ interpret Pointer_DfltBtnNext+AnyOfOrNone(all) {
1341+ action= SetPtrDflt(affect=button,button=+1);
1342+ };
1343+ interpret Pointer_DfltBtnPrev+AnyOfOrNone(all) {
1344+ action= SetPtrDflt(affect=button,button=-1);
1345+ };
1346+ interpret AccessX_Enable+AnyOfOrNone(all) {
1347+ action= LockControls(controls=AccessXKeys);
1348+ };
1349+ interpret AccessX_Feedback_Enable+AnyOfOrNone(all) {
1350+ action= LockControls(controls=AccessXFeedback);
1351+ };
1352+ interpret RepeatKeys_Enable+AnyOfOrNone(all) {
1353+ action= LockControls(controls=RepeatKeys);
1354+ };
1355+ interpret SlowKeys_Enable+AnyOfOrNone(all) {
1356+ action= LockControls(controls=SlowKeys);
1357+ };
1358+ interpret BounceKeys_Enable+AnyOfOrNone(all) {
1359+ action= LockControls(controls=BounceKeys);
1360+ };
1361+ interpret StickyKeys_Enable+AnyOfOrNone(all) {
1362+ action= LockControls(controls=StickyKeys);
1363+ };
1364+ interpret MouseKeys_Enable+AnyOfOrNone(all) {
1365+ action= LockControls(controls=MouseKeys);
1366+ };
1367+ interpret MouseKeys_Accel_Enable+AnyOfOrNone(all) {
1368+ action= LockControls(controls=MouseKeysAccel);
1369+ };
1370+ interpret Overlay1_Enable+AnyOfOrNone(all) {
1371+ action= LockControls(controls=none);
1372+ };
1373+ interpret Overlay2_Enable+AnyOfOrNone(all) {
1374+ action= LockControls(controls=none);
1375+ };
1376+ interpret AudibleBell_Enable+AnyOfOrNone(all) {
1377+ action= LockControls(controls=AudibleBell);
1378+ };
1379+ interpret Terminate_Server+AnyOfOrNone(all) {
1380+ action= Terminate();
1381+ };
1382+ interpret Alt_L+AnyOfOrNone(all) {
1383+ action= SetMods(modifiers=Alt,clearLocks);
1384+ };
1385+ interpret Alt_R+AnyOfOrNone(all) {
1386+ action= SetMods(modifiers=Alt,clearLocks);
1387+ };
1388+ interpret Meta_L+AnyOfOrNone(all) {
1389+ action= SetMods(modifiers=Meta,clearLocks);
1390+ };
1391+ interpret Meta_R+AnyOfOrNone(all) {
1392+ action= SetMods(modifiers=Meta,clearLocks);
1393+ };
1394+ interpret Super_L+AnyOfOrNone(all) {
1395+ action= SetMods(modifiers=Super,clearLocks);
1396+ };
1397+ interpret Super_R+AnyOfOrNone(all) {
1398+ action= SetMods(modifiers=Super,clearLocks);
1399+ };
1400+ interpret Hyper_L+AnyOfOrNone(all) {
1401+ action= SetMods(modifiers=Hyper,clearLocks);
1402+ };
1403+ interpret Hyper_R+AnyOfOrNone(all) {
1404+ action= SetMods(modifiers=Hyper,clearLocks);
1405+ };
1406+ interpret Shift_L+AnyOfOrNone(all) {
1407+ action= SetMods(modifiers=Shift,clearLocks);
1408+ };
1409+ interpret Shift_R+AnyOfOrNone(all) {
1410+ action= SetMods(modifiers=Shift,clearLocks);
1411+ };
1412+ interpret XF86Switch_VT_1+AnyOfOrNone(all) {
1413+ repeat= True;
1414+ action= SwitchScreen(screen=1,!same);
1415+ };
1416+ interpret XF86Switch_VT_2+AnyOfOrNone(all) {
1417+ repeat= True;
1418+ action= SwitchScreen(screen=2,!same);
1419+ };
1420+ interpret XF86Switch_VT_3+AnyOfOrNone(all) {
1421+ repeat= True;
1422+ action= SwitchScreen(screen=3,!same);
1423+ };
1424+ interpret XF86Switch_VT_4+AnyOfOrNone(all) {
1425+ repeat= True;
1426+ action= SwitchScreen(screen=4,!same);
1427+ };
1428+ interpret XF86Switch_VT_5+AnyOfOrNone(all) {
1429+ repeat= True;
1430+ action= SwitchScreen(screen=5,!same);
1431+ };
1432+ interpret XF86Switch_VT_6+AnyOfOrNone(all) {
1433+ repeat= True;
1434+ action= SwitchScreen(screen=6,!same);
1435+ };
1436+ interpret XF86Switch_VT_7+AnyOfOrNone(all) {
1437+ repeat= True;
1438+ action= SwitchScreen(screen=7,!same);
1439+ };
1440+ interpret XF86Switch_VT_8+AnyOfOrNone(all) {
1441+ repeat= True;
1442+ action= SwitchScreen(screen=8,!same);
1443+ };
1444+ interpret XF86Switch_VT_9+AnyOfOrNone(all) {
1445+ repeat= True;
1446+ action= SwitchScreen(screen=9,!same);
1447+ };
1448+ interpret XF86Switch_VT_10+AnyOfOrNone(all) {
1449+ repeat= True;
1450+ action= SwitchScreen(screen=10,!same);
1451+ };
1452+ interpret XF86Switch_VT_11+AnyOfOrNone(all) {
1453+ repeat= True;
1454+ action= SwitchScreen(screen=11,!same);
1455+ };
1456+ interpret XF86Switch_VT_12+AnyOfOrNone(all) {
1457+ repeat= True;
1458+ action= SwitchScreen(screen=12,!same);
1459+ };
1460+ interpret XF86LogGrabInfo+AnyOfOrNone(all) {
1461+ repeat= True;
1462+ action= Private(type=0x86,data[0]=0x50,data[1]=0x72,data[2]=0x47,data[3]=0x72,data[4]=0x62,data[5]=0x73,data[6]=0x00);
1463+ };
1464+ interpret XF86LogWindowTree+AnyOfOrNone(all) {
1465+ repeat= True;
1466+ action= Private(type=0x86,data[0]=0x50,data[1]=0x72,data[2]=0x57,data[3]=0x69,data[4]=0x6e,data[5]=0x73,data[6]=0x00);
1467+ };
1468+ interpret XF86Next_VMode+AnyOfOrNone(all) {
1469+ repeat= True;
1470+ action= Private(type=0x86,data[0]=0x2b,data[1]=0x56,data[2]=0x4d,data[3]=0x6f,data[4]=0x64,data[5]=0x65,data[6]=0x00);
1471+ };
1472+ interpret XF86Prev_VMode+AnyOfOrNone(all) {
1473+ repeat= True;
1474+ action= Private(type=0x86,data[0]=0x2d,data[1]=0x56,data[2]=0x4d,data[3]=0x6f,data[4]=0x64,data[5]=0x65,data[6]=0x00);
1475+ };
1476+ interpret ISO_Level5_Shift+AnyOfOrNone(all) {
1477+ action= SetMods(modifiers=LevelFive,clearLocks);
1478+ };
1479+ interpret ISO_Level5_Latch+AnyOfOrNone(all) {
1480+ action= LatchMods(modifiers=LevelFive,clearLocks,latchToLock);
1481+ };
1482+ interpret ISO_Level5_Lock+AnyOfOrNone(all) {
1483+ action= LockMods(modifiers=LevelFive);
1484+ };
1485+ interpret Caps_Lock+AnyOfOrNone(all) {
1486+ action= LockMods(modifiers=Lock);
1487+ };
1488+ interpret Any+Exactly(Lock) {
1489+ action= LockMods(modifiers=Lock);
1490+ };
1491+ interpret Any+AnyOf(all) {
1492+ action= SetMods(modifiers=modMapMods,clearLocks);
1493+ };
1494+ indicator "Caps Lock" {
1495+ whichModState= locked;
1496+ modifiers= Lock;
1497+ };
1498+ indicator "Num Lock" {
1499+ whichModState= locked;
1500+ modifiers= NumLock;
1501+ };
1502+ indicator "Scroll Lock" {
1503+ whichModState= locked;
1504+ modifiers= ScrollLock;
1505+ };
1506+ indicator "Shift Lock" {
1507+ whichModState= locked;
1508+ modifiers= Shift;
1509+ };
1510+ indicator "Group 2" {
1511+ groups= 0xfffffffe;
1512+ };
1513+ indicator "Mouse Keys" {
1514+ controls= MouseKeys;
1515+ };
1516+};
1517+
1518+xkb_symbols "pc_fr_inet(evdev)" {
1519+ name[1]="French";
1520+
1521+ key <ESC> { [ Escape ] };
1522+ key <AE01> { [ ampersand, 1, onesuperior, exclamdown ] };
1523+ key <AE02> { [ eacute, 2, asciitilde, oneeighth ] };
1524+ key <AE03> { [ quotedbl, 3, numbersign, sterling ] };
1525+ key <AE04> { [ apostrophe, 4, braceleft, dollar ] };
1526+ key <AE05> { [ parenleft, 5, bracketleft, threeeighths ] };
1527+ key <AE06> { [ minus, 6, bar, fiveeighths ] };
1528+ key <AE07> { [ egrave, 7, grave, seveneighths ] };
1529+ key <AE08> { [ underscore, 8, backslash, trademark ] };
1530+ key <AE09> { [ ccedilla, 9, asciicircum, plusminus ] };
1531+ key <AE10> { [ agrave, 0, at, degree ] };
1532+ key <AE11> { [ parenright, degree, bracketright, questiondown ] };
1533+ key <AE12> { [ equal, plus, braceright, dead_ogonek ] };
1534+ key <BKSP> { [ BackSpace, BackSpace ] };
1535+ key <TAB> { [ Tab, ISO_Left_Tab ] };
1536+ key <AD01> { [ a, A, ae, AE ] };
1537+ key <AD02> { [ z, Z, guillemotleft, less ] };
1538+ key <AD03> { [ e, E, EuroSign, cent ] };
1539+ key <AD04> { [ r, R, paragraph, registered ] };
1540+ key <AD05> { [ t, T, tslash, Tslash ] };
1541+ key <AD06> { [ y, Y, leftarrow, yen ] };
1542+ key <AD07> { [ u, U, downarrow, uparrow ] };
1543+ key <AD08> { [ i, I, rightarrow, idotless ] };
1544+ key <AD09> { [ o, O, oslash, Oslash ] };
1545+ key <AD10> { [ p, P, thorn, THORN ] };
1546+ key <AD11> { [ dead_circumflex, dead_diaeresis, dead_diaeresis, dead_abovering ] };
1547+ key <AD12> { [ dollar, sterling, currency, dead_macron ] };
1548+ key <RTRN> { [ Return ] };
1549+ key <LCTL> { [ Control_L ] };
1550+ key <AC01> { [ q, Q, at, Greek_OMEGA ] };
1551+ key <AC02> { [ s, S, ssharp, SSHARP ] };
1552+ key <AC03> { [ d, D, eth, ETH ] };
1553+ key <AC04> { [ f, F, dstroke, ordfeminine ] };
1554+ key <AC05> { [ g, G, eng, ENG ] };
1555+ key <AC06> { [ h, H, hstroke, Hstroke ] };
1556+ key <AC07> { [ j, J, dead_hook, dead_horn ] };
1557+ key <AC08> { [ k, K, kra, ampersand ] };
1558+ key <AC09> { [ l, L, lstroke, Lstroke ] };
1559+ key <AC10> { [ m, M, mu, masculine ] };
1560+ key <AC11> { [ ugrave, percent, dead_circumflex, dead_caron ] };
1561+ key <TLDE> { [ twosuperior, asciitilde, notsign, notsign ] };
1562+ key <LFSH> { [ Shift_L ] };
1563+ key <BKSL> { [ asterisk, mu, dead_grave, dead_breve ] };
1564+ key <AB01> { [ w, W, lstroke, Lstroke ] };
1565+ key <AB02> { [ x, X, guillemotright, greater ] };
1566+ key <AB03> { [ c, C, cent, copyright ] };
1567+ key <AB04> { [ v, V, doublelowquotemark, singlelowquotemark ] };
1568+ key <AB05> { [ b, B, leftdoublequotemark, leftsinglequotemark ] };
1569+ key <AB06> { [ n, N, rightdoublequotemark, rightsinglequotemark ] };
1570+ key <AB07> { [ comma, question, dead_acute, dead_doubleacute ] };
1571+ key <AB08> { [ semicolon, period, U2022, multiply ] };
1572+ key <AB09> { [ colon, slash, periodcentered, division ] };
1573+ key <AB10> { [ exclam, section, dead_belowdot, dead_abovedot ] };
1574+ key <RTSH> { [ Shift_R ] };
1575+ key <KPMU> {
1576+ type= "CTRL+ALT",
1577+ symbols[1]= [ KP_Multiply, KP_Multiply, KP_Multiply, KP_Multiply, XF86ClearGrab ]
1578+ };
1579+ key <LALT> { [ Alt_L ] };
1580+ key <SPCE> { [ space ] };
1581+ key <CAPS> { [ Caps_Lock ] };
1582+ key <FK01> {
1583+ type= "CTRL+ALT",
1584+ symbols[1]= [ F1, F1, F1, F1, XF86Switch_VT_1 ]
1585+ };
1586+ key <FK02> {
1587+ type= "CTRL+ALT",
1588+ symbols[1]= [ F2, F2, F2, F2, XF86Switch_VT_2 ]
1589+ };
1590+ key <FK03> {
1591+ type= "CTRL+ALT",
1592+ symbols[1]= [ F3, F3, F3, F3, XF86Switch_VT_3 ]
1593+ };
1594+ key <FK04> {
1595+ type= "CTRL+ALT",
1596+ symbols[1]= [ F4, F4, F4, F4, XF86Switch_VT_4 ]
1597+ };
1598+ key <FK05> {
1599+ type= "CTRL+ALT",
1600+ symbols[1]= [ F5, F5, F5, F5, XF86Switch_VT_5 ]
1601+ };
1602+ key <FK06> {
1603+ type= "CTRL+ALT",
1604+ symbols[1]= [ F6, F6, F6, F6, XF86Switch_VT_6 ]
1605+ };
1606+ key <FK07> {
1607+ type= "CTRL+ALT",
1608+ symbols[1]= [ F7, F7, F7, F7, XF86Switch_VT_7 ]
1609+ };
1610+ key <FK08> {
1611+ type= "CTRL+ALT",
1612+ symbols[1]= [ F8, F8, F8, F8, XF86Switch_VT_8 ]
1613+ };
1614+ key <FK09> {
1615+ type= "CTRL+ALT",
1616+ symbols[1]= [ F9, F9, F9, F9, XF86Switch_VT_9 ]
1617+ };
1618+ key <FK10> {
1619+ type= "CTRL+ALT",
1620+ symbols[1]= [ F10, F10, F10, F10, XF86Switch_VT_10 ]
1621+ };
1622+ key <NMLK> { [ Num_Lock ] };
1623+ key <SCLK> { [ Scroll_Lock ] };
1624+ key <KP7> { [ KP_Home, KP_7 ] };
1625+ key <KP8> { [ KP_Up, KP_8 ] };
1626+ key <KP9> { [ KP_Prior, KP_9 ] };
1627+ key <KPSU> {
1628+ type= "CTRL+ALT",
1629+ symbols[1]= [ KP_Subtract, KP_Subtract, KP_Subtract, KP_Subtract, XF86Prev_VMode ]
1630+ };
1631+ key <KP4> { [ KP_Left, KP_4 ] };
1632+ key <KP5> { [ KP_Begin, KP_5 ] };
1633+ key <KP6> { [ KP_Right, KP_6 ] };
1634+ key <KPAD> {
1635+ type= "CTRL+ALT",
1636+ symbols[1]= [ KP_Add, KP_Add, KP_Add, KP_Add, XF86Next_VMode ]
1637+ };
1638+ key <KP1> { [ KP_End, KP_1 ] };
1639+ key <KP2> { [ KP_Down, KP_2 ] };
1640+ key <KP3> { [ KP_Next, KP_3 ] };
1641+ key <KP0> { [ KP_Insert, KP_0 ] };
1642+ key <KPDL> { [ KP_Delete, KP_Decimal ] };
1643+ key <LVL3> { [ ISO_Level3_Shift ] };
1644+ key <ZEHA> {
1645+ type= "PC_CONTROL_SUPER_LEVEL2",
1646+ symbols[1]= [ F24, XF86TouchpadToggle ]
1647+ };
1648+ key <LSGT> { [ less, greater, bar, brokenbar ] };
1649+ key <FK11> {
1650+ type= "CTRL+ALT",
1651+ symbols[1]= [ F11, F11, F11, F11, XF86Switch_VT_11 ]
1652+ };
1653+ key <FK12> {
1654+ type= "CTRL+ALT",
1655+ symbols[1]= [ F12, F12, F12, F12, XF86Switch_VT_12 ]
1656+ };
1657+ key <KATA> { [ Katakana ] };
1658+ key <HIRA> { [ Hiragana ] };
1659+ key <HENK> { [ Henkan_Mode ] };
1660+ key <HKTG> { [ Hiragana_Katakana ] };
1661+ key <MUHE> { [ Muhenkan ] };
1662+ key <KPEN> { [ KP_Enter ] };
1663+ key <RCTL> { [ Control_R ] };
1664+ key <KPDV> {
1665+ type= "CTRL+ALT",
1666+ symbols[1]= [ KP_Divide, KP_Divide, KP_Divide, KP_Divide, XF86Ungrab ]
1667+ };
1668+ key <PRSC> {
1669+ type= "PC_ALT_LEVEL2",
1670+ symbols[1]= [ Print, Sys_Req ]
1671+ };
1672+ key <RALT> {
1673+ type= "ONE_LEVEL",
1674+ symbols[1]= [ ISO_Level3_Shift ]
1675+ };
1676+ key <LNFD> { [ Linefeed ] };
1677+ key <HOME> { [ Home ] };
1678+ key <UP> { [ Up ] };
1679+ key <PGUP> { [ Prior ] };
1680+ key <LEFT> { [ Left ] };
1681+ key <RGHT> { [ Right ] };
1682+ key <END> { [ End ] };
1683+ key <DOWN> { [ Down ] };
1684+ key <PGDN> { [ Next ] };
1685+ key <INS> { [ Insert ] };
1686+ key <DELE> { [ Delete ] };
1687+ key <MUTE> { [ XF86AudioMute ] };
1688+ key <VOL-> { [ XF86AudioLowerVolume ] };
1689+ key <VOL+> { [ XF86AudioRaiseVolume ] };
1690+ key <POWR> { [ XF86PowerOff ] };
1691+ key <KPEQ> { [ KP_Equal ] };
1692+ key <I126> { [ plusminus ] };
1693+ key <PAUS> {
1694+ type= "PC_CONTROL_LEVEL2",
1695+ symbols[1]= [ Pause, Break ]
1696+ };
1697+ key <I128> { [ XF86LaunchA ] };
1698+ key <I129> { [ KP_Decimal, KP_Decimal ] };
1699+ key <HNGL> { [ Hangul ] };
1700+ key <HJCV> { [ Hangul_Hanja ] };
1701+ key <LWIN> { [ Super_L ] };
1702+ key <RWIN> { [ Super_R ] };
1703+ key <COMP> { [ Menu ] };
1704+ key <STOP> { [ Cancel ] };
1705+ key <AGAI> { [ Redo ] };
1706+ key <PROP> { [ SunProps ] };
1707+ key <UNDO> { [ Undo ] };
1708+ key <FRNT> { [ SunFront ] };
1709+ key <COPY> { [ XF86Copy ] };
1710+ key <OPEN> { [ XF86Open ] };
1711+ key <PAST> { [ XF86Paste ] };
1712+ key <FIND> { [ Find ] };
1713+ key <CUT> { [ XF86Cut ] };
1714+ key <HELP> { [ Help ] };
1715+ key <I147> { [ XF86MenuKB ] };
1716+ key <I148> { [ XF86Calculator ] };
1717+ key <I150> { [ XF86Sleep ] };
1718+ key <I151> { [ XF86WakeUp ] };
1719+ key <I152> { [ XF86Explorer ] };
1720+ key <I153> { [ XF86Send ] };
1721+ key <I155> { [ XF86Xfer ] };
1722+ key <I156> { [ XF86Launch1 ] };
1723+ key <I157> { [ XF86Launch2 ] };
1724+ key <I158> { [ XF86WWW ] };
1725+ key <I159> { [ XF86DOS ] };
1726+ key <I160> { [ XF86ScreenSaver ] };
1727+ key <I161> { [ XF86RotateWindows ] };
1728+ key <I162> { [ XF86TaskPane ] };
1729+ key <I163> { [ XF86Mail ] };
1730+ key <I164> { [ XF86Favorites ] };
1731+ key <I165> { [ XF86MyComputer ] };
1732+ key <I166> { [ XF86Back ] };
1733+ key <I167> { [ XF86Forward ] };
1734+ key <I169> { [ XF86Eject ] };
1735+ key <I170> { [ XF86Eject ] };
1736+ key <I171> { [ XF86AudioNext ] };
1737+ key <I172> { [ XF86AudioPlay, XF86AudioPause ] };
1738+ key <I173> { [ XF86AudioPrev ] };
1739+ key <I174> { [ XF86AudioStop, XF86Eject ] };
1740+ key <I175> { [ XF86AudioRecord ] };
1741+ key <I176> { [ XF86AudioRewind ] };
1742+ key <I177> { [ XF86Phone ] };
1743+ key <I179> { [ XF86Tools ] };
1744+ key <I180> { [ XF86HomePage ] };
1745+ key <I181> { [ XF86Reload ] };
1746+ key <I182> { [ XF86Close ] };
1747+ key <I185> { [ XF86ScrollUp ] };
1748+ key <I186> { [ XF86ScrollDown ] };
1749+ key <I187> { [ parenleft ] };
1750+ key <I188> { [ parenright ] };
1751+ key <I189> { [ XF86New ] };
1752+ key <I190> { [ Redo ] };
1753+ key <FK13> { [ XF86Tools ] };
1754+ key <FK14> { [ XF86Launch5 ] };
1755+ key <FK15> { [ XF86Launch6 ] };
1756+ key <FK16> { [ XF86Launch7 ] };
1757+ key <FK17> { [ XF86Launch8 ] };
1758+ key <FK18> { [ XF86Launch9 ] };
1759+ key <FK19> { [ F19 ] };
1760+ key <FK20> { [ XF86AudioMicMute ] };
1761+ key <FK21> { [ XF86TouchpadToggle ] };
1762+ key <FK22> { [ XF86TouchpadOn ] };
1763+ key <FK23> {
1764+ type= "PC_SHIFT_SUPER_LEVEL2",
1765+ symbols[1]= [ F23, XF86Assistant ]
1766+ };
1767+ key <FK24> {
1768+ type= "PC_CONTROL_SUPER_LEVEL2",
1769+ symbols[1]= [ F24, XF86TouchpadToggle ]
1770+ };
1771+ key <LVL5> { [ ISO_Level5_Shift ] };
1772+ key <ALT> { [ NoSymbol, Alt_L ] };
1773+ key <META> { [ NoSymbol, Meta_L ] };
1774+ key <SUPR> { [ NoSymbol, Super_L ] };
1775+ key <HYPR> { [ NoSymbol, Hyper_L ] };
1776+ key <I208> { [ XF86AudioPlay ] };
1777+ key <I209> { [ XF86AudioPause ] };
1778+ key <I210> { [ XF86Launch3 ] };
1779+ key <I211> { [ XF86Launch4 ] };
1780+ key <I212> { [ XF86LaunchB ] };
1781+ key <I213> { [ XF86Suspend ] };
1782+ key <I214> { [ XF86Close ] };
1783+ key <I215> { [ XF86AudioPlay ] };
1784+ key <I216> { [ XF86AudioForward ] };
1785+ key <I217> { [ XF86AudioBassBoost ] };
1786+ key <I218> { [ Print ] };
1787+ key <I220> { [ XF86WebCam ] };
1788+ key <I221> { [ XF86AudioPreset ] };
1789+ key <I223> { [ XF86Mail ] };
1790+ key <I224> { [ XF86Messenger ] };
1791+ key <I225> { [ XF86Search ] };
1792+ key <I226> { [ XF86Go ] };
1793+ key <I227> { [ XF86Finance ] };
1794+ key <I228> { [ XF86Game ] };
1795+ key <I229> { [ XF86Shop ] };
1796+ key <I231> { [ Cancel ] };
1797+ key <I232> { [ XF86MonBrightnessDown ] };
1798+ key <I233> { [ XF86MonBrightnessUp ] };
1799+ key <I234> { [ XF86AudioMedia ] };
1800+ key <I235> { [ XF86Display ] };
1801+ key <I236> { [ XF86KbdLightOnOff ] };
1802+ key <I237> { [ XF86KbdBrightnessDown ] };
1803+ key <I238> { [ XF86KbdBrightnessUp ] };
1804+ key <I239> { [ XF86Send ] };
1805+ key <I240> { [ XF86Reply ] };
1806+ key <I241> { [ XF86MailForward ] };
1807+ key <I242> { [ XF86Save ] };
1808+ key <I243> { [ XF86Documents ] };
1809+ key <I244> { [ XF86Battery ] };
1810+ key <I245> { [ XF86Bluetooth ] };
1811+ key <I246> { [ XF86WLAN ] };
1812+ key <I247> { [ XF86UWB ] };
1813+ key <I249> { [ XF86Next_VMode ] };
1814+ key <I250> { [ XF86Prev_VMode ] };
1815+ key <I251> { [ XF86MonBrightnessCycle ] };
1816+ key <I252> { [ XF86BrightnessAuto ] };
1817+ key <I253> { [ XF86DisplayOff ] };
1818+ key <I254> { [ XF86WWAN ] };
1819+ key <I255> { [ XF86RFKill ] };
1820+ key <I256> { [ XF86AudioMicMute ] };
1821+ key <I360> { [ XF86OK ] };
1822+ key <I361> { [ XF86Select ] };
1823+ key <I362> { [ XF86GoTo ] };
1824+ key <I363> { [ XF86Clear ] };
1825+ key <I365> { [ XF86Option ] };
1826+ key <I366> { [ XF86Info ] };
1827+ key <I367> { [ XF86Time ] };
1828+ key <I368> { [ XF86VendorLogo ] };
1829+ key <I370> { [ XF86MediaSelectProgramGuide ] };
1830+ key <I371> { [ XF86NextFavorite ] };
1831+ key <I372> { [ XF86Favorites ] };
1832+ key <I373> { [ XF86MediaSelectProgramGuide ] };
1833+ key <I374> { [ XF86MediaSelectHome ] };
1834+ key <I376> { [ XF86MediaLanguageMenu ] };
1835+ key <I377> { [ XF86MediaTitleMenu ] };
1836+ key <I378> { [ XF86Subtitle ] };
1837+ key <I379> { [ XF86CycleAngle ] };
1838+ key <I380> { [ XF86FullScreen ] };
1839+ key <I381> { [ XF86AudioChannelMode ] };
1840+ key <I382> { [ XF86Keyboard ] };
1841+ key <I383> { [ XF86AspectRatio ] };
1842+ key <I384> { [ XF86MediaSelectPC ] };
1843+ key <I385> { [ XF86MediaSelectTV ] };
1844+ key <I386> { [ XF86MediaSelectCable ] };
1845+ key <I387> { [ XF86MediaSelectVCR ] };
1846+ key <I388> { [ XF86MediaSelectVCRPlus ] };
1847+ key <I389> { [ XF86MediaSelectSatellite ] };
1848+ key <I391> { [ XF86CD ] };
1849+ key <I392> { [ XF86MediaSelectTape ] };
1850+ key <I393> { [ XF86MediaSelectRadio ] };
1851+ key <I394> { [ XF86MediaSelectTuner ] };
1852+ key <I395> { [ XF86MediaPlayer ] };
1853+ key <I396> { [ XF86MediaSelectTeletext ] };
1854+ key <I397> { [ XF86DVD ] };
1855+ key <I398> { [ XF86MediaSelectAuxiliary ] };
1856+ key <I400> { [ XF86Audio ] };
1857+ key <I401> { [ XF86Video ] };
1858+ key <I404> { [ XF86Memo ] };
1859+ key <I405> { [ XF86Calendar ] };
1860+ key <I406> { [ XF86Red ] };
1861+ key <I407> { [ XF86Green ] };
1862+ key <I408> { [ XF86Yellow ] };
1863+ key <I409> { [ XF86Blue ] };
1864+ key <I410> { [ XF86ChannelUp ] };
1865+ key <I411> { [ XF86ChannelDown ] };
1866+ key <I417> { [ XF86MediaPlaySlow ] };
1867+ key <I418> { [ XF86AudioRandomPlay ] };
1868+ key <I419> { [ XF86Break ] };
1869+ key <I421> { [ XF86NumberEntryMode ] };
1870+ key <I424> { [ XF86VideoPhone ] };
1871+ key <I425> { [ XF86Game ] };
1872+ key <I426> { [ XF86ZoomIn ] };
1873+ key <I427> { [ XF86ZoomOut ] };
1874+ key <I428> { [ XF86ZoomReset ] };
1875+ key <I429> { [ XF86Word ] };
1876+ key <I430> { [ XF86Editor ] };
1877+ key <I431> { [ XF86Excel ] };
1878+ key <I432> { [ XF86GraphicsEditor ] };
1879+ key <I433> { [ XF86Presentation ] };
1880+ key <I434> { [ XF86Database ] };
1881+ key <I435> { [ XF86News ] };
1882+ key <I436> { [ XF86Voicemail ] };
1883+ key <I437> { [ XF86Addressbook ] };
1884+ key <I438> { [ XF86Messenger ] };
1885+ key <I439> { [ XF86DisplayToggle ] };
1886+ key <I440> { [ XF86SpellCheck ] };
1887+ key <I441> { [ XF86LogOff ] };
1888+ key <I442> { [ dollar ] };
1889+ key <I443> { [ EuroSign ] };
1890+ key <I444> { [ XF86FrameBack ] };
1891+ key <I445> { [ XF86FrameForward ] };
1892+ key <I446> { [ XF86ContextMenu ] };
1893+ key <I447> { [ XF86MediaRepeat ] };
1894+ key <I448> { [ XF8610ChannelsUp ] };
1895+ key <I449> { [ XF8610ChannelsDown ] };
1896+ key <I450> { [ XF86Images ] };
1897+ key <I452> { [ XF86NotificationCenter ] };
1898+ key <I453> { [ XF86PickupPhone ] };
1899+ key <I454> { [ XF86HangupPhone ] };
1900+ key <I455> { [ XF86LinkPhone ] };
1901+ key <I472> { [ XF86Fn ] };
1902+ key <I473> { [ XF86Fn_Esc ] };
1903+ key <I474> { [ XF86Fn_F1 ] };
1904+ key <I475> { [ XF86Fn_F2 ] };
1905+ key <I476> { [ XF86Fn_F3 ] };
1906+ key <I477> { [ XF86Fn_F4 ] };
1907+ key <I478> { [ XF86Fn_F5 ] };
1908+ key <I479> { [ XF86Fn_F6 ] };
1909+ key <I480> { [ XF86Fn_F7 ] };
1910+ key <I481> { [ XF86Fn_F8 ] };
1911+ key <I482> { [ XF86Fn_F9 ] };
1912+ key <I483> { [ XF86Fn_F10 ] };
1913+ key <I484> { [ XF86Fn_F11 ] };
1914+ key <I485> { [ XF86Fn_F12 ] };
1915+ key <I486> { [ XF86Fn_1 ] };
1916+ key <I487> { [ XF86Fn_2 ] };
1917+ key <I488> { [ XF86Fn_D ] };
1918+ key <I489> { [ XF86Fn_E ] };
1919+ key <I490> { [ XF86Fn_F ] };
1920+ key <I491> { [ XF86Fn_S ] };
1921+ key <I492> { [ XF86Fn_B ] };
1922+ key <I493> { [ XF86FnRightShift ] };
1923+ key <I505> { [ braille_dot_1 ] };
1924+ key <I506> { [ braille_dot_2 ] };
1925+ key <I507> { [ braille_dot_3 ] };
1926+ key <I508> { [ braille_dot_4 ] };
1927+ key <I509> { [ braille_dot_5 ] };
1928+ key <I510> { [ braille_dot_6 ] };
1929+ key <I511> { [ braille_dot_7 ] };
1930+ key <I512> { [ braille_dot_8 ] };
1931+ key <I513> { [ braille_dot_9 ] };
1932+ key <I514> { [ braille_dot_1 ] };
1933+ key <I520> { [ XF86Numeric0 ] };
1934+ key <I521> { [ XF86Numeric1 ] };
1935+ key <I522> { [ XF86Numeric2 ] };
1936+ key <I523> { [ XF86Numeric3 ] };
1937+ key <I524> { [ XF86Numeric4 ] };
1938+ key <I525> { [ XF86Numeric5 ] };
1939+ key <I526> { [ XF86Numeric6 ] };
1940+ key <I527> { [ XF86Numeric7 ] };
1941+ key <I528> { [ XF86Numeric8 ] };
1942+ key <I529> { [ XF86Numeric9 ] };
1943+ key <I530> { [ XF86NumericStar ] };
1944+ key <I531> { [ XF86NumericPound ] };
1945+ key <I532> { [ XF86NumericA ] };
1946+ key <I533> { [ XF86NumericB ] };
1947+ key <I534> { [ XF86NumericC ] };
1948+ key <I535> { [ XF86NumericD ] };
1949+ key <I536> { [ XF86CameraFocus ] };
1950+ key <I537> { [ XF86WPSButton ] };
1951+ key <I538> { [ XF86TouchpadToggle ] };
1952+ key <I539> { [ XF86TouchpadOn ] };
1953+ key <I540> { [ XF86TouchpadOff ] };
1954+ key <I541> { [ XF86CameraZoomIn ] };
1955+ key <I542> { [ XF86CameraZoomOut ] };
1956+ key <I543> { [ XF86CameraUp ] };
1957+ key <I544> { [ XF86CameraDown ] };
1958+ key <I545> { [ XF86CameraLeft ] };
1959+ key <I546> { [ XF86CameraRight ] };
1960+ key <I547> { [ XF86AttendantOn ] };
1961+ key <I548> { [ XF86AttendantOff ] };
1962+ key <I549> { [ XF86AttendantToggle ] };
1963+ key <I550> { [ XF86LightsToggle ] };
1964+ key <I568> { [ XF86ALSToggle ] };
1965+ key <I569> { [ XF86RotationLockToggle ] };
1966+ key <I570> { [ XF86RefreshRateToggle ] };
1967+ key <I584> { [ XF86Buttonconfig ] };
1968+ key <I585> { [ XF86Taskmanager ] };
1969+ key <I586> { [ XF86Journal ] };
1970+ key <I587> { [ XF86ControlPanel ] };
1971+ key <I588> { [ XF86AppSelect ] };
1972+ key <I589> { [ XF86Screensaver ] };
1973+ key <I590> { [ XF86VoiceCommand ] };
1974+ key <I591> { [ XF86Assistant ] };
1975+ key <I592> { [ ISO_Next_Group ] };
1976+ key <I593> { [ XF86EmojiPicker ] };
1977+ key <I594> { [ XF86Dictate ] };
1978+ key <I595> { [ XF86CameraAccessEnable ] };
1979+ key <I596> { [ XF86CameraAccessDisable ] };
1980+ key <I597> { [ XF86CameraAccessToggle ] };
1981+ key <I598> { [ XF86Accessibility ] };
1982+ key <I599> { [ XF86DoNotDisturb ] };
1983+ key <I600> { [ XF86BrightnessMin ] };
1984+ key <I601> { [ XF86BrightnessMax ] };
1985+ key <I602> { [ XF86ElectronicPrivacyScreenOn ] };
1986+ key <I603> { [ XF86ElectronicPrivacyScreenOff ] };
1987+ key <I604> { [ XF86ActionOnSelection ] };
1988+ key <I605> { [ XF86ContextualInsert ] };
1989+ key <I606> { [ XF86ContextualQuery ] };
1990+ key <I616> { [ XF86KbdInputAssistPrev ] };
1991+ key <I617> { [ XF86KbdInputAssistNext ] };
1992+ key <I618> { [ XF86KbdInputAssistPrevgroup ] };
1993+ key <I619> { [ XF86KbdInputAssistNextgroup ] };
1994+ key <I620> { [ XF86KbdInputAssistAccept ] };
1995+ key <I621> { [ XF86KbdInputAssistCancel ] };
1996+ key <I622> { [ XF86RightUp ] };
1997+ key <I623> { [ XF86RightDown ] };
1998+ key <I624> { [ XF86LeftUp ] };
1999+ key <I625> { [ XF86LeftDown ] };
2000+ key <I626> { [ XF86RootMenu ] };
2001+ key <I627> { [ XF86MediaTopMenu ] };
2002+ key <I628> { [ XF86Numeric11 ] };
2003+ key <I629> { [ XF86Numeric12 ] };
2004+ key <I630> { [ XF86AudioDesc ] };
2005+ key <I631> { [ XF863DMode ] };
2006+ key <I632> { [ XF86NextFavorite ] };
2007+ key <I633> { [ XF86StopRecord ] };
2008+ key <I634> { [ XF86PauseRecord ] };
2009+ key <I635> { [ XF86VOD ] };
2010+ key <I636> { [ XF86Unmute ] };
2011+ key <I637> { [ XF86FastReverse ] };
2012+ key <I638> { [ XF86SlowReverse ] };
2013+ key <I639> { [ XF86Data ] };
2014+ key <I640> { [ XF86OnScreenKeyboard ] };
2015+ key <I641> { [ XF86PrivacyScreenToggle ] };
2016+ key <I642> { [ XF86SelectiveScreenshot ] };
2017+ key <I643> { [ XF86NextElement ] };
2018+ key <I644> { [ XF86PreviousElement ] };
2019+ key <I645> { [ XF86AutopilotEngageToggle ] };
2020+ key <I646> { [ XF86MarkWaypoint ] };
2021+ key <I647> { [ XF86Sos ] };
2022+ key <I648> { [ XF86NavChart ] };
2023+ key <I649> { [ XF86FishingChart ] };
2024+ key <I650> { [ XF86SingleRangeRadar ] };
2025+ key <I651> { [ XF86DualRangeRadar ] };
2026+ key <I652> { [ XF86RadarOverlay ] };
2027+ key <I653> { [ XF86TraditionalSonar ] };
2028+ key <I654> { [ XF86ClearvuSonar ] };
2029+ key <I655> { [ XF86SidevuSonar ] };
2030+ key <I656> { [ XF86NavInfo ] };
2031+ key <I657> { [ XF86BrightnessAdjust ] };
2032+ key <I664> { [ XF86Macro1 ] };
2033+ key <I665> { [ XF86Macro2 ] };
2034+ key <I666> { [ XF86Macro3 ] };
2035+ key <I667> { [ XF86Macro4 ] };
2036+ key <I668> { [ XF86Macro5 ] };
2037+ key <I669> { [ XF86Macro6 ] };
2038+ key <I670> { [ XF86Macro7 ] };
2039+ key <I671> { [ XF86Macro8 ] };
2040+ key <I672> { [ XF86Macro9 ] };
2041+ key <I673> { [ XF86Macro10 ] };
2042+ key <I674> { [ XF86Macro11 ] };
2043+ key <I675> { [ XF86Macro12 ] };
2044+ key <I676> { [ XF86Macro13 ] };
2045+ key <I677> { [ XF86Macro14 ] };
2046+ key <I678> { [ XF86Macro15 ] };
2047+ key <I679> { [ XF86Macro16 ] };
2048+ key <I680> { [ XF86Macro17 ] };
2049+ key <I681> { [ XF86Macro18 ] };
2050+ key <I682> { [ XF86Macro19 ] };
2051+ key <I683> { [ XF86Macro20 ] };
2052+ key <I684> { [ XF86Macro21 ] };
2053+ key <I685> { [ XF86Macro22 ] };
2054+ key <I686> { [ XF86Macro23 ] };
2055+ key <I687> { [ XF86Macro24 ] };
2056+ key <I688> { [ XF86Macro25 ] };
2057+ key <I689> { [ XF86Macro26 ] };
2058+ key <I690> { [ XF86Macro27 ] };
2059+ key <I691> { [ XF86Macro28 ] };
2060+ key <I692> { [ XF86Macro29 ] };
2061+ key <I693> { [ XF86Macro30 ] };
2062+ key <I696> { [ XF86MacroRecordStart ] };
2063+ key <I697> { [ XF86MacroRecordStop ] };
2064+ key <I698> { [ XF86MacroPresetCycle ] };
2065+ key <I699> { [ XF86MacroPreset1 ] };
2066+ key <I700> { [ XF86MacroPreset2 ] };
2067+ key <I701> { [ XF86MacroPreset3 ] };
2068+ key <I704> { [ XF86KbdLcdMenu1 ] };
2069+ key <I705> { [ XF86KbdLcdMenu2 ] };
2070+ key <I706> { [ XF86KbdLcdMenu3 ] };
2071+ key <I707> { [ XF86KbdLcdMenu4 ] };
2072+ key <I708> { [ XF86KbdLcdMenu5 ] };
2073+ key <I709> { [ XF86PerformanceMode ] };
2074+ modifier_map Shift { <LFSH>, <RTSH> };
2075+ modifier_map Lock { <CAPS> };
2076+ modifier_map Control { <LCTL>, <RCTL> };
2077+ modifier_map Mod1 { <LALT>, <ALT>, <META> };
2078+ modifier_map Mod2 { <NMLK> };
2079+ modifier_map Mod3 { <LVL5> };
2080+ modifier_map Mod4 { <LWIN>, <RWIN>, <SUPR> };
2081+ modifier_map Mod5 { <LVL3> };
2082+};
2083+
2084+};
@@ -0,0 +1,2084 @@
1+xkb_keymap {
2+xkb_keycodes "evdev_aliases(azerty)" {
3+ minimum = 8;
4+ maximum = 709;
5+ <ESC> = 9;
6+ <AE01> = 10;
7+ <AE02> = 11;
8+ <AE03> = 12;
9+ <AE04> = 13;
10+ <AE05> = 14;
11+ <AE06> = 15;
12+ <AE07> = 16;
13+ <AE08> = 17;
14+ <AE09> = 18;
15+ <AE10> = 19;
16+ <AE11> = 20;
17+ <AE12> = 21;
18+ <BKSP> = 22;
19+ <TAB> = 23;
20+ <AD01> = 24;
21+ <AD02> = 25;
22+ <AD03> = 26;
23+ <AD04> = 27;
24+ <AD05> = 28;
25+ <AD06> = 29;
26+ <AD07> = 30;
27+ <AD08> = 31;
28+ <AD09> = 32;
29+ <AD10> = 33;
30+ <AD11> = 34;
31+ <AD12> = 35;
32+ <RTRN> = 36;
33+ <LCTL> = 37;
34+ <AC01> = 38;
35+ <AC02> = 39;
36+ <AC03> = 40;
37+ <AC04> = 41;
38+ <AC05> = 42;
39+ <AC06> = 43;
40+ <AC07> = 44;
41+ <AC08> = 45;
42+ <AC09> = 46;
43+ <AC10> = 47;
44+ <AC11> = 48;
45+ <TLDE> = 49;
46+ <LFSH> = 50;
47+ <BKSL> = 51;
48+ <AB01> = 52;
49+ <AB02> = 53;
50+ <AB03> = 54;
51+ <AB04> = 55;
52+ <AB05> = 56;
53+ <AB06> = 57;
54+ <AB07> = 58;
55+ <AB08> = 59;
56+ <AB09> = 60;
57+ <AB10> = 61;
58+ <RTSH> = 62;
59+ <KPMU> = 63;
60+ <LALT> = 64;
61+ <SPCE> = 65;
62+ <CAPS> = 66;
63+ <FK01> = 67;
64+ <FK02> = 68;
65+ <FK03> = 69;
66+ <FK04> = 70;
67+ <FK05> = 71;
68+ <FK06> = 72;
69+ <FK07> = 73;
70+ <FK08> = 74;
71+ <FK09> = 75;
72+ <FK10> = 76;
73+ <NMLK> = 77;
74+ <SCLK> = 78;
75+ <KP7> = 79;
76+ <KP8> = 80;
77+ <KP9> = 81;
78+ <KPSU> = 82;
79+ <KP4> = 83;
80+ <KP5> = 84;
81+ <KP6> = 85;
82+ <KPAD> = 86;
83+ <KP1> = 87;
84+ <KP2> = 88;
85+ <KP3> = 89;
86+ <KP0> = 90;
87+ <KPDL> = 91;
88+ <LVL3> = 92;
89+ <ZEHA> = 93;
90+ <LSGT> = 94;
91+ <FK11> = 95;
92+ <FK12> = 96;
93+ <AB11> = 97;
94+ <KATA> = 98;
95+ <HIRA> = 99;
96+ <HENK> = 100;
97+ <HKTG> = 101;
98+ <MUHE> = 102;
99+ <JPCM> = 103;
100+ <KPEN> = 104;
101+ <RCTL> = 105;
102+ <KPDV> = 106;
103+ <PRSC> = 107;
104+ <RALT> = 108;
105+ <LNFD> = 109;
106+ <HOME> = 110;
107+ <UP> = 111;
108+ <PGUP> = 112;
109+ <LEFT> = 113;
110+ <RGHT> = 114;
111+ <END> = 115;
112+ <DOWN> = 116;
113+ <PGDN> = 117;
114+ <INS> = 118;
115+ <DELE> = 119;
116+ <I120> = 120;
117+ <MUTE> = 121;
118+ <VOL-> = 122;
119+ <VOL+> = 123;
120+ <POWR> = 124;
121+ <KPEQ> = 125;
122+ <I126> = 126;
123+ <PAUS> = 127;
124+ <I128> = 128;
125+ <I129> = 129;
126+ <HNGL> = 130;
127+ <HJCV> = 131;
128+ <AE13> = 132;
129+ <LWIN> = 133;
130+ <RWIN> = 134;
131+ <COMP> = 135;
132+ <STOP> = 136;
133+ <AGAI> = 137;
134+ <PROP> = 138;
135+ <UNDO> = 139;
136+ <FRNT> = 140;
137+ <COPY> = 141;
138+ <OPEN> = 142;
139+ <PAST> = 143;
140+ <FIND> = 144;
141+ <CUT> = 145;
142+ <HELP> = 146;
143+ <I147> = 147;
144+ <I148> = 148;
145+ <I149> = 149;
146+ <I150> = 150;
147+ <I151> = 151;
148+ <I152> = 152;
149+ <I153> = 153;
150+ <I154> = 154;
151+ <I155> = 155;
152+ <I156> = 156;
153+ <I157> = 157;
154+ <I158> = 158;
155+ <I159> = 159;
156+ <I160> = 160;
157+ <I161> = 161;
158+ <I162> = 162;
159+ <I163> = 163;
160+ <I164> = 164;
161+ <I165> = 165;
162+ <I166> = 166;
163+ <I167> = 167;
164+ <I168> = 168;
165+ <I169> = 169;
166+ <I170> = 170;
167+ <I171> = 171;
168+ <I172> = 172;
169+ <I173> = 173;
170+ <I174> = 174;
171+ <I175> = 175;
172+ <I176> = 176;
173+ <I177> = 177;
174+ <I178> = 178;
175+ <I179> = 179;
176+ <I180> = 180;
177+ <I181> = 181;
178+ <I182> = 182;
179+ <I183> = 183;
180+ <I184> = 184;
181+ <I185> = 185;
182+ <I186> = 186;
183+ <I187> = 187;
184+ <I188> = 188;
185+ <I189> = 189;
186+ <I190> = 190;
187+ <FK13> = 191;
188+ <FK14> = 192;
189+ <FK15> = 193;
190+ <FK16> = 194;
191+ <FK17> = 195;
192+ <FK18> = 196;
193+ <FK19> = 197;
194+ <FK20> = 198;
195+ <FK21> = 199;
196+ <FK22> = 200;
197+ <FK23> = 201;
198+ <FK24> = 202;
199+ <LVL5> = 203;
200+ <ALT> = 204;
201+ <META> = 205;
202+ <SUPR> = 206;
203+ <HYPR> = 207;
204+ <I208> = 208;
205+ <I209> = 209;
206+ <I210> = 210;
207+ <I211> = 211;
208+ <I212> = 212;
209+ <I213> = 213;
210+ <I214> = 214;
211+ <I215> = 215;
212+ <I216> = 216;
213+ <I217> = 217;
214+ <I218> = 218;
215+ <I219> = 219;
216+ <I220> = 220;
217+ <I221> = 221;
218+ <I222> = 222;
219+ <I223> = 223;
220+ <I224> = 224;
221+ <I225> = 225;
222+ <I226> = 226;
223+ <I227> = 227;
224+ <I228> = 228;
225+ <I229> = 229;
226+ <I230> = 230;
227+ <I231> = 231;
228+ <I232> = 232;
229+ <I233> = 233;
230+ <I234> = 234;
231+ <I235> = 235;
232+ <I236> = 236;
233+ <I237> = 237;
234+ <I238> = 238;
235+ <I239> = 239;
236+ <I240> = 240;
237+ <I241> = 241;
238+ <I242> = 242;
239+ <I243> = 243;
240+ <I244> = 244;
241+ <I245> = 245;
242+ <I246> = 246;
243+ <I247> = 247;
244+ <I248> = 248;
245+ <I249> = 249;
246+ <I250> = 250;
247+ <I251> = 251;
248+ <I252> = 252;
249+ <I253> = 253;
250+ <I254> = 254;
251+ <I255> = 255;
252+ <I256> = 256;
253+ <I360> = 360;
254+ <I361> = 361;
255+ <I362> = 362;
256+ <I363> = 363;
257+ <I364> = 364;
258+ <I365> = 365;
259+ <I366> = 366;
260+ <I367> = 367;
261+ <I368> = 368;
262+ <I369> = 369;
263+ <I370> = 370;
264+ <I371> = 371;
265+ <I372> = 372;
266+ <I373> = 373;
267+ <I374> = 374;
268+ <I375> = 375;
269+ <I376> = 376;
270+ <I377> = 377;
271+ <I378> = 378;
272+ <I379> = 379;
273+ <I380> = 380;
274+ <I381> = 381;
275+ <I382> = 382;
276+ <I383> = 383;
277+ <I384> = 384;
278+ <I385> = 385;
279+ <I386> = 386;
280+ <I387> = 387;
281+ <I388> = 388;
282+ <I389> = 389;
283+ <I390> = 390;
284+ <I391> = 391;
285+ <I392> = 392;
286+ <I393> = 393;
287+ <I394> = 394;
288+ <I395> = 395;
289+ <I396> = 396;
290+ <I397> = 397;
291+ <I398> = 398;
292+ <I399> = 399;
293+ <I400> = 400;
294+ <I401> = 401;
295+ <I402> = 402;
296+ <I403> = 403;
297+ <I404> = 404;
298+ <I405> = 405;
299+ <I406> = 406;
300+ <I407> = 407;
301+ <I408> = 408;
302+ <I409> = 409;
303+ <I410> = 410;
304+ <I411> = 411;
305+ <I412> = 412;
306+ <I413> = 413;
307+ <I414> = 414;
308+ <I415> = 415;
309+ <I416> = 416;
310+ <I417> = 417;
311+ <I418> = 418;
312+ <I419> = 419;
313+ <I420> = 420;
314+ <I421> = 421;
315+ <I422> = 422;
316+ <I423> = 423;
317+ <I424> = 424;
318+ <I425> = 425;
319+ <I426> = 426;
320+ <I427> = 427;
321+ <I428> = 428;
322+ <I429> = 429;
323+ <I430> = 430;
324+ <I431> = 431;
325+ <I432> = 432;
326+ <I433> = 433;
327+ <I434> = 434;
328+ <I435> = 435;
329+ <I436> = 436;
330+ <I437> = 437;
331+ <I438> = 438;
332+ <I439> = 439;
333+ <I440> = 440;
334+ <I441> = 441;
335+ <I442> = 442;
336+ <I443> = 443;
337+ <I444> = 444;
338+ <I445> = 445;
339+ <I446> = 446;
340+ <I447> = 447;
341+ <I448> = 448;
342+ <I449> = 449;
343+ <I450> = 450;
344+ <I452> = 452;
345+ <I453> = 453;
346+ <I454> = 454;
347+ <I455> = 455;
348+ <I456> = 456;
349+ <I457> = 457;
350+ <I458> = 458;
351+ <I459> = 459;
352+ <I472> = 472;
353+ <I473> = 473;
354+ <I474> = 474;
355+ <I475> = 475;
356+ <I476> = 476;
357+ <I477> = 477;
358+ <I478> = 478;
359+ <I479> = 479;
360+ <I480> = 480;
361+ <I481> = 481;
362+ <I482> = 482;
363+ <I483> = 483;
364+ <I484> = 484;
365+ <I485> = 485;
366+ <I486> = 486;
367+ <I487> = 487;
368+ <I488> = 488;
369+ <I489> = 489;
370+ <I490> = 490;
371+ <I491> = 491;
372+ <I492> = 492;
373+ <I493> = 493;
374+ <I505> = 505;
375+ <I506> = 506;
376+ <I507> = 507;
377+ <I508> = 508;
378+ <I509> = 509;
379+ <I510> = 510;
380+ <I511> = 511;
381+ <I512> = 512;
382+ <I513> = 513;
383+ <I514> = 514;
384+ <I520> = 520;
385+ <I521> = 521;
386+ <I522> = 522;
387+ <I523> = 523;
388+ <I524> = 524;
389+ <I525> = 525;
390+ <I526> = 526;
391+ <I527> = 527;
392+ <I528> = 528;
393+ <I529> = 529;
394+ <I530> = 530;
395+ <I531> = 531;
396+ <I532> = 532;
397+ <I533> = 533;
398+ <I534> = 534;
399+ <I535> = 535;
400+ <I536> = 536;
401+ <I537> = 537;
402+ <I538> = 538;
403+ <I539> = 539;
404+ <I540> = 540;
405+ <I541> = 541;
406+ <I542> = 542;
407+ <I543> = 543;
408+ <I544> = 544;
409+ <I545> = 545;
410+ <I546> = 546;
411+ <I547> = 547;
412+ <I548> = 548;
413+ <I549> = 549;
414+ <I550> = 550;
415+ <I568> = 568;
416+ <I569> = 569;
417+ <I570> = 570;
418+ <I584> = 584;
419+ <I585> = 585;
420+ <I586> = 586;
421+ <I587> = 587;
422+ <I588> = 588;
423+ <I589> = 589;
424+ <I590> = 590;
425+ <I591> = 591;
426+ <I592> = 592;
427+ <I593> = 593;
428+ <I594> = 594;
429+ <I595> = 595;
430+ <I596> = 596;
431+ <I597> = 597;
432+ <I598> = 598;
433+ <I599> = 599;
434+ <I600> = 600;
435+ <I601> = 601;
436+ <I602> = 602;
437+ <I603> = 603;
438+ <I604> = 604;
439+ <I605> = 605;
440+ <I606> = 606;
441+ <I616> = 616;
442+ <I617> = 617;
443+ <I618> = 618;
444+ <I619> = 619;
445+ <I620> = 620;
446+ <I621> = 621;
447+ <I622> = 622;
448+ <I623> = 623;
449+ <I624> = 624;
450+ <I625> = 625;
451+ <I626> = 626;
452+ <I627> = 627;
453+ <I628> = 628;
454+ <I629> = 629;
455+ <I630> = 630;
456+ <I631> = 631;
457+ <I632> = 632;
458+ <I633> = 633;
459+ <I634> = 634;
460+ <I635> = 635;
461+ <I636> = 636;
462+ <I637> = 637;
463+ <I638> = 638;
464+ <I639> = 639;
465+ <I640> = 640;
466+ <I641> = 641;
467+ <I642> = 642;
468+ <I643> = 643;
469+ <I644> = 644;
470+ <I645> = 645;
471+ <I646> = 646;
472+ <I647> = 647;
473+ <I648> = 648;
474+ <I649> = 649;
475+ <I650> = 650;
476+ <I651> = 651;
477+ <I652> = 652;
478+ <I653> = 653;
479+ <I654> = 654;
480+ <I655> = 655;
481+ <I656> = 656;
482+ <I657> = 657;
483+ <I664> = 664;
484+ <I665> = 665;
485+ <I666> = 666;
486+ <I667> = 667;
487+ <I668> = 668;
488+ <I669> = 669;
489+ <I670> = 670;
490+ <I671> = 671;
491+ <I672> = 672;
492+ <I673> = 673;
493+ <I674> = 674;
494+ <I675> = 675;
495+ <I676> = 676;
496+ <I677> = 677;
497+ <I678> = 678;
498+ <I679> = 679;
499+ <I680> = 680;
500+ <I681> = 681;
501+ <I682> = 682;
502+ <I683> = 683;
503+ <I684> = 684;
504+ <I685> = 685;
505+ <I686> = 686;
506+ <I687> = 687;
507+ <I688> = 688;
508+ <I689> = 689;
509+ <I690> = 690;
510+ <I691> = 691;
511+ <I692> = 692;
512+ <I693> = 693;
513+ <I696> = 696;
514+ <I697> = 697;
515+ <I698> = 698;
516+ <I699> = 699;
517+ <I700> = 700;
518+ <I701> = 701;
519+ <I704> = 704;
520+ <I705> = 705;
521+ <I706> = 706;
522+ <I707> = 707;
523+ <I708> = 708;
524+ <I709> = 709;
525+ indicator 1 = "Caps Lock";
526+ indicator 2 = "Num Lock";
527+ indicator 3 = "Scroll Lock";
528+ indicator 4 = "Compose";
529+ indicator 5 = "Kana";
530+ indicator 6 = "Sleep";
531+ indicator 7 = "Suspend";
532+ indicator 8 = "Mute";
533+ indicator 9 = "Misc";
534+ indicator 10 = "Mail";
535+ indicator 11 = "Charging";
536+ indicator 12 = "Shift Lock";
537+ indicator 13 = "Group 2";
538+ indicator 14 = "Mouse Keys";
539+ alias <AC12> = <BKSL>;
540+ alias <ALGR> = <RALT>;
541+ alias <MENU> = <COMP>;
542+ alias <HZTG> = <TLDE>;
543+ alias <LMTA> = <LWIN>;
544+ alias <RMTA> = <RWIN>;
545+ alias <OUTP> = <I235>;
546+ alias <KITG> = <I236>;
547+ alias <KIDN> = <I237>;
548+ alias <KIUP> = <I238>;
549+ alias <I121> = <MUTE>;
550+ alias <I122> = <VOL->;
551+ alias <I123> = <VOL+>;
552+ alias <I124> = <POWR>;
553+ alias <I125> = <KPEQ>;
554+ alias <I127> = <PAUS>;
555+ alias <I130> = <HNGL>;
556+ alias <I131> = <HJCV>;
557+ alias <I132> = <AE13>;
558+ alias <I133> = <LWIN>;
559+ alias <I134> = <RWIN>;
560+ alias <I135> = <COMP>;
561+ alias <I136> = <STOP>;
562+ alias <I137> = <AGAI>;
563+ alias <I138> = <PROP>;
564+ alias <I139> = <UNDO>;
565+ alias <I140> = <FRNT>;
566+ alias <I141> = <COPY>;
567+ alias <I142> = <OPEN>;
568+ alias <I143> = <PAST>;
569+ alias <I144> = <FIND>;
570+ alias <I145> = <CUT>;
571+ alias <I146> = <HELP>;
572+ alias <I191> = <FK13>;
573+ alias <I192> = <FK14>;
574+ alias <I193> = <FK15>;
575+ alias <I194> = <FK16>;
576+ alias <I195> = <FK17>;
577+ alias <I196> = <FK18>;
578+ alias <I197> = <FK19>;
579+ alias <I198> = <FK20>;
580+ alias <I199> = <FK21>;
581+ alias <I200> = <FK22>;
582+ alias <I201> = <FK23>;
583+ alias <I202> = <FK24>;
584+ alias <MDSW> = <LVL5>;
585+ alias <KPPT> = <I129>;
586+ alias <LatQ> = <AC01>;
587+ alias <LatW> = <AB01>;
588+ alias <LatE> = <AD03>;
589+ alias <LatR> = <AD04>;
590+ alias <LatT> = <AD05>;
591+ alias <LatY> = <AD06>;
592+ alias <LatU> = <AD07>;
593+ alias <LatI> = <AD08>;
594+ alias <LatO> = <AD09>;
595+ alias <LatP> = <AD10>;
596+ alias <LatA> = <AD01>;
597+ alias <LatS> = <AC02>;
598+ alias <LatD> = <AC03>;
599+ alias <LatF> = <AC04>;
600+ alias <LatG> = <AC05>;
601+ alias <LatH> = <AC06>;
602+ alias <LatJ> = <AC07>;
603+ alias <LatK> = <AC08>;
604+ alias <LatL> = <AC09>;
605+ alias <LatZ> = <AD02>;
606+ alias <LatX> = <AB02>;
607+ alias <LatC> = <AB03>;
608+ alias <LatV> = <AB04>;
609+ alias <LatB> = <AB05>;
610+ alias <LatN> = <AB06>;
611+ alias <LatM> = <AC10>;
612+};
613+
614+xkb_types "complete" {
615+ virtual_modifiers NumLock,Alt,LevelThree,Super,LevelFive,Meta,Hyper=0x4000,ScrollLock=0x8000;
616+
617+ type "ONE_LEVEL" {
618+ modifiers= none;
619+ level_name[1]= "Any";
620+ };
621+ type "TWO_LEVEL" {
622+ modifiers= Shift;
623+ map[Shift]= 2;
624+ level_name[1]= "Base";
625+ level_name[2]= "Shift";
626+ };
627+ type "ALPHABETIC" {
628+ modifiers= Shift+Lock;
629+ map[Shift]= 2;
630+ map[Lock]= 2;
631+ level_name[1]= "Base";
632+ level_name[2]= "Caps";
633+ };
634+ type "PC_ALT_LEVEL2" {
635+ modifiers= Alt;
636+ map[Alt]= 2;
637+ level_name[1]= "Base";
638+ level_name[2]= "Alt";
639+ };
640+ type "PC_SUPER_LEVEL2" {
641+ modifiers= Super;
642+ map[Super]= 2;
643+ level_name[1]= "Base";
644+ level_name[2]= "Super";
645+ };
646+ type "PC_SHIFT_SUPER_LEVEL2" {
647+ modifiers= Shift+Super;
648+ map[Shift+Super]= 2;
649+ map[Shift]= 1;
650+ preserve[Shift]= Shift;
651+ map[Super]= 1;
652+ preserve[Super]= Super;
653+ level_name[1]= "Base";
654+ level_name[2]= "Super";
655+ };
656+ type "PC_CONTROL_LEVEL2" {
657+ modifiers= Control;
658+ map[Control]= 2;
659+ level_name[1]= "Base";
660+ level_name[2]= "Control";
661+ };
662+ type "PC_CONTROL_SUPER_LEVEL2" {
663+ modifiers= Control+Super;
664+ map[Control+Super]= 2;
665+ map[Control]= 1;
666+ preserve[Control]= Control;
667+ map[Super]= 1;
668+ preserve[Super]= Super;
669+ level_name[1]= "Base";
670+ level_name[2]= "Control + Super";
671+ };
672+ type "CTRL+ALT" {
673+ modifiers= Shift+Control+Alt+LevelThree;
674+ map[Shift]= 2;
675+ map[LevelThree]= 3;
676+ map[Shift+LevelThree]= 4;
677+ map[Control]= 1;
678+ preserve[Control]= Control;
679+ map[Shift+Control]= 2;
680+ preserve[Shift+Control]= Control;
681+ map[Control+LevelThree]= 3;
682+ preserve[Control+LevelThree]= Control;
683+ map[Shift+Control+LevelThree]= 4;
684+ preserve[Shift+Control+LevelThree]= Control;
685+ map[Alt]= 1;
686+ preserve[Alt]= Alt;
687+ map[Shift+Alt]= 2;
688+ preserve[Shift+Alt]= Alt;
689+ map[Alt+LevelThree]= 3;
690+ preserve[Alt+LevelThree]= Alt;
691+ map[Shift+Alt+LevelThree]= 4;
692+ preserve[Shift+Alt+LevelThree]= Alt;
693+ map[Control+Alt]= 5;
694+ map[Shift+Control+Alt]= 2;
695+ preserve[Shift+Control+Alt]= Control+Alt;
696+ map[Control+Alt+LevelThree]= 3;
697+ preserve[Control+Alt+LevelThree]= Control+Alt;
698+ map[Shift+Control+Alt+LevelThree]= 4;
699+ preserve[Shift+Control+Alt+LevelThree]= Control+Alt;
700+ level_name[1]= "Base";
701+ level_name[2]= "Shift";
702+ level_name[3]= "AltGr";
703+ level_name[4]= "Shift AltGr";
704+ level_name[5]= "Ctrl+Alt";
705+ };
706+ type "THREE_LEVEL" {
707+ modifiers= Shift+LevelThree;
708+ map[Shift]= 2;
709+ map[LevelThree]= 3;
710+ map[Shift+LevelThree]= 3;
711+ level_name[1]= "Base";
712+ level_name[2]= "Shift";
713+ level_name[3]= "Level3";
714+ };
715+ type "FOUR_LEVEL" {
716+ modifiers= Shift+LevelThree;
717+ map[Shift]= 2;
718+ map[LevelThree]= 3;
719+ map[Shift+LevelThree]= 4;
720+ level_name[1]= "Base";
721+ level_name[2]= "Shift";
722+ level_name[3]= "AltGr";
723+ level_name[4]= "Shift AltGr";
724+ };
725+ type "FOUR_LEVEL_ALPHABETIC" {
726+ modifiers= Shift+Lock+LevelThree;
727+ map[Shift]= 2;
728+ map[Lock]= 2;
729+ map[LevelThree]= 3;
730+ map[Shift+LevelThree]= 4;
731+ map[Lock+LevelThree]= 4;
732+ map[Shift+Lock+LevelThree]= 3;
733+ level_name[1]= "Base";
734+ level_name[2]= "Shift";
735+ level_name[3]= "AltGr";
736+ level_name[4]= "Shift AltGr";
737+ };
738+ type "FOUR_LEVEL_SEMIALPHABETIC" {
739+ modifiers= Shift+Lock+LevelThree;
740+ map[Shift]= 2;
741+ map[Lock]= 2;
742+ map[LevelThree]= 3;
743+ map[Shift+LevelThree]= 4;
744+ map[Lock+LevelThree]= 3;
745+ preserve[Lock+LevelThree]= Lock;
746+ map[Shift+Lock+LevelThree]= 4;
747+ preserve[Shift+Lock+LevelThree]= Lock;
748+ level_name[1]= "Base";
749+ level_name[2]= "Shift";
750+ level_name[3]= "AltGr";
751+ level_name[4]= "Shift AltGr";
752+ };
753+ type "FOUR_LEVEL_KEYPAD" {
754+ modifiers= Shift+NumLock+LevelThree;
755+ map[Shift]= 1;
756+ preserve[Shift]= Shift;
757+ map[NumLock]= 2;
758+ map[LevelThree]= 3;
759+ map[Shift+NumLock]= 2;
760+ preserve[Shift+NumLock]= Shift;
761+ map[Shift+LevelThree]= 4;
762+ map[NumLock+LevelThree]= 3;
763+ map[Shift+NumLock+LevelThree]= 4;
764+ level_name[1]= "Base";
765+ level_name[2]= "NumLock";
766+ level_name[3]= "AltGr";
767+ level_name[4]= "Shift AltGr";
768+ };
769+ type "FOUR_LEVEL_MIXED_KEYPAD" {
770+ modifiers= Shift+NumLock+LevelThree;
771+ map[Shift]= 1;
772+ preserve[Shift]= Shift;
773+ map[NumLock]= 2;
774+ map[LevelThree]= 3;
775+ map[Shift+NumLock]= 2;
776+ preserve[Shift+NumLock]= Shift;
777+ map[Shift+LevelThree]= 4;
778+ map[NumLock+LevelThree]= 3;
779+ map[Shift+NumLock+LevelThree]= 4;
780+ level_name[1]= "Base";
781+ level_name[2]= "NumLock";
782+ level_name[3]= "AltGr";
783+ level_name[4]= "Shift AltGr";
784+ };
785+ type "FOUR_LEVEL_LOCKABLE_LEVEL2" {
786+ modifiers= Shift+LevelThree+LevelFive;
787+ map[Shift]= 2;
788+ map[LevelFive]= 2;
789+ map[LevelThree]= 3;
790+ map[Shift+LevelThree]= 4;
791+ map[LevelThree+LevelFive]= 3;
792+ map[Shift+LevelThree+LevelFive]= 4;
793+ level_name[1]= "Base";
794+ level_name[2]= "Digit";
795+ level_name[3]= "AltGr";
796+ level_name[4]= "Shift AltGr";
797+ };
798+ type "FOUR_LEVEL_X" {
799+ modifiers= Shift+Control+Alt+LevelThree;
800+ map[Shift]= 1;
801+ preserve[Shift]= Shift;
802+ map[LevelThree]= 2;
803+ map[Control]= 1;
804+ preserve[Control]= Control;
805+ map[Alt]= 1;
806+ preserve[Alt]= Alt;
807+ map[Shift+LevelThree]= 3;
808+ map[Shift+Control]= 1;
809+ preserve[Shift+Control]= Shift+Control;
810+ map[Shift+Alt]= 1;
811+ preserve[Shift+Alt]= Shift+Alt;
812+ map[Control+LevelThree]= 2;
813+ preserve[Control+LevelThree]= Control;
814+ map[Alt+LevelThree]= 2;
815+ preserve[Alt+LevelThree]= Alt;
816+ map[Control+Alt]= 4;
817+ map[Shift+Control+LevelThree]= 3;
818+ preserve[Shift+Control+LevelThree]= Control;
819+ map[Shift+Alt+LevelThree]= 3;
820+ preserve[Shift+Alt+LevelThree]= Alt;
821+ map[Shift+Control+Alt]= 4;
822+ preserve[Shift+Control+Alt]= Shift;
823+ map[Control+Alt+LevelThree]= 2;
824+ preserve[Control+Alt+LevelThree]= Control+Alt;
825+ map[Shift+Control+Alt+LevelThree]= 3;
826+ preserve[Shift+Control+Alt+LevelThree]= Control+Alt;
827+ level_name[1]= "Base";
828+ level_name[2]= "AltGr";
829+ level_name[3]= "Shift AltGr";
830+ level_name[4]= "Ctrl+Alt";
831+ };
832+ type "SEPARATE_CAPS_AND_SHIFT_ALPHABETIC" {
833+ modifiers= Shift+Lock+LevelThree;
834+ map[Shift]= 2;
835+ map[Lock]= 4;
836+ preserve[Lock]= Lock;
837+ map[LevelThree]= 3;
838+ map[Shift+LevelThree]= 4;
839+ map[Lock+LevelThree]= 3;
840+ preserve[Lock+LevelThree]= Lock;
841+ map[Shift+Lock+LevelThree]= 3;
842+ level_name[1]= "Base";
843+ level_name[2]= "Shift";
844+ level_name[3]= "AltGr";
845+ level_name[4]= "Caps / Shift AltGr";
846+ };
847+ type "FOUR_LEVEL_PLUS_LOCK" {
848+ modifiers= Shift+Lock+LevelThree;
849+ map[Shift]= 2;
850+ map[LevelThree]= 3;
851+ map[Shift+LevelThree]= 4;
852+ map[Lock]= 5;
853+ map[Shift+Lock]= 2;
854+ map[Lock+LevelThree]= 3;
855+ map[Shift+Lock+LevelThree]= 4;
856+ level_name[1]= "Base";
857+ level_name[2]= "Shift";
858+ level_name[3]= "AltGr";
859+ level_name[4]= "Shift AltGr";
860+ level_name[5]= "Lock";
861+ };
862+ type "EIGHT_LEVEL" {
863+ modifiers= Shift+LevelThree+LevelFive;
864+ map[Shift]= 2;
865+ map[LevelThree]= 3;
866+ map[Shift+LevelThree]= 4;
867+ map[LevelFive]= 5;
868+ map[Shift+LevelFive]= 6;
869+ map[LevelThree+LevelFive]= 7;
870+ map[Shift+LevelThree+LevelFive]= 8;
871+ level_name[1]= "Base";
872+ level_name[2]= "Shift";
873+ level_name[3]= "AltGr";
874+ level_name[4]= "Shift AltGr";
875+ level_name[5]= "X";
876+ level_name[6]= "X Shift";
877+ level_name[7]= "X AltGr";
878+ level_name[8]= "X Shift AltGr";
879+ };
880+ type "EIGHT_LEVEL_ALPHABETIC" {
881+ modifiers= Shift+Lock+LevelThree+LevelFive;
882+ map[Shift]= 2;
883+ map[Lock]= 2;
884+ map[LevelThree]= 3;
885+ map[Shift+LevelThree]= 4;
886+ map[Lock+LevelThree]= 4;
887+ map[Shift+Lock+LevelThree]= 3;
888+ map[LevelFive]= 5;
889+ map[Shift+LevelFive]= 6;
890+ map[Lock+LevelFive]= 6;
891+ map[Shift+Lock+LevelFive]= 5;
892+ map[LevelThree+LevelFive]= 7;
893+ map[Shift+LevelThree+LevelFive]= 8;
894+ map[Lock+LevelThree+LevelFive]= 8;
895+ map[Shift+Lock+LevelThree+LevelFive]= 7;
896+ level_name[1]= "Base";
897+ level_name[2]= "Shift";
898+ level_name[3]= "AltGr";
899+ level_name[4]= "Shift AltGr";
900+ level_name[5]= "X";
901+ level_name[6]= "X Shift";
902+ level_name[7]= "X AltGr";
903+ level_name[8]= "X Shift AltGr";
904+ };
905+ type "EIGHT_LEVEL_SEMIALPHABETIC" {
906+ modifiers= Shift+Lock+LevelThree+LevelFive;
907+ map[Shift]= 2;
908+ map[Lock]= 2;
909+ map[LevelThree]= 3;
910+ map[Shift+LevelThree]= 4;
911+ map[Lock+LevelThree]= 3;
912+ preserve[Lock+LevelThree]= Lock;
913+ map[Shift+Lock+LevelThree]= 4;
914+ preserve[Shift+Lock+LevelThree]= Lock;
915+ map[LevelFive]= 5;
916+ map[Shift+LevelFive]= 6;
917+ map[Lock+LevelFive]= 6;
918+ map[Shift+Lock+LevelFive]= 5;
919+ map[LevelThree+LevelFive]= 7;
920+ map[Shift+LevelThree+LevelFive]= 8;
921+ map[Lock+LevelThree+LevelFive]= 7;
922+ preserve[Lock+LevelThree+LevelFive]= Lock;
923+ map[Shift+Lock+LevelThree+LevelFive]= 8;
924+ preserve[Shift+Lock+LevelThree+LevelFive]= Lock;
925+ level_name[1]= "Base";
926+ level_name[2]= "Shift";
927+ level_name[3]= "AltGr";
928+ level_name[4]= "Shift AltGr";
929+ level_name[5]= "X";
930+ level_name[6]= "X Shift";
931+ level_name[7]= "X AltGr";
932+ level_name[8]= "X Shift AltGr";
933+ };
934+ type "EIGHT_LEVEL_WITH_LEVEL5_LOCK" {
935+ modifiers= Shift+NumLock+LevelThree+LevelFive;
936+ map[Shift]= 2;
937+ map[LevelThree]= 3;
938+ map[Shift+LevelThree]= 4;
939+ map[LevelFive]= 5;
940+ map[Shift+LevelFive]= 6;
941+ preserve[Shift+LevelFive]= Shift;
942+ map[LevelThree+LevelFive]= 7;
943+ map[Shift+LevelThree+LevelFive]= 8;
944+ map[NumLock]= 5;
945+ map[Shift+NumLock]= 6;
946+ preserve[Shift+NumLock]= Shift;
947+ map[NumLock+LevelThree]= 7;
948+ map[Shift+NumLock+LevelThree]= 8;
949+ map[Shift+NumLock+LevelFive]= 2;
950+ map[NumLock+LevelThree+LevelFive]= 3;
951+ map[Shift+NumLock+LevelThree+LevelFive]= 4;
952+ level_name[1]= "Base";
953+ level_name[2]= "Shift";
954+ level_name[3]= "AltGr";
955+ level_name[4]= "Shift AltGr";
956+ level_name[5]= "X";
957+ level_name[6]= "X Shift";
958+ level_name[7]= "X AltGr";
959+ level_name[8]= "X Shift AltGr";
960+ };
961+ type "EIGHT_LEVEL_ALPHABETIC_WITH_LEVEL5_LOCK" {
962+ modifiers= Shift+Lock+NumLock+LevelThree+LevelFive;
963+ map[Shift]= 2;
964+ map[LevelThree]= 3;
965+ map[Shift+LevelThree]= 4;
966+ map[LevelFive]= 5;
967+ map[Shift+LevelFive]= 6;
968+ preserve[Shift+LevelFive]= Shift;
969+ map[LevelThree+LevelFive]= 7;
970+ map[Shift+LevelThree+LevelFive]= 8;
971+ map[NumLock]= 5;
972+ map[Shift+NumLock]= 6;
973+ preserve[Shift+NumLock]= Shift;
974+ map[NumLock+LevelThree]= 7;
975+ map[Shift+NumLock+LevelThree]= 8;
976+ map[Shift+NumLock+LevelFive]= 2;
977+ map[NumLock+LevelThree+LevelFive]= 3;
978+ map[Shift+NumLock+LevelThree+LevelFive]= 4;
979+ map[Lock]= 2;
980+ map[Lock+LevelThree]= 3;
981+ map[Shift+Lock+LevelThree]= 4;
982+ map[Lock+LevelFive]= 5;
983+ map[Shift+Lock+LevelFive]= 6;
984+ map[Lock+LevelThree+LevelFive]= 7;
985+ map[Shift+Lock+LevelThree+LevelFive]= 8;
986+ map[Lock+NumLock]= 5;
987+ map[Shift+Lock+NumLock]= 6;
988+ map[Lock+NumLock+LevelThree]= 7;
989+ map[Shift+Lock+NumLock+LevelThree]= 8;
990+ map[Lock+NumLock+LevelFive]= 2;
991+ map[Lock+NumLock+LevelThree+LevelFive]= 3;
992+ map[Shift+Lock+NumLock+LevelThree+LevelFive]= 4;
993+ level_name[1]= "Base";
994+ level_name[2]= "Shift";
995+ level_name[3]= "AltGr";
996+ level_name[4]= "Shift AltGr";
997+ level_name[5]= "X";
998+ level_name[6]= "X Shift";
999+ level_name[7]= "X AltGr";
1000+ level_name[8]= "X Shift AltGr";
1001+ };
1002+ type "EIGHT_LEVEL_BY_CTRL" {
1003+ modifiers= Shift+Lock+Control+LevelThree;
1004+ map[Shift]= 2;
1005+ map[Lock]= 2;
1006+ map[LevelThree]= 3;
1007+ map[Shift+LevelThree]= 4;
1008+ map[Lock+LevelThree]= 4;
1009+ map[Shift+Lock+LevelThree]= 3;
1010+ map[Control]= 5;
1011+ map[Shift+Control]= 6;
1012+ map[Lock+Control]= 6;
1013+ map[Shift+Lock+Control]= 5;
1014+ map[Control+LevelThree]= 7;
1015+ map[Shift+Control+LevelThree]= 8;
1016+ map[Lock+Control+LevelThree]= 8;
1017+ map[Shift+Lock+Control+LevelThree]= 7;
1018+ level_name[1]= "Base";
1019+ level_name[2]= "Shift";
1020+ level_name[3]= "Level3";
1021+ level_name[4]= "Shift Level3";
1022+ level_name[5]= "Ctrl";
1023+ level_name[6]= "Shift Ctrl";
1024+ level_name[7]= "Level3 Ctrl";
1025+ level_name[8]= "Shift Level3 Ctrl";
1026+ };
1027+ type "KEYPAD" {
1028+ modifiers= NumLock;
1029+ map[NumLock]= 2;
1030+ level_name[1]= "Base";
1031+ level_name[2]= "Number";
1032+ };
1033+ type "SHIFT+ALT" {
1034+ modifiers= Shift+Alt;
1035+ map[Shift+Alt]= 2;
1036+ level_name[1]= "Base";
1037+ level_name[2]= "Shift+Alt";
1038+ };
1039+};
1040+
1041+xkb_compatibility "complete" {
1042+ virtual_modifiers NumLock,Alt,LevelThree,Super,LevelFive,Meta,Hyper=0x4000,ScrollLock=0x8000;
1043+
1044+ interpret.useModMapMods= AnyLevel;
1045+ interpret.repeat= False;
1046+ interpret ISO_Level2_Latch+Exactly(Shift) {
1047+ useModMapMods=level1;
1048+ action= LatchMods(modifiers=Shift,clearLocks,latchToLock);
1049+ };
1050+ interpret Shift_Lock+AnyOf(Shift+Lock) {
1051+ action= LockMods(modifiers=Shift);
1052+ };
1053+ interpret Num_Lock+AnyOf(all) {
1054+ virtualModifier= NumLock;
1055+ action= LockMods(modifiers=NumLock);
1056+ };
1057+ interpret ISO_Level3_Shift+AnyOf(all) {
1058+ virtualModifier= LevelThree;
1059+ useModMapMods=level1;
1060+ action= SetMods(modifiers=LevelThree,clearLocks);
1061+ };
1062+ interpret ISO_Level3_Latch+AnyOf(all) {
1063+ virtualModifier= LevelThree;
1064+ useModMapMods=level1;
1065+ action= LatchMods(modifiers=LevelThree,clearLocks,latchToLock);
1066+ };
1067+ interpret ISO_Level3_Lock+AnyOf(all) {
1068+ virtualModifier= LevelThree;
1069+ useModMapMods=level1;
1070+ action= LockMods(modifiers=LevelThree);
1071+ };
1072+ interpret Alt_L+AnyOf(all) {
1073+ virtualModifier= Alt;
1074+ action= SetMods(modifiers=modMapMods,clearLocks);
1075+ };
1076+ interpret Alt_R+AnyOf(all) {
1077+ virtualModifier= Alt;
1078+ action= SetMods(modifiers=modMapMods,clearLocks);
1079+ };
1080+ interpret Meta_L+AnyOf(all) {
1081+ virtualModifier= Meta;
1082+ action= SetMods(modifiers=modMapMods,clearLocks);
1083+ };
1084+ interpret Meta_R+AnyOf(all) {
1085+ virtualModifier= Meta;
1086+ action= SetMods(modifiers=modMapMods,clearLocks);
1087+ };
1088+ interpret Super_L+AnyOf(all) {
1089+ virtualModifier= Super;
1090+ action= SetMods(modifiers=modMapMods,clearLocks);
1091+ };
1092+ interpret Super_R+AnyOf(all) {
1093+ virtualModifier= Super;
1094+ action= SetMods(modifiers=modMapMods,clearLocks);
1095+ };
1096+ interpret Hyper_L+AnyOf(all) {
1097+ virtualModifier= Hyper;
1098+ action= SetMods(modifiers=modMapMods,clearLocks);
1099+ };
1100+ interpret Hyper_R+AnyOf(all) {
1101+ virtualModifier= Hyper;
1102+ action= SetMods(modifiers=modMapMods,clearLocks);
1103+ };
1104+ interpret Scroll_Lock+AnyOf(all) {
1105+ virtualModifier= ScrollLock;
1106+ action= LockMods(modifiers=modMapMods);
1107+ };
1108+ interpret ISO_Level5_Shift+AnyOf(all) {
1109+ virtualModifier= LevelFive;
1110+ useModMapMods=level1;
1111+ action= SetMods(modifiers=LevelFive,clearLocks);
1112+ };
1113+ interpret ISO_Level5_Latch+AnyOf(all) {
1114+ virtualModifier= LevelFive;
1115+ useModMapMods=level1;
1116+ action= LatchMods(modifiers=LevelFive,clearLocks,latchToLock);
1117+ };
1118+ interpret ISO_Level5_Lock+AnyOf(all) {
1119+ virtualModifier= LevelFive;
1120+ useModMapMods=level1;
1121+ action= LockMods(modifiers=LevelFive);
1122+ };
1123+ interpret ISO_Group_Shift+AnyOfOrNone(all) {
1124+ action= SetGroup(group=+1);
1125+ };
1126+ interpret ISO_Level3_Shift+AnyOfOrNone(all) {
1127+ action= SetMods(modifiers=LevelThree,clearLocks);
1128+ };
1129+ interpret ISO_Level3_Latch+AnyOfOrNone(all) {
1130+ action= LatchMods(modifiers=LevelThree,clearLocks,latchToLock);
1131+ };
1132+ interpret ISO_Level3_Lock+AnyOfOrNone(all) {
1133+ action= LockMods(modifiers=LevelThree);
1134+ };
1135+ interpret ISO_Group_Latch+AnyOfOrNone(all) {
1136+ action= LatchGroup(group=2);
1137+ };
1138+ interpret ISO_Next_Group+AnyOfOrNone(all) {
1139+ action= LockGroup(group=+1);
1140+ };
1141+ interpret ISO_Prev_Group+AnyOfOrNone(all) {
1142+ action= LockGroup(group=-1);
1143+ };
1144+ interpret ISO_First_Group+AnyOfOrNone(all) {
1145+ action= LockGroup(group=1);
1146+ };
1147+ interpret ISO_Last_Group+AnyOfOrNone(all) {
1148+ action= LockGroup(group=2);
1149+ };
1150+ interpret KP_1+AnyOfOrNone(all) {
1151+ repeat= True;
1152+ action= MovePtr(x=-1,y=+1);
1153+ };
1154+ interpret KP_End+AnyOfOrNone(all) {
1155+ repeat= True;
1156+ action= MovePtr(x=-1,y=+1);
1157+ };
1158+ interpret KP_2+AnyOfOrNone(all) {
1159+ repeat= True;
1160+ action= MovePtr(x=+0,y=+1);
1161+ };
1162+ interpret KP_Down+AnyOfOrNone(all) {
1163+ repeat= True;
1164+ action= MovePtr(x=+0,y=+1);
1165+ };
1166+ interpret KP_3+AnyOfOrNone(all) {
1167+ repeat= True;
1168+ action= MovePtr(x=+1,y=+1);
1169+ };
1170+ interpret KP_Next+AnyOfOrNone(all) {
1171+ repeat= True;
1172+ action= MovePtr(x=+1,y=+1);
1173+ };
1174+ interpret KP_4+AnyOfOrNone(all) {
1175+ repeat= True;
1176+ action= MovePtr(x=-1,y=+0);
1177+ };
1178+ interpret KP_Left+AnyOfOrNone(all) {
1179+ repeat= True;
1180+ action= MovePtr(x=-1,y=+0);
1181+ };
1182+ interpret KP_6+AnyOfOrNone(all) {
1183+ repeat= True;
1184+ action= MovePtr(x=+1,y=+0);
1185+ };
1186+ interpret KP_Right+AnyOfOrNone(all) {
1187+ repeat= True;
1188+ action= MovePtr(x=+1,y=+0);
1189+ };
1190+ interpret KP_7+AnyOfOrNone(all) {
1191+ repeat= True;
1192+ action= MovePtr(x=-1,y=-1);
1193+ };
1194+ interpret KP_Home+AnyOfOrNone(all) {
1195+ repeat= True;
1196+ action= MovePtr(x=-1,y=-1);
1197+ };
1198+ interpret KP_8+AnyOfOrNone(all) {
1199+ repeat= True;
1200+ action= MovePtr(x=+0,y=-1);
1201+ };
1202+ interpret KP_Up+AnyOfOrNone(all) {
1203+ repeat= True;
1204+ action= MovePtr(x=+0,y=-1);
1205+ };
1206+ interpret KP_9+AnyOfOrNone(all) {
1207+ repeat= True;
1208+ action= MovePtr(x=+1,y=-1);
1209+ };
1210+ interpret KP_Prior+AnyOfOrNone(all) {
1211+ repeat= True;
1212+ action= MovePtr(x=+1,y=-1);
1213+ };
1214+ interpret KP_5+AnyOfOrNone(all) {
1215+ repeat= True;
1216+ action= PtrBtn(button=default);
1217+ };
1218+ interpret KP_Begin+AnyOfOrNone(all) {
1219+ repeat= True;
1220+ action= PtrBtn(button=default);
1221+ };
1222+ interpret KP_F2+AnyOfOrNone(all) {
1223+ repeat= True;
1224+ action= SetPtrDflt(affect=button,button=1);
1225+ };
1226+ interpret KP_Divide+AnyOfOrNone(all) {
1227+ repeat= True;
1228+ action= SetPtrDflt(affect=button,button=1);
1229+ };
1230+ interpret KP_F3+AnyOfOrNone(all) {
1231+ repeat= True;
1232+ action= SetPtrDflt(affect=button,button=2);
1233+ };
1234+ interpret KP_Multiply+AnyOfOrNone(all) {
1235+ repeat= True;
1236+ action= SetPtrDflt(affect=button,button=2);
1237+ };
1238+ interpret KP_F4+AnyOfOrNone(all) {
1239+ repeat= True;
1240+ action= SetPtrDflt(affect=button,button=3);
1241+ };
1242+ interpret KP_Subtract+AnyOfOrNone(all) {
1243+ repeat= True;
1244+ action= SetPtrDflt(affect=button,button=3);
1245+ };
1246+ interpret KP_Separator+AnyOfOrNone(all) {
1247+ repeat= True;
1248+ action= PtrBtn(button=default,count=2);
1249+ };
1250+ interpret KP_Add+AnyOfOrNone(all) {
1251+ repeat= True;
1252+ action= PtrBtn(button=default,count=2);
1253+ };
1254+ interpret KP_0+AnyOfOrNone(all) {
1255+ repeat= True;
1256+ action= LockPtrBtn(button=default,affect=lock);
1257+ };
1258+ interpret KP_Insert+AnyOfOrNone(all) {
1259+ repeat= True;
1260+ action= LockPtrBtn(button=default,affect=lock);
1261+ };
1262+ interpret KP_Decimal+AnyOfOrNone(all) {
1263+ repeat= True;
1264+ action= LockPtrBtn(button=default,affect=unlock);
1265+ };
1266+ interpret KP_Delete+AnyOfOrNone(all) {
1267+ repeat= True;
1268+ action= LockPtrBtn(button=default,affect=unlock);
1269+ };
1270+ interpret F25+AnyOfOrNone(all) {
1271+ repeat= True;
1272+ action= SetPtrDflt(affect=button,button=1);
1273+ };
1274+ interpret F26+AnyOfOrNone(all) {
1275+ repeat= True;
1276+ action= SetPtrDflt(affect=button,button=2);
1277+ };
1278+ interpret F27+AnyOfOrNone(all) {
1279+ repeat= True;
1280+ action= MovePtr(x=-1,y=-1);
1281+ };
1282+ interpret F29+AnyOfOrNone(all) {
1283+ repeat= True;
1284+ action= MovePtr(x=+1,y=-1);
1285+ };
1286+ interpret F31+AnyOfOrNone(all) {
1287+ repeat= True;
1288+ action= PtrBtn(button=default);
1289+ };
1290+ interpret F33+AnyOfOrNone(all) {
1291+ repeat= True;
1292+ action= MovePtr(x=-1,y=+1);
1293+ };
1294+ interpret F35+AnyOfOrNone(all) {
1295+ repeat= True;
1296+ action= MovePtr(x=+1,y=+1);
1297+ };
1298+ interpret Pointer_Button_Dflt+AnyOfOrNone(all) {
1299+ action= PtrBtn(button=default);
1300+ };
1301+ interpret Pointer_Button1+AnyOfOrNone(all) {
1302+ action= PtrBtn(button=1);
1303+ };
1304+ interpret Pointer_Button2+AnyOfOrNone(all) {
1305+ action= PtrBtn(button=2);
1306+ };
1307+ interpret Pointer_Button3+AnyOfOrNone(all) {
1308+ action= PtrBtn(button=3);
1309+ };
1310+ interpret Pointer_DblClick_Dflt+AnyOfOrNone(all) {
1311+ action= PtrBtn(button=default,count=2);
1312+ };
1313+ interpret Pointer_DblClick1+AnyOfOrNone(all) {
1314+ action= PtrBtn(button=1,count=2);
1315+ };
1316+ interpret Pointer_DblClick2+AnyOfOrNone(all) {
1317+ action= PtrBtn(button=2,count=2);
1318+ };
1319+ interpret Pointer_DblClick3+AnyOfOrNone(all) {
1320+ action= PtrBtn(button=3,count=2);
1321+ };
1322+ interpret Pointer_Drag_Dflt+AnyOfOrNone(all) {
1323+ action= LockPtrBtn(button=default,affect=both);
1324+ };
1325+ interpret Pointer_Drag1+AnyOfOrNone(all) {
1326+ action= LockPtrBtn(button=1,affect=both);
1327+ };
1328+ interpret Pointer_Drag2+AnyOfOrNone(all) {
1329+ action= LockPtrBtn(button=2,affect=both);
1330+ };
1331+ interpret Pointer_Drag3+AnyOfOrNone(all) {
1332+ action= LockPtrBtn(button=3,affect=both);
1333+ };
1334+ interpret Pointer_EnableKeys+AnyOfOrNone(all) {
1335+ action= LockControls(controls=MouseKeys);
1336+ };
1337+ interpret Pointer_Accelerate+AnyOfOrNone(all) {
1338+ action= LockControls(controls=MouseKeysAccel);
1339+ };
1340+ interpret Pointer_DfltBtnNext+AnyOfOrNone(all) {
1341+ action= SetPtrDflt(affect=button,button=+1);
1342+ };
1343+ interpret Pointer_DfltBtnPrev+AnyOfOrNone(all) {
1344+ action= SetPtrDflt(affect=button,button=-1);
1345+ };
1346+ interpret AccessX_Enable+AnyOfOrNone(all) {
1347+ action= LockControls(controls=AccessXKeys);
1348+ };
1349+ interpret AccessX_Feedback_Enable+AnyOfOrNone(all) {
1350+ action= LockControls(controls=AccessXFeedback);
1351+ };
1352+ interpret RepeatKeys_Enable+AnyOfOrNone(all) {
1353+ action= LockControls(controls=RepeatKeys);
1354+ };
1355+ interpret SlowKeys_Enable+AnyOfOrNone(all) {
1356+ action= LockControls(controls=SlowKeys);
1357+ };
1358+ interpret BounceKeys_Enable+AnyOfOrNone(all) {
1359+ action= LockControls(controls=BounceKeys);
1360+ };
1361+ interpret StickyKeys_Enable+AnyOfOrNone(all) {
1362+ action= LockControls(controls=StickyKeys);
1363+ };
1364+ interpret MouseKeys_Enable+AnyOfOrNone(all) {
1365+ action= LockControls(controls=MouseKeys);
1366+ };
1367+ interpret MouseKeys_Accel_Enable+AnyOfOrNone(all) {
1368+ action= LockControls(controls=MouseKeysAccel);
1369+ };
1370+ interpret Overlay1_Enable+AnyOfOrNone(all) {
1371+ action= LockControls(controls=none);
1372+ };
1373+ interpret Overlay2_Enable+AnyOfOrNone(all) {
1374+ action= LockControls(controls=none);
1375+ };
1376+ interpret AudibleBell_Enable+AnyOfOrNone(all) {
1377+ action= LockControls(controls=AudibleBell);
1378+ };
1379+ interpret Terminate_Server+AnyOfOrNone(all) {
1380+ action= Terminate();
1381+ };
1382+ interpret Alt_L+AnyOfOrNone(all) {
1383+ action= SetMods(modifiers=Alt,clearLocks);
1384+ };
1385+ interpret Alt_R+AnyOfOrNone(all) {
1386+ action= SetMods(modifiers=Alt,clearLocks);
1387+ };
1388+ interpret Meta_L+AnyOfOrNone(all) {
1389+ action= SetMods(modifiers=Meta,clearLocks);
1390+ };
1391+ interpret Meta_R+AnyOfOrNone(all) {
1392+ action= SetMods(modifiers=Meta,clearLocks);
1393+ };
1394+ interpret Super_L+AnyOfOrNone(all) {
1395+ action= SetMods(modifiers=Super,clearLocks);
1396+ };
1397+ interpret Super_R+AnyOfOrNone(all) {
1398+ action= SetMods(modifiers=Super,clearLocks);
1399+ };
1400+ interpret Hyper_L+AnyOfOrNone(all) {
1401+ action= SetMods(modifiers=Hyper,clearLocks);
1402+ };
1403+ interpret Hyper_R+AnyOfOrNone(all) {
1404+ action= SetMods(modifiers=Hyper,clearLocks);
1405+ };
1406+ interpret Shift_L+AnyOfOrNone(all) {
1407+ action= SetMods(modifiers=Shift,clearLocks);
1408+ };
1409+ interpret Shift_R+AnyOfOrNone(all) {
1410+ action= SetMods(modifiers=Shift,clearLocks);
1411+ };
1412+ interpret XF86Switch_VT_1+AnyOfOrNone(all) {
1413+ repeat= True;
1414+ action= SwitchScreen(screen=1,!same);
1415+ };
1416+ interpret XF86Switch_VT_2+AnyOfOrNone(all) {
1417+ repeat= True;
1418+ action= SwitchScreen(screen=2,!same);
1419+ };
1420+ interpret XF86Switch_VT_3+AnyOfOrNone(all) {
1421+ repeat= True;
1422+ action= SwitchScreen(screen=3,!same);
1423+ };
1424+ interpret XF86Switch_VT_4+AnyOfOrNone(all) {
1425+ repeat= True;
1426+ action= SwitchScreen(screen=4,!same);
1427+ };
1428+ interpret XF86Switch_VT_5+AnyOfOrNone(all) {
1429+ repeat= True;
1430+ action= SwitchScreen(screen=5,!same);
1431+ };
1432+ interpret XF86Switch_VT_6+AnyOfOrNone(all) {
1433+ repeat= True;
1434+ action= SwitchScreen(screen=6,!same);
1435+ };
1436+ interpret XF86Switch_VT_7+AnyOfOrNone(all) {
1437+ repeat= True;
1438+ action= SwitchScreen(screen=7,!same);
1439+ };
1440+ interpret XF86Switch_VT_8+AnyOfOrNone(all) {
1441+ repeat= True;
1442+ action= SwitchScreen(screen=8,!same);
1443+ };
1444+ interpret XF86Switch_VT_9+AnyOfOrNone(all) {
1445+ repeat= True;
1446+ action= SwitchScreen(screen=9,!same);
1447+ };
1448+ interpret XF86Switch_VT_10+AnyOfOrNone(all) {
1449+ repeat= True;
1450+ action= SwitchScreen(screen=10,!same);
1451+ };
1452+ interpret XF86Switch_VT_11+AnyOfOrNone(all) {
1453+ repeat= True;
1454+ action= SwitchScreen(screen=11,!same);
1455+ };
1456+ interpret XF86Switch_VT_12+AnyOfOrNone(all) {
1457+ repeat= True;
1458+ action= SwitchScreen(screen=12,!same);
1459+ };
1460+ interpret XF86LogGrabInfo+AnyOfOrNone(all) {
1461+ repeat= True;
1462+ action= Private(type=0x86,data[0]=0x50,data[1]=0x72,data[2]=0x47,data[3]=0x72,data[4]=0x62,data[5]=0x73,data[6]=0x00);
1463+ };
1464+ interpret XF86LogWindowTree+AnyOfOrNone(all) {
1465+ repeat= True;
1466+ action= Private(type=0x86,data[0]=0x50,data[1]=0x72,data[2]=0x57,data[3]=0x69,data[4]=0x6e,data[5]=0x73,data[6]=0x00);
1467+ };
1468+ interpret XF86Next_VMode+AnyOfOrNone(all) {
1469+ repeat= True;
1470+ action= Private(type=0x86,data[0]=0x2b,data[1]=0x56,data[2]=0x4d,data[3]=0x6f,data[4]=0x64,data[5]=0x65,data[6]=0x00);
1471+ };
1472+ interpret XF86Prev_VMode+AnyOfOrNone(all) {
1473+ repeat= True;
1474+ action= Private(type=0x86,data[0]=0x2d,data[1]=0x56,data[2]=0x4d,data[3]=0x6f,data[4]=0x64,data[5]=0x65,data[6]=0x00);
1475+ };
1476+ interpret ISO_Level5_Shift+AnyOfOrNone(all) {
1477+ action= SetMods(modifiers=LevelFive,clearLocks);
1478+ };
1479+ interpret ISO_Level5_Latch+AnyOfOrNone(all) {
1480+ action= LatchMods(modifiers=LevelFive,clearLocks,latchToLock);
1481+ };
1482+ interpret ISO_Level5_Lock+AnyOfOrNone(all) {
1483+ action= LockMods(modifiers=LevelFive);
1484+ };
1485+ interpret Caps_Lock+AnyOfOrNone(all) {
1486+ action= LockMods(modifiers=Lock);
1487+ };
1488+ interpret Any+Exactly(Lock) {
1489+ action= LockMods(modifiers=Lock);
1490+ };
1491+ interpret Any+AnyOf(all) {
1492+ action= SetMods(modifiers=modMapMods,clearLocks);
1493+ };
1494+ indicator "Caps Lock" {
1495+ whichModState= locked;
1496+ modifiers= Lock;
1497+ };
1498+ indicator "Num Lock" {
1499+ whichModState= locked;
1500+ modifiers= NumLock;
1501+ };
1502+ indicator "Scroll Lock" {
1503+ whichModState= locked;
1504+ modifiers= ScrollLock;
1505+ };
1506+ indicator "Shift Lock" {
1507+ whichModState= locked;
1508+ modifiers= Shift;
1509+ };
1510+ indicator "Group 2" {
1511+ groups= 0xfffffffe;
1512+ };
1513+ indicator "Mouse Keys" {
1514+ controls= MouseKeys;
1515+ };
1516+};
1517+
1518+xkb_symbols "pc_fr_inet(evdev)" {
1519+ name[1]="French";
1520+
1521+ key <ESC> { [ Escape ] };
1522+ key <AE01> { [ ampersand, 1, onesuperior, exclamdown ] };
1523+ key <AE02> { [ eacute, 2, asciitilde, oneeighth ] };
1524+ key <AE03> { [ quotedbl, 3, numbersign, sterling ] };
1525+ key <AE04> { [ apostrophe, 4, braceleft, dollar ] };
1526+ key <AE05> { [ parenleft, 5, bracketleft, threeeighths ] };
1527+ key <AE06> { [ minus, 6, bar, fiveeighths ] };
1528+ key <AE07> { [ egrave, 7, grave, seveneighths ] };
1529+ key <AE08> { [ underscore, 8, backslash, trademark ] };
1530+ key <AE09> { [ ccedilla, 9, asciicircum, plusminus ] };
1531+ key <AE10> { [ agrave, 0, at, degree ] };
1532+ key <AE11> { [ parenright, degree, bracketright, questiondown ] };
1533+ key <AE12> { [ equal, plus, braceright, dead_ogonek ] };
1534+ key <BKSP> { [ BackSpace, BackSpace ] };
1535+ key <TAB> { [ Tab, ISO_Left_Tab ] };
1536+ key <AD01> { [ a, A, ae, AE ] };
1537+ key <AD02> { [ z, Z, guillemotleft, less ] };
1538+ key <AD03> { [ e, E, EuroSign, cent ] };
1539+ key <AD04> { [ r, R, paragraph, registered ] };
1540+ key <AD05> { [ t, T, tslash, Tslash ] };
1541+ key <AD06> { [ y, Y, leftarrow, yen ] };
1542+ key <AD07> { [ u, U, downarrow, uparrow ] };
1543+ key <AD08> { [ i, I, rightarrow, idotless ] };
1544+ key <AD09> { [ o, O, oslash, Oslash ] };
1545+ key <AD10> { [ p, P, thorn, THORN ] };
1546+ key <AD11> { [ dead_circumflex, dead_diaeresis, dead_diaeresis, dead_abovering ] };
1547+ key <AD12> { [ dollar, sterling, currency, dead_macron ] };
1548+ key <RTRN> { [ Return ] };
1549+ key <LCTL> { [ Control_L ] };
1550+ key <AC01> { [ q, Q, at, Greek_OMEGA ] };
1551+ key <AC02> { [ s, S, ssharp, SSHARP ] };
1552+ key <AC03> { [ d, D, eth, ETH ] };
1553+ key <AC04> { [ f, F, dstroke, ordfeminine ] };
1554+ key <AC05> { [ g, G, eng, ENG ] };
1555+ key <AC06> { [ h, H, hstroke, Hstroke ] };
1556+ key <AC07> { [ j, J, dead_hook, dead_horn ] };
1557+ key <AC08> { [ k, K, kra, ampersand ] };
1558+ key <AC09> { [ l, L, lstroke, Lstroke ] };
1559+ key <AC10> { [ m, M, mu, masculine ] };
1560+ key <AC11> { [ ugrave, percent, dead_circumflex, dead_caron ] };
1561+ key <TLDE> { [ twosuperior, asciitilde, notsign, notsign ] };
1562+ key <LFSH> { [ Shift_L ] };
1563+ key <BKSL> { [ asterisk, mu, dead_grave, dead_breve ] };
1564+ key <AB01> { [ w, W, lstroke, Lstroke ] };
1565+ key <AB02> { [ x, X, guillemotright, greater ] };
1566+ key <AB03> { [ c, C, cent, copyright ] };
1567+ key <AB04> { [ v, V, doublelowquotemark, singlelowquotemark ] };
1568+ key <AB05> { [ b, B, leftdoublequotemark, leftsinglequotemark ] };
1569+ key <AB06> { [ n, N, rightdoublequotemark, rightsinglequotemark ] };
1570+ key <AB07> { [ comma, question, dead_acute, dead_doubleacute ] };
1571+ key <AB08> { [ semicolon, period, U2022, multiply ] };
1572+ key <AB09> { [ colon, slash, periodcentered, division ] };
1573+ key <AB10> { [ exclam, section, dead_belowdot, dead_abovedot ] };
1574+ key <RTSH> { [ Shift_R ] };
1575+ key <KPMU> {
1576+ type= "CTRL+ALT",
1577+ symbols[1]= [ KP_Multiply, KP_Multiply, KP_Multiply, KP_Multiply, XF86ClearGrab ]
1578+ };
1579+ key <LALT> { [ Alt_L ] };
1580+ key <SPCE> { [ space ] };
1581+ key <CAPS> { [ Caps_Lock ] };
1582+ key <FK01> {
1583+ type= "CTRL+ALT",
1584+ symbols[1]= [ F1, F1, F1, F1, XF86Switch_VT_1 ]
1585+ };
1586+ key <FK02> {
1587+ type= "CTRL+ALT",
1588+ symbols[1]= [ F2, F2, F2, F2, XF86Switch_VT_2 ]
1589+ };
1590+ key <FK03> {
1591+ type= "CTRL+ALT",
1592+ symbols[1]= [ F3, F3, F3, F3, XF86Switch_VT_3 ]
1593+ };
1594+ key <FK04> {
1595+ type= "CTRL+ALT",
1596+ symbols[1]= [ F4, F4, F4, F4, XF86Switch_VT_4 ]
1597+ };
1598+ key <FK05> {
1599+ type= "CTRL+ALT",
1600+ symbols[1]= [ F5, F5, F5, F5, XF86Switch_VT_5 ]
1601+ };
1602+ key <FK06> {
1603+ type= "CTRL+ALT",
1604+ symbols[1]= [ F6, F6, F6, F6, XF86Switch_VT_6 ]
1605+ };
1606+ key <FK07> {
1607+ type= "CTRL+ALT",
1608+ symbols[1]= [ F7, F7, F7, F7, XF86Switch_VT_7 ]
1609+ };
1610+ key <FK08> {
1611+ type= "CTRL+ALT",
1612+ symbols[1]= [ F8, F8, F8, F8, XF86Switch_VT_8 ]
1613+ };
1614+ key <FK09> {
1615+ type= "CTRL+ALT",
1616+ symbols[1]= [ F9, F9, F9, F9, XF86Switch_VT_9 ]
1617+ };
1618+ key <FK10> {
1619+ type= "CTRL+ALT",
1620+ symbols[1]= [ F10, F10, F10, F10, XF86Switch_VT_10 ]
1621+ };
1622+ key <NMLK> { [ Num_Lock ] };
1623+ key <SCLK> { [ Scroll_Lock ] };
1624+ key <KP7> { [ KP_Home, KP_7 ] };
1625+ key <KP8> { [ KP_Up, KP_8 ] };
1626+ key <KP9> { [ KP_Prior, KP_9 ] };
1627+ key <KPSU> {
1628+ type= "CTRL+ALT",
1629+ symbols[1]= [ KP_Subtract, KP_Subtract, KP_Subtract, KP_Subtract, XF86Prev_VMode ]
1630+ };
1631+ key <KP4> { [ KP_Left, KP_4 ] };
1632+ key <KP5> { [ KP_Begin, KP_5 ] };
1633+ key <KP6> { [ KP_Right, KP_6 ] };
1634+ key <KPAD> {
1635+ type= "CTRL+ALT",
1636+ symbols[1]= [ KP_Add, KP_Add, KP_Add, KP_Add, XF86Next_VMode ]
1637+ };
1638+ key <KP1> { [ KP_End, KP_1 ] };
1639+ key <KP2> { [ KP_Down, KP_2 ] };
1640+ key <KP3> { [ KP_Next, KP_3 ] };
1641+ key <KP0> { [ KP_Insert, KP_0 ] };
1642+ key <KPDL> { [ KP_Delete, KP_Decimal ] };
1643+ key <LVL3> { [ ISO_Level3_Shift ] };
1644+ key <ZEHA> {
1645+ type= "PC_CONTROL_SUPER_LEVEL2",
1646+ symbols[1]= [ F24, XF86TouchpadToggle ]
1647+ };
1648+ key <LSGT> { [ less, greater, bar, brokenbar ] };
1649+ key <FK11> {
1650+ type= "CTRL+ALT",
1651+ symbols[1]= [ F11, F11, F11, F11, XF86Switch_VT_11 ]
1652+ };
1653+ key <FK12> {
1654+ type= "CTRL+ALT",
1655+ symbols[1]= [ F12, F12, F12, F12, XF86Switch_VT_12 ]
1656+ };
1657+ key <KATA> { [ Katakana ] };
1658+ key <HIRA> { [ Hiragana ] };
1659+ key <HENK> { [ Henkan_Mode ] };
1660+ key <HKTG> { [ Hiragana_Katakana ] };
1661+ key <MUHE> { [ Muhenkan ] };
1662+ key <KPEN> { [ KP_Enter ] };
1663+ key <RCTL> { [ Control_R ] };
1664+ key <KPDV> {
1665+ type= "CTRL+ALT",
1666+ symbols[1]= [ KP_Divide, KP_Divide, KP_Divide, KP_Divide, XF86Ungrab ]
1667+ };
1668+ key <PRSC> {
1669+ type= "PC_ALT_LEVEL2",
1670+ symbols[1]= [ Print, Sys_Req ]
1671+ };
1672+ key <RALT> {
1673+ type= "ONE_LEVEL",
1674+ symbols[1]= [ ISO_Level3_Shift ]
1675+ };
1676+ key <LNFD> { [ Linefeed ] };
1677+ key <HOME> { [ Home ] };
1678+ key <UP> { [ Up ] };
1679+ key <PGUP> { [ Prior ] };
1680+ key <LEFT> { [ Left ] };
1681+ key <RGHT> { [ Right ] };
1682+ key <END> { [ End ] };
1683+ key <DOWN> { [ Down ] };
1684+ key <PGDN> { [ Next ] };
1685+ key <INS> { [ Insert ] };
1686+ key <DELE> { [ Delete ] };
1687+ key <MUTE> { [ XF86AudioMute ] };
1688+ key <VOL-> { [ XF86AudioLowerVolume ] };
1689+ key <VOL+> { [ XF86AudioRaiseVolume ] };
1690+ key <POWR> { [ XF86PowerOff ] };
1691+ key <KPEQ> { [ KP_Equal ] };
1692+ key <I126> { [ plusminus ] };
1693+ key <PAUS> {
1694+ type= "PC_CONTROL_LEVEL2",
1695+ symbols[1]= [ Pause, Break ]
1696+ };
1697+ key <I128> { [ XF86LaunchA ] };
1698+ key <I129> { [ KP_Decimal, KP_Decimal ] };
1699+ key <HNGL> { [ Hangul ] };
1700+ key <HJCV> { [ Hangul_Hanja ] };
1701+ key <LWIN> { [ Super_L ] };
1702+ key <RWIN> { [ Super_R ] };
1703+ key <COMP> { [ Menu ] };
1704+ key <STOP> { [ Cancel ] };
1705+ key <AGAI> { [ Redo ] };
1706+ key <PROP> { [ SunProps ] };
1707+ key <UNDO> { [ Undo ] };
1708+ key <FRNT> { [ SunFront ] };
1709+ key <COPY> { [ XF86Copy ] };
1710+ key <OPEN> { [ XF86Open ] };
1711+ key <PAST> { [ XF86Paste ] };
1712+ key <FIND> { [ Find ] };
1713+ key <CUT> { [ XF86Cut ] };
1714+ key <HELP> { [ Help ] };
1715+ key <I147> { [ XF86MenuKB ] };
1716+ key <I148> { [ XF86Calculator ] };
1717+ key <I150> { [ XF86Sleep ] };
1718+ key <I151> { [ XF86WakeUp ] };
1719+ key <I152> { [ XF86Explorer ] };
1720+ key <I153> { [ XF86Send ] };
1721+ key <I155> { [ XF86Xfer ] };
1722+ key <I156> { [ XF86Launch1 ] };
1723+ key <I157> { [ XF86Launch2 ] };
1724+ key <I158> { [ XF86WWW ] };
1725+ key <I159> { [ XF86DOS ] };
1726+ key <I160> { [ XF86ScreenSaver ] };
1727+ key <I161> { [ XF86RotateWindows ] };
1728+ key <I162> { [ XF86TaskPane ] };
1729+ key <I163> { [ XF86Mail ] };
1730+ key <I164> { [ XF86Favorites ] };
1731+ key <I165> { [ XF86MyComputer ] };
1732+ key <I166> { [ XF86Back ] };
1733+ key <I167> { [ XF86Forward ] };
1734+ key <I169> { [ XF86Eject ] };
1735+ key <I170> { [ XF86Eject ] };
1736+ key <I171> { [ XF86AudioNext ] };
1737+ key <I172> { [ XF86AudioPlay, XF86AudioPause ] };
1738+ key <I173> { [ XF86AudioPrev ] };
1739+ key <I174> { [ XF86AudioStop, XF86Eject ] };
1740+ key <I175> { [ XF86AudioRecord ] };
1741+ key <I176> { [ XF86AudioRewind ] };
1742+ key <I177> { [ XF86Phone ] };
1743+ key <I179> { [ XF86Tools ] };
1744+ key <I180> { [ XF86HomePage ] };
1745+ key <I181> { [ XF86Reload ] };
1746+ key <I182> { [ XF86Close ] };
1747+ key <I185> { [ XF86ScrollUp ] };
1748+ key <I186> { [ XF86ScrollDown ] };
1749+ key <I187> { [ parenleft ] };
1750+ key <I188> { [ parenright ] };
1751+ key <I189> { [ XF86New ] };
1752+ key <I190> { [ Redo ] };
1753+ key <FK13> { [ XF86Tools ] };
1754+ key <FK14> { [ XF86Launch5 ] };
1755+ key <FK15> { [ XF86Launch6 ] };
1756+ key <FK16> { [ XF86Launch7 ] };
1757+ key <FK17> { [ XF86Launch8 ] };
1758+ key <FK18> { [ XF86Launch9 ] };
1759+ key <FK19> { [ F19 ] };
1760+ key <FK20> { [ XF86AudioMicMute ] };
1761+ key <FK21> { [ XF86TouchpadToggle ] };
1762+ key <FK22> { [ XF86TouchpadOn ] };
1763+ key <FK23> {
1764+ type= "PC_SHIFT_SUPER_LEVEL2",
1765+ symbols[1]= [ F23, XF86Assistant ]
1766+ };
1767+ key <FK24> {
1768+ type= "PC_CONTROL_SUPER_LEVEL2",
1769+ symbols[1]= [ F24, XF86TouchpadToggle ]
1770+ };
1771+ key <LVL5> { [ ISO_Level5_Shift ] };
1772+ key <ALT> { [ NoSymbol, Alt_L ] };
1773+ key <META> { [ NoSymbol, Meta_L ] };
1774+ key <SUPR> { [ NoSymbol, Super_L ] };
1775+ key <HYPR> { [ NoSymbol, Hyper_L ] };
1776+ key <I208> { [ XF86AudioPlay ] };
1777+ key <I209> { [ XF86AudioPause ] };
1778+ key <I210> { [ XF86Launch3 ] };
1779+ key <I211> { [ XF86Launch4 ] };
1780+ key <I212> { [ XF86LaunchB ] };
1781+ key <I213> { [ XF86Suspend ] };
1782+ key <I214> { [ XF86Close ] };
1783+ key <I215> { [ XF86AudioPlay ] };
1784+ key <I216> { [ XF86AudioForward ] };
1785+ key <I217> { [ XF86AudioBassBoost ] };
1786+ key <I218> { [ Print ] };
1787+ key <I220> { [ XF86WebCam ] };
1788+ key <I221> { [ XF86AudioPreset ] };
1789+ key <I223> { [ XF86Mail ] };
1790+ key <I224> { [ XF86Messenger ] };
1791+ key <I225> { [ XF86Search ] };
1792+ key <I226> { [ XF86Go ] };
1793+ key <I227> { [ XF86Finance ] };
1794+ key <I228> { [ XF86Game ] };
1795+ key <I229> { [ XF86Shop ] };
1796+ key <I231> { [ Cancel ] };
1797+ key <I232> { [ XF86MonBrightnessDown ] };
1798+ key <I233> { [ XF86MonBrightnessUp ] };
1799+ key <I234> { [ XF86AudioMedia ] };
1800+ key <I235> { [ XF86Display ] };
1801+ key <I236> { [ XF86KbdLightOnOff ] };
1802+ key <I237> { [ XF86KbdBrightnessDown ] };
1803+ key <I238> { [ XF86KbdBrightnessUp ] };
1804+ key <I239> { [ XF86Send ] };
1805+ key <I240> { [ XF86Reply ] };
1806+ key <I241> { [ XF86MailForward ] };
1807+ key <I242> { [ XF86Save ] };
1808+ key <I243> { [ XF86Documents ] };
1809+ key <I244> { [ XF86Battery ] };
1810+ key <I245> { [ XF86Bluetooth ] };
1811+ key <I246> { [ XF86WLAN ] };
1812+ key <I247> { [ XF86UWB ] };
1813+ key <I249> { [ XF86Next_VMode ] };
1814+ key <I250> { [ XF86Prev_VMode ] };
1815+ key <I251> { [ XF86MonBrightnessCycle ] };
1816+ key <I252> { [ XF86BrightnessAuto ] };
1817+ key <I253> { [ XF86DisplayOff ] };
1818+ key <I254> { [ XF86WWAN ] };
1819+ key <I255> { [ XF86RFKill ] };
1820+ key <I256> { [ XF86AudioMicMute ] };
1821+ key <I360> { [ XF86OK ] };
1822+ key <I361> { [ XF86Select ] };
1823+ key <I362> { [ XF86GoTo ] };
1824+ key <I363> { [ XF86Clear ] };
1825+ key <I365> { [ XF86Option ] };
1826+ key <I366> { [ XF86Info ] };
1827+ key <I367> { [ XF86Time ] };
1828+ key <I368> { [ XF86VendorLogo ] };
1829+ key <I370> { [ XF86MediaSelectProgramGuide ] };
1830+ key <I371> { [ XF86NextFavorite ] };
1831+ key <I372> { [ XF86Favorites ] };
1832+ key <I373> { [ XF86MediaSelectProgramGuide ] };
1833+ key <I374> { [ XF86MediaSelectHome ] };
1834+ key <I376> { [ XF86MediaLanguageMenu ] };
1835+ key <I377> { [ XF86MediaTitleMenu ] };
1836+ key <I378> { [ XF86Subtitle ] };
1837+ key <I379> { [ XF86CycleAngle ] };
1838+ key <I380> { [ XF86FullScreen ] };
1839+ key <I381> { [ XF86AudioChannelMode ] };
1840+ key <I382> { [ XF86Keyboard ] };
1841+ key <I383> { [ XF86AspectRatio ] };
1842+ key <I384> { [ XF86MediaSelectPC ] };
1843+ key <I385> { [ XF86MediaSelectTV ] };
1844+ key <I386> { [ XF86MediaSelectCable ] };
1845+ key <I387> { [ XF86MediaSelectVCR ] };
1846+ key <I388> { [ XF86MediaSelectVCRPlus ] };
1847+ key <I389> { [ XF86MediaSelectSatellite ] };
1848+ key <I391> { [ XF86CD ] };
1849+ key <I392> { [ XF86MediaSelectTape ] };
1850+ key <I393> { [ XF86MediaSelectRadio ] };
1851+ key <I394> { [ XF86MediaSelectTuner ] };
1852+ key <I395> { [ XF86MediaPlayer ] };
1853+ key <I396> { [ XF86MediaSelectTeletext ] };
1854+ key <I397> { [ XF86DVD ] };
1855+ key <I398> { [ XF86MediaSelectAuxiliary ] };
1856+ key <I400> { [ XF86Audio ] };
1857+ key <I401> { [ XF86Video ] };
1858+ key <I404> { [ XF86Memo ] };
1859+ key <I405> { [ XF86Calendar ] };
1860+ key <I406> { [ XF86Red ] };
1861+ key <I407> { [ XF86Green ] };
1862+ key <I408> { [ XF86Yellow ] };
1863+ key <I409> { [ XF86Blue ] };
1864+ key <I410> { [ XF86ChannelUp ] };
1865+ key <I411> { [ XF86ChannelDown ] };
1866+ key <I417> { [ XF86MediaPlaySlow ] };
1867+ key <I418> { [ XF86AudioRandomPlay ] };
1868+ key <I419> { [ XF86Break ] };
1869+ key <I421> { [ XF86NumberEntryMode ] };
1870+ key <I424> { [ XF86VideoPhone ] };
1871+ key <I425> { [ XF86Game ] };
1872+ key <I426> { [ XF86ZoomIn ] };
1873+ key <I427> { [ XF86ZoomOut ] };
1874+ key <I428> { [ XF86ZoomReset ] };
1875+ key <I429> { [ XF86Word ] };
1876+ key <I430> { [ XF86Editor ] };
1877+ key <I431> { [ XF86Excel ] };
1878+ key <I432> { [ XF86GraphicsEditor ] };
1879+ key <I433> { [ XF86Presentation ] };
1880+ key <I434> { [ XF86Database ] };
1881+ key <I435> { [ XF86News ] };
1882+ key <I436> { [ XF86Voicemail ] };
1883+ key <I437> { [ XF86Addressbook ] };
1884+ key <I438> { [ XF86Messenger ] };
1885+ key <I439> { [ XF86DisplayToggle ] };
1886+ key <I440> { [ XF86SpellCheck ] };
1887+ key <I441> { [ XF86LogOff ] };
1888+ key <I442> { [ dollar ] };
1889+ key <I443> { [ EuroSign ] };
1890+ key <I444> { [ XF86FrameBack ] };
1891+ key <I445> { [ XF86FrameForward ] };
1892+ key <I446> { [ XF86ContextMenu ] };
1893+ key <I447> { [ XF86MediaRepeat ] };
1894+ key <I448> { [ XF8610ChannelsUp ] };
1895+ key <I449> { [ XF8610ChannelsDown ] };
1896+ key <I450> { [ XF86Images ] };
1897+ key <I452> { [ XF86NotificationCenter ] };
1898+ key <I453> { [ XF86PickupPhone ] };
1899+ key <I454> { [ XF86HangupPhone ] };
1900+ key <I455> { [ XF86LinkPhone ] };
1901+ key <I472> { [ XF86Fn ] };
1902+ key <I473> { [ XF86Fn_Esc ] };
1903+ key <I474> { [ XF86Fn_F1 ] };
1904+ key <I475> { [ XF86Fn_F2 ] };
1905+ key <I476> { [ XF86Fn_F3 ] };
1906+ key <I477> { [ XF86Fn_F4 ] };
1907+ key <I478> { [ XF86Fn_F5 ] };
1908+ key <I479> { [ XF86Fn_F6 ] };
1909+ key <I480> { [ XF86Fn_F7 ] };
1910+ key <I481> { [ XF86Fn_F8 ] };
1911+ key <I482> { [ XF86Fn_F9 ] };
1912+ key <I483> { [ XF86Fn_F10 ] };
1913+ key <I484> { [ XF86Fn_F11 ] };
1914+ key <I485> { [ XF86Fn_F12 ] };
1915+ key <I486> { [ XF86Fn_1 ] };
1916+ key <I487> { [ XF86Fn_2 ] };
1917+ key <I488> { [ XF86Fn_D ] };
1918+ key <I489> { [ XF86Fn_E ] };
1919+ key <I490> { [ XF86Fn_F ] };
1920+ key <I491> { [ XF86Fn_S ] };
1921+ key <I492> { [ XF86Fn_B ] };
1922+ key <I493> { [ XF86FnRightShift ] };
1923+ key <I505> { [ braille_dot_1 ] };
1924+ key <I506> { [ braille_dot_2 ] };
1925+ key <I507> { [ braille_dot_3 ] };
1926+ key <I508> { [ braille_dot_4 ] };
1927+ key <I509> { [ braille_dot_5 ] };
1928+ key <I510> { [ braille_dot_6 ] };
1929+ key <I511> { [ braille_dot_7 ] };
1930+ key <I512> { [ braille_dot_8 ] };
1931+ key <I513> { [ braille_dot_9 ] };
1932+ key <I514> { [ braille_dot_1 ] };
1933+ key <I520> { [ XF86Numeric0 ] };
1934+ key <I521> { [ XF86Numeric1 ] };
1935+ key <I522> { [ XF86Numeric2 ] };
1936+ key <I523> { [ XF86Numeric3 ] };
1937+ key <I524> { [ XF86Numeric4 ] };
1938+ key <I525> { [ XF86Numeric5 ] };
1939+ key <I526> { [ XF86Numeric6 ] };
1940+ key <I527> { [ XF86Numeric7 ] };
1941+ key <I528> { [ XF86Numeric8 ] };
1942+ key <I529> { [ XF86Numeric9 ] };
1943+ key <I530> { [ XF86NumericStar ] };
1944+ key <I531> { [ XF86NumericPound ] };
1945+ key <I532> { [ XF86NumericA ] };
1946+ key <I533> { [ XF86NumericB ] };
1947+ key <I534> { [ XF86NumericC ] };
1948+ key <I535> { [ XF86NumericD ] };
1949+ key <I536> { [ XF86CameraFocus ] };
1950+ key <I537> { [ XF86WPSButton ] };
1951+ key <I538> { [ XF86TouchpadToggle ] };
1952+ key <I539> { [ XF86TouchpadOn ] };
1953+ key <I540> { [ XF86TouchpadOff ] };
1954+ key <I541> { [ XF86CameraZoomIn ] };
1955+ key <I542> { [ XF86CameraZoomOut ] };
1956+ key <I543> { [ XF86CameraUp ] };
1957+ key <I544> { [ XF86CameraDown ] };
1958+ key <I545> { [ XF86CameraLeft ] };
1959+ key <I546> { [ XF86CameraRight ] };
1960+ key <I547> { [ XF86AttendantOn ] };
1961+ key <I548> { [ XF86AttendantOff ] };
1962+ key <I549> { [ XF86AttendantToggle ] };
1963+ key <I550> { [ XF86LightsToggle ] };
1964+ key <I568> { [ XF86ALSToggle ] };
1965+ key <I569> { [ XF86RotationLockToggle ] };
1966+ key <I570> { [ XF86RefreshRateToggle ] };
1967+ key <I584> { [ XF86Buttonconfig ] };
1968+ key <I585> { [ XF86Taskmanager ] };
1969+ key <I586> { [ XF86Journal ] };
1970+ key <I587> { [ XF86ControlPanel ] };
1971+ key <I588> { [ XF86AppSelect ] };
1972+ key <I589> { [ XF86Screensaver ] };
1973+ key <I590> { [ XF86VoiceCommand ] };
1974+ key <I591> { [ XF86Assistant ] };
1975+ key <I592> { [ ISO_Next_Group ] };
1976+ key <I593> { [ XF86EmojiPicker ] };
1977+ key <I594> { [ XF86Dictate ] };
1978+ key <I595> { [ XF86CameraAccessEnable ] };
1979+ key <I596> { [ XF86CameraAccessDisable ] };
1980+ key <I597> { [ XF86CameraAccessToggle ] };
1981+ key <I598> { [ XF86Accessibility ] };
1982+ key <I599> { [ XF86DoNotDisturb ] };
1983+ key <I600> { [ XF86BrightnessMin ] };
1984+ key <I601> { [ XF86BrightnessMax ] };
1985+ key <I602> { [ XF86ElectronicPrivacyScreenOn ] };
1986+ key <I603> { [ XF86ElectronicPrivacyScreenOff ] };
1987+ key <I604> { [ XF86ActionOnSelection ] };
1988+ key <I605> { [ XF86ContextualInsert ] };
1989+ key <I606> { [ XF86ContextualQuery ] };
1990+ key <I616> { [ XF86KbdInputAssistPrev ] };
1991+ key <I617> { [ XF86KbdInputAssistNext ] };
1992+ key <I618> { [ XF86KbdInputAssistPrevgroup ] };
1993+ key <I619> { [ XF86KbdInputAssistNextgroup ] };
1994+ key <I620> { [ XF86KbdInputAssistAccept ] };
1995+ key <I621> { [ XF86KbdInputAssistCancel ] };
1996+ key <I622> { [ XF86RightUp ] };
1997+ key <I623> { [ XF86RightDown ] };
1998+ key <I624> { [ XF86LeftUp ] };
1999+ key <I625> { [ XF86LeftDown ] };
2000+ key <I626> { [ XF86RootMenu ] };
2001+ key <I627> { [ XF86MediaTopMenu ] };
2002+ key <I628> { [ XF86Numeric11 ] };
2003+ key <I629> { [ XF86Numeric12 ] };
2004+ key <I630> { [ XF86AudioDesc ] };
2005+ key <I631> { [ XF863DMode ] };
2006+ key <I632> { [ XF86NextFavorite ] };
2007+ key <I633> { [ XF86StopRecord ] };
2008+ key <I634> { [ XF86PauseRecord ] };
2009+ key <I635> { [ XF86VOD ] };
2010+ key <I636> { [ XF86Unmute ] };
2011+ key <I637> { [ XF86FastReverse ] };
2012+ key <I638> { [ XF86SlowReverse ] };
2013+ key <I639> { [ XF86Data ] };
2014+ key <I640> { [ XF86OnScreenKeyboard ] };
2015+ key <I641> { [ XF86PrivacyScreenToggle ] };
2016+ key <I642> { [ XF86SelectiveScreenshot ] };
2017+ key <I643> { [ XF86NextElement ] };
2018+ key <I644> { [ XF86PreviousElement ] };
2019+ key <I645> { [ XF86AutopilotEngageToggle ] };
2020+ key <I646> { [ XF86MarkWaypoint ] };
2021+ key <I647> { [ XF86Sos ] };
2022+ key <I648> { [ XF86NavChart ] };
2023+ key <I649> { [ XF86FishingChart ] };
2024+ key <I650> { [ XF86SingleRangeRadar ] };
2025+ key <I651> { [ XF86DualRangeRadar ] };
2026+ key <I652> { [ XF86RadarOverlay ] };
2027+ key <I653> { [ XF86TraditionalSonar ] };
2028+ key <I654> { [ XF86ClearvuSonar ] };
2029+ key <I655> { [ XF86SidevuSonar ] };
2030+ key <I656> { [ XF86NavInfo ] };
2031+ key <I657> { [ XF86BrightnessAdjust ] };
2032+ key <I664> { [ XF86Macro1 ] };
2033+ key <I665> { [ XF86Macro2 ] };
2034+ key <I666> { [ XF86Macro3 ] };
2035+ key <I667> { [ XF86Macro4 ] };
2036+ key <I668> { [ XF86Macro5 ] };
2037+ key <I669> { [ XF86Macro6 ] };
2038+ key <I670> { [ XF86Macro7 ] };
2039+ key <I671> { [ XF86Macro8 ] };
2040+ key <I672> { [ XF86Macro9 ] };
2041+ key <I673> { [ XF86Macro10 ] };
2042+ key <I674> { [ XF86Macro11 ] };
2043+ key <I675> { [ XF86Macro12 ] };
2044+ key <I676> { [ XF86Macro13 ] };
2045+ key <I677> { [ XF86Macro14 ] };
2046+ key <I678> { [ XF86Macro15 ] };
2047+ key <I679> { [ XF86Macro16 ] };
2048+ key <I680> { [ XF86Macro17 ] };
2049+ key <I681> { [ XF86Macro18 ] };
2050+ key <I682> { [ XF86Macro19 ] };
2051+ key <I683> { [ XF86Macro20 ] };
2052+ key <I684> { [ XF86Macro21 ] };
2053+ key <I685> { [ XF86Macro22 ] };
2054+ key <I686> { [ XF86Macro23 ] };
2055+ key <I687> { [ XF86Macro24 ] };
2056+ key <I688> { [ XF86Macro25 ] };
2057+ key <I689> { [ XF86Macro26 ] };
2058+ key <I690> { [ XF86Macro27 ] };
2059+ key <I691> { [ XF86Macro28 ] };
2060+ key <I692> { [ XF86Macro29 ] };
2061+ key <I693> { [ XF86Macro30 ] };
2062+ key <I696> { [ XF86MacroRecordStart ] };
2063+ key <I697> { [ XF86MacroRecordStop ] };
2064+ key <I698> { [ XF86MacroPresetCycle ] };
2065+ key <I699> { [ XF86MacroPreset1 ] };
2066+ key <I700> { [ XF86MacroPreset2 ] };
2067+ key <I701> { [ XF86MacroPreset3 ] };
2068+ key <I704> { [ XF86KbdLcdMenu1 ] };
2069+ key <I705> { [ XF86KbdLcdMenu2 ] };
2070+ key <I706> { [ XF86KbdLcdMenu3 ] };
2071+ key <I707> { [ XF86KbdLcdMenu4 ] };
2072+ key <I708> { [ XF86KbdLcdMenu5 ] };
2073+ key <I709> { [ XF86PerformanceMode ] };
2074+ modifier_map Shift { <LFSH>, <RTSH> };
2075+ modifier_map Lock { <CAPS> };
2076+ modifier_map Control { <LCTL>, <RCTL> };
2077+ modifier_map Mod1 { <LALT>, <ALT>, <META> };
2078+ modifier_map Mod2 { <NMLK> };
2079+ modifier_map Mod3 { <LVL5> };
2080+ modifier_map Mod4 { <LWIN>, <RWIN>, <SUPR> };
2081+ modifier_map Mod5 { <LVL3> };
2082+};
2083+
2084+};

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 1

Tags 4

↑↓ moveenter openesc close