detached 9e67979

feat(bindings): generate xkbcommon ABI and implement safe keyboard bindings

commit
9e679793fbcb1259aab513fda45a913edaf43536
author
brice · · 2026-09-28 07:01 UTC
parent
a7f62f3
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
19 files · +11021 -1
A LICENSE +21 -0
@@ -0,0 +1,21 @@
1+MIT License
2+
3+Copyright (c) 2026 purego-xkbcommon contributors
4+
5+Permission is hereby granted, free of charge, to any person obtaining a copy
6+of this software and associated documentation files (the "Software"), to deal
7+in the Software without restriction, including without limitation the rights
8+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+copies of the Software, and to permit persons to whom the Software is
10+furnished to do so, subject to the following conditions:
11+
12+The above copyright notice and this permission notice shall be included in all
13+copies or substantial portions of the Software.
14+
15+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+SOFTWARE.
M README.md +18 -1
@@ -1,3 +1,20 @@
11 # purego-xkbcommon
22
3-Pure Go (no cgo) bindings for libxkbcommon, loaded at runtime with purego.
3+Go 1.27 bindings for Linux `libxkbcommon.so.0`, without cgo or X11. The safe package owns native references; the `raw` package exposes generated ABI constants, types, and function registrations. Install libxkbcommon at runtime and xkeyboard-config for rules-based keymaps. The loader reports missing libraries and required symbols via `Available`.
4+
5+```go
6+ctx, err := xkbcommon.NewContext()
7+if err != nil { return err }
8+defer ctx.Close()
9+keymap, err := ctx.NewKeymapRules("evdev", "pc105", "fr", "", "")
10+if err != nil { return err }
11+defer keymap.Close()
12+state, err := keymap.NewState()
13+if err != nil { return err }
14+defer state.Close()
15+text, err := state.UTF8(xkbcommon.WaylandKeycode(evdevKeycode))
16+```
17+
18+Use `NewKeymapFD(fd, size)` for Wayland `xkb_v1` keymaps; it maps the supplied size with `PROT_READ|MAP_PRIVATE` and requires a trailing NUL. **The caller retains and must close the FD**, on success and failure. `UpdateMask` accepts Wayland modifier masks and group indices. `ComposeState.Feed` and `Status` distinguish composing, composed, cancelled, and ignored keysyms; use `UTF8` only for a composed result. Objects retain their native parents; close each object, in any order. Do not copy value structs containing a mutex.
19+
20+Pinned upstream headers and licenses are in `upstream/`; `upstream/METADATA` and `SHA256SUMS` identify their exact source. Run `GOWORK=off go generate ./...` to regenerate `raw/generated.go`; consumers do not run generation. The generator checks the selected ABI declarations against the headers. `github.com/bnema/purego v0.13.0-bnema.1` matches purego-vulkan and supports `Dlopen`, `Dlsym`, and `RegisterFunc` with cgo disabled.
A cmd/xkbgen/main.go +12 -0
@@ -0,0 +1,12 @@
1+package main
2+
3+import (
4+ "github.com/bnema/purego-xkbcommon/internal/gen"
5+ "log"
6+)
7+
8+func main() {
9+ if err := gen.Generate("."); err != nil {
10+ log.Fatal(err)
11+ }
12+}
A generate.go +3 -0
@@ -0,0 +1,3 @@
1+package xkbcommon
2+
3+//go:generate go run ./cmd/xkbgen
A go.mod +5 -0
@@ -0,0 +1,5 @@
1+module github.com/bnema/purego-xkbcommon
2+
3+go 1.27
4+
5+require github.com/bnema/purego v0.13.0-bnema.1
A go.sum +2 -0 generated file: collapsed
A internal/gen/gen.go +120 -0
@@ -0,0 +1,120 @@
1+// Package gen generates the deliberately bounded libxkbcommon ABI subset.
2+package gen
3+
4+import (
5+ "fmt"
6+ "go/format"
7+ "os"
8+ "regexp"
9+ "strconv"
10+ "strings"
11+)
12+
13+var comments = regexp.MustCompile(`(?s)/\*.*?\*/|//[^\n]*`)
14+
15+func clean(s string) string { return comments.ReplaceAllString(s, "") }
16+func declared(h, name string) bool {
17+ re := regexp.MustCompile(`(?m)\b` + regexp.QuoteMeta(name) + `\s*\([^;{}]*\)\s*;`)
18+ return re.MatchString(clean(h))
19+}
20+
21+var def = regexp.MustCompile(`(?m)^\s*#define\s+(XKB_(?:KEY_|MOD_NAME_|VMOD_NAME_|LED_NAME_)[A-Za-z0-9_]+)\s+("[^"]*"|0x[0-9a-fA-F]+|[0-9]+)\b?`)
22+var en = regexp.MustCompile(`(?s)enum\s+xkb_[a-z_]+\s*\{([^}]*)\}`)
23+var item = regexp.MustCompile(`^\s*(XKB_[A-Z][A-Z0-9_]*)(?:\s*=\s*(.+))?$`)
24+
25+func constants(h string) string {
26+ h = clean(h)
27+ var b strings.Builder
28+ for _, e := range en.FindAllStringSubmatch(h, -1) {
29+ last := int64(-1)
30+ for _, part := range strings.Split(e[1], ",") {
31+ m := item.FindStringSubmatch(strings.TrimSpace(part))
32+ if m == nil {
33+ continue
34+ }
35+ expr := strings.TrimSpace(m[2])
36+ if expr == "" {
37+ last++
38+ expr = strconv.FormatInt(last, 10)
39+ } else if n, err := strconv.ParseInt(expr, 0, 64); err == nil {
40+ last = n
41+ } else if v := regexp.MustCompile(`^\(1 << (\d+)\)$`).FindStringSubmatch(expr); v != nil {
42+ shift, _ := strconv.Atoi(v[1])
43+ last = 1 << shift
44+ } else {
45+ continue
46+ }
47+ fmt.Fprintf(&b, "%s = %s\n", m[1], expr)
48+ }
49+ }
50+ for _, m := range def.FindAllStringSubmatch(h, -1) {
51+ fmt.Fprintf(&b, "%s = %s\n", m[1], m[2])
52+ }
53+ return b.String()
54+}
55+
56+// Functions describes the bound ABI; each name is checked against the pinned headers.
57+// Pointers are uintptr to avoid GC passing Go pointers to native code unexpectedly.
58+var Functions = []struct{ Name, Signature string }{
59+ {"xkb_context_new", "func(uint32) uintptr"}, {"xkb_context_ref", "func(uintptr) uintptr"}, {"xkb_context_unref", "func(uintptr)"},
60+ {"xkb_keymap_new_from_names", "func(uintptr, uintptr, uint32) uintptr"}, {"xkb_keymap_new_from_string", "func(uintptr, uintptr, uint32, uint32) uintptr"}, {"xkb_keymap_new_from_buffer", "func(uintptr, uintptr, uintptr, uint32, uint32) uintptr"},
61+ {"xkb_keymap_ref", "func(uintptr) uintptr"}, {"xkb_keymap_unref", "func(uintptr)"}, {"xkb_keymap_get_as_string", "func(uintptr,uint32) uintptr"},
62+ {"xkb_keymap_mod_get_index", "func(uintptr,uintptr) uint32"}, {"xkb_keymap_num_layouts", "func(uintptr) uint32"},
63+ {"xkb_state_new", "func(uintptr) uintptr"}, {"xkb_state_ref", "func(uintptr) uintptr"}, {"xkb_state_unref", "func(uintptr)"},
64+ {"xkb_state_update_mask", "func(uintptr,uint32,uint32,uint32,uint32,uint32,uint32) uint32"},
65+ {"xkb_state_serialize_layout", "func(uintptr,uint32) uint32"}, {"xkb_state_serialize_mods", "func(uintptr,uint32) uint32"},
66+ {"xkb_state_key_get_one_sym", "func(uintptr,uint32) uint32"}, {"xkb_state_key_get_utf8", "func(uintptr,uint32,uintptr,uintptr) int32"},
67+ {"xkb_keysym_get_name", "func(uint32,uintptr,uintptr) int32"}, {"xkb_keysym_from_name", "func(uintptr,uint32) uint32"},
68+ {"xkb_compose_table_new_from_locale", "func(uintptr,uintptr,uint32) uintptr"}, {"xkb_compose_table_ref", "func(uintptr) uintptr"}, {"xkb_compose_table_unref", "func(uintptr)"},
69+ {"xkb_compose_state_new", "func(uintptr,uint32) uintptr"}, {"xkb_compose_state_ref", "func(uintptr) uintptr"}, {"xkb_compose_state_unref", "func(uintptr)"},
70+ {"xkb_compose_state_feed", "func(uintptr,uint32) uint32"}, {"xkb_compose_state_get_status", "func(uintptr) uint32"},
71+ {"xkb_compose_state_reset", "func(uintptr)"}, {"xkb_compose_state_get_utf8", "func(uintptr,uintptr,uintptr) int32"}, {"xkb_compose_state_get_one_sym", "func(uintptr) uint32"},
72+}
73+
74+func field(name string) string { return strings.ToUpper(name[:1]) + name[1:] }
75+func Generate(root string) error {
76+ h1, err := os.ReadFile(root + "/upstream/xkbcommon.h")
77+ if err != nil {
78+ return err
79+ }
80+ h2, err := os.ReadFile(root + "/upstream/xkbcommon-compose.h")
81+ if err != nil {
82+ return err
83+ }
84+ hdr := string(h1) + "\n" + string(h2)
85+ var b strings.Builder
86+ b.WriteString("// Code generated by go generate; DO NOT EDIT.\npackage raw\n\n")
87+ b.WriteString("// Opaque C handles and scalar typedefs.\ntype Context uintptr\ntype Keymap uintptr\ntype State uintptr\ntype ComposeTable uintptr\ntype ComposeState uintptr\ntype Keycode uint32\ntype Keysym uint32\ntype LayoutIndex uint32\ntype ModIndex uint32\ntype ModMask uint32\ntype LayoutMask uint32\n")
88+ b.WriteString("// RuleNames matches struct xkb_rule_names (five const char pointers).\ntype RuleNames struct { Rules, Model, Layout, Variant, Options uintptr }\n")
89+ b.WriteString("const (\n" + constants(hdr))
90+ for _, f := range []string{"xkbcommon-keysyms.h", "xkbcommon-names.h"} {
91+ data, e := os.ReadFile(root + "/upstream/" + f)
92+ if e != nil {
93+ return e
94+ }
95+ b.WriteString(constants(string(data)))
96+ }
97+ b.WriteString(")\n\n// Funcs holds resolved library functions.\ntype Funcs struct {\n")
98+ for _, f := range Functions {
99+ if !declared(hdr, f.Name) {
100+ return fmt.Errorf("missing pinned declaration: %s", f.Name)
101+ }
102+ fmt.Fprintf(&b, "%s %s\n", field(f.Name), f.Signature)
103+ }
104+ b.WriteString("}\n\n// Symbols is the complete required symbol set.\nvar Symbols = []string{\n")
105+ for _, f := range Functions {
106+ fmt.Fprintf(&b, "%q,\n", f.Name)
107+ }
108+ b.WriteString("}\n\n// Register registers prevalidated addresses in a Funcs value.\nfunc Register(f *Funcs, register func(any,uintptr)) {\n")
109+ for _, f := range Functions {
110+ fmt.Fprintf(&b, "register(&f.%s, addresses[%q])\n", field(f.Name), f.Name)
111+ }
112+ b.WriteString("}\n")
113+ // address map is passed in, not a global mutable singleton.
114+ s := strings.Replace(b.String(), "func Register(f *Funcs, register func(any,uintptr))", "func Register(f *Funcs, addresses map[string]uintptr, register func(any,uintptr))", 1)
115+ formatted, err := format.Source([]byte(s))
116+ if err != nil {
117+ return fmt.Errorf("format generated file: %w", err)
118+ }
119+ return os.WriteFile(root+"/raw/generated.go", formatted, 0644)
120+}
A internal/gen/gen_test.go +25 -0
@@ -0,0 +1,25 @@
1+package gen
2+
3+import (
4+ "strings"
5+ "testing"
6+)
7+
8+func TestDeclarations(t *testing.T) {
9+ h := "/* xkb_fake(void); */\nXKB_EXPORT struct xkb_context *\nxkb_context_new(enum xkb_context_flags flags);"
10+ if !declared(h, "xkb_context_new") || declared(h, "xkb_fake") {
11+ t.Fatal("incorrect declaration selection")
12+ }
13+ if declared(h, "xkb_context_unref") {
14+ t.Fatal("missing declaration accepted")
15+ }
16+}
17+func TestConstants(t *testing.T) {
18+ h := "enum xkb_test { XKB_A = (1 << 2), XKB_B, XKB_C = 0x10 };\n#define XKB_MOD_NAME_SHIFT \"Shift\"\n#define XKB_KEY_dead_acute 0xfe51\n"
19+ got := constants(h)
20+ for _, want := range []string{"XKB_A = (1 << 2)", "XKB_B = 5", "XKB_C = 0x10", "XKB_MOD_NAME_SHIFT = \"Shift\"", "XKB_KEY_dead_acute = 0xfe51"} {
21+ if !strings.Contains(got, want) {
22+ t.Fatalf("missing %s in %s", want, got)
23+ }
24+ }
25+}
A loader.go +41 -0
@@ -0,0 +1,41 @@
1+package xkbcommon
2+
3+import (
4+ "fmt"
5+ "sync"
6+
7+ "github.com/bnema/purego"
8+ "github.com/bnema/purego-xkbcommon/raw"
9+)
10+
11+var loader struct {
12+ sync.Once
13+ f raw.Funcs
14+ err error
15+}
16+
17+// Available resolves the SONAME and every required symbol, reporting the first
18+// incompatible symbol rather than failing later in a keyboard event callback.
19+func Available() error {
20+ loader.Do(func() {
21+ lib, err := purego.Dlopen("libxkbcommon.so.0", purego.RTLD_NOW|purego.RTLD_LOCAL)
22+ if err != nil {
23+ loader.err = fmt.Errorf("xkbcommon: load libxkbcommon.so.0: %w", err)
24+ return
25+ }
26+ addresses := make(map[string]uintptr, len(raw.Symbols))
27+ for _, name := range raw.Symbols {
28+ address, e := purego.Dlsym(lib, name)
29+ if e != nil || address == 0 {
30+ loader.err = fmt.Errorf("xkbcommon: incompatible libxkbcommon.so.0: missing %s: %v", name, e)
31+ _ = purego.Dlclose(lib)
32+ return
33+ }
34+ addresses[name] = address
35+ }
36+ raw.Register(&loader.f, addresses, purego.RegisterFunc)
37+ // Intentionally keep the library open: registered function pointers and live
38+ // native objects remain valid for the process lifetime.
39+ })
40+ return loader.err
41+}
A raw/generated.go +2834 -0 large diff (2834 lines changed): collapsed
A upstream/LICENSE +279 -0
@@ -0,0 +1,279 @@
1+The following is a list of all copyright notices and license statements which
2+appear in the xkbcommon source tree, along with the SPDX short license
3+identifiers which source files use to refer to them. To see which parts are
4+covered by which license and copyright, refer to the source files.
5+
6+If making new contributions, the MIT License is vastly preferred.
7+
8+All licenses are derivative of the MIT/X11 license, mostly identical other
9+than no-endorsement clauses (e.g. paragraph 4 of The Open Group's license).
10+
11+These statements are split into two sections: one for the code compiled and
12+distributed as part of the libxkbcommon shared library and the code component
13+of all tests, and another only for the test data under test/data, which is
14+distributed with the xkbcommon source code, but not installed to the system.
15+
16+BEGINNING OF SOFTWARE COPYRIGHT/LICENSE STATEMENTS:
17+
18+
19+-------------------------------------------------------------------------------
20+SPDX full name: MIT License
21+SPDX short identifier: MIT
22+License text:
23+
24+Copyright © 2008-2009 Dan Nicholson <dbn.lists@gmail.com>
25+Copyright © 2009-2012, 2016 Daniel Stone <daniel@fooishbar.org>
26+Copyright © 2012-2014, 2020-2022, 2025 Ran Benita <ran@unusedvar.com>
27+Copyright © 2010-2012, 2016 Intel Corporation
28+Copyright © 2013-2015, 2018-2020 Red Hat, Inc.
29+Copyright © 2023-2024 Pierre Le Marre <dev@wismill.eu>
30+Copyright (c) 1991, Oracle and/or its affiliates.
31+Copyright © 2008-2011 Kristian Høgsberg
32+Copyright © 2010 Francisco Jerez <currojerez@riseup.net>
33+Copyright © 2012 Collabora, Ltd.
34+Copyright © 2015 Kazunobu Kuriyama <kazunobu.kuriyama@nifty.com>
35+Copyright (C) 2011 Joseph Adams <joeyadams3.14159@gmail.com>
36+
37+Permission is hereby granted, free of charge, to any person obtaining a
38+copy of this software and associated documentation files (the "Software"),
39+to deal in the Software without restriction, including without limitation
40+the rights to use, copy, modify, merge, publish, distribute, sublicense,
41+and/or sell copies of the Software, and to permit persons to whom the
42+Software is furnished to do so, subject to the following conditions:
43+
44+The above copyright notice and this permission notice (including the next
45+paragraph) shall be included in all copies or substantial portions of the
46+Software.
47+
48+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
49+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
50+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
51+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
52+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
53+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
54+DEALINGS IN THE SOFTWARE.
55+
56+
57+-------------------------------------------------------------------------------
58+SPDX full name: MIT Open Group variant
59+SPDX short identifier: MIT-open-group
60+License text:
61+
62+Copyright 1985, 1987, 1988, 1990, 1998 The Open Group
63+
64+Permission is hereby granted, free of charge, to any person obtaining a
65+copy of this software and associated documentation files (the "Software"),
66+to deal in the Software without restriction, including without limitation
67+the rights to use, copy, modify, merge, publish, distribute, sublicense,
68+and/or sell copies of the Software, and to permit persons to whom the
69+Software is furnished to do so, subject to the following conditions:
70+
71+The above copyright notice and this permission notice shall be included in
72+all copies or substantial portions of the Software.
73+
74+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
75+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
76+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
77+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
78+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
79+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
80+
81+Except as contained in this notice, the names of the authors or their
82+institutions shall not be used in advertising or otherwise to promote the
83+sale, use or other dealings in this Software without prior written
84+authorization from the authors.
85+
86+
87+-------------------------------------------------------------------------------
88+SPDX full name: Historical Permission Notice and Disclaimer
89+SPDX short identifier: HPND
90+License text:
91+
92+Copyright (c) 1993, 1994, 1995, 1996 by Silicon Graphics Computer Systems, Inc.
93+
94+Permission to use, copy, modify, and distribute this
95+software and its documentation for any purpose and without
96+fee is hereby granted, provided that the above copyright
97+notice appear in all copies and that both that copyright
98+notice and this permission notice appear in supporting
99+documentation, and that the name of Silicon Graphics not be
100+used in advertising or publicity pertaining to distribution
101+of the software without specific prior written permission.
102+Silicon Graphics makes no representation about the suitability
103+of this software for any purpose. It is provided "as is"
104+without any express or implied warranty.
105+
106+SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
107+SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
108+AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
109+GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
110+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
111+DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
112+OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
113+THE USE OR PERFORMANCE OF THIS SOFTWARE.
114+
115+-------------------------------------------------------------------------------
116+SPDX full name: Historical Permission Notice and Disclaimer - sell variant
117+SPDX short identifier: HPND-sell-variant
118+License text:
119+
120+Copyright 1992 by Oki Technosystems Laboratory, Inc.
121+Copyright 1992 by Fuji Xerox Co., Ltd.
122+
123+Permission to use, copy, modify, distribute, and sell this software
124+and its documentation for any purpose is hereby granted without fee,
125+provided that the above copyright notice appear in all copies and
126+that both that copyright notice and this permission notice appear
127+in supporting documentation, and that the name of Oki Technosystems
128+Laboratory and Fuji Xerox not be used in advertising or publicity
129+pertaining to distribution of the software without specific, written
130+prior permission.
131+Oki Technosystems Laboratory and Fuji Xerox make no representations
132+about the suitability of this software for any purpose. It is provided
133+"as is" without express or implied warranty.
134+
135+OKI TECHNOSYSTEMS LABORATORY AND FUJI XEROX DISCLAIM ALL WARRANTIES
136+WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
137+MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL OKI TECHNOSYSTEMS
138+LABORATORY AND FUJI XEROX BE LIABLE FOR ANY SPECIAL, INDIRECT OR
139+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
140+OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
141+OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
142+OR PERFORMANCE OF THIS SOFTWARE.
143+
144+
145+-------------------------------------------------------------------------------
146+SPDX full name: <none>
147+SPDX short identifier: LicenseRef-digital-equipment-corporation
148+License text:
149+
150+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
151+
152+ All Rights Reserved
153+
154+Permission to use, copy, modify, and distribute this software and its
155+documentation for any purpose and without fee is hereby granted,
156+provided that the above copyright notice appear in all copies and that
157+both that copyright notice and this permission notice appear in
158+supporting documentation, and that the name of Digital not be
159+used in advertising or publicity pertaining to distribution of the
160+software without specific, written prior permission.
161+
162+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
163+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
164+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
165+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
166+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
167+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
168+SOFTWARE.
169+
170+
171+-------------------------------------------------------------------------------
172+
173+
174+
175+END OF SOFTWARE COPYRIGHT/LICENSE STATEMENTS
176+
177+
178+BEGINNING OF LICENSE STATEMENTS ONLY FOR UNDISTRIBUTED DATA FILES IN test/data,
179+derived from xkeyboard-config and libX11 nls/ directory:
180+
181+
182+
183+-------------------------------------------------------------------------------
184+SPDX full name: Historical Permission Notice and Disclaimer - sell variant
185+SPDX short identifier: HPND-sell-variant
186+
187+Copyright 1996 by Joseph Moss
188+Copyright (C) 2002-2007 Free Software Foundation, Inc.
189+Copyright (C) Dmitry Golubev <lastguru@mail.ru>, 2003-2004
190+Copyright (C) 2004, Gregory Mokhin <mokhin@bog.msu.ru>
191+Copyright (C) 2006 Erdal Ronahî
192+
193+Permission to use, copy, modify, distribute, and sell this software and its
194+documentation for any purpose is hereby granted without fee, provided that
195+the above copyright notice appear in all copies and that both that
196+copyright notice and this permission notice appear in supporting
197+documentation, and that the name of the copyright holder(s) not be used in
198+advertising or publicity pertaining to distribution of the software without
199+specific, written prior permission. The copyright holder(s) makes no
200+representations about the suitability of this software for any purpose. It
201+is provided "as is" without express or implied warranty.
202+
203+THE COPYRIGHT HOLDER(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
204+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
205+EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
206+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
207+DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
208+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
209+PERFORMANCE OF THIS SOFTWARE.
210+
211+
212+-------------------------------------------------------------------------------
213+SPDX full name: MIT License
214+SPDX short identifier: MIT
215+
216+Copyright 2004-2005 Sun Microsystems, Inc. All rights reserved.
217+
218+
219+-------------------------------------------------------------------------------
220+SPDX full name: X11 License
221+SPDX short identifier: X11
222+License text:
223+
224+Copyright (c) 1996 X Consortium
225+
226+Permission is hereby granted, free of charge, to any person obtaining
227+a copy of this software and associated documentation files (the
228+"Software"), to deal in the Software without restriction, including
229+without limitation the rights to use, copy, modify, merge, publish,
230+distribute, sublicense, and/or sell copies of the Software, and to
231+permit persons to whom the Software is furnished to do so, subject to
232+the following conditions:
233+
234+The above copyright notice and this permission notice shall be
235+included in all copies or substantial portions of the Software.
236+
237+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
238+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
239+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
240+IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
241+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
242+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
243+OTHER DEALINGS IN THE SOFTWARE.
244+
245+Except as contained in this notice, the name of the X Consortium shall
246+not be used in advertising or otherwise to promote the sale, use or
247+other dealings in this Software without prior written authorization
248+from the X Consortium.
249+
250+
251+
252+-------------------------------------------------------------------------------
253+SPDX full name: MIT Open Group variant
254+SPDX short identifier: MIT-open-group
255+
256+Copyright (C) 2004, 2006 Ævar Arnfjörð Bjarmason <avarab@gmail.com>
257+
258+
259+-------------------------------------------------------------------------------
260+SPDX full name: <none>
261+SPDX short identifier: MIT-open-group
262+SPDX short identifier: LicenseRef-anton-zinoviev
263+License text:
264+
265+Copyright (C) 1999, 2000 by Anton Zinoviev <anton@lml.bas.bg>
266+
267+This software may be used, modified, copied, distributed, and sold,
268+in both source and binary form provided that the above copyright
269+and these terms are retained. Under no circumstances is the author
270+responsible for the proper functioning of this software, nor does
271+the author assume any responsibility for damages incurred with its
272+use.
273+
274+Permission is granted to anyone to use, distribute and modify
275+this file in any way, provided that the above copyright notice
276+is left intact and the author of the modification summarizes
277+the changes in this header.
278+
279+This file is distributed without any expressed or implied warranty.
A upstream/METADATA +6 -0
@@ -0,0 +1,6 @@
1+Source: https://github.com/xkbcommon/libxkbcommon
2+Tag: xkbcommon-1.13.2
3+Commit: d1442aaa6b635551182e83c3b55037f4c118c962
4+Files: include/xkbcommon/{xkbcommon.h,xkbcommon-compose.h,xkbcommon-keysyms.h,xkbcommon-names.h}, LICENSE
5+SHA-256: see SHA256SUMS (paths relative to repository root)
6+Note: the keysyms header includes third-party copyright and license notices; preserve it verbatim.
A upstream/SHA256SUMS +5 -0
@@ -0,0 +1,5 @@
1+967e97b28658f0037bbe164a237bdfb0c3ec790e67f6c29372ea5b09306f61f3 upstream/LICENSE
2+6e2d985b3653c3674df87731931b98a68e4dcb72d5ff90e457708e8e16ce818d upstream/xkbcommon-compose.h
3+17e58db5edc299d13b4365adce6c6d805e16642977ffaacf98d9be0c4c7071ff upstream/xkbcommon.h
4+13023369f65a17411606084e3e09557b4886aeb15f89affba4aaa86490a463f3 upstream/xkbcommon-keysyms.h
5+a5b0ed01c8b1816da8b5ed29cf776eb2ad1f707cf03ff74e62e36a5ca9009f61 upstream/xkbcommon-names.h
A upstream/xkbcommon-compose.h +621 -0
@@ -0,0 +1,621 @@
1+/*
2+ * Copyright © 2013 Ran Benita
3+ * SPDX-License-Identifier: MIT
4+ */
5+
6+#ifndef _XKBCOMMON_COMPOSE_H
7+#define _XKBCOMMON_COMPOSE_H
8+
9+#include <xkbcommon/xkbcommon.h>
10+
11+#ifdef __cplusplus
12+extern "C" {
13+#endif
14+
15+/**
16+ * @file
17+ * libxkbcommon Compose API - support for Compose and dead-keys.
18+ */
19+
20+/**
21+ * @defgroup compose Compose and dead-keys support
22+ * Support for Compose and dead-keys.
23+ * @since 0.5.0
24+ *
25+ * @{
26+ */
27+
28+/**
29+ * @page compose-overview Overview
30+ * @parblock
31+ *
32+ * Compose and dead-keys are a common feature of many keyboard input
33+ * systems. They extend the range of the keysyms that can be produced
34+ * directly from a keyboard by using a sequence of key strokes, instead
35+ * of just one.
36+ *
37+ * Here are some example sequences, in the libX11 Compose file format:
38+ *
39+ * <dead_acute> <a> : "á" aacute # LATIN SMALL LETTER A WITH ACUTE
40+ * <Multi_key> <A> <T> : "@" at # COMMERCIAL AT
41+ *
42+ * When the user presses a key which produces the `<dead_acute>` keysym,
43+ * nothing initially happens (thus the key is dubbed a *dead-key*). But
44+ * when the user enters `<a>`, “á” is *composed*, in place of “a”. If
45+ * instead the user had entered a keysym which does not follow
46+ * `<dead_acute>` in any compose sequence, the sequence is said to be
47+ * *cancelled*.
48+ *
49+ * Compose files define many such sequences. For a description of the
50+ * common file format for Compose files, see the `Compose(5)` man page.
51+ *
52+ * A successfully-composed sequence has two results: a keysym and a UTF-8
53+ * string. At least one of the two is defined for each sequence. If only
54+ * a keysym is given, the keysym’s string representation is used for the
55+ * result string (using xkb_keysym_to_utf8()).
56+ *
57+ * This library provides low-level support for Compose file parsing and
58+ * processing. Higher-level APIs (such as libX11’s `Xutf8LookupString(3)`)
59+ * may be built upon it, or it can be used directly.
60+ *
61+ * @endparblock
62+ */
63+
64+/**
65+ * @page compose-conflicting Conflicting Sequences
66+ * @parblock
67+ *
68+ * To avoid ambiguity, a sequence is not allowed to be a prefix of another.
69+ * When such a conflict occurs, the sequence defined last is the one retained.
70+ *
71+ * Sequences of length 1 are allowed.
72+ *
73+ * @endparblock
74+ */
75+
76+/**
77+ * @page compose-cancellation Cancellation Behavior
78+ * @parblock
79+ *
80+ * What should happen when a sequence is cancelled? For example, consider
81+ * there are only the above sequences, and the input keysyms are
82+ * `<dead_acute> <b>`. There are a few approaches:
83+ *
84+ * 1. Swallow the cancelling keysym; that is, no keysym is produced.
85+ * This is the approach taken by libX11.
86+ * 2. Let the cancelling keysym through; that is, `<b>` is produced.
87+ * 3. Replay the entire sequence; that is, `<dead_acute> <b>` is produced.
88+ * This is the approach taken by Microsoft Windows (approximately;
89+ * instead of `<dead_acute>`, the underlying key is used. This is
90+ * difficult to simulate with XKB keymaps).
91+ *
92+ * You can program whichever approach best fits users' expectations.
93+ *
94+ * @endparblock
95+ */
96+
97+/**
98+ * @struct xkb_compose_table
99+ * Opaque Compose table object.
100+ *
101+ * The compose table holds the definitions of the Compose sequences, as
102+ * gathered from Compose files. It is immutable.
103+ */
104+struct xkb_compose_table;
105+
106+/**
107+ * @struct xkb_compose_state
108+ * Opaque Compose state object.
109+ *
110+ * The compose state maintains state for compose sequence matching, such
111+ * as which possible sequences are being matched, and the position within
112+ * these sequences. It acts as a simple state machine wherein keysyms are
113+ * the input, and composed keysyms and strings are the output.
114+ *
115+ * The compose state is usually associated with a keyboard device.
116+ */
117+struct xkb_compose_state;
118+
119+/** Flags affecting Compose file compilation. */
120+enum xkb_compose_compile_flags {
121+ /** Do not apply any flags. */
122+ XKB_COMPOSE_COMPILE_NO_FLAGS = 0
123+};
124+
125+/** The recognized Compose file formats. */
126+enum xkb_compose_format {
127+ /** The classic libX11 Compose text format, described in Compose(5). */
128+ XKB_COMPOSE_FORMAT_TEXT_V1 = 1
129+};
130+
131+/**
132+ * @page compose-locale Compose Locale
133+ * @parblock
134+ *
135+ * Compose files are locale dependent:
136+ * - Compose files are written for a locale, and the locale is used when
137+ * searching for the appropriate file to use.
138+ * - Compose files may reference the locale internally, with directives
139+ * such as `%%L`.
140+ *
141+ * As such, functions like `xkb_compose_table::xkb_compose_table_new_from_locale()`
142+ * require a `locale` parameter. This will usually be the current locale (see
143+ * `locale(7)` for more details). You may also want to allow the user to
144+ * explicitly configure it, so he can use the Compose file of a given
145+ * locale, but not use that locale for other things.
146+ *
147+ * You may query the current locale as follows:
148+ *
149+ * ```c
150+ * const char *locale;
151+ * locale = setlocale(LC_CTYPE, NULL);
152+ * ```
153+ *
154+ * This will only give useful results if the program had previously set
155+ * the current locale using setlocale(3), with `LC_CTYPE` or `LC_ALL`
156+ * and a non-`NULL` argument.
157+ *
158+ * If you prefer not to use the locale system of the C runtime library,
159+ * you may nevertheless obtain the user’s locale directly using
160+ * environment variables, as described in `locale(7)`. For example,
161+ *
162+ * ```c
163+ * const char *locale;
164+ * locale = getenv("LC_ALL");
165+ * if (!locale || !*locale)
166+ * locale = getenv("LC_CTYPE");
167+ * if (!locale || !*locale)
168+ * locale = getenv("LANG");
169+ * if (!locale || !*locale)
170+ * locale = "C";
171+ * ```
172+ *
173+ * Note that some locales supported by the C standard library may not
174+ * have a Compose file assigned.
175+ *
176+ * @endparblock
177+ */
178+
179+/**
180+ * Create a compose table for a given locale.
181+ *
182+ * The locale is used for searching the file-system for an appropriate
183+ * Compose file. The search order is described in Compose(5). It is
184+ * affected by the following environment variables:
185+ *
186+ * 1. `XCOMPOSEFILE` - see Compose(5).
187+ * 2. `XDG_CONFIG_HOME` - before `$HOME/.XCompose` is checked,
188+ * `$XDG_CONFIG_HOME/XCompose` is checked (with a fall back to
189+ * `$HOME/.config/XCompose` if `XDG_CONFIG_HOME` is not defined).
190+ * This is a libxkbcommon extension to the search procedure in
191+ * Compose(5) (since libxkbcommon 1.0.0). Note that other
192+ * implementations, such as libX11, might not find a Compose file in
193+ * this path.
194+ * 3. `HOME` - see Compose(5).
195+ * 4. `XLOCALEDIR` - if set, used as the base directory for the system’s
196+ * X locale files, e.g. `/usr/share/X11/locale`, instead of the
197+ * preconfigured directory.
198+ *
199+ * Since 1.12, system locales not registered in `$XLOCALEDIR` will fallback
200+ * to `en_US.UTF-8`, if missing locale detection is supported by the C standard
201+ * library in use.
202+ *
203+ * @param context
204+ * The library context in which to create the compose table.
205+ * @param locale
206+ * The current locale. See @ref compose-locale.
207+ * \n
208+ * The value is copied, so it is safe to pass the result of `getenv(3)`
209+ * (or similar) without fear of it being invalidated by a subsequent
210+ * `setenv(3)` (or similar).
211+ * @param flags
212+ * Optional flags for the compose table, or 0.
213+ *
214+ * @returns A compose table for the given locale, or `NULL` if the
215+ * compilation failed or a Compose file was not found.
216+ *
217+ * @memberof xkb_compose_table
218+ */
219+XKB_EXPORT struct xkb_compose_table *
220+xkb_compose_table_new_from_locale(struct xkb_context *context,
221+ const char *locale,
222+ enum xkb_compose_compile_flags flags);
223+
224+/**
225+ * Create a new compose table from a Compose file.
226+ *
227+ * @param context
228+ * The library context in which to create the compose table.
229+ * @param file
230+ * The Compose file to compile.
231+ * @param locale
232+ * The current locale. See @ref compose-locale.
233+ * @param format
234+ * The text format of the Compose file to compile.
235+ * @param flags
236+ * Optional flags for the compose table, or 0.
237+ *
238+ * @returns A compose table compiled from the given file, or `NULL` if
239+ * the compilation failed.
240+ *
241+ * @memberof xkb_compose_table
242+ */
243+XKB_EXPORT struct xkb_compose_table *
244+xkb_compose_table_new_from_file(struct xkb_context *context,
245+ FILE *file,
246+ const char *locale,
247+ enum xkb_compose_format format,
248+ enum xkb_compose_compile_flags flags);
249+
250+/**
251+ * Create a new compose table from a memory buffer.
252+ *
253+ * This is just like xkb_compose_table_new_from_file(), but instead of
254+ * a file, gets the table as one enormous string.
255+ *
256+ * @see xkb_compose_table_new_from_file()
257+ * @memberof xkb_compose_table
258+ */
259+XKB_EXPORT struct xkb_compose_table *
260+xkb_compose_table_new_from_buffer(struct xkb_context *context,
261+ const char *buffer, size_t length,
262+ const char *locale,
263+ enum xkb_compose_format format,
264+ enum xkb_compose_compile_flags flags);
265+
266+/**
267+ * Take a new reference on a compose table.
268+ *
269+ * @returns The passed in object.
270+ *
271+ * @memberof xkb_compose_table
272+ */
273+XKB_EXPORT struct xkb_compose_table *
274+xkb_compose_table_ref(struct xkb_compose_table *table);
275+
276+/**
277+ * Release a reference on a compose table, and possibly free it.
278+ *
279+ * @param table The object. If it is `NULL`, this function does nothing.
280+ *
281+ * @memberof xkb_compose_table
282+ */
283+XKB_EXPORT void
284+xkb_compose_table_unref(struct xkb_compose_table *table);
285+
286+/**
287+ * @struct xkb_compose_table_entry
288+ * Opaque Compose table entry object.
289+ *
290+ * Represents a single entry in a Compose file in the iteration API.
291+ * It is immutable.
292+ *
293+ * @sa xkb_compose_table_iterator_new
294+ * @since 1.6.0
295+ */
296+struct xkb_compose_table_entry;
297+
298+/**
299+ * Get the left-hand keysym sequence of a Compose table entry.
300+ *
301+ * For example, given the following entry:
302+ *
303+ * ```
304+ * <dead_tilde> <space> : "~" asciitilde # TILDE
305+ * ```
306+ *
307+ * it will return `{XKB_KEY_dead_tilde, XKB_KEY_space}`.
308+ *
309+ * @param[in] entry The compose table entry object to process.
310+ *
311+ * @param[out] sequence_length Number of keysyms in the sequence.
312+ *
313+ * @returns The array of left-hand side keysyms. The number of keysyms
314+ * is returned in the @p sequence_length out-parameter.
315+ *
316+ * @memberof xkb_compose_table_entry
317+ * @since 1.6.0
318+ */
319+XKB_EXPORT const xkb_keysym_t *
320+xkb_compose_table_entry_sequence(struct xkb_compose_table_entry *entry,
321+ size_t *sequence_length);
322+
323+/**
324+ * Get the right-hand result keysym of a Compose table entry.
325+ *
326+ * For example, given the following entry:
327+ *
328+ * ```
329+ * <dead_tilde> <space> : "~" asciitilde # TILDE
330+ * ```
331+ *
332+ * it will return `XKB_KEY_asciitilde`.
333+ *
334+ * The keysym is optional; if the entry does not specify a keysym,
335+ * returns `XKB_KEY_NoSymbol`.
336+ *
337+ * @memberof xkb_compose_table_entry
338+ * @since 1.6.0
339+ */
340+XKB_EXPORT xkb_keysym_t
341+xkb_compose_table_entry_keysym(struct xkb_compose_table_entry *entry);
342+
343+/**
344+ * Get the right-hand result string of a Compose table entry.
345+ *
346+ * The string is UTF-8 encoded and `NULL`-terminated.
347+ *
348+ * For example, given the following entry:
349+ *
350+ * ```
351+ * <dead_tilde> <space> : "~" asciitilde # TILDE
352+ * ```
353+ *
354+ * it will return `"~"`.
355+ *
356+ * The string is optional; if the entry does not specify a string,
357+ * returns the empty string.
358+ *
359+ * @memberof xkb_compose_table_entry
360+ * @since 1.6.0
361+ */
362+XKB_EXPORT const char *
363+xkb_compose_table_entry_utf8(struct xkb_compose_table_entry *entry);
364+
365+/**
366+ * @struct xkb_compose_table_iterator
367+ * Iterator over a compose table’s entries.
368+ *
369+ * @sa xkb_compose_table_iterator_new()
370+ * @since 1.6.0
371+ */
372+struct xkb_compose_table_iterator;
373+
374+/**
375+ * Create a new iterator for a compose table.
376+ *
377+ * Intended use:
378+ *
379+ * ```c
380+ * struct xkb_compose_table_iterator *iter = xkb_compose_table_iterator_new(compose_table);
381+ * struct xkb_compose_table_entry *entry;
382+ * while ((entry = xkb_compose_table_iterator_next(iter))) {
383+ * // ...
384+ * }
385+ * xkb_compose_table_iterator_free(iter);
386+ * ```
387+ *
388+ * @returns A new compose table iterator, or `NULL` on failure.
389+ *
390+ * @memberof xkb_compose_table_iterator
391+ * @sa xkb_compose_table_iterator_free()
392+ * @since 1.6.0
393+ */
394+XKB_EXPORT struct xkb_compose_table_iterator *
395+xkb_compose_table_iterator_new(struct xkb_compose_table *table);
396+
397+/**
398+ * Free a compose iterator.
399+ *
400+ * @memberof xkb_compose_table_iterator
401+ * @since 1.6.0
402+ */
403+XKB_EXPORT void
404+xkb_compose_table_iterator_free(struct xkb_compose_table_iterator *iter);
405+
406+/**
407+ * Get the next compose entry from a compose table iterator.
408+ *
409+ * The entries are returned in lexicographic order of the left-hand
410+ * side of entries. This does not correspond to the order in which
411+ * the entries appear in the Compose file.
412+ *
413+ * @attention The return value is valid until the next call to this function.
414+ *
415+ * Returns `NULL` in case there is no more entries.
416+ *
417+ * @memberof xkb_compose_table_iterator
418+ * @since 1.6.0
419+ */
420+XKB_EXPORT struct xkb_compose_table_entry *
421+xkb_compose_table_iterator_next(struct xkb_compose_table_iterator *iter);
422+
423+/** Flags for compose state creation. */
424+enum xkb_compose_state_flags {
425+ /** Do not apply any flags. */
426+ XKB_COMPOSE_STATE_NO_FLAGS = 0
427+};
428+
429+/**
430+ * Create a new compose state object.
431+ *
432+ * @param table
433+ * The compose table the state will use.
434+ * @param flags
435+ * Optional flags for the compose state, or 0.
436+ *
437+ * @returns A new compose state, or `NULL` on failure.
438+ *
439+ * @memberof xkb_compose_state
440+ */
441+XKB_EXPORT struct xkb_compose_state *
442+xkb_compose_state_new(struct xkb_compose_table *table,
443+ enum xkb_compose_state_flags flags);
444+
445+/**
446+ * Take a new reference on a compose state object.
447+ *
448+ * @returns The passed in object.
449+ *
450+ * @memberof xkb_compose_state
451+ */
452+XKB_EXPORT struct xkb_compose_state *
453+xkb_compose_state_ref(struct xkb_compose_state *state);
454+
455+/**
456+ * Release a reference on a compose state object, and possibly free it.
457+ *
458+ * @param state The object. If `NULL`, do nothing.
459+ *
460+ * @memberof xkb_compose_state
461+ */
462+XKB_EXPORT void
463+xkb_compose_state_unref(struct xkb_compose_state *state);
464+
465+/**
466+ * Get the compose table which a compose state object is using.
467+ *
468+ * @returns The compose table which was passed to xkb_compose_state_new()
469+ * when creating this state object.
470+ *
471+ * This function does not take a new reference on the compose table; you
472+ * must explicitly reference it yourself if you plan to use it beyond the
473+ * lifetime of the state.
474+ *
475+ * @memberof xkb_compose_state
476+ */
477+XKB_EXPORT struct xkb_compose_table *
478+xkb_compose_state_get_compose_table(struct xkb_compose_state *state);
479+
480+/** Status of the Compose sequence state machine. */
481+enum xkb_compose_status {
482+ /** The initial state; no sequence has started yet. */
483+ XKB_COMPOSE_NOTHING,
484+ /** In the middle of a sequence. */
485+ XKB_COMPOSE_COMPOSING,
486+ /** A complete sequence has been matched. */
487+ XKB_COMPOSE_COMPOSED,
488+ /** The last sequence was cancelled due to an unmatched keysym. */
489+ XKB_COMPOSE_CANCELLED
490+};
491+
492+/** The effect of a keysym fed to xkb_compose_state_feed(). */
493+enum xkb_compose_feed_result {
494+ /** The keysym had no effect - it did not affect the status. */
495+ XKB_COMPOSE_FEED_IGNORED,
496+ /** The keysym started, advanced or cancelled a sequence. */
497+ XKB_COMPOSE_FEED_ACCEPTED
498+};
499+
500+/**
501+ * Feed one keysym to the Compose sequence state machine.
502+ *
503+ * This function can advance into a compose sequence, cancel a sequence,
504+ * start a new sequence, or do nothing in particular. The resulting
505+ * status may be observed with `xkb_compose_state_get_status()`.
506+ *
507+ * Some keysyms, such as keysyms for modifier keys, are ignored - they
508+ * have no effect on the status or otherwise.
509+ *
510+ * The following is a description of the possible status transitions, in
511+ * the format CURRENT STATUS => NEXT STATUS, given a non-ignored input
512+ * keysym `keysym`:
513+ *
514+ @verbatim
515+ NOTHING or CANCELLED or COMPOSED =>
516+ NOTHING if keysym does not start a sequence.
517+ COMPOSING if keysym starts a sequence.
518+ COMPOSED if keysym starts and terminates a single-keysym sequence.
519+
520+ COMPOSING =>
521+ COMPOSING if keysym advances any of the currently possible
522+ sequences but does not terminate any of them.
523+ COMPOSED if keysym terminates one of the currently possible
524+ sequences.
525+ CANCELLED if keysym does not advance any of the currently
526+ possible sequences.
527+ @endverbatim
528+ *
529+ * The current Compose formats do not support multiple-keysyms. Therefore, if
530+ * you are using a function such as `xkb_state::xkb_state_key_get_syms()`
531+ * and it returns more than one keysym, consider feeding `XKB_KEY_NoSymbol`
532+ * instead.
533+ *
534+ * @param state
535+ * The compose state object.
536+ * @param keysym
537+ * A keysym, usually obtained after a key-press event, with a
538+ * function such as `xkb_state::xkb_state_key_get_one_sym()`.
539+ *
540+ * @returns Whether the keysym was ignored. This is useful, for example,
541+ * if you want to keep a record of the sequence matched thus far.
542+ *
543+ * @memberof xkb_compose_state
544+ */
545+XKB_EXPORT enum xkb_compose_feed_result
546+xkb_compose_state_feed(struct xkb_compose_state *state,
547+ xkb_keysym_t keysym);
548+
549+/**
550+ * Reset the Compose sequence state machine.
551+ *
552+ * The status is set to `::XKB_COMPOSE_NOTHING`, and the current sequence
553+ * is discarded.
554+ *
555+ * @memberof xkb_compose_state
556+ */
557+XKB_EXPORT void
558+xkb_compose_state_reset(struct xkb_compose_state *state);
559+
560+/**
561+ * Get the current status of the compose state machine.
562+ *
563+ * @see xkb_compose_status
564+ * @memberof xkb_compose_state
565+ **/
566+XKB_EXPORT enum xkb_compose_status
567+xkb_compose_state_get_status(struct xkb_compose_state *state);
568+
569+/**
570+ * Get the result Unicode/UTF-8 string for a composed sequence.
571+ *
572+ * See @ref compose-overview for more details. This function is only
573+ * useful when the status is `::XKB_COMPOSE_COMPOSED`.
574+ *
575+ * @param[in] state
576+ * The compose state.
577+ * @param[out] buffer
578+ * A buffer to write the string into.
579+ * @param[in] size
580+ * Size of the buffer.
581+ *
582+ * @warning If the buffer passed is too small, the string is truncated
583+ * (though still `NULL`-terminated).
584+ *
585+ * @returns
586+ * The number of bytes required for the string, excluding the `NULL` byte.
587+ * If the sequence is not complete, or does not have a viable result
588+ * string, returns 0, and sets `buffer` to the empty string (if possible).
589+ * @returns
590+ * You may check if truncation has occurred by comparing the return value
591+ * with the size of `buffer`, similarly to the `snprintf(3)` function.
592+ * You may safely pass `NULL` and 0 to `buffer` and `size` to find the
593+ * required size (without the `NULL`-byte).
594+ *
595+ * @memberof xkb_compose_state
596+ **/
597+XKB_EXPORT int
598+xkb_compose_state_get_utf8(struct xkb_compose_state *state,
599+ char *buffer, size_t size);
600+
601+/**
602+ * Get the result keysym for a composed sequence.
603+ *
604+ * See @ref compose-overview for more details. This function is only
605+ * useful when the status is `::XKB_COMPOSE_COMPOSED`.
606+ *
607+ * @returns The result keysym. If the sequence is not complete, or does
608+ * not specify a result keysym, returns `XKB_KEY_NoSymbol`.
609+ *
610+ * @memberof xkb_compose_state
611+ **/
612+XKB_EXPORT xkb_keysym_t
613+xkb_compose_state_get_one_sym(struct xkb_compose_state *state);
614+
615+/** @} */
616+
617+#ifdef __cplusplus
618+} /* extern "C" */
619+#endif
620+
621+#endif /* _XKBCOMMON_COMPOSE_H */
A upstream/xkbcommon-keysyms.h +3545 -0 large diff (3545 lines changed): collapsed
A upstream/xkbcommon-names.h +144 -0
@@ -0,0 +1,144 @@
1+/*
2+ * Copyright © 2012 Intel Corporation
3+ * SPDX-License-Identifier: MIT
4+ *
5+ * Author: Daniel Stone <daniel@fooishbar.org>
6+ */
7+
8+#ifndef _XKBCOMMON_NAMES_H
9+#define _XKBCOMMON_NAMES_H
10+
11+/**
12+ * @file
13+ * @brief Predefined names for common modifiers and LEDs.
14+ */
15+
16+/**
17+ * @defgroup modifier-names Predefined names for common modifiers and LEDs
18+ *
19+ * @{
20+ */
21+
22+/**
23+ * @defgroup real-modifier-names Real modifiers names
24+ *
25+ * [*Real* modifiers][real modifier] names are hardcoded in libxkbcommon.
26+ *
27+ * [real modifier]: @ref real-modifier-def
28+ *
29+ * @{
30+ */
31+#define XKB_MOD_NAME_SHIFT "Shift"
32+#define XKB_MOD_NAME_CAPS "Lock"
33+#define XKB_MOD_NAME_CTRL "Control"
34+#define XKB_MOD_NAME_MOD1 "Mod1"
35+#define XKB_MOD_NAME_MOD2 "Mod2"
36+#define XKB_MOD_NAME_MOD3 "Mod3"
37+#define XKB_MOD_NAME_MOD4 "Mod4"
38+#define XKB_MOD_NAME_MOD5 "Mod5"
39+/** @} */
40+
41+/**
42+ * @defgroup virtual-modifier-names Virtual modifiers names
43+ *
44+ * Common [*virtual* modifiers][virtual modifiers], encoded in [xkeyboard-config]
45+ * in the [compat] and [symbols] files. They have been stable since the beginning
46+ * of the project and are unlikely to ever change.
47+ *
48+ * [virtual modifiers]: @ref virtual-modifier-def
49+ * [xkeyboard-config]: https://gitlab.freedesktop.org/xkeyboard-config/xkeyboard-config
50+ * [compat]: @ref the-xkb_compat-section
51+ * [symbols]: @ref the-xkb_symbols-section
52+ *
53+ * @{
54+ */
55+/** @since 1.8.0 */
56+#define XKB_VMOD_NAME_ALT "Alt"
57+/** @since 1.8.0 */
58+#define XKB_VMOD_NAME_HYPER "Hyper"
59+/** @since 1.8.0 */
60+#define XKB_VMOD_NAME_LEVEL3 "LevelThree"
61+/** @since 1.8.0 */
62+#define XKB_VMOD_NAME_LEVEL5 "LevelFive"
63+/** @since 1.8.0 */
64+#define XKB_VMOD_NAME_META "Meta"
65+/** @since 1.8.0 */
66+#define XKB_VMOD_NAME_NUM "NumLock"
67+/** @since 1.8.0 */
68+#define XKB_VMOD_NAME_SCROLL "ScrollLock"
69+/** @since 1.8.0 */
70+#define XKB_VMOD_NAME_SUPER "Super"
71+/** @} */
72+
73+/**
74+ * @defgroup legacy-virtual-modifier-names Legacy virtual modifier names
75+ *
76+ * Usual [*virtual* modifiers][virtual modifiers] mappings to
77+ * [*real* modifiers][real modifiers].
78+ *
79+ * @deprecated Use @ref virtual-modifier-names instead
80+ *
81+ * [virtual modifiers]: @ref virtual-modifier-def
82+ * [real modifiers]: @ref real-modifier-def
83+ *
84+ * @{
85+ */
86+/**
87+ * Usual [*real* modifier][real modifier] for the
88+ * [*virtual* modifier][virtual modifier] `Alt`.
89+ *
90+ * @deprecated Use `::XKB_VMOD_NAME_ALT` instead.
91+ * @since 1.10: deprecated
92+ *
93+ * [virtual modifier]: @ref virtual-modifier-def
94+ * [real modifier]: @ref real-modifier-def
95+ */
96+#define XKB_MOD_NAME_ALT "Mod1"
97+/**
98+ * Usual [*real* modifier][real modifier] for the
99+ * [*virtual* modifier][virtual modifier] `Super`.
100+ *
101+ * @deprecated Use `::XKB_VMOD_NAME_SUPER` instead.
102+ * @since 1.10: deprecated
103+ *
104+ * [virtual modifier]: @ref virtual-modifier-def
105+ * [real modifier]: @ref real-modifier-def
106+ */
107+#define XKB_MOD_NAME_LOGO "Mod4"
108+/**
109+ * Usual [*real* modifier][real modifier] for the
110+ * [*virtual* modifier][virtual modifier] `NumLock`.
111+ *
112+ * @deprecated Use `::XKB_VMOD_NAME_NUM` instead.
113+ * @since 1.10: deprecated
114+ *
115+ * [virtual modifier]: @ref virtual-modifier-def
116+ * [real modifier]: @ref real-modifier-def
117+ */
118+#define XKB_MOD_NAME_NUM "Mod2"
119+/** @} */
120+
121+/**
122+ * @defgroup led-names LEDs names
123+ *
124+ * LEDs names are encoded in [xkeyboard-config], in the [keycodes] and [compat]
125+ * files. They have been stable since the beginning of the project and are
126+ * unlikely to ever change.
127+ *
128+ * [xkeyboard-config]: https://gitlab.freedesktop.org/xkeyboard-config/xkeyboard-config
129+ * [keycodes]: @ref the-xkb_keycodes-section
130+ * [compat]: @ref the-xkb_compat-section
131+ *
132+ * @{
133+ */
134+#define XKB_LED_NAME_NUM "Num Lock"
135+#define XKB_LED_NAME_CAPS "Caps Lock"
136+#define XKB_LED_NAME_SCROLL "Scroll Lock"
137+/** @since 1.8.0 */
138+#define XKB_LED_NAME_COMPOSE "Compose"
139+#define XKB_LED_NAME_KANA "Kana"
140+/** @} */
141+
142+/** @} */
143+
144+#endif
A upstream/xkbcommon.h +2598 -0
@@ -0,0 +1,2598 @@
1+/*
2+ * For MIT-open-group:
3+ * Copyright 1985, 1987, 1990, 1998 The Open Group
4+ * Copyright 2008 Dan Nicholson
5+ *
6+ * For HPND:
7+ * Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
8+ * SPDX-License-Identifier: HPND
9+ *
10+ * For MIT:
11+ * Copyright © 2009-2012 Daniel Stone
12+ * Copyright © 2012 Intel Corporation
13+ * Copyright © 2012 Ran Benita
14+ *
15+ * SPDX-License-Identifier: MIT-open-group AND HPND AND MIT
16+ *
17+ * Author: Daniel Stone <daniel@fooishbar.org>
18+ */
19+
20+#ifndef _XKBCOMMON_H_
21+#define _XKBCOMMON_H_
22+
23+#include <stdbool.h>
24+#include <stdint.h>
25+#include <stdio.h>
26+#include <stdarg.h>
27+
28+#include <xkbcommon/xkbcommon-names.h>
29+#include <xkbcommon/xkbcommon-keysyms.h>
30+
31+#ifdef __cplusplus
32+extern "C" {
33+#endif
34+
35+#if defined(__GNUC__) && !defined(__CYGWIN__)
36+# define XKB_EXPORT __attribute__((visibility("default")))
37+#elif defined(_WIN32)
38+# define XKB_EXPORT __declspec(dllexport)
39+#else
40+# define XKB_EXPORT
41+#endif
42+
43+/**
44+ * @file
45+ * Main libxkbcommon API.
46+ */
47+
48+/**
49+ * @struct xkb_context
50+ * Opaque top level library context object.
51+ *
52+ * The context contains various general library data and state, like
53+ * logging level and include paths.
54+ *
55+ * Objects are created in a specific context, and multiple contexts may
56+ * coexist simultaneously. Objects from different contexts are completely
57+ * separated and do not share any memory or state.
58+ */
59+struct xkb_context;
60+
61+/**
62+ * @struct xkb_keymap
63+ * Opaque compiled keymap object.
64+ *
65+ * The keymap object holds all of the static keyboard information obtained
66+ * from compiling XKB files.
67+ *
68+ * A keymap is immutable after it is created (besides reference counts, etc.);
69+ * if you need to change it, you must create a new one.
70+ */
71+struct xkb_keymap;
72+
73+/**
74+ * @struct xkb_state
75+ * Opaque keyboard state object.
76+ *
77+ * State objects contain the active state of a keyboard (or keyboards), such
78+ * as the currently effective layout and the active modifiers. It acts as a
79+ * simple state machine, wherein key presses and releases are the input, and
80+ * key symbols (keysyms) are the output.
81+ */
82+struct xkb_state;
83+
84+/**
85+ * A number used to represent a physical key on a keyboard.
86+ *
87+ * A standard PC-compatible keyboard might have 102 keys. An appropriate
88+ * keymap would assign each of them a keycode, by which the user should
89+ * refer to the key throughout the library.
90+ *
91+ * Historically, the X11 protocol, and consequentially the XKB protocol,
92+ * assign only 8 bits for keycodes. This limits the number of different
93+ * keys that can be used simultaneously in a single keymap to 256
94+ * (disregarding other limitations). This library does not share this limit;
95+ * keycodes beyond 255 (*extended* keycodes) are not treated specially.
96+ * Keymaps and applications which are compatible with X11 should not use
97+ * these keycodes.
98+ *
99+ * The values of specific keycodes are determined by the keymap and the
100+ * underlying input system. For example, with an X11-compatible keymap
101+ * and Linux evdev scan codes (see `linux/input.h`), a fixed offset is used:
102+ *
103+ * The keymap defines a canonical name for each key, plus possible aliases.
104+ * Historically, the XKB protocol restricts these names to at most 4 (ASCII)
105+ * characters, but this library does not share this limit.
106+ *
107+ * @code
108+ * xkb_keycode_t keycode_A = KEY_A + 8;
109+ * @endcode
110+ *
111+ * @sa xkb_keycode_is_legal_ext() xkb_keycode_is_legal_x11()
112+ */
113+typedef uint32_t xkb_keycode_t;
114+
115+/**
116+ * A number used to represent the symbols generated from a key on a keyboard.
117+ *
118+ * A key, represented by a keycode, may generate different symbols according
119+ * to keyboard state. For example, on a QWERTY keyboard, pressing the key
120+ * labled \<A\> generates the symbol ‘a’. If the Shift key is held, it
121+ * generates the symbol ‘A’. If a different layout is used, say Greek,
122+ * it generates the symbol ‘α’. And so on.
123+ *
124+ * Each such symbol is represented by a *keysym* (short for “key symbol”).
125+ * Note that keysyms are somewhat more general, in that they can also represent
126+ * some “function”, such as “Left” or “Right” for the arrow keys. For more
127+ * information, see: Appendix A [“KEYSYM Encoding”][encoding] of the X Window
128+ * System Protocol.
129+ *
130+ * Specifically named keysyms can be found in the
131+ * xkbcommon/xkbcommon-keysyms.h header file. Their name does not include
132+ * the `XKB_KEY_` prefix.
133+ *
134+ * Besides those, any Unicode/ISO&nbsp;10646 character in the range U+0100 to
135+ * U+10FFFF can be represented by a keysym value in the range 0x01000100 to
136+ * 0x0110FFFF. The name of Unicode keysyms is `U<codepoint>`, e.g. `UA1B2`.
137+ *
138+ * The name of other unnamed keysyms is the hexadecimal representation of
139+ * their value, e.g. `0xabcd1234`.
140+ *
141+ * Keysym names are case-sensitive.
142+ *
143+ * @note **Encoding:** Keysyms are 32-bit integers with the 3 most significant
144+ * bits always set to zero. Thus valid keysyms are in the range
145+ * `0 .. 0x1fffffff` = @ref XKB_KEYSYM_MAX.
146+ * See: Appendix A [“KEYSYM Encoding”][encoding] of the X Window System Protocol.
147+ *
148+ * [encoding]: https://www.x.org/releases/current/doc/xproto/x11protocol.html#keysym_encoding
149+ *
150+ * @ingroup keysyms
151+ * @sa `::XKB_KEYSYM_MAX`
152+ */
153+typedef uint32_t xkb_keysym_t;
154+
155+/**
156+ * Index of a keyboard layout.
157+ *
158+ * The layout index is a state component which determines which <em>keyboard
159+ * layout</em> is active. These may be different alphabets, different key
160+ * arrangements, etc.
161+ *
162+ * Layout indices are consecutive. The first layout has index 0.
163+ *
164+ * Each layout is not required to have a name, and the names are not
165+ * guaranteed to be unique (though they are usually provided and unique).
166+ * Therefore, it is not safe to use the name as a unique identifier for a
167+ * layout. Layout names are case-sensitive.
168+ *
169+ * Layout names are specified in the layout’s definition, for example
170+ * “English (US)”. These are different from the (conventionally) short names
171+ * which are used to locate the layout, for example `us` or `us(intl)`. These
172+ * names are not present in a compiled keymap.
173+ *
174+ * If the user selects layouts from a list generated from the XKB registry
175+ * (using libxkbregistry or directly), and this metadata is needed later on, it
176+ * is recommended to store it along with the keymap.
177+ *
178+ * Layouts are also called *groups* by XKB.
179+ *
180+ * @sa xkb_keymap::xkb_keymap_num_layouts()
181+ * @sa xkb_keymap::xkb_keymap_num_layouts_for_key()
182+ */
183+typedef uint32_t xkb_layout_index_t;
184+/** A mask of layout indices. */
185+typedef uint32_t xkb_layout_mask_t;
186+
187+/**
188+ * Index of a shift level.
189+ *
190+ * Any key, in any layout, can have several <em>shift levels</em>. Each
191+ * shift level can assign different keysyms to the key. The shift level
192+ * to use is chosen according to the current keyboard state; for example,
193+ * if no keys are pressed, the first level may be used; if the Left Shift
194+ * key is pressed, the second; if Num Lock is pressed, the third; and
195+ * many such combinations are possible (see `xkb_mod_index_t`).
196+ *
197+ * Level indices are consecutive. The first level has index 0.
198+ */
199+typedef uint32_t xkb_level_index_t;
200+
201+/**
202+ * Index of a modifier.
203+ *
204+ * A @e modifier is a state component which changes the way keys are
205+ * interpreted. A keymap defines a set of modifiers, such as Alt, Shift,
206+ * Num Lock or Meta, and specifies which keys may @e activate which
207+ * modifiers (in a many-to-many relationship, i.e. a key can activate
208+ * several modifiers, and a modifier may be activated by several keys.
209+ * Different keymaps do this differently).
210+ *
211+ * When retrieving the keysyms for a key, the active modifier set is
212+ * consulted; this determines the correct shift level to use within the
213+ * currently active layout (see `xkb_level_index_t`).
214+ *
215+ * Modifier indices are consecutive. The first modifier has index 0.
216+ *
217+ * Each modifier must have a name, and the names are unique. Therefore, it
218+ * is safe to use the name as a unique identifier for a modifier. The names
219+ * of some common modifiers are provided in the `xkbcommon/xkbcommon-names.h`
220+ * header file. Modifier names are case-sensitive.
221+ *
222+ * @sa xkb_keymap_num_mods()
223+ */
224+typedef uint32_t xkb_mod_index_t;
225+/** A mask of modifier indices. */
226+typedef uint32_t xkb_mod_mask_t;
227+
228+/**
229+ * Index of a keyboard LED.
230+ *
231+ * LEDs are logical objects which may be @e active or @e inactive. They
232+ * typically correspond to the lights on the keyboard. Their state is
233+ * determined by the current keyboard state.
234+ *
235+ * LED indices are non-consecutive. The first LED has index 0.
236+ *
237+ * Each LED must have a name, and the names are unique. Therefore,
238+ * it is safe to use the name as a unique identifier for a LED. The names
239+ * of some common LEDs are provided in the `xkbcommon/xkbcommon-names.h`
240+ * header file. LED names are case-sensitive.
241+ *
242+ * @warning A given keymap may specify an exact index for a given LED.
243+ * Therefore, LED indexing is not necessarily sequential, as opposed to
244+ * modifiers and layouts. This means that when iterating over the LEDs
245+ * in a keymap using e.g. xkb_keymap::xkb_keymap_num_leds(), some indices might
246+ * be invalid.
247+ * Given such an index, functions like xkb_keymap::xkb_keymap_led_get_name()
248+ * will return `NULL`, and `xkb_state::xkb_state_led_index_is_active()` will
249+ * return -1.
250+ *
251+ * LEDs are also called *indicators* by XKB.
252+ *
253+ * @sa `xkb_keymap::xkb_keymap_num_leds()`
254+ */
255+typedef uint32_t xkb_led_index_t;
256+/** A mask of LED indices. */
257+typedef uint32_t xkb_led_mask_t;
258+
259+/** Invalid keycode */
260+#define XKB_KEYCODE_INVALID (0xffffffff)
261+/** Invalid layout index */
262+#define XKB_LAYOUT_INVALID (0xffffffff)
263+/** Invalid level index */
264+#define XKB_LEVEL_INVALID (0xffffffff)
265+/** Invalid modifier index */
266+#define XKB_MOD_INVALID (0xffffffff)
267+/** Invalid LED index */
268+#define XKB_LED_INVALID (0xffffffff)
269+
270+/** Maximum legal keycode */
271+#define XKB_KEYCODE_MAX (0xffffffff - 1)
272+
273+/**
274+ * Maximum keysym value
275+ *
276+ * @since 1.6.0
277+ * @sa xkb_keysym_t
278+ * @ingroup keysyms
279+ */
280+#define XKB_KEYSYM_MAX 0x1fffffff
281+
282+/**
283+ * Test whether a value is a valid extended keycode.
284+ * @sa xkb_keycode_t
285+ **/
286+#define xkb_keycode_is_legal_ext(key) ((key) <= XKB_KEYCODE_MAX)
287+
288+/**
289+ * Test whether a value is a valid X11 keycode.
290+ * @sa xkb_keycode_t
291+ */
292+#define xkb_keycode_is_legal_x11(key) ((key) >= 8 && (key) <= 255)
293+
294+/**
295+ * @defgroup rules-api Rules
296+ * Utility functions related to *rules*, whose purpose is introduced in:
297+ * @ref xkb-the-config "".
298+ *
299+ * @{
300+ */
301+
302+/**
303+ * @struct xkb_rmlvo_builder
304+ * Opaque [RMLVO] configuration object.
305+ *
306+ * It denotes the configuration values by which a user picks a keymap.
307+ *
308+ * @see [Introduction to RMLVO][RMLVO]
309+ * @see @ref rules-api ""
310+ * @since 1.11.0
311+ *
312+ * [RMLVO]: @ref RMLVO-intro
313+ */
314+struct xkb_rmlvo_builder;
315+
316+enum xkb_rmlvo_builder_flags {
317+ XKB_RMLVO_BUILDER_NO_FLAGS = 0
318+};
319+
320+/**
321+ * Create a new [RMLVO] builder.
322+ *
323+ * @param context The context in which to create the builder.
324+ * @param rules The ruleset.
325+ * If `NULL` or the empty string `""`, a default value is used.
326+ * If the `XKB_DEFAULT_RULES` environment variable is set, it is used
327+ * as the default. Otherwise the system default is used.
328+ * @param model The keyboard model.
329+ * If `NULL` or the empty string `""`, a default value is used.
330+ * If the `XKB_DEFAULT_MODEL` environment variable is set, it is used
331+ * as the default. Otherwise the system default is used.
332+ * @param flags Optional flags for the builder, or 0.
333+ *
334+ * @returns A `xkb_rmlvo_builder`, or `NULL` if the compilation failed.
335+ *
336+ * @see `xkb_rule_names` for a detailed description of `rules` and `model`.
337+ * @since 1.11.0
338+ * @memberof xkb_rmlvo_builder
339+ *
340+ * [RMLVO]: @ref RMLVO-intro
341+ */
342+XKB_EXPORT struct xkb_rmlvo_builder*
343+xkb_rmlvo_builder_new(struct xkb_context *context,
344+ const char *rules, const char *model,
345+ enum xkb_rmlvo_builder_flags flags);
346+
347+/**
348+ * Append a layout to the given [RMLVO] builder.
349+ *
350+ * @param rmlvo The builder to modify.
351+ * @param layout The name of the layout.
352+ * @param variant The name of the layout variant, or `NULL` to
353+ * select the default variant.
354+ * @param options An array of options to apply only to this layout, or
355+ * `NULL` if there is no such options.
356+ * @param options_len The length of @p options.
357+ *
358+ * @note The options are only effectual if the corresponding ruleset has the
359+ * proper rules to handle them as *layout-specific* options.
360+ * @note See `rxkb_option_is_layout_specific()` to query whether an option
361+ * supports the layout-specific feature.
362+ *
363+ * @returns `true` if the call succeeded, otherwise `false`.
364+ *
365+ * @since 1.11.0
366+ * @memberof xkb_rmlvo_builder
367+ *
368+ * [RMLVO]: @ref RMLVO-intro
369+ */
370+XKB_EXPORT bool
371+xkb_rmlvo_builder_append_layout(struct xkb_rmlvo_builder *rmlvo,
372+ const char *layout, const char *variant,
373+ const char* const* options, size_t options_len);
374+
375+/**
376+ * Append an option to the given [RMLVO] builder.
377+ *
378+ * @param rmlvo The builder to modify.
379+ * @param option The name of the option.
380+ *
381+ * @returns `true` if the call succeeded, otherwise `false`.
382+ *
383+ * @since 1.11.0
384+ * @memberof xkb_rmlvo_builder
385+ *
386+ * [RMLVO]: @ref RMLVO-intro
387+ */
388+XKB_EXPORT bool
389+xkb_rmlvo_builder_append_option(struct xkb_rmlvo_builder *rmlvo,
390+ const char *option);
391+
392+/**
393+ * Take a new reference on a [RMLVO] builder.
394+ *
395+ * @param rmlvo The builder to reference.
396+ *
397+ * @returns The passed in builder.
398+ *
399+ * @since 1.11.0
400+ * @memberof xkb_rmlvo_builder
401+ *
402+ * [RMLVO]: @ref RMLVO-intro
403+ */
404+XKB_EXPORT struct xkb_rmlvo_builder *
405+xkb_rmlvo_builder_ref(struct xkb_rmlvo_builder *rmlvo);
406+
407+/**
408+ * Release a reference on a [RMLVO] builder, and possibly free it.
409+ *
410+ * @param rmlvo The builder. If it is `NULL`, this function does nothing.
411+ *
412+ * @since 1.11.0
413+ * @memberof xkb_rmlvo_builder
414+ *
415+ * [RMLVO]: @ref RMLVO-intro
416+ */
417+XKB_EXPORT void
418+xkb_rmlvo_builder_unref(struct xkb_rmlvo_builder *rmlvo);
419+
420+/**
421+ * Names to compile a keymap with, also known as [RMLVO].
422+ *
423+ * The names are the common configuration values by which a user picks
424+ * a keymap.
425+ *
426+ * If the entire struct is `NULL`, then each field is taken to be `NULL`.
427+ * You should prefer passing `NULL` instead of choosing your own defaults.
428+ *
429+ * @see [Introduction to RMLVO][RMLVO]
430+ * @see @ref rules-api ""
431+ *
432+ * [RMLVO]: @ref RMLVO-intro
433+ */
434+struct xkb_rule_names {
435+ /**
436+ * The rules file to use. The rules file describes how to interpret
437+ * the values of the model, layout, variant and options fields.
438+ *
439+ * If `NULL` or the empty string `""`, a default value is used.
440+ * If the `XKB_DEFAULT_RULES` environment variable is set, it is used
441+ * as the default. Otherwise the system default is used.
442+ */
443+ const char *rules;
444+ /**
445+ * The keyboard model by which to interpret keycodes and LEDs.
446+ *
447+ * If `NULL` or the empty string `""`, a default value is used.
448+ * If the `XKB_DEFAULT_MODEL` environment variable is set, it is used
449+ * as the default. Otherwise the system default is used.
450+ */
451+ const char *model;
452+ /**
453+ * A comma separated list of layouts (languages) to include in the
454+ * keymap.
455+ *
456+ * If `NULL` or the empty string `""`, a default value is used.
457+ * If the `XKB_DEFAULT_LAYOUT` environment variable is set, it is used
458+ * as the default. Otherwise the system default is used.
459+ */
460+ const char *layout;
461+ /**
462+ * A comma separated list of variants, one per layout, which may
463+ * modify or augment the respective layout in various ways.
464+ *
465+ * Generally, should either be empty or have the same number of values
466+ * as the number of layouts. You may use empty values as in `intl,,neo`.
467+ *
468+ * If `NULL` or the empty string `""`, and a default value is also used
469+ * for the layout, a default value is used. Otherwise no variant is
470+ * used.
471+ * If the `XKB_DEFAULT_VARIANT` environment variable is set, it is used
472+ * as the default. Otherwise the system default is used.
473+ */
474+ const char *variant;
475+ /**
476+ * A comma separated list of options, through which the user specifies
477+ * non-layout related preferences, like which key combinations are used
478+ * for switching layouts, or which key is the Compose key.
479+ *
480+ * If `NULL`, a default value is used. If the empty string `""`, no
481+ * options are used.
482+ * If the `XKB_DEFAULT_OPTIONS` environment variable is set, it is used
483+ * as the default. Otherwise the system default is used.
484+ *
485+ * Each option can additionally have a *layout index specifier*, so that it
486+ * applies only if matching the given layout. The index is specified by
487+ * appending `!` immediately after the option name, then the 1-indexed
488+ * target layout in decimal format: e.g. `ns:option!2`. When no layout is
489+ * specified, it matches any layout.
490+ *
491+ * @note The layout index specifier is only effectual if the corresponding
492+ * ruleset has the proper rules to handle the option as *layout-specific*.
493+ * @note See `rxkb_option_is_layout_specific()` to query whether an option
494+ * supports the layout-specific feature.
495+ *
496+ * @since 1.11.0: Layout index specifier using `!`.
497+ */
498+ const char *options;
499+};
500+
501+/**
502+ * Keymap components, also known as [KcCGST].
503+ *
504+ * The components are the result of the [RMLVO] resolution.
505+ *
506+ * @see [Introduction to RMLVO][RMLVO]
507+ * @see [Introduction to KcCGST][KcCGST]
508+ * @see @ref rules-api ""
509+ *
510+ * [RMLVO]: @ref RMLVO-intro
511+ * [KcCGST]: @ref KcCGST-intro
512+ */
513+struct xkb_component_names {
514+ char *keycodes;
515+ char *compatibility;
516+ char *geometry;
517+ char *symbols;
518+ char *types;
519+};
520+
521+/**
522+ * Resolve [RMLVO] names to [KcCGST] components.
523+ *
524+ * This function is used primarily for *debugging*. See
525+ * `xkb_keymap::xkb_keymap_new_from_names2()` for creating keymaps from
526+ * [RMLVO] names.
527+ *
528+ * @param[in] context The context in which to resolve the names.
529+ * @param[in] rmlvo_in The [RMLVO] names to use.
530+ * @param[out] rmlvo_out The [RMLVO] names actually used after resolving
531+ * missing values.
532+ * @param[out] components_out The [KcCGST] components resulting of the [RMLVO]
533+ * resolution.
534+ *
535+ * @c rmlvo_out and @c components can be omitted by using `NULL`, but not both.
536+ *
537+ * If @c components is not `NULL`, it is filled with dynamically-allocated
538+ * strings that should be freed by the caller.
539+ *
540+ * @returns `true` if the [RMLVO] names could be resolved, `false` otherwise.
541+ *
542+ * @see [Introduction to RMLVO][RMLVO]
543+ * @see [Introduction to KcCGST][KcCGST]
544+ * @see xkb_rule_names
545+ * @see xkb_component_names
546+ * @see xkb_keymap::xkb_keymap_new_from_names2()
547+ *
548+ * @since 1.9.0
549+ * @memberof xkb_component_names
550+ *
551+ * [RMLVO]: @ref RMLVO-intro
552+ * [KcCGST]: @ref KcCGST-intro
553+ */
554+XKB_EXPORT bool
555+xkb_components_names_from_rules(struct xkb_context *context,
556+ const struct xkb_rule_names *rmlvo_in,
557+ struct xkb_rule_names *rmlvo_out,
558+ struct xkb_component_names *components_out);
559+
560+/** @} */
561+
562+/**
563+ * @defgroup keysyms Keysyms
564+ * Utility functions related to *keysyms* (short for “key symbols”).
565+ *
566+ * @{
567+ */
568+
569+/**
570+ * @page keysym-transformations Keysym Transformations
571+ *
572+ * Keysym translation is subject to several *keysym transformations*,
573+ * as described in the XKB specification. These are:
574+ *
575+ * <dl>
576+ * <dt>Capitalization transformation</dt>
577+ * <dd>
578+ * If the Caps Lock modifier is
579+ * active and was not consumed by the translation process, keysyms
580+ * are transformed to their upper-case form (if applicable).
581+ * Similarly, the UTF-8/UTF-32 string produced is capitalized.
582+ *
583+ * This is described in:
584+ * https://www.x.org/releases/current/doc/kbproto/xkbproto.html#Interpreting_the_Lock_Modifier
585+ * </dd>
586+ * <dt>Control transformation</dt>
587+ * <dd>
588+ * If the Control modifier is active and
589+ * was not consumed by the translation process, the string produced
590+ * is transformed to its matching ASCII control character (if
591+ * applicable). Keysyms are not affected.
592+ *
593+ * This is described in:
594+ * https://www.x.org/releases/current/doc/kbproto/xkbproto.html#Interpreting_the_Control_Modifier
595+ * </dd>
596+ * </dl>
597+ *
598+ * Each relevant function discusses which transformations it performs.
599+ *
600+ * These transformations are not applicable when a key produces multiple
601+ * keysyms.
602+ */
603+
604+
605+/**
606+ * Get the name of a keysym.
607+ *
608+ * For a description of how keysyms are named, see @ref xkb_keysym_t.
609+ *
610+ * @param[in] keysym The keysym.
611+ * @param[out] buffer A string buffer to write the name into.
612+ * @param[in] size Size of the buffer.
613+ *
614+ * @warning If the buffer passed is too small, the string is truncated
615+ * (though still `NULL`-terminated); a size of at least 64 bytes is recommended.
616+ *
617+ * @returns The number of bytes in the name, excluding the `NULL` byte. If
618+ * the keysym is invalid, returns -1.
619+ *
620+ * You may check if truncation has occurred by comparing the return value
621+ * with the length of buffer, similarly to the `snprintf(3)` function.
622+ *
623+ * @sa `xkb_keysym_t`
624+ */
625+XKB_EXPORT int
626+xkb_keysym_get_name(xkb_keysym_t keysym, char *buffer, size_t size);
627+
628+/** Flags for xkb_keysym_from_name(). */
629+enum xkb_keysym_flags {
630+ /** Do not apply any flags. */
631+ XKB_KEYSYM_NO_FLAGS = 0,
632+ /** Find keysym by case-insensitive search. */
633+ XKB_KEYSYM_CASE_INSENSITIVE = (1 << 0)
634+};
635+
636+/**
637+ * Get a keysym from its name.
638+ *
639+ * @param name The name of a keysym. See remarks in `xkb_keysym_get_name()`;
640+ * this function will accept any name returned by that function.
641+ * @param flags A set of flags controlling how the search is done. If
642+ * invalid flags are passed, this will fail with `XKB_KEY_NoSymbol`.
643+ *
644+ * If you use the `::XKB_KEYSYM_CASE_INSENSITIVE` flag and two keysym names
645+ * differ only by case, then the lower-case keysym name is returned. For
646+ * instance, for KEY_a and KEY_A, this function would return KEY_a for the
647+ * case-insensitive search. If this functionality is needed, it is
648+ * recommended to first call this function without this flag; and if that
649+ * fails, only then to try with this flag, while possibly warning the user
650+ * he had misspelled the name, and might get wrong results.
651+ *
652+ * Case folding is done according to the C locale; the current locale is not
653+ * consulted.
654+ *
655+ * @returns The keysym. If the name is invalid, returns `XKB_KEY_NoSymbol`.
656+ *
657+ * @sa xkb_keysym_t
658+ * @since 1.9.0: Enable support for C0 and C1 control characters in the Unicode
659+ * notation.
660+ */
661+XKB_EXPORT xkb_keysym_t
662+xkb_keysym_from_name(const char *name, enum xkb_keysym_flags flags);
663+
664+/**
665+ * Get the Unicode/UTF-8 representation of a keysym.
666+ *
667+ * @param[in] keysym The keysym.
668+ * @param[out] buffer A buffer to write the UTF-8 string into.
669+ * @param[in] size The size of buffer. Must be at least 5.
670+ *
671+ * @returns The number of bytes written to the buffer (including the
672+ * terminating byte). If the keysym does not have a Unicode
673+ * representation, returns 0. If the buffer is too small, returns -1.
674+ *
675+ * This function does not perform any @ref keysym-transformations.
676+ * Therefore, prefer to use `xkb_state::xkb_state_key_get_utf8()` if possible.
677+ *
678+ * @sa `xkb_state::xkb_state_key_get_utf8()`
679+ */
680+XKB_EXPORT int
681+xkb_keysym_to_utf8(xkb_keysym_t keysym, char *buffer, size_t size);
682+
683+/**
684+ * Get the Unicode/UTF-32 representation of a keysym.
685+ *
686+ * @returns The Unicode/UTF-32 representation of keysym, which is also
687+ * compatible with UCS-4. If the keysym does not have a Unicode
688+ * representation, returns 0.
689+ *
690+ * This function does not perform any @ref keysym-transformations.
691+ * Therefore, prefer to use xkb_state_key_get_utf32() if possible.
692+ *
693+ * @sa `xkb_state::xkb_state_key_get_utf32()`
694+ */
695+XKB_EXPORT uint32_t
696+xkb_keysym_to_utf32(xkb_keysym_t keysym);
697+
698+/**
699+ * Get the keysym corresponding to a Unicode/UTF-32 codepoint.
700+ *
701+ * @returns The keysym corresponding to the specified Unicode
702+ * codepoint, or XKB_KEY_NoSymbol if there is none.
703+ *
704+ * This function is the inverse of @ref xkb_keysym_to_utf32. In cases
705+ * where a single codepoint corresponds to multiple keysyms, returns
706+ * the keysym with the lowest value.
707+ *
708+ * Unicode codepoints which do not have a special (legacy) keysym
709+ * encoding use a direct encoding scheme. These keysyms don’t usually
710+ * have an associated keysym constant (`XKB_KEY_*`).
711+ *
712+ * @sa `xkb_keysym_to_utf32()`
713+ * @since 1.0.0
714+ * @since 1.9.0: Enable support for all noncharacters.
715+ */
716+XKB_EXPORT xkb_keysym_t
717+xkb_utf32_to_keysym(uint32_t ucs);
718+
719+/**
720+ * Convert a keysym to its uppercase form.
721+ *
722+ * If there is no such form, the keysym is returned unchanged.
723+ *
724+ * The conversion rules are the *simple* (i.e. one-to-one) Unicode case
725+ * mappings (with some exceptions, see hereinafter) and do not depend
726+ * on the locale. If you need the special case mappings (i.e. not
727+ * one-to-one or locale-dependent), prefer to work with the Unicode
728+ * representation instead, when possible.
729+ *
730+ * Exceptions to the Unicode mappings:
731+ *
732+ * | Lower keysym | Lower letter | Upper keysym | Upper letter | Comment |
733+ * | ------------ | ------------ | ------------ | ------------ | ------- |
734+ * | `ssharp` | `U+00DF`: ß | `U1E9E` | `U+1E9E`: ẞ | [Council for German Orthography] |
735+ *
736+ * [Council for German Orthography]: https://www.rechtschreibrat.com/regeln-und-woerterverzeichnis/
737+ *
738+ * @since 0.8.0: Initial implementation, based on `libX11`.
739+ * @since 1.8.0: Use Unicode 16.0 mappings for complete Unicode coverage.
740+ * @since 1.12.0: Update to Unicode 17.0.
741+ */
742+XKB_EXPORT xkb_keysym_t
743+xkb_keysym_to_upper(xkb_keysym_t ks);
744+
745+/**
746+ * Convert a keysym to its lowercase form.
747+ *
748+ * If there is no such form, the keysym is returned unchanged.
749+ *
750+ * The conversion rules are the *simple* (i.e. one-to-one) Unicode case
751+ * mappings and do not depend on the locale. If you need the special
752+ * case mappings (i.e. not one-to-one or locale-dependent), prefer to
753+ * work with the Unicode representation instead, when possible.
754+ *
755+ * @since 0.8.0: Initial implementation, based on `libX11`.
756+ * @since 1.8.0: Use Unicode 16.0 mappings for complete Unicode coverage.
757+ * @since 1.12.0: Update to Unicode 17.0.
758+ */
759+XKB_EXPORT xkb_keysym_t
760+xkb_keysym_to_lower(xkb_keysym_t ks);
761+
762+/** @} */
763+
764+/**
765+ * @defgroup context Library Context
766+ * Creating, destroying and using library contexts.
767+ *
768+ * Every keymap compilation request must have a context associated with
769+ * it. The context keeps around state such as the include path.
770+ *
771+ * @{
772+ */
773+
774+/**
775+ * @page envvars Environment Variables
776+ *
777+ * The user may set some environment variables which affect the library:
778+ *
779+ * - `XKB_CONFIG_ROOT`, `XKB_CONFIG_UNVERSIONED_EXTENSIONS_PATH`,
780+ * `XKB_CONFIG_VERSIONED_EXTENSIONS_PATH`, `XKB_CONFIG_EXTRA_PATH`,
781+ * `XDG_CONFIG_DIR`, `HOME` - see @ref include-path.
782+ * - `XKB_LOG_LEVEL` - see `xkb_context::xkb_context_set_log_level()`.
783+ * - `XKB_LOG_VERBOSITY` - see `xkb_context::xkb_context_set_log_verbosity()`.
784+ * - `XKB_DEFAULT_RULES`, `XKB_DEFAULT_MODEL`, `XKB_DEFAULT_LAYOUT`,
785+ * `XKB_DEFAULT_VARIANT`, `XKB_DEFAULT_OPTIONS` - see `xkb_rule_names`.
786+ */
787+
788+/** Flags for context creation. */
789+enum xkb_context_flags {
790+ /** Do not apply any context flags. */
791+ XKB_CONTEXT_NO_FLAGS = 0,
792+ /**
793+ * Create this context with an empty include path.
794+ *
795+ * This may be useful e.g.:
796+ * - to have full control over the included paths;
797+ * - for clients that do not need to access the XKB directories, e.g.
798+ * if only retrieving keymap from the Wayland or X server. It avoids
799+ * potential issues with directory access permissions.
800+ */
801+ XKB_CONTEXT_NO_DEFAULT_INCLUDES = (1 << 0),
802+ /**
803+ * Don’t take RMLVO names from the environment.
804+ *
805+ * @since 0.3.0
806+ */
807+ XKB_CONTEXT_NO_ENVIRONMENT_NAMES = (1 << 1),
808+ /**
809+ * Disable the use of secure_getenv for this context, so that privileged
810+ * processes can use environment variables. Client uses at their own risk.
811+ *
812+ * @since 1.5.0
813+ */
814+ XKB_CONTEXT_NO_SECURE_GETENV = (1 << 2)
815+};
816+
817+/**
818+ * Create a new context.
819+ *
820+ * @param flags Optional flags for the context, or 0.
821+ *
822+ * @returns A new context, or `NULL` on failure.
823+ *
824+ * @memberof xkb_context
825+ */
826+XKB_EXPORT struct xkb_context *
827+xkb_context_new(enum xkb_context_flags flags);
828+
829+/**
830+ * Take a new reference on a context.
831+ *
832+ * @returns The passed in context.
833+ *
834+ * @memberof xkb_context
835+ */
836+XKB_EXPORT struct xkb_context *
837+xkb_context_ref(struct xkb_context *context);
838+
839+/**
840+ * Release a reference on a context, and possibly free it.
841+ *
842+ * @param context The context. If it is `NULL`, this function does nothing.
843+ *
844+ * @memberof xkb_context
845+ */
846+XKB_EXPORT void
847+xkb_context_unref(struct xkb_context *context);
848+
849+/**
850+ * Store custom user data in the context.
851+ *
852+ * This may be useful in conjunction with `xkb_context::xkb_context_set_log_fn()`
853+ * or other callbacks.
854+ *
855+ * @memberof xkb_context
856+ */
857+XKB_EXPORT void
858+xkb_context_set_user_data(struct xkb_context *context, void *user_data);
859+
860+/**
861+ * Retrieves stored user data from the context.
862+ *
863+ * @returns The stored user data. If the user data wasn’t set, or the
864+ * passed in context is `NULL`, returns `NULL`.
865+ *
866+ * This may be useful to access private user data from callbacks like a
867+ * custom logging function.
868+ *
869+ * @memberof xkb_context
870+ **/
871+XKB_EXPORT void *
872+xkb_context_get_user_data(struct xkb_context *context);
873+
874+/** @} */
875+
876+/**
877+ * @defgroup include-path Include Paths
878+ * Manipulating the include paths in a context.
879+ *
880+ * The include paths are the file-system paths that are searched when an
881+ * include statement is encountered during keymap compilation.
882+ *
883+ * The default include paths are, in that lookup order:
884+ *
885+ * <dl>
886+ * <dt>User</dt>
887+ * <dd>
888+ * - The path `$XDG_CONFIG_HOME/xkb`, where `$XDG_CONFIG_HOME` is the value of
889+ * the environment variable `XDG_CONFIG_HOME`, with the usual fallback to
890+ * `$HOME/.config/` if unset.
891+ *
892+ * See @ref custom-configuration "" for further information.
893+ * - @deprecated The *legacy* path `$HOME/.xkb`, where `$HOME` is the value of
894+ * the environment variable `HOME`.
895+ * <!-- [HACK] blank required by Doxygen -->
896+ *
897+ * </dd>
898+ * <dt>System</dt>
899+ * <dd>
900+ * - The `XKB_CONFIG_EXTRA_PATH` environment variable, if defined, otherwise the
901+ * system configuration directory, defined at library configuration time
902+ * (usually `/etc/xkb`).
903+ *
904+ * One can adapt the @ref custom-configuration "" instructions by replacing
905+ * `$XDG_CONFIG_HOME` with the system configuration directory in the
906+ * file locations.
907+ * - Each subdirectory of each XKB extensions directory (versioned, then
908+ * unversioned if no corresponding versioned subdirectory), listed in
909+ * lexicographic order. The extensions directories are defined by the
910+ * environment variables `XKB_CONFIG_VERSIONED_EXTENSIONS_PATH` and
911+ * `XKB_CONFIG_UNVERSIONED_EXTENSIONS_PATH` and default to the system XKB
912+ * root extensions directories, defined at library configuration time (usually
913+ * `/usr/share/xkeyboard-config-<VERSION>.d` and
914+ * `/usr/share/xkeyboard-config.d`).
915+ *
916+ * See @ref packaging-keyboard-layouts "" for further information.
917+ * - The `XKB_CONFIG_ROOT` environment variable, if defined, otherwise
918+ * the system XKB root, defined at library configuration time
919+ * (usually `/usr/share/xkeyboard-config-<VERSION>` or `/usr/share/X11/xkb`).
920+ *
921+ * @warning Do not modify the system XKB root files, because they will be
922+ * overwritten by any update of the `xkeyboard-config`/`xkb-data` package.
923+ * - Since 1.12.2: if the previous path failed, it fallbacks to the *legacy X11
924+ * path* defined at compilation time (usually `/usr/share/X11/xkb`). This
925+ * fallback is skipped is `XKB_CONFIG_ROOT` is explicitly set to an empty
926+ * string.
927+ * </dd>
928+ * </dl>
929+ *
930+ * @{
931+ */
932+
933+/**
934+ * Append a new entry to the context’s include path.
935+ *
936+ * @returns 1 on success, or 0 if the include path could not be added or is
937+ * inaccessible.
938+ *
939+ * @memberof xkb_context
940+ */
941+XKB_EXPORT int
942+xkb_context_include_path_append(struct xkb_context *context, const char *path);
943+
944+/**
945+ * Append the default include paths to the context’s include path.
946+ *
947+ * @returns 1 on success, or 0 if no default include path could be added.
948+ *
949+ * @memberof xkb_context
950+ */
951+XKB_EXPORT int
952+xkb_context_include_path_append_default(struct xkb_context *context);
953+
954+/**
955+ * Reset the context’s include path to the default.
956+ *
957+ * Removes all entries from the context’s include path, and inserts the
958+ * default paths.
959+ *
960+ * @returns 1 on success, or 0 if the primary include path could not be added.
961+ *
962+ * @memberof xkb_context
963+ */
964+XKB_EXPORT int
965+xkb_context_include_path_reset_defaults(struct xkb_context *context);
966+
967+/**
968+ * Remove all entries from the context’s include path.
969+ *
970+ * @memberof xkb_context
971+ */
972+XKB_EXPORT void
973+xkb_context_include_path_clear(struct xkb_context *context);
974+
975+/**
976+ * Get the number of paths in the context’s include path.
977+ *
978+ * @memberof xkb_context
979+ */
980+XKB_EXPORT unsigned int
981+xkb_context_num_include_paths(struct xkb_context *context);
982+
983+/**
984+ * Get a specific include path from the context’s include path.
985+ *
986+ * @returns The include path at the specified index. If the index is
987+ * invalid, returns NULL.
988+ *
989+ * @memberof xkb_context
990+ */
991+XKB_EXPORT const char *
992+xkb_context_include_path_get(struct xkb_context *context, unsigned int index);
993+
994+/** @} */
995+
996+/**
997+ * @defgroup logging Logging Handling
998+ * Manipulating how logging from this library is handled.
999+ *
1000+ * @{
1001+ */
1002+
1003+/** Specifies a logging level. */
1004+enum xkb_log_level {
1005+ XKB_LOG_LEVEL_CRITICAL = 10, /**< Log critical internal errors only. */
1006+ XKB_LOG_LEVEL_ERROR = 20, /**< Log all errors. */
1007+ XKB_LOG_LEVEL_WARNING = 30, /**< Log warnings and errors. */
1008+ XKB_LOG_LEVEL_INFO = 40, /**< Log information, warnings, and errors. */
1009+ XKB_LOG_LEVEL_DEBUG = 50 /**< Log everything. */
1010+};
1011+
1012+/**
1013+ * Set the current logging level.
1014+ *
1015+ * @param context The context in which to set the logging level.
1016+ * @param level The logging level to use. Only messages from this level
1017+ * and below will be logged.
1018+ *
1019+ * The default level is `::XKB_LOG_LEVEL_ERROR`. The environment variable
1020+ * `XKB_LOG_LEVEL`, if set in the time the context was created, overrides the
1021+ * default value. It may be specified as a level number or name.
1022+ *
1023+ * @memberof xkb_context
1024+ */
1025+XKB_EXPORT void
1026+xkb_context_set_log_level(struct xkb_context *context,
1027+ enum xkb_log_level level);
1028+
1029+/**
1030+ * Get the current logging level.
1031+ *
1032+ * @memberof xkb_context
1033+ */
1034+XKB_EXPORT enum xkb_log_level
1035+xkb_context_get_log_level(struct xkb_context *context);
1036+
1037+/**
1038+ * Sets the current logging verbosity.
1039+ *
1040+ * The library can generate a number of warnings which are not helpful to
1041+ * ordinary users of the library. The verbosity may be increased if more
1042+ * information is desired (e.g. when developing a new keymap).
1043+ *
1044+ * The default verbosity is 0. The environment variable `XKB_LOG_VERBOSITY`,
1045+ * if set in the time the context was created, overrides the default value.
1046+ *
1047+ * @param context The context in which to use the set verbosity.
1048+ * @param verbosity The verbosity to use. Currently used values are
1049+ * 1 to 10, higher values being more verbose. 0 would result in no verbose
1050+ * messages being logged.
1051+ *
1052+ * Most verbose messages are of level `::XKB_LOG_LEVEL_WARNING` or lower.
1053+ *
1054+ * @memberof xkb_context
1055+ */
1056+XKB_EXPORT void
1057+xkb_context_set_log_verbosity(struct xkb_context *context, int verbosity);
1058+
1059+/**
1060+ * Get the current logging verbosity of the context.
1061+ *
1062+ * @memberof xkb_context
1063+ */
1064+XKB_EXPORT int
1065+xkb_context_get_log_verbosity(struct xkb_context *context);
1066+
1067+/**
1068+ * Set a custom function to handle logging messages.
1069+ *
1070+ * @param context The context in which to use the set logging function.
1071+ * @param log_fn The function that will be called for logging messages.
1072+ * Passing `NULL` restores the default function, which logs to stderr.
1073+ *
1074+ * By default, log messages from this library are printed to stderr. This
1075+ * function allows you to replace the default behavior with a custom
1076+ * handler. The handler is only called with messages which match the
1077+ * current logging level and verbosity settings for the context.
1078+ * level is the logging level of the message. @a format and @a args are
1079+ * the same as in the `vprintf(3)` function.
1080+ *
1081+ * You may use `xkb_context::xkb_context_set_user_data()` on the context, and
1082+ * then call `xkb_context::xkb_context_get_user_data()` from within the logging
1083+ * function to provide it with additional private context.
1084+ *
1085+ * @memberof xkb_context
1086+ */
1087+XKB_EXPORT void
1088+xkb_context_set_log_fn(struct xkb_context *context,
1089+ void (*log_fn)(struct xkb_context *context,
1090+ enum xkb_log_level level,
1091+ const char *format, va_list args));
1092+
1093+/** @} */
1094+
1095+/**
1096+ * @defgroup keymap Keymap Creation
1097+ * Creating and destroying keymaps.
1098+ *
1099+ * @{
1100+ */
1101+
1102+/** Flags for keymap compilation. */
1103+enum xkb_keymap_compile_flags {
1104+ /** Do not apply any flags. */
1105+ XKB_KEYMAP_COMPILE_NO_FLAGS = 0
1106+};
1107+
1108+/**
1109+ * The possible keymap formats.
1110+ *
1111+ * See @ref keymap-text-format-v1-v2 "" for the complete description of the
1112+ * formats and @ref keymap-support "" for detailed differences between the
1113+ * formats.
1114+ *
1115+ * @remark A keymap can be parsed in one format and serialized in another,
1116+ * thanks to automatic fallback mechanisms.
1117+ *
1118+ * <table>
1119+ * <caption>
1120+ * Keymap format to use depending on the target protocol
1121+ * </caption>
1122+ * <thead>
1123+ * <tr>
1124+ * <th colspan="2">Protocol</th>
1125+ * <th colspan="2">libxkbcommon keymap format</th>
1126+ * </tr>
1127+ * <tr>
1128+ * <th>Name</th>
1129+ * <th>Keymap format</th>
1130+ * <th>Parsing</th>
1131+ * <th>Serialization</th>
1132+ * </tr>
1133+ * </thead>
1134+ * <tbody>
1135+ * <tr>
1136+ * <th>X11</th>
1137+ * <td>XKB</td>
1138+ * <td>
1139+ * `::XKB_KEYMAP_FORMAT_TEXT_V1`
1140+ * </td>
1141+ * <td>
1142+ * *Always* use `::XKB_KEYMAP_FORMAT_TEXT_V1`, since the other formats are
1143+ * incompatible.
1144+ * </td>
1145+ * </tr>
1146+ * <tr>
1147+ * <th>Wayland</th>
1148+ * <td><code>[xkb_v1]</code></td>
1149+ * <td>
1150+ * <dl>
1151+ * <dt>Wayland compositors<dt>
1152+ * <dd>
1153+ * The format depends on the keyboard layout database (usually [xkeyboard-config]).
1154+ * Note that since v2 is a superset of v1, compositors are encouraged to use
1155+ * `::XKB_KEYMAP_FORMAT_TEXT_V2` whenever possible.
1156+ * </dd>
1157+ * <dt>Client apps</dt>
1158+ * <dd>
1159+ * Clients should use `::XKB_KEYMAP_FORMAT_TEXT_V1` to parse the keymap sent
1160+ * by a Wayland compositor, at least until `::XKB_KEYMAP_FORMAT_TEXT_V2`
1161+ * stabilizes.
1162+ * </dd>
1163+ * </td>
1164+ * <td>
1165+ * At the time of writing (July 2025), the Wayland <code>[xkb_v1]</code> keymap
1166+ * format is only defined as “libxkbcommon compatible”. In theory it enables
1167+ * flexibility, but the set of supported features varies depending on the
1168+ * libxkbcommon version and libxkbcommon keymap format used. Unfortunately there
1169+ * is currently no Wayland API for keymap format *negotiation*.
1170+ *
1171+ * Therefore the **recommended** serialization format is
1172+ * `::XKB_KEYMAP_FORMAT_TEXT_V1`, in order to ensure maximum compatibility for
1173+ * interchange.
1174+ *
1175+ * Serializing using `::XKB_KEYMAP_FORMAT_TEXT_V2` should be considered
1176+ * **experimental**, as some clients may fail to parse the resulting string.
1177+ * </td>
1178+ * </tr>
1179+ * </tbody>
1180+ * </table>
1181+ *
1182+ * [xkb_v1]: https://wayland.freedesktop.org/docs/html/apa.html#protocol-spec-wl_keyboard-enum-keymap_format
1183+ * [xkeyboard-config]: https://gitlab.freedesktop.org/xkeyboard-config/xkeyboard-config
1184+ */
1185+enum xkb_keymap_format {
1186+ /**
1187+ * The classic XKB text format, as generated by `xkbcomp -xkb`.
1188+ *
1189+ * @important This format should *always* be used when *serializing* a
1190+ * keymap for **X11**.
1191+ *
1192+ * @important For the **Wayland** <code>[xkb_v1]</code> format, it is
1193+ * advised to use this format as well for serializing, in order to ensure
1194+ * maximum compatibility for interchange.
1195+ *
1196+ * [xkb_v1]: https://wayland.freedesktop.org/docs/html/apa.html#protocol-spec-wl_keyboard-enum-keymap_format
1197+ */
1198+ XKB_KEYMAP_FORMAT_TEXT_V1 = 1,
1199+ /**
1200+ * Xkbcommon extensions of the classic XKB text format, **incompatible with
1201+ * X11**.
1202+ *
1203+ * @important Do *not* use when *serializing* a keymap for **X11**
1204+ * (incompatible).
1205+ *
1206+ * @important Considered *experimental* when *serializing* for **Wayland**:
1207+ * at the time of writing (July 2025), there is only one XKB keymap format
1208+ * <code>[xkb_v1]</code> in Wayland and no Wayland API for keymap format
1209+ * *negotiation*, so the clients may not be able to parse the keymap if it
1210+ * uses v2-specific features. Therefore a compositor may *parse* keymaps
1211+ * using `::XKB_KEYMAP_FORMAT_TEXT_V2` but it should serialize them using
1212+ * `::XKB_KEYMAP_FORMAT_TEXT_V1` and rely on the automatic *fallback*
1213+ * mechanisms.
1214+ *
1215+ * @since 1.11.0
1216+ *
1217+ * [xkb_v1]: https://wayland.freedesktop.org/docs/html/apa.html#protocol-spec-wl_keyboard-enum-keymap_format
1218+ */
1219+ XKB_KEYMAP_FORMAT_TEXT_V2 = 2
1220+};
1221+
1222+/**
1223+ * Create a keymap from a [RMLVO] builder.
1224+ *
1225+ * The primary keymap entry point: creates a new XKB keymap from a set of
1226+ * [RMLVO] \(Rules + Model + Layouts + Variants + Options) names.
1227+ *
1228+ * @param rmlvo The [RMLVO] builder to use. See `xkb_rmlvo_builder`.
1229+ * @param format The text format of the keymap file to compile.
1230+ * @param flags Optional flags for the keymap, or 0.
1231+ *
1232+ * @returns A keymap compiled according to the [RMLVO] names, or `NULL` if
1233+ * the compilation failed.
1234+ *
1235+ * @since 1.11.0
1236+ * @sa `xkb_keymap_new_from_names2()`
1237+ * @sa `xkb_rmlvo_builder`
1238+ * @memberof xkb_keymap
1239+ *
1240+ * [RMLVO]: @ref RMLVO-intro
1241+ */
1242+XKB_EXPORT struct xkb_keymap *
1243+xkb_keymap_new_from_rmlvo(const struct xkb_rmlvo_builder *rmlvo,
1244+ enum xkb_keymap_format format,
1245+ enum xkb_keymap_compile_flags flags);
1246+
1247+/**
1248+ * Create a keymap from [RMLVO] names.
1249+ *
1250+ * Same as `xkb_keymap_new_from_names2()`, but with the keymap format fixed to:
1251+ * `::XKB_KEYMAP_FORMAT_TEXT_V2`.
1252+ *
1253+ * @deprecated Use `xkb_keymap_new_from_names2()` instead.
1254+ * @since 1.11.0: Deprecated
1255+ * @since 1.11.0: Use internally `::XKB_KEYMAP_FORMAT_TEXT_V2` instead of
1256+ * `::XKB_KEYMAP_FORMAT_TEXT_V1`
1257+ * @sa `xkb_keymap_new_from_names2()`
1258+ * @sa `xkb_rule_names`
1259+ * @sa `xkb_keymap_new_from_rmlvo()`
1260+ * @memberof xkb_keymap
1261+ *
1262+ * [RMLVO]: @ref RMLVO-intro
1263+ */
1264+XKB_EXPORT struct xkb_keymap *
1265+xkb_keymap_new_from_names(struct xkb_context *context,
1266+ const struct xkb_rule_names *names,
1267+ enum xkb_keymap_compile_flags flags);
1268+
1269+/**
1270+ * Create a keymap from [RMLVO] names.
1271+ *
1272+ * The primary keymap entry point: creates a new XKB keymap from a set of
1273+ * [RMLVO] \(Rules + Model + Layouts + Variants + Options) names.
1274+ *
1275+ * @param context The context in which to create the keymap.
1276+ * @param names The [RMLVO] names to use. See xkb_rule_names.
1277+ * @param format The text format of the keymap file to compile.
1278+ * @param flags Optional flags for the keymap, or 0.
1279+ *
1280+ * @returns A keymap compiled according to the [RMLVO] names, or `NULL` if
1281+ * the compilation failed.
1282+ *
1283+ * @sa `xkb_rule_names`
1284+ * @sa `xkb_keymap_new_from_rmlvo()`
1285+ * @memberof xkb_keymap
1286+ * @since 1.11.0
1287+ *
1288+ * [RMLVO]: @ref RMLVO-intro
1289+ */
1290+XKB_EXPORT struct xkb_keymap *
1291+xkb_keymap_new_from_names2(struct xkb_context *context,
1292+ const struct xkb_rule_names *names,
1293+ enum xkb_keymap_format format,
1294+ enum xkb_keymap_compile_flags flags);
1295+
1296+/**
1297+ * Create a keymap from a keymap file.
1298+ *
1299+ * @param context The context in which to create the keymap.
1300+ * @param file The keymap file to compile.
1301+ * @param format The text format of the keymap file to compile.
1302+ * @param flags Optional flags for the keymap, or 0.
1303+ *
1304+ * @returns A keymap compiled from the given XKB keymap file, or `NULL` if
1305+ * the compilation failed.
1306+ *
1307+ * The file must contain a complete keymap. For example, in the
1308+ * `::XKB_KEYMAP_FORMAT_TEXT_V1` format, this means the file must contain one
1309+ * top level `%xkb_keymap` section, which in turn contains other required
1310+ * sections.
1311+ *
1312+ * @memberof xkb_keymap
1313+ */
1314+XKB_EXPORT struct xkb_keymap *
1315+xkb_keymap_new_from_file(struct xkb_context *context, FILE *file,
1316+ enum xkb_keymap_format format,
1317+ enum xkb_keymap_compile_flags flags);
1318+
1319+/**
1320+ * Create a keymap from a keymap string.
1321+ *
1322+ * This is just like `xkb_keymap_new_from_file()`, but instead of a file, gets
1323+ * the keymap as one enormous string.
1324+ *
1325+ * @see `xkb_keymap_new_from_file()`
1326+ * @memberof xkb_keymap
1327+ */
1328+XKB_EXPORT struct xkb_keymap *
1329+xkb_keymap_new_from_string(struct xkb_context *context, const char *string,
1330+ enum xkb_keymap_format format,
1331+ enum xkb_keymap_compile_flags flags);
1332+
1333+/**
1334+ * Create a keymap from a memory buffer.
1335+ *
1336+ * This is just like `xkb_keymap_new_from_string()`, but takes a length argument
1337+ * so the input string does not have to be zero-terminated.
1338+ *
1339+ * @see `xkb_keymap_new_from_string()`
1340+ * @memberof xkb_keymap
1341+ * @since 0.3.0
1342+ */
1343+XKB_EXPORT struct xkb_keymap *
1344+xkb_keymap_new_from_buffer(struct xkb_context *context, const char *buffer,
1345+ size_t length, enum xkb_keymap_format format,
1346+ enum xkb_keymap_compile_flags flags);
1347+
1348+/**
1349+ * Take a new reference on a keymap.
1350+ *
1351+ * @returns The passed in keymap.
1352+ *
1353+ * @memberof xkb_keymap
1354+ */
1355+XKB_EXPORT struct xkb_keymap *
1356+xkb_keymap_ref(struct xkb_keymap *keymap);
1357+
1358+/**
1359+ * Release a reference on a keymap, and possibly free it.
1360+ *
1361+ * @param keymap The keymap. If it is `NULL`, this function does nothing.
1362+ *
1363+ * @memberof xkb_keymap
1364+ */
1365+XKB_EXPORT void
1366+xkb_keymap_unref(struct xkb_keymap *keymap);
1367+
1368+/**
1369+ * Get the keymap as a string in the format from which it was created.
1370+ * @sa `xkb_keymap::xkb_keymap_get_as_string()`
1371+ **/
1372+#define XKB_KEYMAP_USE_ORIGINAL_FORMAT ((enum xkb_keymap_format) -1)
1373+
1374+/**
1375+ * Flags to control keymap serialization.
1376+ *
1377+ * @since 1.12.0
1378+ */
1379+enum xkb_keymap_serialize_flags {
1380+ /** Do not apply any flags. */
1381+ XKB_KEYMAP_SERIALIZE_NO_FLAGS = 0,
1382+ /** Enable pretty-printing */
1383+ XKB_KEYMAP_SERIALIZE_PRETTY = (1 << 0),
1384+ /** Do not drop unused bits (key types, compatibility entries) */
1385+ XKB_KEYMAP_SERIALIZE_KEEP_UNUSED = (1 << 1),
1386+};
1387+
1388+/**
1389+ * Get the compiled keymap as a string.
1390+ *
1391+ * Same as `xkb_keymap::xkb_keymap_get_as_string2()` using
1392+ * `::XKB_KEYMAP_SERIALIZE_NO_FLAGS`.
1393+ *
1394+ * @since 1.12.0: Drop unused types and compatibility entries and do not
1395+ * pretty-print.
1396+ *
1397+ * @sa `xkb_keymap::xkb_keymap_get_as_string2()`
1398+ * @memberof xkb_keymap
1399+ */
1400+XKB_EXPORT char *
1401+xkb_keymap_get_as_string(struct xkb_keymap *keymap,
1402+ enum xkb_keymap_format format);
1403+
1404+/**
1405+ * Get the compiled keymap as a string.
1406+ *
1407+ * @param keymap The keymap to get as a string.
1408+ * @param format The keymap format to use for the string. You can pass
1409+ * in the special value `::XKB_KEYMAP_USE_ORIGINAL_FORMAT` to use the format
1410+ * from which the keymap was originally created. When used as an *interchange*
1411+ * format such as Wayland <code>[xkb_v1]</code>, the format should be explicit.
1412+ * @param flags Optional flags to control the serialization, or 0.
1413+ *
1414+ * @returns The keymap as a `NULL`-terminated string, or `NULL` if unsuccessful.
1415+ *
1416+ * The returned string may be fed back into `xkb_keymap_new_from_string()`
1417+ * to get the exact same keymap (possibly in another process, etc.).
1418+ *
1419+ * The returned string is *dynamically allocated* and should be freed by the
1420+ * caller.
1421+ *
1422+ * @since 1.12.0
1423+ *
1424+ * @sa `xkb_keymap_get_as_string()`
1425+ * @sa `xkb_keymap_new_from_string()`
1426+ * @memberof xkb_keymap
1427+ *
1428+ * [xkb_v1]: https://wayland.freedesktop.org/docs/html/apa.html#protocol-spec-wl_keyboard-enum-keymap_format
1429+ */
1430+XKB_EXPORT char *
1431+xkb_keymap_get_as_string2(struct xkb_keymap *keymap,
1432+ enum xkb_keymap_format format,
1433+ enum xkb_keymap_serialize_flags flags);
1434+
1435+/** @} */
1436+
1437+/**
1438+ * @defgroup components Keymap Components
1439+ * Enumeration of state components in a keymap.
1440+ *
1441+ * @{
1442+ */
1443+
1444+/**
1445+ * Get the minimum keycode in the keymap.
1446+ *
1447+ * @sa xkb_keycode_t
1448+ * @memberof xkb_keymap
1449+ * @since 0.3.1
1450+ */
1451+XKB_EXPORT xkb_keycode_t
1452+xkb_keymap_min_keycode(struct xkb_keymap *keymap);
1453+
1454+/**
1455+ * Get the maximum keycode in the keymap.
1456+ *
1457+ * @sa xkb_keycode_t
1458+ * @memberof xkb_keymap
1459+ * @since 0.3.1
1460+ */
1461+XKB_EXPORT xkb_keycode_t
1462+xkb_keymap_max_keycode(struct xkb_keymap *keymap);
1463+
1464+/**
1465+ * The iterator used by `xkb_keymap_key_for_each()`.
1466+ *
1467+ * @sa xkb_keymap_key_for_each
1468+ * @memberof xkb_keymap
1469+ * @since 0.3.1
1470+ */
1471+typedef void
1472+(*xkb_keymap_key_iter_t)(struct xkb_keymap *keymap, xkb_keycode_t key,
1473+ void *data);
1474+
1475+/**
1476+ * Run a specified function for every valid keycode in the keymap. If a
1477+ * keymap is sparse, this function may be called fewer than
1478+ * (max_keycode - min_keycode + 1) times.
1479+ *
1480+ * @sa xkb_keymap_min_keycode()
1481+ * @sa xkb_keymap_max_keycode()
1482+ * @sa xkb_keycode_t
1483+ * @memberof xkb_keymap
1484+ * @since 0.3.1
1485+ */
1486+XKB_EXPORT void
1487+xkb_keymap_key_for_each(struct xkb_keymap *keymap, xkb_keymap_key_iter_t iter,
1488+ void *data);
1489+
1490+/**
1491+ * Find the name of the key with the given keycode.
1492+ *
1493+ * This function always returns the canonical name of the key (see
1494+ * description in `xkb_keycode_t`).
1495+ *
1496+ * @returns The key name. If no key with this keycode exists,
1497+ * returns `NULL`.
1498+ *
1499+ * @sa xkb_keycode_t
1500+ * @memberof xkb_keymap
1501+ * @since 0.6.0
1502+ */
1503+XKB_EXPORT const char *
1504+xkb_keymap_key_get_name(struct xkb_keymap *keymap, xkb_keycode_t key);
1505+
1506+/**
1507+ * Find the keycode of the key with the given name.
1508+ *
1509+ * The name can be either a canonical name or an alias.
1510+ *
1511+ * @returns The keycode. If no key with this name exists,
1512+ * returns `::XKB_KEYCODE_INVALID`.
1513+ *
1514+ * @sa xkb_keycode_t
1515+ * @memberof xkb_keymap
1516+ * @since 0.6.0
1517+ */
1518+XKB_EXPORT xkb_keycode_t
1519+xkb_keymap_key_by_name(struct xkb_keymap *keymap, const char *name);
1520+
1521+/**
1522+ * Get the number of modifiers in the keymap.
1523+ *
1524+ * @sa xkb_mod_index_t
1525+ * @memberof xkb_keymap
1526+ */
1527+XKB_EXPORT xkb_mod_index_t
1528+xkb_keymap_num_mods(struct xkb_keymap *keymap);
1529+
1530+/**
1531+ * Get the name of a modifier by index.
1532+ *
1533+ * @returns The name. If the index is invalid, returns `NULL`.
1534+ *
1535+ * @sa xkb_mod_index_t
1536+ * @memberof xkb_keymap
1537+ */
1538+XKB_EXPORT const char *
1539+xkb_keymap_mod_get_name(struct xkb_keymap *keymap, xkb_mod_index_t idx);
1540+
1541+/**
1542+ * Get the index of a modifier by name.
1543+ *
1544+ * @returns The index. If no modifier with this name exists, returns
1545+ * `::XKB_MOD_INVALID`.
1546+ *
1547+ * @sa xkb_mod_index_t
1548+ * @memberof xkb_keymap
1549+ */
1550+XKB_EXPORT xkb_mod_index_t
1551+xkb_keymap_mod_get_index(struct xkb_keymap *keymap, const char *name);
1552+
1553+/**
1554+ * Get the encoding of a modifier by name.
1555+ *
1556+ * In X11 terminology it corresponds to the mapping to the *[real modifiers]*.
1557+ *
1558+ * @returns The encoding of a modifier. Note that it may be 0 if the name does
1559+ * not exist or if the modifier is not mapped.
1560+ *
1561+ * @since 1.10.0
1562+ * @sa `xkb_keymap_mod_get_mask2()`
1563+ * @memberof xkb_keymap
1564+ *
1565+ * [real modifiers]: @ref real-modifier-def
1566+ */
1567+XKB_EXPORT xkb_mod_mask_t
1568+xkb_keymap_mod_get_mask(struct xkb_keymap *keymap, const char *name);
1569+
1570+/**
1571+ * Get the encoding of a modifier by index.
1572+ *
1573+ * In X11 terminology it corresponds to the mapping to the *[real modifiers]*.
1574+ *
1575+ * @returns The encoding of a modifier. Note that it may be 0 if the modifier is
1576+ * not mapped.
1577+ *
1578+ * @since 1.11.0
1579+ * @sa `xkb_keymap_mod_get_mask()`
1580+ * @memberof xkb_keymap
1581+ *
1582+ * [real modifiers]: @ref real-modifier-def
1583+ */
1584+XKB_EXPORT xkb_mod_mask_t
1585+xkb_keymap_mod_get_mask2(struct xkb_keymap *keymap, xkb_mod_index_t idx);
1586+
1587+/**
1588+ * Get the number of layouts in the keymap.
1589+ *
1590+ * @sa `xkb_layout_index_t`
1591+ * @sa `xkb_rule_names`
1592+ * @sa `xkb_keymap_num_layouts_for_key()`
1593+ * @memberof xkb_keymap
1594+ */
1595+XKB_EXPORT xkb_layout_index_t
1596+xkb_keymap_num_layouts(struct xkb_keymap *keymap);
1597+
1598+/**
1599+ * Get the name of a layout by index.
1600+ *
1601+ * @returns The name. If the index is invalid, or the layout does not have
1602+ * a name, returns `NULL`.
1603+ *
1604+ * @sa xkb_layout_index_t
1605+ * For notes on layout names.
1606+ * @memberof xkb_keymap
1607+ */
1608+XKB_EXPORT const char *
1609+xkb_keymap_layout_get_name(struct xkb_keymap *keymap, xkb_layout_index_t idx);
1610+
1611+/**
1612+ * Get the index of a layout by name.
1613+ *
1614+ * @returns The index. If no layout exists with this name, returns
1615+ * `::XKB_LAYOUT_INVALID`. If more than one layout in the keymap has this name,
1616+ * returns the lowest index among them.
1617+ *
1618+ * @sa `xkb_layout_index_t` for notes on layout names.
1619+ * @memberof xkb_keymap
1620+ */
1621+XKB_EXPORT xkb_layout_index_t
1622+xkb_keymap_layout_get_index(struct xkb_keymap *keymap, const char *name);
1623+
1624+/**
1625+ * Get the number of LEDs in the keymap.
1626+ *
1627+ * @warning The range [ 0...`xkb_keymap_num_leds()` ) includes all of the LEDs
1628+ * in the keymap, but may also contain inactive LEDs. When iterating over
1629+ * this range, you need the handle this case when calling functions such as
1630+ * `xkb_keymap_led_get_name()` or `xkb_state::xkb_state_led_index_is_active()`.
1631+ *
1632+ * @sa xkb_led_index_t
1633+ * @memberof xkb_keymap
1634+ */
1635+XKB_EXPORT xkb_led_index_t
1636+xkb_keymap_num_leds(struct xkb_keymap *keymap);
1637+
1638+/**
1639+ * Get the name of a LED by index.
1640+ *
1641+ * @returns The name. If the index is invalid, returns `NULL`.
1642+ *
1643+ * @memberof xkb_keymap
1644+ */
1645+XKB_EXPORT const char *
1646+xkb_keymap_led_get_name(struct xkb_keymap *keymap, xkb_led_index_t idx);
1647+
1648+/**
1649+ * Get the index of a LED by name.
1650+ *
1651+ * @returns The index. If no LED with this name exists, returns
1652+ * `::XKB_LED_INVALID`.
1653+ *
1654+ * @memberof xkb_keymap
1655+ */
1656+XKB_EXPORT xkb_led_index_t
1657+xkb_keymap_led_get_index(struct xkb_keymap *keymap, const char *name);
1658+
1659+/**
1660+ * Get the number of layouts for a specific key.
1661+ *
1662+ * This number can be different from `xkb_keymap_num_layouts()`, but is always
1663+ * smaller. It is the appropriate value to use when iterating over the
1664+ * layouts of a key.
1665+ *
1666+ * @sa xkb_layout_index_t
1667+ * @memberof xkb_keymap
1668+ */
1669+XKB_EXPORT xkb_layout_index_t
1670+xkb_keymap_num_layouts_for_key(struct xkb_keymap *keymap, xkb_keycode_t key);
1671+
1672+/**
1673+ * Get the number of shift levels for a specific key and layout.
1674+ *
1675+ * If @c layout is out of range for this key (that is, larger or equal to
1676+ * the value returned by `xkb_keymap_num_layouts_for_key()`), it is brought
1677+ * back into range in a manner consistent with
1678+ * `xkb_state::xkb_state_key_get_layout()`.
1679+ *
1680+ * @sa xkb_level_index_t
1681+ * @memberof xkb_keymap
1682+ */
1683+XKB_EXPORT xkb_level_index_t
1684+xkb_keymap_num_levels_for_key(struct xkb_keymap *keymap, xkb_keycode_t key,
1685+ xkb_layout_index_t layout);
1686+
1687+/**
1688+ * Retrieves every possible modifier mask that produces the specified
1689+ * shift level for a specific key and layout.
1690+ *
1691+ * This API is useful for inverse key transformation; i.e. finding out
1692+ * which modifiers need to be active in order to be able to type the
1693+ * keysym(s) corresponding to the specific key code, layout and level.
1694+ *
1695+ * @warning It returns only up to masks_size modifier masks. If the
1696+ * buffer passed is too small, some of the possible modifier combinations
1697+ * will not be returned.
1698+ *
1699+ * @param[in] keymap The keymap.
1700+ * @param[in] key The keycode of the key.
1701+ * @param[in] layout The layout for which to get modifiers.
1702+ * @param[in] level The shift level in the layout for which to get the
1703+ * modifiers. This should be smaller than:
1704+ * @code xkb_keymap_num_levels_for_key(keymap, key) @endcode
1705+ * @param[out] masks_out A buffer in which the requested masks should be
1706+ * stored.
1707+ * @param[out] masks_size The number of elements in the buffer pointed to by
1708+ * masks_out.
1709+ *
1710+ * If @c layout is out of range for this key (that is, larger or equal to
1711+ * the value returned by `xkb_keymap_num_layouts_for_key()`), it is brought
1712+ * back into range in a manner consistent with
1713+ * `xkb_state::xkb_state_key_get_layout()`.
1714+ *
1715+ * @returns The number of modifier masks stored in the masks_out array.
1716+ * If the key is not in the keymap or if the specified shift level cannot
1717+ * be reached it returns 0 and does not modify the masks_out buffer.
1718+ *
1719+ * @sa xkb_level_index_t
1720+ * @sa xkb_mod_mask_t
1721+ * @memberof xkb_keymap
1722+ * @since 1.0.0
1723+ */
1724+XKB_EXPORT size_t
1725+xkb_keymap_key_get_mods_for_level(struct xkb_keymap *keymap,
1726+ xkb_keycode_t key,
1727+ xkb_layout_index_t layout,
1728+ xkb_level_index_t level,
1729+ xkb_mod_mask_t *masks_out,
1730+ size_t masks_size);
1731+
1732+/**
1733+ * Get the keysyms obtained from pressing a key in a given layout and
1734+ * shift level.
1735+ *
1736+ * This function is like `xkb_state::xkb_state_key_get_syms()`, only the layout
1737+ * and shift level are not derived from the keyboard state but are instead
1738+ * specified explicitly.
1739+ *
1740+ * @param[in] keymap The keymap.
1741+ * @param[in] key The keycode of the key.
1742+ * @param[in] layout The layout for which to get the keysyms.
1743+ * @param[in] level The shift level in the layout for which to get the
1744+ * keysyms. This should be smaller than:
1745+ * @code xkb_keymap_num_levels_for_key(keymap, key) @endcode
1746+ * @param[out] syms_out An immutable array of keysyms corresponding to the
1747+ * key in the given layout and shift level.
1748+ *
1749+ * If @c layout is out of range for this key (that is, larger or equal to
1750+ * the value returned by `xkb_keymap_num_layouts_for_key()`), it is brought
1751+ * back into range in a manner consistent with
1752+ * `xkb_state::xkb_state_key_get_layout()`.
1753+ *
1754+ * @returns The number of keysyms in the syms_out array. If no keysyms
1755+ * are produced by the key in the given layout and shift level, returns 0
1756+ * and sets @p syms_out to `NULL`.
1757+ *
1758+ * @sa `xkb_state::xkb_state_key_get_syms()`
1759+ * @memberof xkb_keymap
1760+ */
1761+XKB_EXPORT int
1762+xkb_keymap_key_get_syms_by_level(struct xkb_keymap *keymap,
1763+ xkb_keycode_t key,
1764+ xkb_layout_index_t layout,
1765+ xkb_level_index_t level,
1766+ const xkb_keysym_t **syms_out);
1767+
1768+/**
1769+ * Determine whether a key should repeat or not.
1770+ *
1771+ * A keymap may specify different repeat behaviors for different keys.
1772+ * Most keys should generally exhibit repeat behavior; for example, holding
1773+ * the `a` key down in a text editor should normally insert a single ‘a’
1774+ * character every few milliseconds, until the key is released. However,
1775+ * there are keys which should not or do not need to be repeated. For
1776+ * example, repeating modifier keys such as Left/Right Shift or Caps Lock
1777+ * is not generally useful or desired.
1778+ *
1779+ * @returns 1 if the key should repeat, 0 otherwise.
1780+ *
1781+ * @memberof xkb_keymap
1782+ */
1783+XKB_EXPORT int
1784+xkb_keymap_key_repeats(struct xkb_keymap *keymap, xkb_keycode_t key);
1785+
1786+/** @} */
1787+
1788+/**
1789+ * @defgroup state Keyboard State
1790+ * Creating, destroying and manipulating keyboard state objects.
1791+ *
1792+ * @{
1793+ */
1794+
1795+/**
1796+ * Create a new keyboard state object.
1797+ *
1798+ * @param keymap The keymap which the state will use.
1799+ *
1800+ * @returns A new keyboard state object, or `NULL` on failure.
1801+ *
1802+ * @memberof xkb_state
1803+ */
1804+XKB_EXPORT struct xkb_state *
1805+xkb_state_new(struct xkb_keymap *keymap);
1806+
1807+/**
1808+ * Take a new reference on a keyboard state object.
1809+ *
1810+ * @returns The passed in object.
1811+ *
1812+ * @memberof xkb_state
1813+ */
1814+XKB_EXPORT struct xkb_state *
1815+xkb_state_ref(struct xkb_state *state);
1816+
1817+/**
1818+ * Release a reference on a keyboard state object, and possibly free it.
1819+ *
1820+ * @param state The state. If it is `NULL`, this function does nothing.
1821+ *
1822+ * @memberof xkb_state
1823+ */
1824+XKB_EXPORT void
1825+xkb_state_unref(struct xkb_state *state);
1826+
1827+/**
1828+ * Get the keymap which a keyboard state object is using.
1829+ *
1830+ * @returns The keymap which was passed to `xkb_state_new()` when creating
1831+ * this state object.
1832+ *
1833+ * This function does not take a new reference on the keymap; you must
1834+ * explicitly reference it yourself if you plan to use it beyond the
1835+ * lifetime of the state.
1836+ *
1837+ * @memberof xkb_state
1838+ */
1839+XKB_EXPORT struct xkb_keymap *
1840+xkb_state_get_keymap(struct xkb_state *state);
1841+
1842+/**
1843+ * @page server-client-state Server State and Client State
1844+ * @parblock
1845+ *
1846+ * The xkb_state API is used by two distinct actors in most window-system
1847+ * architectures:
1848+ *
1849+ * 1. A *server* - for example, a Wayland compositor, an X11 server, an evdev
1850+ * listener.
1851+ *
1852+ * Servers maintain the XKB state for a device according to input events from
1853+ * the device, such as key presses and releases, and out-of-band events from
1854+ * the user, like UI layout switchers.
1855+ *
1856+ * 2. A *client* - for example, a Wayland client, an X11 client.
1857+ *
1858+ * Clients do not listen to input from the device; instead, whenever the
1859+ * server state changes, the server serializes the state and notifies the
1860+ * clients that the state has changed; the clients then update the state
1861+ * from the serialization.
1862+ *
1863+ * Some entry points in the xkb_state API are only meant for servers and some
1864+ * are only meant for clients, and the two should generally not be mixed.
1865+ *
1866+ * @endparblock
1867+ */
1868+
1869+/** Specifies the direction of the key (press / release). */
1870+enum xkb_key_direction {
1871+ XKB_KEY_UP, /**< The key was released. */
1872+ XKB_KEY_DOWN /**< The key was pressed. */
1873+};
1874+
1875+/**
1876+ * Modifier and layout types for state objects. This enum is bitmaskable,
1877+ * e.g. (`::XKB_STATE_MODS_DEPRESSED` | `::XKB_STATE_MODS_LATCHED`) is valid to
1878+ * exclude locked modifiers.
1879+ *
1880+ * In XKB, the `DEPRESSED` components are also known as *base*.
1881+ */
1882+enum xkb_state_component {
1883+ /** Depressed modifiers, i.e. a key is physically holding them. */
1884+ XKB_STATE_MODS_DEPRESSED = (1 << 0),
1885+ /** Latched modifiers, i.e. will be unset after the next non-modifier
1886+ * key press. */
1887+ XKB_STATE_MODS_LATCHED = (1 << 1),
1888+ /** Locked modifiers, i.e. will be unset after the key provoking the
1889+ * lock has been pressed again. */
1890+ XKB_STATE_MODS_LOCKED = (1 << 2),
1891+ /** Effective modifiers, i.e. currently active and affect key
1892+ * processing (derived from the other state components).
1893+ * Use this unless you explicitly care how the state came about. */
1894+ XKB_STATE_MODS_EFFECTIVE = (1 << 3),
1895+ /** Depressed layout, i.e. a key is physically holding it. */
1896+ XKB_STATE_LAYOUT_DEPRESSED = (1 << 4),
1897+ /** Latched layout, i.e. will be unset after the next non-modifier
1898+ * key press. */
1899+ XKB_STATE_LAYOUT_LATCHED = (1 << 5),
1900+ /** Locked layout, i.e. will be unset after the key provoking the lock
1901+ * has been pressed again. */
1902+ XKB_STATE_LAYOUT_LOCKED = (1 << 6),
1903+ /** Effective layout, i.e. currently active and affects key processing
1904+ * (derived from the other state components).
1905+ * Use this unless you explicitly care how the state came about. */
1906+ XKB_STATE_LAYOUT_EFFECTIVE = (1 << 7),
1907+ /** LEDs (derived from the other state components). */
1908+ XKB_STATE_LEDS = (1 << 8)
1909+};
1910+
1911+/**
1912+ * Update the keyboard state to reflect a given key being pressed or
1913+ * released.
1914+ *
1915+ * This entry point is intended for *server* applications and should not be used
1916+ * by *client* applications; see @ref server-client-state for details.
1917+ *
1918+ * A series of calls to this function should be consistent; that is, a call
1919+ * with `::XKB_KEY_DOWN` for a key should be matched by an `::XKB_KEY_UP`; if a
1920+ * key is pressed twice, it should be released twice; etc. Otherwise (e.g. due
1921+ * to missed input events), situations like “stuck modifiers” may occur.
1922+ *
1923+ * This function is often used in conjunction with the function
1924+ * `xkb_state_key_get_syms()` (or `xkb_state_key_get_one_sym()`), for example,
1925+ * when handling a key event. In this case, you should prefer to get the
1926+ * keysyms *before* updating the key, such that the keysyms reported for
1927+ * the key event are not affected by the event itself. This is the
1928+ * conventional behavior.
1929+ *
1930+ * @returns A mask of state components that have changed as a result of
1931+ * the update. If nothing in the state has changed, returns 0.
1932+ *
1933+ * @memberof xkb_state
1934+ *
1935+ * @sa `xkb_state_update_mask()`
1936+ */
1937+XKB_EXPORT enum xkb_state_component
1938+xkb_state_update_key(struct xkb_state *state, xkb_keycode_t key,
1939+ enum xkb_key_direction direction);
1940+
1941+/**
1942+ * Update the keyboard state to change the latched and locked state of
1943+ * the modifiers and layout.
1944+ *
1945+ * This entry point is intended for *server* applications and should not be used
1946+ * by *client* applications; see @ref server-client-state for details.
1947+ *
1948+ * Use this function to update the latched and locked state according to
1949+ * “out of band” (non-device) inputs, such as UI layout switchers.
1950+ *
1951+ * @par Layout out of range
1952+ * @parblock
1953+ *
1954+ * If the effective layout, after taking into account the depressed, latched and
1955+ * locked layout, is out of range (negative or greater than the maximum layout),
1956+ * it is brought into range. Currently, the layout is wrapped using integer
1957+ * modulus (with negative values wrapping from the end). The wrapping behavior
1958+ * may be made configurable in the future.
1959+ *
1960+ * @endparblock
1961+ *
1962+ * @param state The keyboard state object.
1963+ * @param affect_latched_mods
1964+ * @param latched_mods
1965+ * Modifiers to set as latched or unlatched. Only modifiers in
1966+ * @p affect_latched_mods are considered.
1967+ * @param affect_latched_layout
1968+ * @param latched_layout
1969+ * Layout to latch. Only considered if @p affect_latched_layout is true.
1970+ * Maybe be out of range (including negative) -- see note above.
1971+ * @param affect_locked_mods
1972+ * @param locked_mods
1973+ * Modifiers to set as locked or unlocked. Only modifiers in
1974+ * @p affect_locked_mods are considered.
1975+ * @param affect_locked_layout
1976+ * @param locked_layout
1977+ * Layout to lock. Only considered if @p affect_locked_layout is true.
1978+ * Maybe be out of range (including negative) -- see note above.
1979+ *
1980+ * @returns A mask of state components that have changed as a result of
1981+ * the update. If nothing in the state has changed, returns 0.
1982+ *
1983+ * @memberof xkb_state
1984+ *
1985+ * @sa xkb_state_update_mask()
1986+ */
1987+XKB_EXPORT enum xkb_state_component
1988+xkb_state_update_latched_locked(struct xkb_state *state,
1989+ xkb_mod_mask_t affect_latched_mods,
1990+ xkb_mod_mask_t latched_mods,
1991+ bool affect_latched_layout,
1992+ int32_t latched_layout,
1993+ xkb_mod_mask_t affect_locked_mods,
1994+ xkb_mod_mask_t locked_mods,
1995+ bool affect_locked_layout,
1996+ int32_t locked_layout);
1997+
1998+/**
1999+ * Update a keyboard state from a set of explicit masks.
2000+ *
2001+ * This entry point is intended for *client* applications; see @ref
2002+ * server-client-state for details. *Server* applications should use
2003+ * `xkb_state_update_key()` instead.
2004+ *
2005+ * All parameters must always be passed, or the resulting state may be
2006+ * incoherent.
2007+ *
2008+ * @warning The serialization is lossy and will not survive round trips; it must
2009+ * only be used to feed client state objects, and must not be used to update the
2010+ * server state.
2011+ *
2012+ * @returns A mask of state components that have changed as a result of
2013+ * the update. If nothing in the state has changed, returns 0.
2014+ *
2015+ * @memberof xkb_state
2016+ *
2017+ * @sa `xkb_state_component`
2018+ * @sa `xkb_state_update_key()`
2019+ */
2020+XKB_EXPORT enum xkb_state_component
2021+xkb_state_update_mask(struct xkb_state *state,
2022+ xkb_mod_mask_t depressed_mods,
2023+ xkb_mod_mask_t latched_mods,
2024+ xkb_mod_mask_t locked_mods,
2025+ xkb_layout_index_t depressed_layout,
2026+ xkb_layout_index_t latched_layout,
2027+ xkb_layout_index_t locked_layout);
2028+
2029+/**
2030+ * Get the keysyms obtained from pressing a particular key in a given
2031+ * keyboard state.
2032+ *
2033+ * Get the keysyms for a key according to the current active layout,
2034+ * modifiers and shift level for the key, as determined by a keyboard
2035+ * state.
2036+ *
2037+ * @param[in] state The keyboard state object.
2038+ * @param[in] key The keycode of the key.
2039+ * @param[out] syms_out An immutable array of keysyms corresponding the
2040+ * key in the given keyboard state.
2041+ *
2042+ * As an extension to XKB, this function can return more than one keysym.
2043+ * If you do not want to handle this case, you can use
2044+ * `xkb_state_key_get_one_sym()` for a simpler interface.
2045+ *
2046+ * @returns The number of keysyms in the syms_out array. If no keysyms
2047+ * are produced by the key in the given keyboard state, returns 0 and sets
2048+ * syms_out to `NULL`.
2049+ *
2050+ * This function performs Capitalization @ref keysym-transformations.
2051+ *
2052+ * @memberof xkb_state
2053+ *
2054+ * @since 1.9.0 This function now performs @ref keysym-transformations.
2055+ */
2056+XKB_EXPORT int
2057+xkb_state_key_get_syms(struct xkb_state *state, xkb_keycode_t key,
2058+ const xkb_keysym_t **syms_out);
2059+
2060+/**
2061+ * Get the Unicode/UTF-8 string obtained from pressing a particular key
2062+ * in a given keyboard state.
2063+ *
2064+ * @param[in] state The keyboard state object.
2065+ * @param[in] key The keycode of the key.
2066+ * @param[out] buffer A buffer to write the string into.
2067+ * @param[in] size Size of the buffer.
2068+ *
2069+ * @warning If the buffer passed is too small, the string is truncated
2070+ * (though still `NULL`-terminated).
2071+ *
2072+ * @returns The number of bytes required for the string, excluding the
2073+ * `NULL` byte. If there is nothing to write, returns 0.
2074+ *
2075+ * You may check if truncation has occurred by comparing the return value
2076+ * with the size of @p buffer, similarly to the `snprintf(3)` function.
2077+ * You may safely pass `NULL` and 0 to @p buffer and @p size to find the
2078+ * required size (without the `NULL`-byte).
2079+ *
2080+ * This function performs Capitalization and Control @ref
2081+ * keysym-transformations.
2082+ *
2083+ * @memberof xkb_state
2084+ * @since 0.4.1
2085+ */
2086+XKB_EXPORT int
2087+xkb_state_key_get_utf8(struct xkb_state *state, xkb_keycode_t key,
2088+ char *buffer, size_t size);
2089+
2090+/**
2091+ * Get the Unicode/UTF-32 codepoint obtained from pressing a particular
2092+ * key in a a given keyboard state.
2093+ *
2094+ * @returns The UTF-32 representation for the key, if it consists of only
2095+ * a single codepoint. Otherwise, returns 0.
2096+ *
2097+ * This function performs Capitalization and Control @ref
2098+ * keysym-transformations.
2099+ *
2100+ * @memberof xkb_state
2101+ * @since 0.4.1
2102+ */
2103+XKB_EXPORT uint32_t
2104+xkb_state_key_get_utf32(struct xkb_state *state, xkb_keycode_t key);
2105+
2106+/**
2107+ * Get the single keysym obtained from pressing a particular key in a
2108+ * given keyboard state.
2109+ *
2110+ * This function is similar to `xkb_state_key_get_syms()`, but intended
2111+ * for users which cannot or do not want to handle the case where
2112+ * multiple keysyms are returned (in which case this function is
2113+ * preferred).
2114+ *
2115+ * @returns The keysym. If the key does not have exactly one keysym,
2116+ * returns `XKB_KEY_NoSymbol`.
2117+ *
2118+ * This function performs Capitalization @ref keysym-transformations.
2119+ *
2120+ * @sa xkb_state_key_get_syms()
2121+ * @memberof xkb_state
2122+ */
2123+XKB_EXPORT xkb_keysym_t
2124+xkb_state_key_get_one_sym(struct xkb_state *state, xkb_keycode_t key);
2125+
2126+/**
2127+ * Get the effective layout index for a key in a given keyboard state.
2128+ *
2129+ * @returns The layout index for the key in the given keyboard state. If
2130+ * the given keycode is invalid, or if the key is not included in any
2131+ * layout at all, returns `::XKB_LAYOUT_INVALID`.
2132+ *
2133+ * @invariant If the returned layout is valid, the following always holds:
2134+ * @code
2135+ * xkb_state_key_get_layout(state, key) < xkb_keymap_num_layouts_for_key(keymap, key)
2136+ * @endcode
2137+ *
2138+ * @memberof xkb_state
2139+ */
2140+XKB_EXPORT xkb_layout_index_t
2141+xkb_state_key_get_layout(struct xkb_state *state, xkb_keycode_t key);
2142+
2143+/**
2144+ * Get the effective shift level for a key in a given keyboard state and
2145+ * layout.
2146+ *
2147+ * @param state The keyboard state.
2148+ * @param key The keycode of the key.
2149+ * @param layout The layout for which to get the shift level. This must be
2150+ * smaller than:
2151+ * @code xkb_keymap_num_layouts_for_key(keymap, key) @endcode
2152+ * usually it would be:
2153+ * @code xkb_state_key_get_layout(state, key) @endcode
2154+ *
2155+ * @return The shift level index. If the key or layout are invalid,
2156+ * returns `::XKB_LEVEL_INVALID`.
2157+ *
2158+ * @invariant If the returned level is valid, the following always holds:
2159+ * @code
2160+ * xkb_state_key_get_level(state, key, layout) < xkb_keymap_num_levels_for_key(keymap, key, layout)
2161+ * @endcode
2162+ *
2163+ * @memberof xkb_state
2164+ */
2165+XKB_EXPORT xkb_level_index_t
2166+xkb_state_key_get_level(struct xkb_state *state, xkb_keycode_t key,
2167+ xkb_layout_index_t layout);
2168+
2169+/**
2170+ * Match flags for `xkb_state::xkb_state_mod_indices_are_active()` and
2171+ * `xkb_state::xkb_state_mod_names_are_active()`, specifying the conditions for a
2172+ * successful match. `::XKB_STATE_MATCH_NON_EXCLUSIVE` is bitmaskable with
2173+ * the other modes.
2174+ */
2175+enum xkb_state_match {
2176+ /** Returns true if any of the modifiers are active. */
2177+ XKB_STATE_MATCH_ANY = (1 << 0),
2178+ /** Returns true if all of the modifiers are active. */
2179+ XKB_STATE_MATCH_ALL = (1 << 1),
2180+ /** Makes matching non-exclusive, i.e. will not return false if a
2181+ * modifier not specified in the arguments is active. */
2182+ XKB_STATE_MATCH_NON_EXCLUSIVE = (1 << 16)
2183+};
2184+
2185+/**
2186+ * The counterpart to `xkb_state::xkb_state_update_mask()` for modifiers, to be
2187+ * used on the server side of serialization.
2188+ *
2189+ * This entry point is intended for *server* applications; see @ref
2190+ * server-client-state for details. *Client* applications should use the
2191+ * `xkb_state_mod_*_is_active` API.
2192+ *
2193+ * @param state The keyboard state.
2194+ * @param components A mask of the modifier state components to serialize.
2195+ * State components other than `XKB_STATE_MODS_*` are ignored.
2196+ * If `::XKB_STATE_MODS_EFFECTIVE` is included, all other state components are
2197+ * ignored.
2198+ *
2199+ * @returns A `xkb_mod_mask_t` representing the given components of the
2200+ * modifier state.
2201+ *
2202+ * @memberof xkb_state
2203+ */
2204+XKB_EXPORT xkb_mod_mask_t
2205+xkb_state_serialize_mods(struct xkb_state *state,
2206+ enum xkb_state_component components);
2207+
2208+/**
2209+ * The counterpart to `xkb_state::xkb_state_update_mask()` for layouts, to be
2210+ * used on the server side of serialization.
2211+ *
2212+ * This entry point is intended for *server* applications; see @ref
2213+ * server-client-state for details. *Client* applications should use the
2214+ * xkb_state_layout_*_is_active API.
2215+ *
2216+ * @param state The keyboard state.
2217+ * @param components A mask of the layout state components to serialize.
2218+ * State components other than `XKB_STATE_LAYOUT_*` are ignored.
2219+ * If `::XKB_STATE_LAYOUT_EFFECTIVE` is included, all other state components are
2220+ * ignored.
2221+ *
2222+ * @returns A layout index representing the given components of the
2223+ * layout state.
2224+ *
2225+ * @memberof xkb_state
2226+ */
2227+XKB_EXPORT xkb_layout_index_t
2228+xkb_state_serialize_layout(struct xkb_state *state,
2229+ enum xkb_state_component components);
2230+
2231+/**
2232+ * Test whether a modifier is active in a given keyboard state by name.
2233+ *
2234+ * @warning For [virtual modifiers], this function may *overmatch* in case
2235+ * there are virtual modifiers with overlapping mappings to [real modifiers].
2236+ *
2237+ * @returns 1 if the modifier is active, 0 if it is not. If the modifier
2238+ * name does not exist in the keymap, returns -1.
2239+ *
2240+ * @memberof xkb_state
2241+ *
2242+ * @since 0.1.0: Works only with *real* modifiers
2243+ * @since 1.8.0: Works also with *virtual* modifiers
2244+ *
2245+ * [virtual modifiers]: @ref virtual-modifier-def
2246+ * [real modifiers]: @ref real-modifier-def
2247+ */
2248+XKB_EXPORT int
2249+xkb_state_mod_name_is_active(struct xkb_state *state, const char *name,
2250+ enum xkb_state_component type);
2251+
2252+/**
2253+ * Test whether a set of modifiers are active in a given keyboard state by
2254+ * name.
2255+ *
2256+ * @warning For [virtual modifiers], this function may *overmatch* in case
2257+ * there are virtual modifiers with overlapping mappings to [real modifiers].
2258+ *
2259+ * @param state The keyboard state.
2260+ * @param type The component of the state against which to match the
2261+ * given modifiers.
2262+ * @param match The manner by which to match the state against the
2263+ * given modifiers.
2264+ * @param ... The set of of modifier names to test, terminated by a NULL
2265+ * argument (sentinel).
2266+ *
2267+ * @returns 1 if the modifiers are active, 0 if they are not. If any of
2268+ * the modifier names do not exist in the keymap, returns -1.
2269+ *
2270+ * @memberof xkb_state
2271+ *
2272+ * @since 0.1.0: Works only with *real* modifiers
2273+ * @since 1.8.0: Works also with *virtual* modifiers
2274+ *
2275+ * [virtual modifiers]: @ref virtual-modifier-def
2276+ * [real modifiers]: @ref real-modifier-def
2277+ */
2278+XKB_EXPORT int
2279+xkb_state_mod_names_are_active(struct xkb_state *state,
2280+ enum xkb_state_component type,
2281+ enum xkb_state_match match,
2282+ ...);
2283+
2284+/**
2285+ * Test whether a modifier is active in a given keyboard state by index.
2286+ *
2287+ * @warning For [virtual modifiers], this function may *overmatch* in case
2288+ * there are virtual modifiers with overlapping mappings to [real modifiers].
2289+ *
2290+ * @returns 1 if the modifier is active, 0 if it is not. If the modifier
2291+ * index is invalid in the keymap, returns -1.
2292+ *
2293+ * @memberof xkb_state
2294+ *
2295+ * @since 0.1.0: Works only with *real* modifiers
2296+ * @since 1.8.0: Works also with *virtual* modifiers
2297+ *
2298+ * [virtual modifiers]: @ref virtual-modifier-def
2299+ * [real modifiers]: @ref real-modifier-def
2300+ */
2301+XKB_EXPORT int
2302+xkb_state_mod_index_is_active(struct xkb_state *state, xkb_mod_index_t idx,
2303+ enum xkb_state_component type);
2304+
2305+/**
2306+ * Test whether a set of modifiers are active in a given keyboard state by
2307+ * index.
2308+ *
2309+ * @warning For [virtual modifiers], this function may *overmatch* in case
2310+ * there are virtual modifiers with overlapping mappings to [real modifiers].
2311+ *
2312+ * @param state The keyboard state.
2313+ * @param type The component of the state against which to match the
2314+ * given modifiers.
2315+ * @param match The manner by which to match the state against the
2316+ * given modifiers.
2317+ * @param ... The set of of modifier indices to test, terminated by a
2318+ * `::XKB_MOD_INVALID` argument (sentinel).
2319+ *
2320+ * @returns 1 if the modifiers are active, 0 if they are not. If any of
2321+ * the modifier indices are invalid in the keymap, returns -1.
2322+ *
2323+ * @memberof xkb_state
2324+ *
2325+ * @since 0.1.0: Works only with *real* modifiers
2326+ * @since 1.8.0: Works also with *virtual* modifiers
2327+ *
2328+ * [virtual modifiers]: @ref virtual-modifier-def
2329+ * [real modifiers]: @ref real-modifier-def
2330+ */
2331+XKB_EXPORT int
2332+xkb_state_mod_indices_are_active(struct xkb_state *state,
2333+ enum xkb_state_component type,
2334+ enum xkb_state_match match,
2335+ ...);
2336+
2337+/**
2338+ * @page consumed-modifiers Consumed Modifiers
2339+ * @parblock
2340+ *
2341+ * Some functions, like `xkb_state::xkb_state_key_get_syms()`, look at the state
2342+ * of the modifiers in the keymap and derive from it the correct shift level
2343+ * to use for the key. For example, in a US layout, pressing the key
2344+ * labeled `<A>` while the Shift modifier is active, generates the keysym
2345+ * `A`. In this case, the Shift modifier is said to be *consumed*.
2346+ * However, the Num Lock modifier does not affect this translation at all,
2347+ * even if it is active, so it is not consumed by this translation.
2348+ *
2349+ * It may be desirable for some application to not reuse consumed modifiers
2350+ * for further processing, e.g. for hotkeys or keyboard shortcuts. To
2351+ * understand why, consider some requirements from a standard shortcut
2352+ * mechanism, and how they are implemented:
2353+ *
2354+ * 1. The shortcut’s modifiers must match exactly to the state. For
2355+ * example, it is possible to bind separate actions to `<Alt><Tab>`
2356+ * and to `<Alt><Shift><Tab>`. Further, if only `<Alt><Tab>` is
2357+ * bound to an action, pressing `<Alt><Shift><Tab>` should not
2358+ * trigger the shortcut.
2359+ * Effectively, this means that the modifiers are compared using the
2360+ * equality operator (`==`).
2361+ *
2362+ * 2. Only relevant modifiers are considered for the matching. For example,
2363+ * Caps Lock and Num Lock should not generally affect the matching, e.g.
2364+ * when matching `<Alt><Tab>` against the state, it does not matter
2365+ * whether Num Lock is active or not. These relevant, or *significant*,
2366+ * modifiers usually include Alt, Control, Shift, Super and similar.
2367+ * Effectively, this means that non-significant modifiers are masked out,
2368+ * before doing the comparison as described above.
2369+ *
2370+ * 3. The matching must be independent of the layout/keymap. For example,
2371+ * the `<Plus>` (+) symbol is found on the first level on some layouts,
2372+ * but requires holding Shift on others. If you simply bind the action
2373+ * to the `<Plus>` keysym, it would work for the unshifted kind, but
2374+ * not for the others, because the match against Shift would fail. If
2375+ * you bind the action to `<Shift><Plus>`, only the shifted kind would
2376+ * work. So what is needed is to recognize that Shift is used up in the
2377+ * translation of the keysym itself, and therefore should not be included
2378+ * in the matching.
2379+ * Effectively, this means that consumed modifiers (Shift in this example)
2380+ * are masked out as well, before doing the comparison.
2381+ *
2382+ * In summary, this is approximately how the matching would be performed:
2383+ *
2384+ * ```c
2385+ * (keysym == shortcut_keysym) &&
2386+ * ((state_mods & ~consumed_mods & significant_mods) == shortcut_mods)
2387+ * ```
2388+ *
2389+ * @c state_mods are the modifiers reported by
2390+ * `xkb_state::xkb_state_mod_index_is_active()` and similar functions.
2391+ * @c consumed_mods are the modifiers reported by
2392+ * `xkb_state::xkb_state_mod_index_is_consumed()` and similar functions.
2393+ * @c significant_mods are decided upon by the application/toolkit/user;
2394+ * it is up to them to decide whether these are configurable or hard-coded.
2395+ *
2396+ * @endparblock
2397+ */
2398+
2399+/**
2400+ * Consumed modifiers mode.
2401+ *
2402+ * There are several possible methods for deciding which modifiers are
2403+ * consumed and which are not, each applicable for different systems or
2404+ * situations. The mode selects the method to use.
2405+ *
2406+ * Keep in mind that in all methods, the keymap may decide to *preserve*
2407+ * a modifier, meaning it is not reported as consumed even if it would
2408+ * have otherwise.
2409+ */
2410+enum xkb_consumed_mode {
2411+ /**
2412+ * This is the mode defined in the XKB specification and used by libX11.
2413+ *
2414+ * A modifier is consumed if and only if it *may affect* key translation.
2415+ *
2416+ * For example, if `Control+Alt+<Backspace>` produces some assigned keysym,
2417+ * then when pressing just `<Backspace>`, `Control` and `Alt` are consumed,
2418+ * even though they are not active, since if they *were* active they would
2419+ * have affected key translation.
2420+ */
2421+ XKB_CONSUMED_MODE_XKB,
2422+ /**
2423+ * This is the mode used by the GTK+ toolkit.
2424+ *
2425+ * The mode consists of the following two independent heuristics:
2426+ *
2427+ * - The currently active set of modifiers, excluding modifiers which do
2428+ * not affect the key (as described for @ref XKB_CONSUMED_MODE_XKB), are
2429+ * considered consumed, if the keysyms produced when all of them are
2430+ * active are different from the keysyms produced when no modifiers are
2431+ * active.
2432+ *
2433+ * - A single modifier is considered consumed if the keysyms produced for
2434+ * the key when it is the only active modifier are different from the
2435+ * keysyms produced when no modifiers are active.
2436+ */
2437+ XKB_CONSUMED_MODE_GTK
2438+};
2439+
2440+/**
2441+ * Get the mask of modifiers consumed by translating a given key.
2442+ *
2443+ * @param state The keyboard state.
2444+ * @param key The keycode of the key.
2445+ * @param mode The consumed modifiers mode to use; see enum description.
2446+ *
2447+ * @returns a mask of the consumed [real modifiers] modifiers.
2448+ *
2449+ * @memberof xkb_state
2450+ * @since 0.7.0
2451+ *
2452+ * [real modifiers]: @ref real-modifier-def
2453+ */
2454+XKB_EXPORT xkb_mod_mask_t
2455+xkb_state_key_get_consumed_mods2(struct xkb_state *state, xkb_keycode_t key,
2456+ enum xkb_consumed_mode mode);
2457+
2458+/**
2459+ * Same as `xkb_state_key_get_consumed_mods2()` with mode `::XKB_CONSUMED_MODE_XKB`.
2460+ *
2461+ * @memberof xkb_state
2462+ * @since 0.4.1
2463+ */
2464+XKB_EXPORT xkb_mod_mask_t
2465+xkb_state_key_get_consumed_mods(struct xkb_state *state, xkb_keycode_t key);
2466+
2467+/**
2468+ * Test whether a modifier is consumed by keyboard state translation for
2469+ * a key.
2470+ *
2471+ * @warning For [virtual modifiers], this function may *overmatch* in case
2472+ * there are virtual modifiers with overlapping mappings to [real modifiers].
2473+ *
2474+ * @param state The keyboard state.
2475+ * @param key The keycode of the key.
2476+ * @param idx The index of the modifier to check.
2477+ * @param mode The consumed modifiers mode to use; see enum description.
2478+ *
2479+ * @returns 1 if the modifier is consumed, 0 if it is not. If the modifier
2480+ * index is not valid in the keymap, returns -1.
2481+ *
2482+ * @sa xkb_state_mod_mask_remove_consumed()
2483+ * @sa xkb_state_key_get_consumed_mods()
2484+ * @memberof xkb_state
2485+ * @since 0.7.0: Works only with *real* modifiers
2486+ * @since 1.8.0: Works also with *virtual* modifiers
2487+ *
2488+ * [virtual modifiers]: @ref virtual-modifier-def
2489+ * [real modifiers]: @ref real-modifier-def
2490+ */
2491+XKB_EXPORT int
2492+xkb_state_mod_index_is_consumed2(struct xkb_state *state,
2493+ xkb_keycode_t key,
2494+ xkb_mod_index_t idx,
2495+ enum xkb_consumed_mode mode);
2496+
2497+/**
2498+ * Same as `xkb_state_mod_index_is_consumed2()` with mode `::XKB_CONSUMED_MOD_XKB`.
2499+ *
2500+ * @warning For [virtual modifiers], this function may *overmatch* in case
2501+ * there are virtual modifiers with overlapping mappings to [real modifiers].
2502+ *
2503+ * @memberof xkb_state
2504+ * @since 0.4.1: Works only with *real* modifiers
2505+ * @since 1.8.0: Works also with *virtual* modifiers
2506+ *
2507+ * [virtual modifiers]: @ref virtual-modifier-def
2508+ * [real modifiers]: @ref real-modifier-def
2509+ */
2510+XKB_EXPORT int
2511+xkb_state_mod_index_is_consumed(struct xkb_state *state, xkb_keycode_t key,
2512+ xkb_mod_index_t idx);
2513+
2514+/**
2515+ * Remove consumed modifiers from a modifier mask for a key.
2516+ *
2517+ * @deprecated Use `xkb_state_key_get_consumed_mods2()` instead.
2518+ *
2519+ * Takes the given modifier mask, and removes all modifiers which are
2520+ * consumed for that particular key (as in `xkb_state_mod_index_is_consumed()`).
2521+ *
2522+ * @returns a mask of [real modifiers] modifiers.
2523+ *
2524+ * @sa xkb_state_mod_index_is_consumed()
2525+ * @memberof xkb_state
2526+ * @since 0.5.0: Works only with *real* modifiers
2527+ * @since 1.8.0: Works also with *virtual* modifiers
2528+ *
2529+ * [real modifiers]: @ref real-modifier-def
2530+ */
2531+XKB_EXPORT xkb_mod_mask_t
2532+xkb_state_mod_mask_remove_consumed(struct xkb_state *state, xkb_keycode_t key,
2533+ xkb_mod_mask_t mask);
2534+
2535+/**
2536+ * Test whether a layout is active in a given keyboard state by name.
2537+ *
2538+ * @returns 1 if the layout is active, 0 if it is not. If no layout with
2539+ * this name exists in the keymap, return -1.
2540+ *
2541+ * If multiple layouts in the keymap have this name, the one with the lowest
2542+ * index is tested.
2543+ *
2544+ * @sa xkb_layout_index_t
2545+ * @memberof xkb_state
2546+ */
2547+XKB_EXPORT int
2548+xkb_state_layout_name_is_active(struct xkb_state *state, const char *name,
2549+ enum xkb_state_component type);
2550+
2551+/**
2552+ * Test whether a layout is active in a given keyboard state by index.
2553+ *
2554+ * @returns 1 if the layout is active, 0 if it is not. If the layout index
2555+ * is not valid in the keymap, returns -1.
2556+ *
2557+ * @sa xkb_layout_index_t
2558+ * @memberof xkb_state
2559+ */
2560+XKB_EXPORT int
2561+xkb_state_layout_index_is_active(struct xkb_state *state,
2562+ xkb_layout_index_t idx,
2563+ enum xkb_state_component type);
2564+
2565+/**
2566+ * Test whether a LED is active in a given keyboard state by name.
2567+ *
2568+ * @returns 1 if the LED is active, 0 if it not. If no LED with this name
2569+ * exists in the keymap, returns -1.
2570+ *
2571+ * @sa xkb_led_index_t
2572+ * @memberof xkb_state
2573+ */
2574+XKB_EXPORT int
2575+xkb_state_led_name_is_active(struct xkb_state *state, const char *name);
2576+
2577+/**
2578+ * Test whether a LED is active in a given keyboard state by index.
2579+ *
2580+ * @returns 1 if the LED is active, 0 if it not. If the LED index is not
2581+ * valid in the keymap, returns -1.
2582+ *
2583+ * @sa xkb_led_index_t
2584+ * @memberof xkb_state
2585+ */
2586+XKB_EXPORT int
2587+xkb_state_led_index_is_active(struct xkb_state *state, xkb_led_index_t idx);
2588+
2589+/** @} */
2590+
2591+/* Leave this include last, so it can pick up our types, etc. */
2592+#include <xkbcommon/xkbcommon-compat.h>
2593+
2594+#ifdef __cplusplus
2595+} /* extern "C" */
2596+#endif
2597+
2598+#endif /* _XKBCOMMON_H_ */
A xkbcommon.go +492 -0
@@ -0,0 +1,492 @@
1+// Package xkbcommon interprets Wayland keyboard maps with libxkbcommon,
2+// loaded at runtime without cgo. Close owned values when they are no longer used.
3+package xkbcommon
4+
5+import (
6+ "errors"
7+ "fmt"
8+ "runtime"
9+ "strings"
10+ "sync"
11+ "syscall"
12+ "unsafe"
13+
14+ "github.com/bnema/purego-xkbcommon/raw"
15+)
16+
17+var ErrClosed = errors.New("xkbcommon: closed handle")
18+
19+func cstr(s string) []byte { return append([]byte(s), 0) }
20+func ptr(b []byte) uintptr {
21+ if len(b) == 0 {
22+ return 0
23+ }
24+ return uintptr(unsafe.Pointer(&b[0]))
25+}
26+func validString(s string) error {
27+ if strings.IndexByte(s, 0) >= 0 {
28+ return errors.New("xkbcommon: embedded NUL")
29+ }
30+ return nil
31+}
32+
33+// Keycodes from wl_keyboard are evdev codes; add 8 before calling State.KeySym or State.UTF8.
34+func WaylandKeycode(evdev uint32) uint32 { return evdev + 8 }
35+
36+type Context struct {
37+ mu sync.Mutex
38+ h uintptr
39+}
40+
41+func NewContext() (*Context, error) {
42+ if err := Available(); err != nil {
43+ return nil, err
44+ }
45+ h := loader.f.Xkb_context_new(0)
46+ if h == 0 {
47+ return nil, errors.New("xkbcommon: create context failed")
48+ }
49+ return &Context{h: h}, nil
50+}
51+func (c *Context) Close() error {
52+ if c == nil {
53+ return nil
54+ }
55+ c.mu.Lock()
56+ defer c.mu.Unlock()
57+ if c.h != 0 {
58+ loader.f.Xkb_context_unref(c.h)
59+ c.h = 0
60+ }
61+ return nil
62+}
63+func (c *Context) retain() (uintptr, error) {
64+ if c == nil {
65+ return 0, ErrClosed
66+ }
67+ c.mu.Lock()
68+ defer c.mu.Unlock()
69+ if c.h == 0 {
70+ return 0, ErrClosed
71+ }
72+ loader.f.Xkb_context_ref(c.h)
73+ return c.h, nil
74+}
75+func releaseContext(h uintptr) { loader.f.Xkb_context_unref(h) }
76+
77+type Keymap struct {
78+ mu sync.Mutex
79+ h, context uintptr
80+}
81+
82+func newKeymap(ctx *Context, build func(uintptr) uintptr) (*Keymap, error) {
83+ h, e := ctx.retain()
84+ if e != nil {
85+ return nil, e
86+ }
87+ k := build(h)
88+ if k == 0 {
89+ releaseContext(h)
90+ return nil, errors.New("xkbcommon: invalid keymap")
91+ }
92+ return &Keymap{h: k, context: h}, nil
93+}
94+
95+// NewKeymapString compiles a NUL-free xkb_v1 text keymap.
96+func (c *Context) NewKeymapString(text string) (*Keymap, error) {
97+ if e := validString(text); e != nil {
98+ return nil, e
99+ }
100+ b := cstr(text)
101+ return newKeymap(c, func(h uintptr) uintptr {
102+ v := loader.f.Xkb_keymap_new_from_string(h, ptr(b), raw.XKB_KEYMAP_FORMAT_TEXT_V1, 0)
103+ runtime.KeepAlive(b)
104+ return v
105+ })
106+}
107+
108+// NewKeymapRules compiles an evdev rules keymap. Empty rules/model/variant/options
109+// use libxkbcommon defaults; layout is e.g. "us", "fr", "de", or "us,de".
110+func (c *Context) NewKeymapRules(rules, model, layout, variant, options string) (*Keymap, error) {
111+ args := []string{rules, model, layout, variant, options}
112+ var b [5][]byte
113+ var n raw.RuleNames
114+ p := []*uintptr{&n.Rules, &n.Model, &n.Layout, &n.Variant, &n.Options}
115+ for i, s := range args {
116+ if e := validString(s); e != nil {
117+ return nil, e
118+ }
119+ if s != "" {
120+ b[i] = cstr(s)
121+ *p[i] = ptr(b[i])
122+ }
123+ }
124+ return newKeymap(c, func(h uintptr) uintptr {
125+ v := loader.f.Xkb_keymap_new_from_names(h, uintptr(unsafe.Pointer(&n)), 0)
126+ runtime.KeepAlive(b)
127+ runtime.KeepAlive(n)
128+ return v
129+ })
130+}
131+
132+// NewKeymapFD maps exactly size bytes read-only and privately, then compiles the
133+// Wayland xkb_v1 format. The caller retains ownership of fd, including on error;
134+// this function never closes it. The mapping is removed before return. size must
135+// include the terminating NUL required by the Wayland protocol.
136+func (c *Context) NewKeymapFD(fd int, size int) (*Keymap, error) {
137+ if fd < 0 || size < 1 || size > 64<<20 {
138+ return nil, errors.New("xkbcommon: invalid keymap FD or size (limit 64 MiB)")
139+ }
140+ var stat syscall.Stat_t
141+ if e := syscall.Fstat(fd, &stat); e != nil {
142+ return nil, fmt.Errorf("xkbcommon: stat keymap FD: %w", e)
143+ }
144+ if stat.Mode&syscall.S_IFMT != syscall.S_IFREG || stat.Size < int64(size) {
145+ return nil, errors.New("xkbcommon: keymap FD is not a regular file of the supplied size")
146+ }
147+ b, e := syscall.Mmap(fd, 0, size, syscall.PROT_READ, syscall.MAP_PRIVATE)
148+ if e != nil {
149+ return nil, fmt.Errorf("xkbcommon: mmap keymap: %w", e)
150+ }
151+ defer syscall.Munmap(b)
152+ if b[len(b)-1] != 0 {
153+ return nil, errors.New("xkbcommon: Wayland keymap not NUL terminated")
154+ }
155+ return newKeymap(c, func(h uintptr) uintptr {
156+ v := loader.f.Xkb_keymap_new_from_buffer(h, ptr(b), uintptr(size-1), raw.XKB_KEYMAP_FORMAT_TEXT_V1, 0)
157+ runtime.KeepAlive(b)
158+ return v
159+ })
160+}
161+func (k *Keymap) Close() error {
162+ if k == nil {
163+ return nil
164+ }
165+ k.mu.Lock()
166+ h, ctx := k.h, k.context
167+ k.h = 0
168+ k.context = 0
169+ if h != 0 {
170+ loader.f.Xkb_keymap_unref(h)
171+ }
172+ k.mu.Unlock()
173+ if ctx != 0 {
174+ releaseContext(ctx)
175+ }
176+ return nil
177+}
178+func (k *Keymap) retain() (uintptr, error) {
179+ if k == nil {
180+ return 0, ErrClosed
181+ }
182+ k.mu.Lock()
183+ defer k.mu.Unlock()
184+ if k.h == 0 {
185+ return 0, ErrClosed
186+ }
187+ loader.f.Xkb_keymap_ref(k.h)
188+ return k.h, nil
189+}
190+func (k *Keymap) ModIndex(name string) (uint32, error) {
191+ if e := validString(name); e != nil {
192+ return 0, e
193+ }
194+ if k == nil {
195+ return 0, ErrClosed
196+ }
197+ b := cstr(name)
198+ k.mu.Lock()
199+ defer k.mu.Unlock()
200+ if k.h == 0 {
201+ return 0, ErrClosed
202+ }
203+ v := loader.f.Xkb_keymap_mod_get_index(k.h, ptr(b))
204+ runtime.KeepAlive(b)
205+ return v, nil
206+}
207+func (k *Keymap) LayoutCount() (uint32, error) {
208+ if k == nil {
209+ return 0, ErrClosed
210+ }
211+ k.mu.Lock()
212+ defer k.mu.Unlock()
213+ if k.h == 0 {
214+ return 0, ErrClosed
215+ }
216+ return loader.f.Xkb_keymap_num_layouts(k.h), nil
217+}
218+func (k *Keymap) NewState() (*State, error) {
219+ h, e := k.retain()
220+ if e != nil {
221+ return nil, e
222+ }
223+ s := loader.f.Xkb_state_new(h)
224+ if s == 0 {
225+ loader.f.Xkb_keymap_unref(h)
226+ return nil, errors.New("xkbcommon: create state failed")
227+ }
228+ return &State{h: s, keymap: h}, nil
229+}
230+
231+type State struct {
232+ mu sync.Mutex
233+ h, keymap uintptr
234+}
235+
236+func (s *State) Close() error {
237+ if s == nil {
238+ return nil
239+ }
240+ s.mu.Lock()
241+ h, k := s.h, s.keymap
242+ s.h = 0
243+ s.keymap = 0
244+ if h != 0 {
245+ loader.f.Xkb_state_unref(h)
246+ }
247+ s.mu.Unlock()
248+ if k != 0 {
249+ loader.f.Xkb_keymap_unref(k)
250+ }
251+ return nil
252+}
253+
254+// UpdateMask accepts depressed/latched/locked modifier masks and layout group indices
255+// in the order supplied by wl_keyboard.modifiers. It returns changed components.
256+func (s *State) UpdateMask(depressed, latched, locked, groupDepressed, groupLatched, groupLocked uint32) (uint32, error) {
257+ if s == nil {
258+ return 0, ErrClosed
259+ }
260+ s.mu.Lock()
261+ defer s.mu.Unlock()
262+ if s.h == 0 {
263+ return 0, ErrClosed
264+ }
265+ return loader.f.Xkb_state_update_mask(s.h, depressed, latched, locked, groupDepressed, groupLatched, groupLocked), nil
266+}
267+func (s *State) Layout() (uint32, error) {
268+ if s == nil {
269+ return 0, ErrClosed
270+ }
271+ s.mu.Lock()
272+ defer s.mu.Unlock()
273+ if s.h == 0 {
274+ return 0, ErrClosed
275+ }
276+ return loader.f.Xkb_state_serialize_layout(s.h, raw.XKB_STATE_LAYOUT_EFFECTIVE), nil
277+}
278+func (s *State) Mods() (uint32, error) {
279+ if s == nil {
280+ return 0, ErrClosed
281+ }
282+ s.mu.Lock()
283+ defer s.mu.Unlock()
284+ if s.h == 0 {
285+ return 0, ErrClosed
286+ }
287+ return loader.f.Xkb_state_serialize_mods(s.h, raw.XKB_STATE_MODS_EFFECTIVE), nil
288+}
289+func (s *State) KeySym(keycode uint32) (uint32, error) {
290+ if s == nil {
291+ return 0, ErrClosed
292+ }
293+ s.mu.Lock()
294+ defer s.mu.Unlock()
295+ if s.h == 0 {
296+ return 0, ErrClosed
297+ }
298+ return loader.f.Xkb_state_key_get_one_sym(s.h, keycode), nil
299+}
300+
301+// sizedUTF8 probes the required byte count (excluding NUL) and retries if it grows.
302+func sizedUTF8(call func(uintptr, uintptr) int32) (string, error) {
303+ n := call(0, 0)
304+ if n < 0 {
305+ return "", errors.New("xkbcommon: UTF-8 conversion failed")
306+ }
307+ if n == 0 {
308+ return "", nil
309+ }
310+ for attempt := 0; attempt < 3; attempt++ {
311+ if n > 1<<20 {
312+ return "", errors.New("xkbcommon: UTF-8 result exceeds 1 MiB")
313+ }
314+ b := make([]byte, int(n)+1)
315+ got := call(ptr(b), uintptr(len(b)))
316+ runtime.KeepAlive(b)
317+ if got < 0 {
318+ return "", errors.New("xkbcommon: UTF-8 conversion failed")
319+ }
320+ if int(got) < len(b) {
321+ return string(b[:got]), nil
322+ }
323+ n = got
324+ }
325+ return "", errors.New("xkbcommon: UTF-8 result changed during sizing")
326+}
327+func (s *State) UTF8(keycode uint32) (string, error) {
328+ if s == nil {
329+ return "", ErrClosed
330+ }
331+ s.mu.Lock()
332+ defer s.mu.Unlock()
333+ if s.h == 0 {
334+ return "", ErrClosed
335+ }
336+ return sizedUTF8(func(p, n uintptr) int32 { return loader.f.Xkb_state_key_get_utf8(s.h, keycode, p, n) })
337+}
338+func KeysymName(sym uint32) (string, error) {
339+ if e := Available(); e != nil {
340+ return "", e
341+ }
342+ return sizedUTF8(func(p, n uintptr) int32 { return loader.f.Xkb_keysym_get_name(sym, p, n) })
343+}
344+func KeysymFromName(name string) (uint32, error) {
345+ if e := Available(); e != nil {
346+ return 0, e
347+ }
348+ if e := validString(name); e != nil {
349+ return 0, e
350+ }
351+ b := cstr(name)
352+ v := loader.f.Xkb_keysym_from_name(ptr(b), 0)
353+ runtime.KeepAlive(b)
354+ return v, nil
355+}
356+
357+type ComposeTable struct {
358+ mu sync.Mutex
359+ h, context uintptr
360+}
361+
362+func (c *Context) NewComposeTable(locale string) (*ComposeTable, error) {
363+ if e := validString(locale); e != nil {
364+ return nil, e
365+ }
366+ ctx, e := c.retain()
367+ if e != nil {
368+ return nil, e
369+ }
370+ b := cstr(locale)
371+ h := loader.f.Xkb_compose_table_new_from_locale(ctx, ptr(b), 0)
372+ runtime.KeepAlive(b)
373+ if h == 0 {
374+ releaseContext(ctx)
375+ return nil, fmt.Errorf("xkbcommon: no compose table for %q", locale)
376+ }
377+ return &ComposeTable{h: h, context: ctx}, nil
378+}
379+func (t *ComposeTable) Close() error {
380+ if t == nil {
381+ return nil
382+ }
383+ t.mu.Lock()
384+ h, ctx := t.h, t.context
385+ t.h = 0
386+ t.context = 0
387+ if h != 0 {
388+ loader.f.Xkb_compose_table_unref(h)
389+ }
390+ t.mu.Unlock()
391+ if ctx != 0 {
392+ releaseContext(ctx)
393+ }
394+ return nil
395+}
396+func (t *ComposeTable) NewState() (*ComposeState, error) {
397+ if t == nil {
398+ return nil, ErrClosed
399+ }
400+ t.mu.Lock()
401+ if t.h == 0 {
402+ t.mu.Unlock()
403+ return nil, ErrClosed
404+ }
405+ table := loader.f.Xkb_compose_table_ref(t.h)
406+ t.mu.Unlock()
407+ h := loader.f.Xkb_compose_state_new(table, 0)
408+ if h == 0 {
409+ loader.f.Xkb_compose_table_unref(table)
410+ return nil, errors.New("xkbcommon: create compose state failed")
411+ }
412+ return &ComposeState{h: h, table: table}, nil
413+}
414+
415+type ComposeState struct {
416+ mu sync.Mutex
417+ h, table uintptr
418+}
419+
420+func (s *ComposeState) Close() error {
421+ if s == nil {
422+ return nil
423+ }
424+ s.mu.Lock()
425+ h, t := s.h, s.table
426+ s.h = 0
427+ s.table = 0
428+ if h != 0 {
429+ loader.f.Xkb_compose_state_unref(h)
430+ }
431+ s.mu.Unlock()
432+ if t != 0 {
433+ loader.f.Xkb_compose_table_unref(t)
434+ }
435+ return nil
436+}
437+func (s *ComposeState) Feed(sym uint32) (uint32, error) {
438+ if s == nil {
439+ return 0, ErrClosed
440+ }
441+ s.mu.Lock()
442+ defer s.mu.Unlock()
443+ if s.h == 0 {
444+ return 0, ErrClosed
445+ }
446+ return loader.f.Xkb_compose_state_feed(s.h, sym), nil
447+}
448+func (s *ComposeState) Status() (uint32, error) {
449+ if s == nil {
450+ return 0, ErrClosed
451+ }
452+ s.mu.Lock()
453+ defer s.mu.Unlock()
454+ if s.h == 0 {
455+ return 0, ErrClosed
456+ }
457+ return loader.f.Xkb_compose_state_get_status(s.h), nil
458+}
459+func (s *ComposeState) UTF8() (string, error) {
460+ if s == nil {
461+ return "", ErrClosed
462+ }
463+ s.mu.Lock()
464+ defer s.mu.Unlock()
465+ if s.h == 0 {
466+ return "", ErrClosed
467+ }
468+ return sizedUTF8(func(p, n uintptr) int32 { return loader.f.Xkb_compose_state_get_utf8(s.h, p, n) })
469+}
470+func (s *ComposeState) KeySym() (uint32, error) {
471+ if s == nil {
472+ return 0, ErrClosed
473+ }
474+ s.mu.Lock()
475+ defer s.mu.Unlock()
476+ if s.h == 0 {
477+ return 0, ErrClosed
478+ }
479+ return loader.f.Xkb_compose_state_get_one_sym(s.h), nil
480+}
481+func (s *ComposeState) Reset() error {
482+ if s == nil {
483+ return ErrClosed
484+ }
485+ s.mu.Lock()
486+ defer s.mu.Unlock()
487+ if s.h == 0 {
488+ return ErrClosed
489+ }
490+ loader.f.Xkb_compose_state_reset(s.h)
491+ return nil
492+}
A xkbcommon_test.go +250 -0
@@ -0,0 +1,250 @@
1+package xkbcommon
2+
3+import (
4+ "errors"
5+ "os"
6+ "os/exec"
7+ "strings"
8+ "testing"
9+ "unsafe"
10+
11+ "github.com/bnema/purego-xkbcommon/raw"
12+)
13+
14+func live(t *testing.T) *Context {
15+ t.Helper()
16+ if err := Available(); err != nil {
17+ if strings.Contains(err.Error(), "load libxkbcommon.so.0") {
18+ t.Skipf("live libxkbcommon.so.0 absent: %v", err)
19+ }
20+ t.Fatal(err)
21+ }
22+ c, e := NewContext()
23+ if e != nil {
24+ t.Fatal(e)
25+ }
26+ t.Cleanup(func() { c.Close() })
27+ return c
28+}
29+func rules(t *testing.T, c *Context, layout string) *Keymap {
30+ t.Helper()
31+ k, e := c.NewKeymapRules("evdev", "pc105", layout, "", "")
32+ if e != nil {
33+ t.Fatalf("rules %s: %v", layout, e)
34+ }
35+ t.Cleanup(func() { k.Close() })
36+ return k
37+}
38+func state(t *testing.T, k *Keymap) *State {
39+ t.Helper()
40+ s, e := k.NewState()
41+ if e != nil {
42+ t.Fatal(e)
43+ }
44+ t.Cleanup(func() { s.Close() })
45+ return s
46+}
47+func TestABI(t *testing.T) {
48+ if unsafe.Sizeof(raw.RuleNames{}) != 5*unsafe.Sizeof(uintptr(0)) {
49+ t.Fatal("rule names ABI")
50+ }
51+ if unsafe.Sizeof(raw.Keycode(0)) != 4 || unsafe.Sizeof(raw.Keysym(0)) != 4 || unsafe.Sizeof(raw.ModMask(0)) != 4 {
52+ t.Fatal("scalar ABI")
53+ }
54+}
55+func TestSymbols(t *testing.T) {
56+ live(t)
57+ if len(raw.Symbols) < 25 {
58+ t.Fatal("incomplete required symbol set")
59+ }
60+}
61+func TestMalformedAndLifetime(t *testing.T) {
62+ c := live(t)
63+ if _, e := c.NewKeymapString("garbage"); e == nil {
64+ t.Fatal("malformed keymap compiled")
65+ }
66+ if _, e := c.NewKeymapString("foo\x00bar"); e == nil {
67+ t.Fatal("embedded NUL")
68+ }
69+ k := rules(t, c, "us")
70+ s := state(t, k)
71+ c.Close()
72+ k.Close()
73+ for i := 0; i < 3; i++ {
74+ c.Close()
75+ k.Close()
76+ }
77+ if _, e := k.NewState(); !errors.Is(e, ErrClosed) {
78+ t.Fatal(e)
79+ }
80+ v, e := s.UTF8(38)
81+ if e != nil || v != "a" {
82+ t.Fatalf("state after parent close: %q %v", v, e)
83+ }
84+ s.Close()
85+ s.Close()
86+ if _, e := s.KeySym(38); !errors.Is(e, ErrClosed) {
87+ t.Fatal(e)
88+ }
89+}
90+func TestFD(t *testing.T) {
91+ c := live(t)
92+ out, e := exec.Command("xkbcli", "compile-keymap", "--rules", "evdev", "--model", "pc105", "--layout", "fr", "--output-format", "1").Output()
93+ if e != nil {
94+ t.Fatalf("reference xkbcli: %v", e)
95+ }
96+ f, e := os.CreateTemp(t.TempDir(), "keymap")
97+ if e != nil {
98+ t.Fatal(e)
99+ }
100+ defer f.Close()
101+ data := append(out, 0)
102+ if _, e = f.Write(data); e != nil {
103+ t.Fatal(e)
104+ }
105+ other, e := c.NewKeymapFD(int(f.Fd()), len(data))
106+ if e != nil {
107+ t.Fatal(e)
108+ }
109+ other.Close()
110+ if _, e = f.Stat(); e != nil {
111+ t.Fatalf("FD was closed: %v", e)
112+ }
113+ if _, e = c.NewKeymapFD(int(f.Fd()), len(data)-1); e == nil {
114+ t.Fatal("missing NUL accepted")
115+ }
116+ if _, e = c.NewKeymapFD(-1, len(data)); e == nil {
117+ t.Fatal("negative FD")
118+ }
119+}
120+func TestLayoutsAndDifferential(t *testing.T) {
121+ c := live(t)
122+ for _, tc := range []struct {
123+ layout string
124+ code uint32
125+ want string
126+ alt bool
127+ }{{"us", 38, "a", false}, {"fr", 24, "a", false}, {"de", 29, "z", false}, {"de", 26, "€", true}, {"fr", 26, "€", true}} {
128+ t.Run(tc.layout+tc.want, func(t *testing.T) {
129+ k := rules(t, c, tc.layout)
130+ s := state(t, k)
131+ if tc.alt {
132+ idx, e := k.ModIndex("LevelThree")
133+ if e != nil || idx == ^uint32(0) || idx >= 32 {
134+ t.Fatalf("LevelThree: %d %v", idx, e)
135+ }
136+ s.UpdateMask(1<<idx, 0, 0, 0, 0, 0)
137+ }
138+ got, e := s.UTF8(tc.code)
139+ if e != nil || got != tc.want {
140+ t.Fatalf("utf8 %q want %q: %v", got, tc.want, e)
141+ }
142+ sym, e := s.KeySym(tc.code)
143+ if e != nil {
144+ t.Fatal(e)
145+ }
146+ name, e := KeysymName(sym)
147+ if e != nil || name == "" {
148+ t.Fatalf("name %q: %v", name, e)
149+ }
150+ back, e := KeysymFromName(name)
151+ if e != nil || back != sym {
152+ t.Fatalf("name roundtrip %d %d %v", sym, back, e)
153+ }
154+ // Compare safe calls to the independently resolved native entry points for this real rules keymap.
155+ nativeSym := loader.f.Xkb_state_key_get_one_sym(s.h, tc.code)
156+ if nativeSym != sym {
157+ t.Fatalf("native sym %d != %d", nativeSym, sym)
158+ }
159+ nativeN := loader.f.Xkb_state_key_get_utf8(s.h, tc.code, 0, 0)
160+ if nativeN != int32(len(got)) {
161+ t.Fatalf("native bytes %d != %d", nativeN, len(got))
162+ }
163+ })
164+ }
165+ k := rules(t, c, "us,de")
166+ s := state(t, k)
167+ n, e := k.LayoutCount()
168+ if e != nil || n != 2 {
169+ t.Fatalf("layouts %d %v", n, e)
170+ }
171+ s.UpdateMask(0, 0, 0, 0, 0, 1)
172+ group, e := s.Layout()
173+ if e != nil || group != 1 {
174+ t.Fatalf("group %d %v", group, e)
175+ }
176+ v, _ := s.UTF8(29)
177+ if v != "z" {
178+ t.Fatalf("group 1 %q", v)
179+ }
180+ shift, e := k.ModIndex("Shift")
181+ if e != nil || shift >= 32 {
182+ t.Fatalf("shift %d %v", shift, e)
183+ }
184+ s.UpdateMask(1<<shift, 0, 0, 0, 0, 1)
185+ v, _ = s.UTF8(29)
186+ if v != "Z" {
187+ t.Fatalf("shift group 1 %q", v)
188+ }
189+ mods, _ := s.Mods()
190+ if mods&(1<<shift) == 0 {
191+ t.Fatalf("mods %#x", mods)
192+ }
193+}
194+func TestCompose(t *testing.T) {
195+ c := live(t)
196+ table, e := c.NewComposeTable("en_US.UTF-8")
197+ if e != nil {
198+ t.Fatal(e)
199+ }
200+ s, e := table.NewState()
201+ if e != nil {
202+ t.Fatal(e)
203+ }
204+ table.Close()
205+ c.Close()
206+ if _, e = s.Feed(raw.XKB_KEY_dead_acute); e != nil {
207+ t.Fatal(e)
208+ }
209+ status, _ := s.Status()
210+ if status != raw.XKB_COMPOSE_COMPOSING {
211+ t.Fatalf("status %d", status)
212+ }
213+ s.Feed(raw.XKB_KEY_e)
214+ status, _ = s.Status()
215+ if status != raw.XKB_COMPOSE_COMPOSED {
216+ t.Fatalf("status %d", status)
217+ }
218+ v, e := s.UTF8()
219+ if e != nil || v != "é" {
220+ t.Fatalf("compose %q %v", v, e)
221+ }
222+ s.Reset()
223+ s.Feed(raw.XKB_KEY_Multi_key)
224+ s.Feed(raw.XKB_KEY_apostrophe)
225+ s.Feed(raw.XKB_KEY_e)
226+ v, _ = s.UTF8()
227+ if v != "é" {
228+ t.Fatalf("multikey %q", v)
229+ }
230+ s.Close()
231+ s.Close()
232+ table.Close()
233+ if _, e = s.UTF8(); !errors.Is(e, ErrClosed) {
234+ t.Fatal(e)
235+ }
236+}
237+func TestSizing(t *testing.T) {
238+ v, e := sizedUTF8(func(p, n uintptr) int32 { return 0 })
239+ if e != nil || v != "" {
240+ t.Fatalf("%q %v", v, e)
241+ }
242+ _, e = sizedUTF8(func(p, n uintptr) int32 { return -1 })
243+ if e == nil {
244+ t.Fatal("negative result accepted")
245+ }
246+ v, e = KeysymName(raw.XKB_KEY_EuroSign)
247+ if e != nil || v != "EuroSign" {
248+ t.Fatalf("name %q %v", v, e)
249+ }
250+}

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 2

↑↓ moveenter openesc close