3rdparty/xkbcommon: update bundled version 0.4.1 -> 0.8.2

0.8.2 + subsequent commits up to 31f1f355700870c6615399fbfa7934934b3a9a57.
There were couple commits after 0.8.2. Mostly minor stuff, with 2 exceptions:
fix off-by-one error in xkb_file_type_to_string() and undefined behavior in src/x11/keymap.c

We currently don't use any of the features added in later releases of
libxkbcommon, therefore the minimal required version in src/gui/configure.json
remains the same.

[ChangeLog][Third-Party Code] updated bundled libxkbcommon 0.4.1 -> 0.8.2 (up to 31f1f355700870c6615399fbfa7934934b3a9a57)

Task-number: QTBUG-71109
Change-Id: Ia03c3dc31c5f39e78dcb5915a45e82797b065ccb
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
bb10
Gatis Paeglis 2018-10-16 12:09:10 +02:00
parent aa633ff276
commit 76c762558a
57 changed files with 6104 additions and 3540 deletions

View File

@ -4,6 +4,10 @@ include(xkbcommon.pri)
# in xcb-plugin.pro (linked to system libraries or if Qt was configured with -qt-xcb then
# linked to -lxcb-static).
INCLUDEPATH += $$PWD/xkbcommon/src/x11
# Need to rename several files, qmake has problems processing a project when
# sub-directories contain files with an equal names.
SOURCES += \
$$PWD/xkbcommon/src/x11/util.c \
$$PWD/xkbcommon/src/x11/x11-keymap.c \ # renamed: keymap.c -> x11-keymap.c

View File

@ -8,47 +8,53 @@ INCLUDEPATH += $$PWD/xkbcommon \
include($$shadowed($$PWD/../gui/qtgui-config.pri))
DEFINES += DFLT_XKB_CONFIG_ROOT='\\"/usr/share/X11/xkb\\"' # unused, but needs to be set to something
# Unused (but needs to be set to something) - we don't use APIs that read xkb
# config files from file system. We use APIs that fetch the necessary keymap
# details directly from X server.
DEFINES += DFLT_XKB_CONFIG_ROOT='\\"/usr/share/X11/xkb\\"'
# Unused (but needs to be set to something) - After QTBUG-42181, this needs to
# be become a configure switch.
DEFINES += XLOCALEDIR='\\"/usr/share/X11/locale/\\"'
### RMLVO names can be overwritten with environmental variables (see libxkbcommon documentation)
DEFINES += DEFAULT_XKB_RULES='\\"evdev\\"'
DEFINES += DEFAULT_XKB_MODEL='\\"pc105\\"'
DEFINES += DEFAULT_XKB_LAYOUT='\\"us\\"'
# Need to rename several files, qmake has problems processing a project when
# sub-directories contain files with an equal names.
# libxkbcommon generates some of these files while executing "./autogen.sh"
# and some while executing "make" (actually YACC)
SOURCES += \
$$PWD/xkbcommon/src/atom.c \
$$PWD/xkbcommon/src/xkb-compat.c \ # renamed: compat.c -> xkb-compat.c
$$PWD/xkbcommon/src/context.c \
$$PWD/xkbcommon/src/xkb-keymap.c \ # renamed: keymap.c -> xkb-keymap.c
$$PWD/xkbcommon/src/keysym.c \
$$PWD/xkbcommon/src/keysym-utf.c \
$$PWD/xkbcommon/src/state.c \
$$PWD/xkbcommon/src/text.c \
$$PWD/xkbcommon/src/context-priv.c \
$$PWD/xkbcommon/src/keymap.c \
$$PWD/xkbcommon/src/keymap-priv.c \
$$PWD/xkbcommon/src/utils.c \
$$PWD/xkbcommon/src/utf8.c
SOURCES += \
$$PWD/xkbcommon/src/xkbcomp/action.c \
$$PWD/xkbcommon/src/xkbcomp/ast-build.c \
$$PWD/xkbcommon/src/xkbcomp/compat.c \
$$PWD/xkbcommon/src/xkbcomp/expr.c \
$$PWD/xkbcommon/src/xkbcomp/include.c \
$$PWD/xkbcommon/src/xkbcomp/keycodes.c \
$$PWD/xkbcommon/src/xkbcomp/keymap-dump.c \
$$PWD/xkbcommon/src/xkbcomp/keymap.c \
$$PWD/xkbcommon/src/xkbcomp/keywords.c \
$$PWD/xkbcommon/src/xkbcomp/rules.c \
$$PWD/xkbcommon/src/xkbcomp/scanner.c \
$$PWD/xkbcommon/src/xkbcomp/symbols.c \
$$PWD/xkbcommon/src/xkbcomp/types.c \
$$PWD/xkbcommon/src/xkbcomp/vmod.c \
$$PWD/xkbcommon/src/atom.c \
$$PWD/xkbcommon/src/compose/paths.c \
$$PWD/xkbcommon/src/compose/parser.c \
$$PWD/xkbcommon/src/compose/compose-state.c \ # renamed: keymap.c -> compose-state.c
$$PWD/xkbcommon/src/compose/table.c \
$$PWD/xkbcommon/src/xkbcomp/xkbcomp-keymap.c \ # renamed: keymap.c -> xkbcomp-keymap.c
$$PWD/xkbcommon/src/xkbcomp/xkbcomp.c \
$$PWD/xkbcommon/src/xkbcomp/parser.c
$$PWD/xkbcommon/src/xkbcomp/keymap-dump.c \
$$PWD/xkbcommon/src/xkbcomp/rules.c \
$$PWD/xkbcommon/src/xkbcomp/expr.c \
$$PWD/xkbcommon/src/xkbcomp/action.c \
$$PWD/xkbcommon/src/xkbcomp/compat.c \
$$PWD/xkbcommon/src/xkbcomp/types.c \
$$PWD/xkbcommon/src/xkbcomp/scanner.c \
$$PWD/xkbcommon/src/xkbcomp/xkbcomp-parser.c \ # renamed: parser.c -> xkbcomp-parser.c
$$PWD/xkbcommon/src/xkbcomp/ast-build.c \
$$PWD/xkbcommon/src/xkbcomp/keywords.c \
$$PWD/xkbcommon/src/xkbcomp/keycodes.c \
$$PWD/xkbcommon/src/xkbcomp/vmod.c \
$$PWD/xkbcommon/src/xkbcomp/include.c \
$$PWD/xkbcommon/src/xkbcomp/symbols.c \
$$PWD/xkbcommon/src/context-priv.c \
$$PWD/xkbcommon/src/text.c \
$$PWD/xkbcommon/src/context.c \
$$PWD/xkbcommon/src/keysym.c \
$$PWD/xkbcommon/src/utf8.c \
$$PWD/xkbcommon/src/state.c
TR_EXCLUDE += $$PWD/*

View File

@ -1,19 +0,0 @@
diff --git a/src/3rdparty/xkbcommon/src/x11/util.c b/src/3rdparty/xkbcommon/src/x11/util.c
index 92ff2e6..7659c71 100644
--- a/src/3rdparty/xkbcommon/src/x11/util.c
+++ b/src/3rdparty/xkbcommon/src/x11/util.c
@@ -198,8 +198,12 @@ adopt_atoms(struct xkb_context *ctx, xcb_connection_t *conn,
* sit there waiting. Sad.
*/
err_discard:
- for (size_t j = i + 1; j < stop; j++)
- xcb_discard_reply(conn, cookies[j].sequence);
+ for (size_t j = i + 1; j < stop; j++) {
+ if (from[j] != XCB_ATOM_NONE) {
+ reply = xcb_get_atom_name_reply(conn, cookies[j % SIZE], NULL);
+ free(reply);
+ }
+ }
return false;
}
}

View File

@ -20,7 +20,7 @@ BEGINNING OF SOFTWARE COPYRIGHT/LICENSE STATEMENTS:
-------------------------------------------------------------------------------
Copyright © 2009-2012 Daniel Stone
Copyright © 2009-2012, 2016 Daniel Stone
Copyright © 2012 Ran Benita <ran234@gmail.com>
Copyright © 2010, 2012 Intel Corporation
Copyright © 2008, 2009 Dan Nicholson
@ -186,3 +186,30 @@ CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
-------------------------------------------------------------------------------
Copyright 1992 by Oki Technosystems Laboratory, Inc.
Copyright 1992 by Fuji Xerox Co., Ltd.
Permission to use, copy, modify, distribute, and sell this software
and its documentation for any purpose is hereby granted without fee,
provided that the above copyright notice appear in all copies and
that both that copyright notice and this permission notice appear
in supporting documentation, and that the name of Oki Technosystems
Laboratory and Fuji Xerox not be used in advertising or publicity
pertaining to distribution of the software without specific, written
prior permission.
Oki Technosystems Laboratory and Fuji Xerox make no representations
about the suitability of this software for any purpose. It is provided
"as is" without express or implied warranty.
OKI TECHNOSYSTEMS LABORATORY AND FUJI XEROX DISCLAIM ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL OKI TECHNOSYSTEMS
LABORATORY AND FUJI XEROX BE LIABLE FOR ANY SPECIAL, INDIRECT OR
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
OR PERFORMANCE OF THIS SOFTWARE.

View File

@ -1,4 +1,278 @@
libxkbcommon 0.4.1
libxkbcommon 0.8.2 - 2018-08-05
==================
- Fix various problems found with fuzzing (see commit messages for
more details):
- Fix a few NULL-dereferences, out-of-bounds access and undefined behavior
in the XKB text format parser.
libxkbcommon 0.8.1 - 2018-08-03
==================
- Fix various problems found in the meson build (see commit messages for more
details):
- Fix compilation on Darwin.
- Fix compilation of the x11 tests and demos when XCB is installed in a
non-standard location.
- Fix xkbcommon-x11.pc missing the Requires specification.
- Fix various problems found with fuzzing and Coverity (see commit messages for
more details):
- Fix stack overflow in the XKB text format parser when evaluating boolean
negation.
- Fix NULL-dereferences in the XKB text format parser when some unsupported
tokens appear (the tokens are still parsed for backward compatibility).
- Fix NULL-dereference in the XKB text format parser when parsing an
xkb_geometry section.
- Fix an infinite loop in the Compose text format parser on some inputs.
- Fix an invalid free() when using multiple keysyms.
- Replace the Unicode characters for the leftanglebracket and rightanglebracket
keysyms from the deprecated LEFT/RIGHT-POINTING ANGLE BRACKET to
MATHEMATICAL LEFT/RIGHT ANGLE BRACKET.
- Reject out-of-range Unicode codepoints in xkb_keysym_to_utf8 and
xkb_keysym_to_utf32.
libxkbcommon 0.8.0 - 2017-12-15
==================
- Added xkb_keysym_to_{upper,lower} to perform case-conversion directly on
keysyms. This is useful in some odd cases, but working with the Unicode
representations should be preferred when possible.
- Added Unicode conversion rules for the signifblank and permille keysyms.
- Fixed a bug in the parsing of XKB key type definitions where the number
of levels were determined by the number of level *names*. Keymaps which
omit level names were hence miscompiled.
This regressed in version 0.4.3. Keymaps from xkeyboard-config were not
affected since they don't omit level names.
- New API:
xkb_keysym_to_upper()
xkb_keysym_to_lower()
libxkbcommon 0.7.2 - 2017-08-04
==================
- Added a Meson build system as an alternative to existing autotools build
system.
The intent is to remove the autotools build in one of the next releases.
Please try to convert to it and report any problems.
See http://mesonbuild.com/Quick-guide.html for basic usage, the
meson_options.txt for the project-specific configuration options,
and the PACKAGING file for more details.
There are some noteworthy differences compared to the autotools build:
- Feature auto-detection is not performed. By default, all features are
enabled (currently: docs, x11, wayland). The build fails if any of
the required dependencies are not available. To disable a feature,
pass -Denable-<feature>=false to meson.
- The libraries are either installed as shared or static, as specified
by the -Ddefault_library=shared/static option. With autotools, both
versions are installed by default.
- xorg-util-macros is not used.
- A parser generator (bison/byacc) is always required - there is no
fallback to pre-generated output bundled in the tarball, as there is
in autotools.
- Removed Android.mk support.
- Removed the *-uninstalled.pc pkgconfig files.
- Ported the interactive-wayland demo program to v6 of the xdg-shell
protocol.
- Added new keysym definitions from xproto.
- New API:
XKB_KEY_XF86Keyboard
XKB_KEY_XF86WWAN
XKB_KEY_XF86RFKill
XKB_KEY_XF86AudioPreset
libxkbcommon 0.7.1 - 2017-01-18
==================
- Fixed various reported problems when the current locale is tr_TR.UTF-8.
The function xkb_keysym_from_name() used to perform case-insensitive
string comparisons in a locale-dependent way, but required it to to
work as in the C/ASCII locale (the so called "Turkish i problem").
The function is now no longer affected by the current locale.
- Fixed compilation in NetBSD.
libxkbcommon 0.7.0 - 2016-11-11
==================
- Added support for different "modes" of calculating consumed modifiers.
The existing mode, based on the XKB standard, has proven to be
unintuitive in various shortcut implementations.
A new mode, based on the calculation used by the GTK toolkit, is added.
This mode is less eager to declare a modifier as consumed.
- Added a new interactive demo program using the Wayland protocol.
See the PACKAGING file for the new (optional) test dependencies.
- Fixed a compilation error on GNU Hurd.
- New API:
enum xkb_consumed_mode
XKB_CONSUMED_MODE_XKB
XKB_CONSUMED_MODE_GTK
xkb_state_key_get_consumed_mods2
xkb_state_mod_index_is_consumed2
libxkbcommon 0.6.1 - 2016-04-08
==================
- Added LICENSE to distributed files in tarball releases.
- Minor typo fix in xkb_keymap_get_as_string() documentation.
libxkbcommon 0.6.0 - 2016-03-16
==================
- If the XKB_CONFIG_ROOT environment variable is set, it is used as the XKB
configuration root instead of the path determined at build time.
- Tests and benchmarks now build correctly on OSX.
- An XKB keymap provides a name for each key it defines. Traditionally,
these names are limited to at most 4 characters, and are thus somewhat
obscure, but might still be useful (xkbcommon lifts the 4 character limit).
The new functions xkb_keymap_key_get_name() and xkb_keymap_key_by_name()
can be used to get the name of a key or find a key by name. Note that
a key may have aliases.
- Documentation improvements.
- New API:
xkb_keymap_key_by_name()
xkb_keymap_key_get_name()
libxkbcommon 0.5.0 - 2014-10-18
==================
- Added support for Compose/dead keys in a new module (included in
libxkbcommon). See the documentation or the
xkbcommon/xkbcommon-compose.h header file for more details.
- Improved and reordered some sections of the documentation.
- The doxygen HTML pages were made nicer to read.
- Most tests now run also on non-linux platforms.
- A warning is emitted by default about RMLVO values which are not used
during keymap compilation, which are most often a user misconfiguration.
For example, "terminate:ctrl_alt_backspace" instead of
"terminate:ctrl_alt_bksp".
- Added symbol versioning for libxkbcommon and libxkbcommon-x11.
Note: binaries compiled against this and future versions will not be
able to link against the previous versions of the library.
- Removed several compatablity symbols from the binary (the API isn't
affected). This affects binaries which
1. Were compiled against a pre-stable (<0.2.0) version of libxkbcommon, and
2. Are linked against the this or later version of libxkbcommon.
Such a scenario is likely to fail already.
- If Xvfb is not available, the x11comp test is now correctly skipped
instead of hanging.
- Benchmarks were moved to a separate bench/ directory.
- Build fixes from OpenBSD.
- Fixed a bug where key type entries such as "map[None] = Level2;" were
ignored.
- New API:
XKB_COMPOSE_*
xkb_compose_*
libxkbcommon 0.4.3 - 2014-08-19
==================
- Fixed a bug which caused xkb_x11_keymap_new_from_device() to misrepresent
modifiers for some keymaps.
https://github.com/xkbcommon/libxkbcommon/issues/9
- Fixed a bug which caused xkb_x11_keymap_new_from_device() to ignore XKB
PrivateAction's.
- Modifiers are now always fully resolved after xkb_state_update_mask().
Previously the given state components were used as-is, without
considering virtual modifier mappings.
Note: this only affects non-standard uses of xkb_state_update_mask().
- Added a test for xkbcommon-x11, "x11comp". The test uses the system's
Xvfb server and xkbcomp. If they do not exist or fail, the test is
skipped.
- Fixed memory leaks after parse errors in the XKB yacc parser.
The fix required changes which are currently incompatible with byacc.
libxkbcommon 0.4.2 - 2014-05-15
==================
- Fixed a bug where explicitly passing "--enable-x11" to ./configure would
in fact disable it (regressed in 0.4.1).
- Added @since version annotations to the API documentation for everything
introduced after the initial stable release (0.2.0).
- Added a section to the documentation about keysym transformations, and
clarified which functions perform a given transformation.
- XKB files which fail to compile during keymap construction can no longer
have any effect on the resulting keymap: changes are only applied when
the entire compilation succeeds.
Note: this was a minor correctness issue inherited from xkbcomp.
- Fix an out-of-bounds array access in src/x11/util.c:adopt_atoms()
error-handling code.
Note: it seems impossible to trigger in the current code since the input
size cannot exceed the required size.
libxkbcommon 0.4.1 - 2014-03-27
==================
- Converted README to markdown and added a Quick Guide to the
@ -15,7 +289,7 @@ libxkbcommon 0.4.1
is converted to an appropriate control character.
This matches the behavior of libX11's XLookupString(3), and
required by the XKB specification:
http://www.x.org/releases/current/doc/kbproto/xkbproto.html#Interpreting_the_Control_Modifier
https://www.x.org/releases/current/doc/kbproto/xkbproto.html#Interpreting_the_Control_Modifier
https://bugs.freedesktop.org/show_bug.cgi?id=75892
@ -41,7 +315,8 @@ libxkbcommon 0.4.1
- Bug fixes.
libxkbcommon 0.4.0
libxkbcommon 0.4.0 - 2014-02-02
==================
- Add a new add-on library, xkbcommon-x11, to support creating keymaps
@ -68,7 +343,7 @@ libxkbcommon 0.4.0
xkb_x11_* types and functions, XKB_X11_* constants.
libxkbcommon 0.3.2
libxkbcommon 0.3.2 - 2013-11-22
==================
- Log messages from the library now look like "xkbcommon: ERROR" by
@ -77,7 +352,7 @@ libxkbcommon 0.3.2
- Apply capitalization transformation on keysyms in
xkb_keysym_get_one_sym(), to match the behavior specified in the XKB
specification:
http://www.x.org/releases/current/doc/kbproto/xkbproto.html#Interpreting_the_Lock_Modifier
https://www.x.org/releases/current/doc/kbproto/xkbproto.html#Interpreting_the_Lock_Modifier
- Support byacc for generating the parser, in addition to Bison.
@ -90,7 +365,7 @@ libxkbcommon 0.3.2
- Bug fixes.
libxkbcommon 0.3.1
libxkbcommon 0.3.1 - 2013-06-03
==================
- Replace the flex scanner with a hand-written one. flex is no longer
@ -102,7 +377,7 @@ libxkbcommon 0.3.1
xkb_keymap_key_for_each()
libxkbcommon 0.3.0
libxkbcommon 0.3.0 - 2013-04-01
==================
- Allow passing NULL to *_unref() functions; do nothing instead of

View File

@ -1,100 +1,66 @@
# libxkbcommon
xkbcommon is a keymap compiler and support library which processes a
reduced subset of keymaps as defined by the XKB specification. Primarily,
a keymap is created from a set of Rules/Model/Layout/Variant/Options names,
processed through an XKB ruleset, and compiled into a struct xkb_keymap,
which is the base type for all xkbcommon operations.
From an xkb_keymap, an xkb_state object is created which holds the current
state of all modifiers, groups, LEDs, etc, relating to that keymap. All
key events must be fed into the xkb_state object using xkb_state_update_key().
Once this is done, the xkb_state object will be properly updated, and the
keysyms to use can be obtained with xkb_state_key_get_syms().
libxkbcommon does not distribute a dataset itself, other than for testing
purposes. The most common dataset is xkeyboard-config, as used by all
current distributions for their X11 XKB data. More information on
xkeyboard-config is available here:
http://www.freedesktop.org/wiki/Software/XKeyboardConfig
libxkbcommon is a keyboard keymap compiler and support library which
processes a reduced subset of keymaps as defined by the XKB (X Keyboard
Extension) specification. It also contains a module for handling Compose
and dead keys.
## Quick Guide
See [Quick Guide](doc/quick-guide.md).
## Building
libxkbcommon is built with [Meson](http://mesonbuild.com/):
meson setup build
ninja -C build
To build for use with Wayland, you can disable X11 support while still
using the X11 keyboard configuration resource files thusly:
meson setup build \
-Denable-x11=false \
-Dxkb-config-root=/usr/share/X11/xkb \
-Dx-locale-root=/usr/share/X11/locale
ninja -C build
## API
While xkbcommon's API is somewhat derived from the classic XKB API as found
While libxkbcommon's API is somewhat derived from the classic XKB API as found
in X11/extensions/XKB.h and friends, it has been substantially reworked to
expose fewer internal details to clients. The supported API is available
in the xkbcommon/xkbcommon-*.h files. Additional support is provided for
X11 (XCB) clients, in the xkbcommon-x11 library, xkbcommon/xkbcommon-x11.h.
expose fewer internal details to clients.
The xkbcommon API and ABI are stable. We will attempt to not break ABI during
a minor release series, so applications written against 0.1.0 should be
completely compatible with 0.5.3, but not necessarily with 1.0.0. However, new
symbols may be introduced in any release. Thus, anyone packaging xkbcommon
should make sure any package depending on it depends on a release greater than
or equal to the version it was built against (or earlier, if it doesn't use
any newly-introduced symbols), but less than the next major release.
See the [API Documentation](https://xkbcommon.org/doc/current/modules.html).
## Dataset
libxkbcommon does not distribute a keymap dataset itself, other than for
testing purposes. The most common dataset is xkeyboard-config, which is used
by all current distributions for their X11 XKB data. More information on
xkeyboard-config is available here:
https://www.freedesktop.org/wiki/Software/XKeyboardConfig
The dataset for Compose is distributed in libX11, as part of the X locale
data.
## Relation to X11
Relative to the XKB 1.1 specification implemented in current X servers,
xkbcommon has removed support for some parts of the specification which
introduced unnecessary complications. Many of these removals were in fact
not implemented, or half-implemented at best, as well as being totally
unused in the standard dataset.
Notable removals:
- geometry support
+ there were very few geometry definitions available, and while
xkbcommon was responsible for parsing this insanely complex format,
it never actually did anything with it
+ hopefully someone will develop a companion library which supports
keyboard geometries in a more useful format
- KcCGST (keycodes/compat/geometry/symbols/types) API
+ use RMLVO instead; KcCGST is now an implementation detail
+ including pre-defined keymap files
- XKM support
+ may come in an optional X11 support/compatibility library
- around half of the interpret actions
+ pointer device, message and redirect actions in particular
- non-virtual modifiers
+ core and virtual modifiers have been collapsed into the same
namespace, with a 'significant' flag that largely parallels the
core/virtual split
- radio groups
+ completely unused in current keymaps, never fully implemented
- overlays
+ almost completely unused in current keymaps
- key behaviors
+ used to implement radio groups and overlays, and to deal with things
like keys that physically lock; unused in current keymaps
- indicator behaviours such as LED-controls-key
+ the only supported LED behaviour is key-controls-LED; again this
was never really used in current keymaps
Notable additions:
- 32-bit keycodes
- extended number of modifiers
- extended number of groups
- multiple keysyms per level
+ this requires incompatible dataset changes, such that X11 would
not be able to parse these
See [Compatibility](doc/compat.md) notes.
## Development
An extremely rudimentary homepage can be found at
http://xkbcommon.org
https://xkbcommon.org
xkbcommon is maintained in git at
https://github.com/xkbcommon/libxkbcommon
Patches are always welcome, and may be sent to either
<xorg-devel@lists.x.org> or <wayland-devel@lists.freedesktop.org>
or through github.
Bugs are also welcome, and may be reported either at
Bug reports are also welcome, and may be filed either at
Bugzilla https://bugs.freedesktop.org/describecomponents.cgi?product=libxkbcommon
or
Github https://github.com/xkbcommon/libxkbcommon/issues

View File

@ -6,22 +6,24 @@
"Description": "xkbcommon is a keymap compiler and support library which processes a reduced subset of keymaps as defined by the XKB specification.",
"Homepage": "http://xkbcommon.org/",
"Version": "0.4.1",
"Version": "0.8.2 + subsequent commits up to 31f1f355700870c6615399fbfa7934934b3a9a57",
"License": "MIT Licenses (with no-advertisement clause)",
"LicenseId": "MIT",
"LicenseFile": "COPYING",
"Copyright": "Copyright 1985, 1987, 1988, 1990, 1998 The Open Group
Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
"LicenseFile": "LICENSE",
"Copyright": "Copyright 2009-2012, 2016 Daniel Stone
Copyright 2012 Ran Benita <ran234@gmail.com>
Copyright 2010, 2012 Intel Corporation
Copyright 2008, 2009 Dan Nicholson
Copyright 2010 Francisco Jerez <currojerez@riseup.net>
Copyright 1985, 1987, 1988, 1990, 1998 The Open Group
Copyright 1993, 1994, 1995, 1996 by Silicon Graphics Computer Systems, Inc.
Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
Copyright 2011 Joseph Adams <joeyadams3.14159@gmail.com>
Copyright 1996 by Joseph Moss
Copyright 2002-2007 Free Software Foundation, Inc.
Copyright 2003-2004 Dmitry Golubev <lastguru@mail.ru>
Copyright 2004, Gregory Mokhin <mokhin@bog.msu.ru>
Copyright 2006 Erdal Ronahî
Copyright 2008, 2009 Dan Nicholson
Copyright 2009-2012 Daniel Stone
Copyright 2010, 2012 Intel Corporation
Copyright 2010 Francisco Jerez <currojerez@riseup.net>
Copyright 2011 Joseph Adams <joeyadams3.14159@gmail.com>
Copyright 2012 Ran Benita <ran234@gmail.com>"
Copyright 1992 by Oki Technosystems Laboratory, Inc.
Copyright 1992 by Fuji Xerox Co., Ltd."
}

View File

@ -0,0 +1,196 @@
/*
* Copyright © 2013 Ran Benita <ran234@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "table.h"
#include "utils.h"
#include "keysym.h"
struct xkb_compose_state {
int refcnt;
enum xkb_compose_state_flags flags;
struct xkb_compose_table *table;
/*
* Offsets into xkb_compose_table::nodes.
*
* They maintain the current and previous position in the trie; see
* xkb_compose_state_feed().
*
* This is also sufficient for inferring the current status; see
* xkb_compose_state_get_status().
*/
uint32_t prev_context;
uint32_t context;
};
XKB_EXPORT struct xkb_compose_state *
xkb_compose_state_new(struct xkb_compose_table *table,
enum xkb_compose_state_flags flags)
{
struct xkb_compose_state *state;
state = calloc(1, sizeof(*state));
if (!state)
return NULL;
state->refcnt = 1;
state->table = xkb_compose_table_ref(table);
state->flags = flags;
state->prev_context = 0;
state->context = 0;
return state;
}
XKB_EXPORT struct xkb_compose_state *
xkb_compose_state_ref(struct xkb_compose_state *state)
{
state->refcnt++;
return state;
}
XKB_EXPORT void
xkb_compose_state_unref(struct xkb_compose_state *state)
{
if (!state || --state->refcnt > 0)
return;
xkb_compose_table_unref(state->table);
free(state);
}
XKB_EXPORT struct xkb_compose_table *
xkb_compose_state_get_compose_table(struct xkb_compose_state *state)
{
return state->table;
}
XKB_EXPORT enum xkb_compose_feed_result
xkb_compose_state_feed(struct xkb_compose_state *state, xkb_keysym_t keysym)
{
uint32_t context;
const struct compose_node *node;
/*
* Modifiers do not affect the sequence directly. In particular,
* they do not cancel a sequence; otherwise it'd be impossible to
* have a sequence like <dead_acute><A> (needs Shift in the middle).
*
* The following test is not really accurate - in order to test if
* a key is "modifier key", we really need the keymap, but we don't
* have it here. However, this is (approximately) what libX11 does
* as well.
*/
if (xkb_keysym_is_modifier(keysym))
return XKB_COMPOSE_FEED_IGNORED;
node = &darray_item(state->table->nodes, state->context);
context = (node->is_leaf ? 0 : node->u.successor);
node = &darray_item(state->table->nodes, context);
while (node->keysym != keysym && node->next != 0) {
context = node->next;
node = &darray_item(state->table->nodes, context);
}
if (node->keysym != keysym)
context = 0;
state->prev_context = state->context;
state->context = context;
return XKB_COMPOSE_FEED_ACCEPTED;
}
XKB_EXPORT void
xkb_compose_state_reset(struct xkb_compose_state *state)
{
state->prev_context = 0;
state->context = 0;
}
XKB_EXPORT enum xkb_compose_status
xkb_compose_state_get_status(struct xkb_compose_state *state)
{
const struct compose_node *prev_node, *node;
prev_node = &darray_item(state->table->nodes, state->prev_context);
node = &darray_item(state->table->nodes, state->context);
if (state->context == 0 && !prev_node->is_leaf)
return XKB_COMPOSE_CANCELLED;
if (state->context == 0)
return XKB_COMPOSE_NOTHING;
if (!node->is_leaf)
return XKB_COMPOSE_COMPOSING;
return XKB_COMPOSE_COMPOSED;
}
XKB_EXPORT int
xkb_compose_state_get_utf8(struct xkb_compose_state *state,
char *buffer, size_t size)
{
const struct compose_node *node =
&darray_item(state->table->nodes, state->context);
if (!node->is_leaf)
goto fail;
/* If there's no string specified, but only a keysym, try to do the
* most helpful thing. */
if (node->u.leaf.utf8 == 0 && node->u.leaf.keysym != XKB_KEY_NoSymbol) {
char name[64];
int ret;
ret = xkb_keysym_to_utf8(node->u.leaf.keysym, name, sizeof(name));
if (ret < 0 || ret == 0) {
/* ret < 0 is impossible.
* ret == 0 means the keysym has no string representation. */
goto fail;
}
return snprintf(buffer, size, "%s", name);
}
return snprintf(buffer, size, "%s",
&darray_item(state->table->utf8, node->u.leaf.utf8));
fail:
if (size > 0)
buffer[0] = '\0';
return 0;
}
XKB_EXPORT xkb_keysym_t
xkb_compose_state_get_one_sym(struct xkb_compose_state *state)
{
const struct compose_node *node =
&darray_item(state->table->nodes, state->context);
if (!node->is_leaf)
return XKB_KEY_NoSymbol;
return node->u.leaf.keysym;
}

View File

@ -0,0 +1,737 @@
/*
* Copyright © 2013 Ran Benita <ran234@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
/******************************************************************
Copyright 1992 by Oki Technosystems Laboratory, Inc.
Copyright 1992 by Fuji Xerox Co., Ltd.
Permission to use, copy, modify, distribute, and sell this software
and its documentation for any purpose is hereby granted without fee,
provided that the above copyright notice appear in all copies and
that both that copyright notice and this permission notice appear
in supporting documentation, and that the name of Oki Technosystems
Laboratory and Fuji Xerox not be used in advertising or publicity
pertaining to distribution of the software without specific, written
prior permission.
Oki Technosystems Laboratory and Fuji Xerox make no representations
about the suitability of this software for any purpose. It is provided
"as is" without express or implied warranty.
OKI TECHNOSYSTEMS LABORATORY AND FUJI XEROX DISCLAIM ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL OKI TECHNOSYSTEMS
LABORATORY AND FUJI XEROX BE LIABLE FOR ANY SPECIAL, INDIRECT OR
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
OR PERFORMANCE OF THIS SOFTWARE.
Author: Yasuhiro Kawai Oki Technosystems Laboratory
Author: Kazunori Nishihara Fuji Xerox
******************************************************************/
#include <errno.h>
#include "utils.h"
#include "scanner-utils.h"
#include "table.h"
#include "paths.h"
#include "utf8.h"
#include "parser.h"
#define MAX_LHS_LEN 10
#define MAX_INCLUDE_DEPTH 5
/*
* Grammar adapted from libX11/modules/im/ximcp/imLcPrs.c.
* See also the XCompose(5) manpage.
*
* FILE ::= { [PRODUCTION] [COMMENT] "\n" | INCLUDE }
* INCLUDE ::= "include" '"' INCLUDE_STRING '"'
* PRODUCTION ::= LHS ":" RHS [ COMMENT ]
* COMMENT ::= "#" {<any character except null or newline>}
* LHS ::= EVENT { EVENT }
* EVENT ::= [MODIFIER_LIST] "<" keysym ">"
* MODIFIER_LIST ::= (["!"] {MODIFIER} ) | "None"
* MODIFIER ::= ["~"] MODIFIER_NAME
* MODIFIER_NAME ::= ("Ctrl"|"Lock"|"Caps"|"Shift"|"Alt"|"Meta")
* RHS ::= ( STRING | keysym | STRING keysym )
* STRING ::= '"' { CHAR } '"'
* CHAR ::= GRAPHIC_CHAR | ESCAPED_CHAR
* GRAPHIC_CHAR ::= locale (codeset) dependent code
* ESCAPED_CHAR ::= ('\\' | '\"' | OCTAL | HEX )
* OCTAL ::= '\' OCTAL_CHAR [OCTAL_CHAR [OCTAL_CHAR]]
* OCTAL_CHAR ::= (0|1|2|3|4|5|6|7)
* HEX ::= '\' (x|X) HEX_CHAR [HEX_CHAR]]
* HEX_CHAR ::= (0|1|2|3|4|5|6|7|8|9|A|B|C|D|E|F|a|b|c|d|e|f)
*
* INCLUDE_STRING is a filesystem path, with the following %-expansions:
* %% - '%'.
* %H - The user's home directory (the $HOME environment variable).
* %L - The name of the locale specific Compose file (e.g.,
* "/usr/share/X11/locale/<localename>/Compose").
* %S - The name of the system directory for Compose files (e.g.,
* "/usr/share/X11/locale").
*/
enum rules_token {
TOK_END_OF_FILE = 0,
TOK_END_OF_LINE,
TOK_INCLUDE,
TOK_INCLUDE_STRING,
TOK_LHS_KEYSYM,
TOK_COLON,
TOK_BANG,
TOK_TILDE,
TOK_STRING,
TOK_IDENT,
TOK_ERROR
};
/* Values returned with some tokens, like yylval. */
union lvalue {
struct {
/* Still \0-terminated. */
const char *str;
size_t len;
} string;
};
static enum rules_token
lex(struct scanner *s, union lvalue *val)
{
skip_more_whitespace_and_comments:
/* Skip spaces. */
while (is_space(peek(s)))
if (next(s) == '\n')
return TOK_END_OF_LINE;
/* Skip comments. */
if (chr(s, '#')) {
skip_to_eol(s);
goto skip_more_whitespace_and_comments;
}
/* See if we're done. */
if (eof(s)) return TOK_END_OF_FILE;
/* New token. */
s->token_line = s->line;
s->token_column = s->column;
s->buf_pos = 0;
/* LHS Keysym. */
if (chr(s, '<')) {
while (peek(s) != '>' && !eol(s) && !eof(s))
buf_append(s, next(s));
if (!chr(s, '>')) {
scanner_err(s, "unterminated keysym literal");
return TOK_ERROR;
}
if (!buf_append(s, '\0')) {
scanner_err(s, "keysym literal is too long");
return TOK_ERROR;
}
val->string.str = s->buf;
val->string.len = s->buf_pos;
return TOK_LHS_KEYSYM;
}
/* Colon. */
if (chr(s, ':'))
return TOK_COLON;
if (chr(s, '!'))
return TOK_BANG;
if (chr(s, '~'))
return TOK_TILDE;
/* String literal. */
if (chr(s, '\"')) {
while (!eof(s) && !eol(s) && peek(s) != '\"') {
if (chr(s, '\\')) {
uint8_t o;
if (chr(s, '\\')) {
buf_append(s, '\\');
}
else if (chr(s, '"')) {
buf_append(s, '"');
}
else if (chr(s, 'x') || chr(s, 'X')) {
if (hex(s, &o))
buf_append(s, (char) o);
else
scanner_warn(s, "illegal hexadecimal escape sequence in string literal");
}
else if (oct(s, &o)) {
buf_append(s, (char) o);
}
else {
scanner_warn(s, "unknown escape sequence (%c) in string literal", peek(s));
/* Ignore. */
}
} else {
buf_append(s, next(s));
}
}
if (!chr(s, '\"')) {
scanner_err(s, "unterminated string literal");
return TOK_ERROR;
}
if (!buf_append(s, '\0')) {
scanner_err(s, "string literal is too long");
return TOK_ERROR;
}
if (!is_valid_utf8(s->buf, s->buf_pos - 1)) {
scanner_err(s, "string literal is not a valid UTF-8 string");
return TOK_ERROR;
}
val->string.str = s->buf;
val->string.len = s->buf_pos;
return TOK_STRING;
}
/* Identifier or include. */
if (is_alpha(peek(s)) || peek(s) == '_') {
s->buf_pos = 0;
while (is_alnum(peek(s)) || peek(s) == '_')
buf_append(s, next(s));
if (!buf_append(s, '\0')) {
scanner_err(s, "identifier is too long");
return TOK_ERROR;
}
if (streq(s->buf, "include"))
return TOK_INCLUDE;
val->string.str = s->buf;
val->string.len = s->buf_pos;
return TOK_IDENT;
}
/* Discard rest of line. */
skip_to_eol(s);
scanner_err(s, "unrecognized token");
return TOK_ERROR;
}
static enum rules_token
lex_include_string(struct scanner *s, struct xkb_compose_table *table,
union lvalue *val_out)
{
while (is_space(peek(s)))
if (next(s) == '\n')
return TOK_END_OF_LINE;
s->token_line = s->line;
s->token_column = s->column;
s->buf_pos = 0;
if (!chr(s, '\"')) {
scanner_err(s, "include statement must be followed by a path");
return TOK_ERROR;
}
while (!eof(s) && !eol(s) && peek(s) != '\"') {
if (chr(s, '%')) {
if (chr(s, '%')) {
buf_append(s, '%');
}
else if (chr(s, 'H')) {
const char *home = secure_getenv("HOME");
if (!home) {
scanner_err(s, "%%H was used in an include statement, but the HOME environment variable is not set");
return TOK_ERROR;
}
if (!buf_appends(s, home)) {
scanner_err(s, "include path after expanding %%H is too long");
return TOK_ERROR;
}
}
else if (chr(s, 'L')) {
char *path = get_locale_compose_file_path(table->locale);
if (!path) {
scanner_err(s, "failed to expand %%L to the locale Compose file");
return TOK_ERROR;
}
if (!buf_appends(s, path)) {
free(path);
scanner_err(s, "include path after expanding %%L is too long");
return TOK_ERROR;
}
free(path);
}
else if (chr(s, 'S')) {
const char *xlocaledir = get_xlocaledir_path();
if (!buf_appends(s, xlocaledir)) {
scanner_err(s, "include path after expanding %%S is too long");
return TOK_ERROR;
}
}
else {
scanner_err(s, "unknown %% format (%c) in include statement", peek(s));
return TOK_ERROR;
}
} else {
buf_append(s, next(s));
}
}
if (!chr(s, '\"')) {
scanner_err(s, "unterminated include statement");
return TOK_ERROR;
}
if (!buf_append(s, '\0')) {
scanner_err(s, "include path is too long");
return TOK_ERROR;
}
val_out->string.str = s->buf;
val_out->string.len = s->buf_pos;
return TOK_INCLUDE_STRING;
}
struct production {
xkb_keysym_t lhs[MAX_LHS_LEN];
unsigned int len;
xkb_keysym_t keysym;
char string[256];
/* At least one of these is true. */
bool has_keysym;
bool has_string;
/* The matching is as follows: (active_mods & modmask) == mods. */
xkb_mod_mask_t modmask;
xkb_mod_mask_t mods;
};
static uint32_t
add_node(struct xkb_compose_table *table, xkb_keysym_t keysym)
{
struct compose_node new = {
.keysym = keysym,
.next = 0,
.is_leaf = true,
};
darray_append(table->nodes, new);
return darray_size(table->nodes) - 1;
}
static void
add_production(struct xkb_compose_table *table, struct scanner *s,
const struct production *production)
{
unsigned lhs_pos;
uint32_t curr;
struct compose_node *node;
curr = 0;
node = &darray_item(table->nodes, curr);
/*
* Insert the sequence to the trie, creating new nodes as needed.
*
* TODO: This can be sped up a bit by first trying the path that the
* previous production took, and only then doing the linear search
* through the trie levels. This will work because sequences in the
* Compose files are often clustered by a common prefix; especially
* in the 1st and 2nd keysyms, which is where the largest variation
* (thus, longest search) is.
*/
for (lhs_pos = 0; lhs_pos < production->len; lhs_pos++) {
while (production->lhs[lhs_pos] != node->keysym) {
if (node->next == 0) {
uint32_t next = add_node(table, production->lhs[lhs_pos]);
/* Refetch since add_node could have realloc()ed. */
node = &darray_item(table->nodes, curr);
node->next = next;
}
curr = node->next;
node = &darray_item(table->nodes, curr);
}
if (lhs_pos + 1 == production->len)
break;
if (node->is_leaf) {
if (node->u.leaf.utf8 != 0 ||
node->u.leaf.keysym != XKB_KEY_NoSymbol) {
scanner_warn(s, "a sequence already exists which is a prefix of this sequence; overriding");
node->u.leaf.utf8 = 0;
node->u.leaf.keysym = XKB_KEY_NoSymbol;
}
{
uint32_t successor = add_node(table, production->lhs[lhs_pos + 1]);
/* Refetch since add_node could have realloc()ed. */
node = &darray_item(table->nodes, curr);
node->is_leaf = false;
node->u.successor = successor;
}
}
curr = node->u.successor;
node = &darray_item(table->nodes, curr);
}
if (!node->is_leaf) {
scanner_warn(s, "this compose sequence is a prefix of another; skipping line");
return;
}
if (node->u.leaf.utf8 != 0 || node->u.leaf.keysym != XKB_KEY_NoSymbol) {
bool same_string =
(node->u.leaf.utf8 == 0 && !production->has_string) ||
(
node->u.leaf.utf8 != 0 && production->has_string &&
streq(&darray_item(table->utf8, node->u.leaf.utf8),
production->string)
);
bool same_keysym =
(node->u.leaf.keysym == XKB_KEY_NoSymbol && !production->has_keysym) ||
(
node->u.leaf.keysym != XKB_KEY_NoSymbol && production->has_keysym &&
node->u.leaf.keysym == production->keysym
);
if (same_string && same_keysym) {
scanner_warn(s, "this compose sequence is a duplicate of another; skipping line");
return;
}
scanner_warn(s, "this compose sequence already exists; overriding");
}
if (production->has_string) {
node->u.leaf.utf8 = darray_size(table->utf8);
darray_append_items(table->utf8, production->string,
strlen(production->string) + 1);
}
if (production->has_keysym) {
node->u.leaf.keysym = production->keysym;
}
}
/* Should match resolve_modifier(). */
#define ALL_MODS_MASK ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3))
static xkb_mod_index_t
resolve_modifier(const char *name)
{
static const struct {
const char *name;
xkb_mod_index_t mod;
} mods[] = {
{ "Shift", 0 },
{ "Ctrl", 2 },
{ "Alt", 3 },
{ "Meta", 3 },
{ "Lock", 1 },
{ "Caps", 1 },
};
for (unsigned i = 0; i < ARRAY_SIZE(mods); i++)
if (streq(name, mods[i].name))
return mods[i].mod;
return XKB_MOD_INVALID;
}
static bool
parse(struct xkb_compose_table *table, struct scanner *s,
unsigned include_depth);
static bool
do_include(struct xkb_compose_table *table, struct scanner *s,
const char *path, unsigned include_depth)
{
FILE *file;
bool ok;
char *string;
size_t size;
struct scanner new_s;
if (include_depth >= MAX_INCLUDE_DEPTH) {
scanner_err(s, "maximum include depth (%d) exceeded; maybe there is an include loop?",
MAX_INCLUDE_DEPTH);
return false;
}
file = fopen(path, "r");
if (!file) {
scanner_err(s, "failed to open included Compose file \"%s\": %s",
path, strerror(errno));
return false;
}
ok = map_file(file, &string, &size);
if (!ok) {
scanner_err(s, "failed to read included Compose file \"%s\": %s",
path, strerror(errno));
goto err_file;
}
scanner_init(&new_s, table->ctx, string, size, path, s->priv);
ok = parse(table, &new_s, include_depth + 1);
if (!ok)
goto err_unmap;
err_unmap:
unmap_file(string, size);
err_file:
fclose(file);
return ok;
}
static bool
parse(struct xkb_compose_table *table, struct scanner *s,
unsigned include_depth)
{
enum rules_token tok;
union lvalue val;
xkb_keysym_t keysym;
struct production production;
enum { MAX_ERRORS = 10 };
int num_errors = 0;
initial:
production.len = 0;
production.has_keysym = false;
production.has_string = false;
production.mods = 0;
production.modmask = 0;
/* fallthrough */
initial_eol:
switch (tok = lex(s, &val)) {
case TOK_END_OF_LINE:
goto initial_eol;
case TOK_END_OF_FILE:
goto finished;
case TOK_INCLUDE:
goto include;
default:
goto lhs_tok;
}
include:
switch (tok = lex_include_string(s, table, &val)) {
case TOK_INCLUDE_STRING:
goto include_eol;
default:
goto unexpected;
}
include_eol:
switch (tok = lex(s, &val)) {
case TOK_END_OF_LINE:
if (!do_include(table, s, val.string.str, include_depth))
goto fail;
goto initial;
default:
goto unexpected;
}
lhs:
tok = lex(s, &val);
lhs_tok:
switch (tok) {
case TOK_COLON:
if (production.len <= 0) {
scanner_warn(s, "expected at least one keysym on left-hand side; skipping line");
goto skip;
}
goto rhs;
case TOK_IDENT:
if (streq(val.string.str, "None")) {
production.mods = 0;
production.modmask = ALL_MODS_MASK;
goto lhs_keysym;
}
goto lhs_mod_list_tok;
case TOK_TILDE:
goto lhs_mod_list_tok;
case TOK_BANG:
production.modmask = ALL_MODS_MASK;
goto lhs_mod_list;
default:
goto lhs_keysym_tok;
}
lhs_keysym:
tok = lex(s, &val);
lhs_keysym_tok:
switch (tok) {
case TOK_LHS_KEYSYM:
keysym = xkb_keysym_from_name(val.string.str, XKB_KEYSYM_NO_FLAGS);
if (keysym == XKB_KEY_NoSymbol) {
scanner_err(s, "unrecognized keysym \"%s\" on left-hand side",
val.string.str);
goto error;
}
if (production.len + 1 > MAX_LHS_LEN) {
scanner_warn(s, "too many keysyms (%d) on left-hand side; skipping line",
MAX_LHS_LEN + 1);
goto skip;
}
production.lhs[production.len++] = keysym;
production.mods = 0;
production.modmask = 0;
goto lhs;
default:
goto unexpected;
}
lhs_mod_list:
tok = lex(s, &val);
lhs_mod_list_tok: {
bool tilde = false;
xkb_mod_index_t mod;
if (tok != TOK_TILDE && tok != TOK_IDENT)
goto lhs_keysym_tok;
if (tok == TOK_TILDE) {
tilde = true;
tok = lex(s, &val);
}
if (tok != TOK_IDENT)
goto unexpected;
mod = resolve_modifier(val.string.str);
if (mod == XKB_MOD_INVALID) {
scanner_err(s, "unrecognized modifier \"%s\"",
val.string.str);
goto error;
}
production.modmask |= 1 << mod;
if (tilde)
production.mods &= ~(1 << mod);
else
production.mods |= 1 << mod;
goto lhs_mod_list;
}
rhs:
switch (tok = lex(s, &val)) {
case TOK_STRING:
if (production.has_string) {
scanner_warn(s, "right-hand side can have at most one string; skipping line");
goto skip;
}
if (val.string.len <= 0) {
scanner_warn(s, "right-hand side string must not be empty; skipping line");
goto skip;
}
if (val.string.len >= sizeof(production.string)) {
scanner_warn(s, "right-hand side string is too long; skipping line");
goto skip;
}
strcpy(production.string, val.string.str);
production.has_string = true;
goto rhs;
case TOK_IDENT:
keysym = xkb_keysym_from_name(val.string.str, XKB_KEYSYM_NO_FLAGS);
if (keysym == XKB_KEY_NoSymbol) {
scanner_err(s, "unrecognized keysym \"%s\" on right-hand side",
val.string.str);
goto error;
}
if (production.has_keysym) {
scanner_warn(s, "right-hand side can have at most one keysym; skipping line");
goto skip;
}
production.keysym = keysym;
production.has_keysym = true;
/* fallthrough */
case TOK_END_OF_LINE:
if (!production.has_string && !production.has_keysym) {
scanner_warn(s, "right-hand side must have at least one of string or keysym; skipping line");
goto skip;
}
add_production(table, s, &production);
goto initial;
default:
goto unexpected;
}
unexpected:
if (tok != TOK_ERROR)
scanner_err(s, "unexpected token");
error:
num_errors++;
if (num_errors <= MAX_ERRORS)
goto skip;
scanner_err(s, "too many errors");
goto fail;
fail:
scanner_err(s, "failed to parse file");
return false;
skip:
while (tok != TOK_END_OF_LINE && tok != TOK_END_OF_FILE)
tok = lex(s, &val);
goto initial;
finished:
return true;
}
bool
parse_string(struct xkb_compose_table *table, const char *string, size_t len,
const char *file_name)
{
struct scanner s;
scanner_init(&s, table->ctx, string, len, file_name, NULL);
if (!parse(table, &s, 0))
return false;
/* Maybe the allocator can use the excess space. */
darray_shrink(table->nodes);
darray_shrink(table->utf8);
return true;
}
bool
parse_file(struct xkb_compose_table *table, FILE *file, const char *file_name)
{
bool ok;
char *string;
size_t size;
ok = map_file(file, &string, &size);
if (!ok) {
log_err(table->ctx, "Couldn't read Compose file %s: %s\n",
file_name, strerror(errno));
return false;
}
ok = parse_string(table, string, size, file_name);
unmap_file(string, size);
return ok;
}

View File

@ -0,0 +1,36 @@
/*
* Copyright © 2013 Ran Benita <ran234@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef COMPOSE_PARSER_H
#define COMPOSE_PARSER_H
bool
parse_string(struct xkb_compose_table *table,
const char *string, size_t len,
const char *file_name);
bool
parse_file(struct xkb_compose_table *table,
FILE *file, const char *file_name);
#endif

View File

@ -0,0 +1,203 @@
/*
* Copyright © 2014 Ran Benita <ran234@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "utils.h"
#include "paths.h"
enum resolve_name_direction {
LEFT_TO_RIGHT,
RIGHT_TO_LEFT,
};
const char *
get_xlocaledir_path(void)
{
const char *dir = secure_getenv("XLOCALEDIR");
if (!dir)
dir = XLOCALEDIR;
return dir;
}
/*
* Files like compose.dir have the format LEFT: RIGHT. Lookup @name in
* such a file and return its matching value, according to @direction.
* @filename is relative to the xlocaledir.
*/
static char *
resolve_name(const char *filename, enum resolve_name_direction direction,
const char *name)
{
int ret;
bool ok;
const char *xlocaledir;
char path[512];
FILE *file;
char *string;
size_t string_size;
const char *end;
const char *s, *left, *right;
char *match;
size_t left_len, right_len, name_len;
xlocaledir = get_xlocaledir_path();
ret = snprintf(path, sizeof(path), "%s/%s", xlocaledir, filename);
if (ret < 0 || (size_t) ret >= sizeof(path))
return false;
file = fopen(path, "r");
if (!file)
return false;
ok = map_file(file, &string, &string_size);
fclose(file);
if (!ok)
return false;
s = string;
end = string + string_size;
name_len = strlen(name);
match = NULL;
while (s < end) {
/* Skip spaces. */
while (s < end && is_space(*s))
s++;
/* Skip comments. */
if (s < end && *s == '#') {
while (s < end && *s != '\n')
s++;
continue;
}
/* Get the left value. */
left = s;
while (s < end && !is_space(*s) && *s != ':')
s++;
left_len = s - left;
/* There's an optional colon between left and right. */
if (s < end && *s == ':')
s++;
/* Skip spaces. */
while (s < end && is_space(*s))
s++;
/* Get the right value. */
right = s;
while (s < end && !is_space(*s))
s++;
right_len = s - right;
/* Discard rest of line. */
while (s < end && *s != '\n')
s++;
if (direction == LEFT_TO_RIGHT) {
if (left_len == name_len && memcmp(left, name, left_len) == 0) {
match = strndup(right, right_len);
break;
}
}
else if (direction == RIGHT_TO_LEFT) {
if (right_len == name_len && memcmp(right, name, right_len) == 0) {
match = strndup(left, left_len);
break;
}
}
}
unmap_file(string, string_size);
return match;
}
char *
resolve_locale(const char *locale)
{
char *alias = resolve_name("locale.alias", LEFT_TO_RIGHT, locale);
return alias ? alias : strdup(locale);
}
const char *
get_xcomposefile_path(void)
{
return secure_getenv("XCOMPOSEFILE");
}
char *
get_home_xcompose_file_path(void)
{
int ret;
const char *home;
char *path;
home = secure_getenv("HOME");
if (!home)
return NULL;
ret = asprintf(&path, "%s/.XCompose", home);
if (ret <0)
return NULL;
return path;
}
char *
get_locale_compose_file_path(const char *locale)
{
char *resolved;
char *path;
/*
* WARNING: Random workaround ahead.
*
* We currently do not support non-UTF-8 Compose files. The C/POSIX
* locale is specified to be the default fallback locale with an
* ASCII charset. But for some reason the compose.dir points the C
* locale to the iso8859-1/Compose file, which is not ASCII but
* ISO8859-1. Since this is bound to happen a lot, and since our API
* is UTF-8 based, and since 99% of the time a C locale is really just
* a misconfiguration for UTF-8, let's do the most helpful thing.
*/
if (streq(locale, "C"))
locale = "en_US.UTF-8";
resolved = resolve_name("compose.dir", RIGHT_TO_LEFT, locale);
if (!resolved)
return NULL;
if (resolved[0] == '/') {
path = resolved;
}
else {
const char *xlocaledir = get_xlocaledir_path();
int ret = asprintf(&path, "%s/%s", xlocaledir, resolved);
free(resolved);
if (ret < 0)
return NULL;
}
return path;
}

View File

@ -0,0 +1,42 @@
/*
* Copyright © 2014 Ran Benita <ran234@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef COMPOSE_RESOLVE_H
#define COMPOSE_RESOLVE_H
char *
resolve_locale(const char *locale);
const char *
get_xlocaledir_path(void);
const char *
get_xcomposefile_path(void);
char *
get_home_xcompose_file_path(void);
char *
get_locale_compose_file_path(const char *locale);
#endif

View File

@ -0,0 +1,219 @@
/*
* Copyright © 2013 Ran Benita <ran234@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "utils.h"
#include "table.h"
#include "parser.h"
#include "paths.h"
static struct xkb_compose_table *
xkb_compose_table_new(struct xkb_context *ctx,
const char *locale,
enum xkb_compose_format format,
enum xkb_compose_compile_flags flags)
{
char *resolved_locale;
struct xkb_compose_table *table;
struct compose_node root;
resolved_locale = resolve_locale(locale);
if (!resolved_locale)
return NULL;
table = calloc(1, sizeof(*table));
if (!table) {
free(resolved_locale);
return NULL;
}
table->refcnt = 1;
table->ctx = xkb_context_ref(ctx);
table->locale = resolved_locale;
table->format = format;
table->flags = flags;
darray_init(table->nodes);
darray_init(table->utf8);
root.keysym = XKB_KEY_NoSymbol;
root.next = 0;
root.is_leaf = true;
root.u.leaf.utf8 = 0;
root.u.leaf.keysym = XKB_KEY_NoSymbol;
darray_append(table->nodes, root);
darray_append(table->utf8, '\0');
return table;
}
XKB_EXPORT struct xkb_compose_table *
xkb_compose_table_ref(struct xkb_compose_table *table)
{
table->refcnt++;
return table;
}
XKB_EXPORT void
xkb_compose_table_unref(struct xkb_compose_table *table)
{
if (!table || --table->refcnt > 0)
return;
free(table->locale);
darray_free(table->nodes);
darray_free(table->utf8);
xkb_context_unref(table->ctx);
free(table);
}
XKB_EXPORT struct xkb_compose_table *
xkb_compose_table_new_from_file(struct xkb_context *ctx,
FILE *file,
const char *locale,
enum xkb_compose_format format,
enum xkb_compose_compile_flags flags)
{
struct xkb_compose_table *table;
bool ok;
if (flags & ~(XKB_COMPOSE_COMPILE_NO_FLAGS)) {
log_err_func(ctx, "unrecognized flags: %#x\n", flags);
return NULL;
}
if (format != XKB_COMPOSE_FORMAT_TEXT_V1) {
log_err_func(ctx, "unsupported compose format: %d\n", format);
return NULL;
}
table = xkb_compose_table_new(ctx, locale, format, flags);
if (!table)
return NULL;
ok = parse_file(table, file, "(unknown file)");
if (!ok) {
xkb_compose_table_unref(table);
return NULL;
}
return table;
}
XKB_EXPORT struct xkb_compose_table *
xkb_compose_table_new_from_buffer(struct xkb_context *ctx,
const char *buffer, size_t length,
const char *locale,
enum xkb_compose_format format,
enum xkb_compose_compile_flags flags)
{
struct xkb_compose_table *table;
bool ok;
if (flags & ~(XKB_COMPOSE_COMPILE_NO_FLAGS)) {
log_err_func(ctx, "unrecognized flags: %#x\n", flags);
return NULL;
}
if (format != XKB_COMPOSE_FORMAT_TEXT_V1) {
log_err_func(ctx, "unsupported compose format: %d\n", format);
return NULL;
}
table = xkb_compose_table_new(ctx, locale, format, flags);
if (!table)
return NULL;
ok = parse_string(table, buffer, length, "(input string)");
if (!ok) {
xkb_compose_table_unref(table);
return NULL;
}
return table;
}
XKB_EXPORT struct xkb_compose_table *
xkb_compose_table_new_from_locale(struct xkb_context *ctx,
const char *locale,
enum xkb_compose_compile_flags flags)
{
struct xkb_compose_table *table;
char *path = NULL;
const char *cpath;
FILE *file;
bool ok;
if (flags & ~(XKB_COMPOSE_COMPILE_NO_FLAGS)) {
log_err_func(ctx, "unrecognized flags: %#x\n", flags);
return NULL;
}
table = xkb_compose_table_new(ctx, locale, XKB_COMPOSE_FORMAT_TEXT_V1,
flags);
if (!table)
return NULL;
cpath = get_xcomposefile_path();
if (cpath) {
file = fopen(cpath, "r");
if (file)
goto found_path;
}
cpath = path = get_home_xcompose_file_path();
if (path) {
file = fopen(path, "r");
if (file)
goto found_path;
}
free(path);
path = NULL;
cpath = path = get_locale_compose_file_path(table->locale);
if (path) {
file = fopen(path, "r");
if (file)
goto found_path;
}
free(path);
path = NULL;
log_err(ctx, "couldn't find a Compose file for locale \"%s\"\n", locale);
xkb_compose_table_unref(table);
return NULL;
found_path:
ok = parse_file(table, file, cpath);
fclose(file);
if (!ok) {
xkb_compose_table_unref(table);
return NULL;
}
log_dbg(ctx, "created compose table from locale %s with path %s\n",
table->locale, path);
free(path);
return table;
}

View File

@ -0,0 +1,100 @@
/*
* Copyright © 2013 Ran Benita <ran234@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef COMPOSE_COMPOSE_H
#define COMPOSE_COMPOSE_H
#include "xkbcommon/xkbcommon-compose.h"
#include "utils.h"
#include "context.h"
/*
* The compose table data structure is a simple trie. An example will
* help. Given these sequences:
*
* <A> <B> : "first" dead_a
* <A> <C> <D> : "second" dead_b
* <E> <F> : "third" dead_c
*
* the trie would look like:
*
* [root] ---> [<A>] -----------------> [<E>] -#
* | | |
* # v v
* [<B>] ---> [<C>] -# [<F>] -#
* | | -
* # v #
* [<D>] -#
* |
* #
* where:
* - [root] is a special empty root node.
* - [<X>] is a node for a sequence keysym <X>.
* - right arrows are `next` pointers.
* - down arrows are `successor` pointers.
* - # is a nil pointer.
*
* The nodes are all kept in a contiguous array. Pointers are represented
* as integer offsets into this array. A nil pointer is represented as 0
* (which, helpfully, is the offset of the empty root node).
*
* Nodes without a successor are leaf nodes. Since a sequence cannot be a
* prefix of another, these are exactly the nodes which terminate the
* sequences (in a bijective manner).
*
* A leaf contains the result data of its sequence. The result keysym is
* contained in the node struct itself; the result UTF-8 string is a byte
* offset into an array of the form "\0first\0second\0third" (the initial
* \0 is so offset 0 points to an empty string).
*/
struct compose_node {
xkb_keysym_t keysym;
/* Offset into xkb_compose_table::nodes. */
unsigned int next:31;
bool is_leaf:1;
union {
/* Offset into xkb_compose_table::nodes. */
uint32_t successor;
struct {
/* Offset into xkb_compose_table::utf8. */
uint32_t utf8;
xkb_keysym_t keysym;
} leaf;
} u;
};
struct xkb_compose_table {
int refcnt;
enum xkb_compose_format format;
enum xkb_compose_compile_flags flags;
struct xkb_context *ctx;
char *locale;
darray_char utf8;
darray(struct compose_node) nodes;
};
#endif

View File

@ -75,12 +75,16 @@ err:
XKB_EXPORT int
xkb_context_include_path_append_default(struct xkb_context *ctx)
{
const char *home;
const char *home, *root;
char *user_path;
int err;
int ret = 0;
ret |= xkb_context_include_path_append(ctx, DFLT_XKB_CONFIG_ROOT);
root = secure_getenv("XKB_CONFIG_ROOT");
if (root != NULL)
ret |= xkb_context_include_path_append(ctx, root);
else
ret |= xkb_context_include_path_append(ctx, DFLT_XKB_CONFIG_ROOT);
home = secure_getenv("HOME");
if (!home)

View File

@ -23,7 +23,7 @@
#ifndef CCAN_DARRAY_H
#define CCAN_DARRAY_H
/* Originally taken from: http://ccodearchive.net/info/darray.html
/* Originally taken from: https://ccodearchive.net/info/darray.html
* But modified for libxkbcommon. */
#include <stdlib.h>
@ -44,6 +44,13 @@
darray_init(arr); \
} while (0)
#define darray_steal(arr, to, to_size) do { \
*(to) = (arr).item; \
if (to_size) \
*(unsigned int *) (to_size) = (arr).size; \
darray_init(arr); \
} while (0)
/*
* Typedefs for darrays of common types. These are useful
* when you want to pass a pointer to an darray(T) around.
@ -78,7 +85,6 @@ typedef darray (unsigned long) darray_ulong;
#define darray_item(arr, i) ((arr).item[i])
#define darray_size(arr) ((arr).size)
#define darray_empty(arr) ((arr).size == 0)
#define darray_mem(arr, offset) ((arr).item + (offset))
/*** Insertion (single item) ***/
@ -98,12 +104,16 @@ typedef darray (unsigned long) darray_ulong;
#define darray_from_items(arr, items, count) do { \
unsigned __count = (count); \
darray_resize(arr, __count); \
memcpy((arr).item, items, __count * sizeof(*(arr).item)); \
if (__count != 0) \
memcpy((arr).item, items, __count * sizeof(*(arr).item)); \
} while (0)
#define darray_copy(arr_to, arr_from) \
darray_from_items((arr_to), (arr_from).item, (arr_from).size)
#define darray_concat(arr_to, arr_from) \
darray_append_items((arr_to), (arr_from).item, (arr_from).size)
/*** String buffer ***/
#define darray_append_string(arr, str) do { \
@ -160,6 +170,12 @@ typedef darray (unsigned long) darray_ulong;
sizeof(*(arr).item))); \
} while (0)
#define darray_shrink(arr) do { \
if ((arr).size > 0) \
(arr).item = realloc((arr).item, \
((arr).alloc = (arr).size) * sizeof(*(arr).item)); \
} while (0)
static inline unsigned
darray_next_alloc(unsigned alloc, unsigned need, unsigned itemSize)
{
@ -190,7 +206,4 @@ darray_next_alloc(unsigned alloc, unsigned need, unsigned itemSize)
(idx) < (arr).size; \
(idx)++, (val)++)
#define darray_foreach_reverse(i, arr) \
for ((i) = &(arr).item[(arr).size]; (i)-- > &(arr).item[0]; )
#endif /* CCAN_DARRAY_H */

View File

@ -29,23 +29,25 @@
static void
update_builtin_keymap_fields(struct xkb_keymap *keymap)
{
struct xkb_context *ctx = keymap->ctx;
const struct xkb_mod builtin_mods[] = {
{ .name = xkb_atom_intern_literal(ctx, "Shift"), .type = MOD_REAL },
{ .name = xkb_atom_intern_literal(ctx, "Lock"), .type = MOD_REAL },
{ .name = xkb_atom_intern_literal(ctx, "Control"), .type = MOD_REAL },
{ .name = xkb_atom_intern_literal(ctx, "Mod1"), .type = MOD_REAL },
{ .name = xkb_atom_intern_literal(ctx, "Mod2"), .type = MOD_REAL },
{ .name = xkb_atom_intern_literal(ctx, "Mod3"), .type = MOD_REAL },
{ .name = xkb_atom_intern_literal(ctx, "Mod4"), .type = MOD_REAL },
{ .name = xkb_atom_intern_literal(ctx, "Mod5"), .type = MOD_REAL },
/* Predefined (AKA real, core, X11) modifiers. The order is important! */
static const char *const builtin_mods[] = {
[0] = "Shift",
[1] = "Lock",
[2] = "Control",
[3] = "Mod1",
[4] = "Mod2",
[5] = "Mod3",
[6] = "Mod4",
[7] = "Mod5"
};
/*
* Add predefined (AKA real, core, X11) modifiers.
* The order is important!
*/
darray_append_items(keymap->mods, builtin_mods, ARRAY_SIZE(builtin_mods));
for (unsigned i = 0; i < ARRAY_SIZE(builtin_mods); i++) {
keymap->mods.mods[i].name = xkb_atom_intern(keymap->ctx,
builtin_mods[i],
strlen(builtin_mods[i]));
keymap->mods.mods[i].type = MOD_REAL;
}
keymap->mods.num_mods = ARRAY_SIZE(builtin_mods);
}
struct xkb_keymap *
@ -75,7 +77,7 @@ XkbKeyByName(struct xkb_keymap *keymap, xkb_atom_t name, bool use_aliases)
{
struct xkb_key *key;
xkb_foreach_key(key, keymap)
xkb_keys_foreach(key, keymap)
if (key->name == name)
return key;
@ -89,7 +91,7 @@ XkbKeyByName(struct xkb_keymap *keymap, xkb_atom_t name, bool use_aliases)
}
xkb_atom_t
XkbResolveKeyAlias(struct xkb_keymap *keymap, xkb_atom_t name)
XkbResolveKeyAlias(const struct xkb_keymap *keymap, xkb_atom_t name)
{
for (unsigned i = 0; i < keymap->num_key_aliases; i++)
if (keymap->key_aliases[i].alias == name)
@ -116,8 +118,33 @@ XkbEscapeMapName(char *name)
return;
while (*name) {
if (!(legal[*name / 8] & (1 << (*name % 8))))
unsigned char c = *name;
if (!(legal[c / 8] & (1 << (c % 8))))
*name = '_';
name++;
}
}
xkb_mod_index_t
XkbModNameToIndex(const struct xkb_mod_set *mods, xkb_atom_t name,
enum mod_type type)
{
xkb_mod_index_t i;
const struct xkb_mod *mod;
xkb_mods_enumerate(i, mod, mods)
if ((mod->type & type) && name == mod->name)
return i;
return XKB_MOD_INVALID;
}
bool
XkbLevelsSameSyms(const struct xkb_level *a, const struct xkb_level *b)
{
if (a->num_syms != b->num_syms)
return false;
if (a->num_syms <= 1)
return a->u.sym == b->u.sym;
return memcmp(a->u.syms, b->u.syms, sizeof(*a->u.syms) * a->num_syms) == 0;
}

View File

@ -68,11 +68,11 @@ xkb_keymap_unref(struct xkb_keymap *keymap)
if (keymap->keys) {
struct xkb_key *key;
xkb_foreach_key(key, keymap) {
xkb_keys_foreach(key, keymap) {
if (key->groups) {
for (unsigned i = 0; i < key->num_groups; i++) {
if (key->groups[i].levels) {
for (unsigned j = 0; j < XkbKeyGroupWidth(key, i); j++)
for (unsigned j = 0; j < XkbKeyNumLevels(key, i); j++)
if (key->groups[i].levels[j].num_syms > 1)
free(key->groups[i].levels[j].u.syms);
free(key->groups[i].levels);
@ -93,8 +93,6 @@ xkb_keymap_unref(struct xkb_keymap *keymap)
free(keymap->sym_interprets);
free(keymap->key_aliases);
free(keymap->group_names);
darray_free(keymap->mods);
darray_free(keymap->leds);
free(keymap->keycodes_section_name);
free(keymap->symbols_section_name);
free(keymap->types_section_name);
@ -263,7 +261,7 @@ xkb_keymap_get_as_string(struct xkb_keymap *keymap,
XKB_EXPORT xkb_mod_index_t
xkb_keymap_num_mods(struct xkb_keymap *keymap)
{
return darray_size(keymap->mods);
return keymap->mods.num_mods;
}
/**
@ -272,10 +270,10 @@ xkb_keymap_num_mods(struct xkb_keymap *keymap)
XKB_EXPORT const char *
xkb_keymap_mod_get_name(struct xkb_keymap *keymap, xkb_mod_index_t idx)
{
if (idx >= darray_size(keymap->mods))
if (idx >= keymap->mods.num_mods)
return NULL;
return xkb_atom_text(keymap->ctx, darray_item(keymap->mods, idx).name);
return xkb_atom_text(keymap->ctx, keymap->mods.mods[idx].name);
}
/**
@ -284,19 +282,13 @@ xkb_keymap_mod_get_name(struct xkb_keymap *keymap, xkb_mod_index_t idx)
XKB_EXPORT xkb_mod_index_t
xkb_keymap_mod_get_index(struct xkb_keymap *keymap, const char *name)
{
xkb_mod_index_t i;
xkb_atom_t atom;
const struct xkb_mod *mod;
atom = xkb_atom_lookup(keymap->ctx, name);
if (atom == XKB_ATOM_NONE)
return XKB_MOD_INVALID;
darray_enumerate(i, mod, keymap->mods)
if (mod->name == atom)
return i;
return XKB_MOD_INVALID;
return XkbModNameToIndex(&keymap->mods, atom, MOD_BOTH);
}
/**
@ -365,13 +357,13 @@ xkb_keymap_num_levels_for_key(struct xkb_keymap *keymap, xkb_keycode_t kc,
if (!key)
return 0;
layout = wrap_group_into_range(layout, key->num_groups,
layout = XkbWrapGroupIntoRange(layout, key->num_groups,
key->out_of_range_group_action,
key->out_of_range_group_number);
if (layout == XKB_LAYOUT_INVALID)
return 0;
return XkbKeyGroupWidth(key, layout);
return XkbKeyNumLevels(key, layout);
}
/**
@ -380,7 +372,7 @@ xkb_keymap_num_levels_for_key(struct xkb_keymap *keymap, xkb_keycode_t kc,
XKB_EXPORT xkb_led_index_t
xkb_keymap_num_leds(struct xkb_keymap *keymap)
{
return darray_size(keymap->leds);
return keymap->num_leds;
}
/**
@ -389,10 +381,10 @@ xkb_keymap_num_leds(struct xkb_keymap *keymap)
XKB_EXPORT const char *
xkb_keymap_led_get_name(struct xkb_keymap *keymap, xkb_led_index_t idx)
{
if (idx >= darray_size(keymap->leds))
if (idx >= keymap->num_leds)
return NULL;
return xkb_atom_text(keymap->ctx, darray_item(keymap->leds, idx).name);
return xkb_atom_text(keymap->ctx, keymap->leds[idx].name);
}
/**
@ -408,7 +400,7 @@ xkb_keymap_led_get_index(struct xkb_keymap *keymap, const char *name)
if (atom == XKB_ATOM_NONE)
return XKB_LED_INVALID;
darray_enumerate(i, led, keymap->leds)
xkb_leds_enumerate(i, led, keymap)
if (led->name == atom)
return i;
@ -431,13 +423,13 @@ xkb_keymap_key_get_syms_by_level(struct xkb_keymap *keymap,
if (!key)
goto err;
layout = wrap_group_into_range(layout, key->num_groups,
layout = XkbWrapGroupIntoRange(layout, key->num_groups,
key->out_of_range_group_action,
key->out_of_range_group_number);
if (layout == XKB_LAYOUT_INVALID)
goto err;
if (level >= XkbKeyGroupWidth(key, layout))
if (level >= XkbKeyNumLevels(key, layout))
goto err;
num_syms = key->groups[layout].levels[level].num_syms;
@ -474,10 +466,44 @@ xkb_keymap_key_for_each(struct xkb_keymap *keymap, xkb_keymap_key_iter_t iter,
{
struct xkb_key *key;
xkb_foreach_key(key, keymap)
xkb_keys_foreach(key, keymap)
iter(keymap, key->keycode, data);
}
XKB_EXPORT const char *
xkb_keymap_key_get_name(struct xkb_keymap *keymap, xkb_keycode_t kc)
{
const struct xkb_key *key = XkbKey(keymap, kc);
if (!key)
return NULL;
return xkb_atom_text(keymap->ctx, key->name);
}
XKB_EXPORT xkb_keycode_t
xkb_keymap_key_by_name(struct xkb_keymap *keymap, const char *name)
{
struct xkb_key *key;
xkb_atom_t atom;
atom = xkb_atom_lookup(keymap->ctx, name);
if (atom) {
xkb_atom_t ratom = XkbResolveKeyAlias(keymap, atom);
if (ratom)
atom = ratom;
}
if (!atom)
return XKB_KEYCODE_INVALID;
xkb_keys_foreach(key, keymap) {
if (key->name == atom)
return key->keycode;
}
return XKB_KEYCODE_INVALID;
}
/**
* Simple boolean specifying whether or not the key should repeat.
*/

View File

@ -228,7 +228,6 @@ struct xkb_pointer_button_action {
struct xkb_private_action {
enum xkb_action_type type;
enum xkb_action_flags flags;
uint8_t data[7];
};
@ -254,6 +253,7 @@ struct xkb_key_type {
xkb_atom_t name;
struct xkb_mods mods;
xkb_level_index_t num_levels;
unsigned int num_level_names;
xkb_atom_t *level_names;
unsigned int num_entries;
struct xkb_key_type_entry *entries;
@ -325,7 +325,7 @@ struct xkb_group {
bool explicit_type;
/* Points to a type in keymap->types. */
const struct xkb_key_type *type;
/* Use XkbKeyGroupWidth for the number of levels. */
/* Use XkbKeyNumLevels for the number of levels. */
struct xkb_level *levels;
};
@ -353,6 +353,11 @@ struct xkb_mod {
xkb_mod_mask_t mapping; /* vmod -> real mod mapping */
};
struct xkb_mod_set {
struct xkb_mod mods[XKB_MAX_MODS];
unsigned int num_mods;
};
/* Common keyboard description structure */
struct xkb_keymap {
struct xkb_context *ctx;
@ -377,7 +382,7 @@ struct xkb_keymap {
unsigned int num_sym_interprets;
struct xkb_sym_interpret *sym_interprets;
darray(struct xkb_mod) mods;
struct xkb_mod_set mods;
/* Number of groups in the key with the most groups. */
xkb_layout_index_t num_groups;
@ -385,7 +390,8 @@ struct xkb_keymap {
xkb_layout_index_t num_group_names;
xkb_atom_t *group_names;
darray(struct xkb_led) leds;
struct xkb_led leds[XKB_MAX_LEDS];
unsigned int num_leds;
char *keycodes_section_name;
char *symbols_section_name;
@ -393,10 +399,30 @@ struct xkb_keymap {
char *compat_section_name;
};
#define xkb_foreach_key(iter, keymap) \
for (iter = keymap->keys + keymap->min_key_code; \
iter <= keymap->keys + keymap->max_key_code; \
iter++)
#define xkb_keys_foreach(iter, keymap) \
for ((iter) = (keymap)->keys + (keymap)->min_key_code; \
(iter) <= (keymap)->keys + (keymap)->max_key_code; \
(iter)++)
#define xkb_mods_foreach(iter, mods_) \
for ((iter) = (mods_)->mods; \
(iter) < (mods_)->mods + (mods_)->num_mods; \
(iter)++)
#define xkb_mods_enumerate(idx, iter, mods_) \
for ((idx) = 0, (iter) = (mods_)->mods; \
(idx) < (mods_)->num_mods; \
(idx)++, (iter)++)
#define xkb_leds_foreach(iter, keymap) \
for ((iter) = (keymap)->leds; \
(iter) < (keymap)->leds + (keymap)->num_leds; \
(iter)++)
#define xkb_leds_enumerate(idx, iter, keymap) \
for ((idx) = 0, (iter) = (keymap)->leds; \
(idx) < (keymap)->num_leds; \
(idx)++, (iter)++)
static inline const struct xkb_key *
XkbKey(struct xkb_keymap *keymap, xkb_keycode_t kc)
@ -407,7 +433,7 @@ XkbKey(struct xkb_keymap *keymap, xkb_keycode_t kc)
}
static inline xkb_level_index_t
XkbKeyGroupWidth(const struct xkb_key *key, xkb_layout_index_t layout)
XkbKeyNumLevels(const struct xkb_key *key, xkb_layout_index_t layout)
{
return key->groups[layout].type->num_levels;
}
@ -421,17 +447,27 @@ struct xkb_key *
XkbKeyByName(struct xkb_keymap *keymap, xkb_atom_t name, bool use_aliases);
xkb_atom_t
XkbResolveKeyAlias(struct xkb_keymap *keymap, xkb_atom_t name);
XkbResolveKeyAlias(const struct xkb_keymap *keymap, xkb_atom_t name);
void
XkbEscapeMapName(char *name);
xkb_mod_index_t
XkbModNameToIndex(const struct xkb_mod_set *mods, xkb_atom_t name,
enum mod_type type);
bool
XkbLevelsSameSyms(const struct xkb_level *a, const struct xkb_level *b);
xkb_layout_index_t
wrap_group_into_range(int32_t group,
XkbWrapGroupIntoRange(int32_t group,
xkb_layout_index_t num_groups,
enum xkb_range_exceed_type out_of_range_group_action,
xkb_layout_index_t out_of_range_group_number);
xkb_mod_mask_t
mod_mask_get_effective(struct xkb_keymap *keymap, xkb_mod_mask_t mods);
struct xkb_keymap_format_ops {
bool (*keymap_new_from_names)(struct xkb_keymap *keymap,
const struct xkb_rule_names *names);

View File

@ -521,7 +521,7 @@ static const struct codepair keysymtab[] = {
{ 0x0aa8, 0x200a }, /* hairspace HAIR SPACE */
{ 0x0aa9, 0x2014 }, /* emdash — EM DASH */
{ 0x0aaa, 0x2013 }, /* endash EN DASH */
/* 0x0aac signifblank ? ??? */
{ 0x0aac, 0x2423 }, /* signifblank ␣ OPEN BOX */
{ 0x0aae, 0x2026 }, /* ellipsis … HORIZONTAL ELLIPSIS */
{ 0x0aaf, 0x2025 }, /* doubbaselinedot ‥ TWO DOT LEADER */
{ 0x0ab0, 0x2153 }, /* onethird ⅓ VULGAR FRACTION ONE THIRD */
@ -534,9 +534,9 @@ static const struct codepair keysymtab[] = {
{ 0x0ab7, 0x215a }, /* fivesixths ⅚ VULGAR FRACTION FIVE SIXTHS */
{ 0x0ab8, 0x2105 }, /* careof ℅ CARE OF */
{ 0x0abb, 0x2012 }, /* figdash FIGURE DASH */
{ 0x0abc, 0x2329 }, /* leftanglebracket 〈 LEFT-POINTING ANGLE BRACKET */
{ 0x0abc, 0x27e8 }, /* leftanglebracket ⟨ MATHEMATICAL LEFT ANGLE BRACKET */
{ 0x0abd, 0x002e }, /* decimalpoint . FULL STOP */
{ 0x0abe, 0x232a }, /* rightanglebracket 〉 RIGHT-POINTING ANGLE BRACKET */
{ 0x0abe, 0x27e9 }, /* rightanglebracket ⟩ MATHEMATICAL RIGHT ANGLE BRACKET */
/* 0x0abf marker ? ??? */
{ 0x0ac3, 0x215b }, /* oneeighth ⅛ VULGAR FRACTION ONE EIGHTH */
{ 0x0ac4, 0x215c }, /* threeeighths ⅜ VULGAR FRACTION THREE EIGHTHS */
@ -554,6 +554,7 @@ static const struct codepair keysymtab[] = {
{ 0x0ad2, 0x201c }, /* leftdoublequotemark “ LEFT DOUBLE QUOTATION MARK */
{ 0x0ad3, 0x201d }, /* rightdoublequotemark ” RIGHT DOUBLE QUOTATION MARK */
{ 0x0ad4, 0x211e }, /* prescription ℞ PRESCRIPTION TAKE */
{ 0x0ad5, 0x2030 }, /* permille ‰ PER MILLE SIGN */
{ 0x0ad6, 0x2032 }, /* minutes PRIME */
{ 0x0ad7, 0x2033 }, /* seconds ″ DOUBLE PRIME */
{ 0x0ad9, 0x271d }, /* latincross ✝ LATIN CROSS */
@ -880,9 +881,15 @@ xkb_keysym_to_utf32(xkb_keysym_t keysym)
keysym == XKB_KEY_KP_Enter || keysym == XKB_KEY_KP_Equal)
return keysym & 0x7f;
/* also check for directly encoded 24-bit UCS characters */
if ((keysym & 0xff000000) == 0x01000000)
return keysym & 0x00ffffff;
/* also check for directly encoded Unicode codepoints */
/*
* In theory, this is supposed to start from 0x100100, such that the ASCII
* range, which is already covered by 0x00-0xff, can't be encoded in two
* ways. However, changing this after a couple of decades probably won't
* go well, so it stays as it is.
*/
if (0x01000000 <= keysym && keysym <= 0x0110ffff)
return keysym - 0x01000000;
/* search main table */
return bin_search(keysymtab, ARRAY_SIZE(keysymtab) - 1, keysym);

View File

@ -76,7 +76,7 @@ compare_by_name(const void *a, const void *b)
{
const char *key = a;
const struct name_keysym *entry = b;
return strcasecmp(key, get_name(entry));
return istrcmp(key, get_name(entry));
}
XKB_EXPORT int
@ -109,7 +109,7 @@ xkb_keysym_get_name(xkb_keysym_t ks, char *buffer, size_t size)
/*
* Find the correct keysym if one case-insensitive match is given.
*
* The name_to_keysym table is sorted by strcasecmp(). So bsearch() may return
* The name_to_keysym table is sorted by istrcmp(). So bsearch() may return
* _any_ of all possible case-insensitive duplicates. This function searches the
* returned entry @entry, all previous and all next entries that match by
* case-insensitive comparison and returns the exact match to @name. If @icase
@ -138,7 +138,7 @@ find_sym(const struct name_keysym *entry, const char *name, bool icase)
for (iter = entry - 1; iter >= name_to_keysym; --iter) {
if (!icase && strcmp(get_name(iter), name) == 0)
return iter;
if (strcasecmp(get_name(iter), get_name(entry)) != 0)
if (istrcmp(get_name(iter), get_name(entry)) != 0)
break;
if (icase && xkb_keysym_is_lower(iter->keysym))
return iter;
@ -148,7 +148,7 @@ find_sym(const struct name_keysym *entry, const char *name, bool icase)
for (iter = entry + 1; iter < last; ++iter) {
if (!icase && strcmp(get_name(iter), name) == 0)
return iter;
if (strcasecmp(get_name(iter), get_name(entry)) != 0)
if (istrcmp(get_name(iter), get_name(entry)) != 0)
break;
if (icase && xkb_keysym_is_lower(iter->keysym))
return iter;
@ -165,7 +165,7 @@ xkb_keysym_from_name(const char *s, enum xkb_keysym_flags flags)
const struct name_keysym *entry;
char *tmp;
xkb_keysym_t val;
bool icase = !!(flags & XKB_KEYSYM_CASE_INSENSITIVE);
bool icase = (flags & XKB_KEYSYM_CASE_INSENSITIVE);
if (flags & ~XKB_KEYSYM_CASE_INSENSITIVE)
return XKB_KEY_NoSymbol;
@ -223,6 +223,18 @@ xkb_keysym_is_keypad(xkb_keysym_t keysym)
return keysym >= XKB_KEY_KP_Space && keysym <= XKB_KEY_KP_Equal;
}
bool
xkb_keysym_is_modifier(xkb_keysym_t keysym)
{
return
(keysym >= XKB_KEY_Shift_L && keysym <= XKB_KEY_Hyper_R) ||
/* libX11 only goes upto XKB_KEY_ISO_Level5_Lock. */
(keysym >= XKB_KEY_ISO_Lock && keysym <= XKB_KEY_ISO_Last_Group_Lock) ||
keysym == XKB_KEY_Mode_switch ||
keysym == XKB_KEY_Num_Lock;
}
static void
XConvertCase(xkb_keysym_t sym, xkb_keysym_t *lower, xkb_keysym_t *upper);
@ -252,7 +264,7 @@ xkb_keysym_is_upper(xkb_keysym_t ks)
return (ks == upper ? true : false);
}
xkb_keysym_t
XKB_EXPORT xkb_keysym_t
xkb_keysym_to_lower(xkb_keysym_t ks)
{
xkb_keysym_t lower, upper;
@ -262,7 +274,7 @@ xkb_keysym_to_lower(xkb_keysym_t ks)
return lower;
}
xkb_keysym_t
XKB_EXPORT xkb_keysym_t
xkb_keysym_to_upper(xkb_keysym_t ks)
{
xkb_keysym_t lower, upper;

View File

@ -59,10 +59,7 @@ xkb_keysym_is_upper(xkb_keysym_t keysym);
bool
xkb_keysym_is_keypad(xkb_keysym_t keysym);
xkb_keysym_t
xkb_keysym_to_upper(xkb_keysym_t ks);
xkb_keysym_t
xkb_keysym_to_lower(xkb_keysym_t ks);
bool
xkb_keysym_is_modifier(xkb_keysym_t keysym);
#endif

View File

@ -2213,6 +2213,7 @@ static const char *keysym_names =
"XF86AudioNext\0"
"XF86AudioPause\0"
"XF86AudioPlay\0"
"XF86AudioPreset\0"
"XF86AudioPrev\0"
"XF86AudioRaiseVolume\0"
"XF86AudioRandomPlay\0"
@ -2262,6 +2263,7 @@ static const char *keysym_names =
"XF86KbdBrightnessDown\0"
"XF86KbdBrightnessUp\0"
"XF86KbdLightOnOff\0"
"XF86Keyboard\0"
"XF86Launch0\0"
"XF86Launch1\0"
"XF86Launch2\0"
@ -2314,6 +2316,7 @@ static const char *keysym_names =
"XF86Refresh\0"
"XF86Reload\0"
"XF86Reply\0"
"XF86RFKill\0"
"XF86RockerDown\0"
"XF86RockerEnter\0"
"XF86RockerUp\0"
@ -2373,6 +2376,7 @@ static const char *keysym_names =
"XF86WheelButton\0"
"XF86WLAN\0"
"XF86Word\0"
"XF86WWAN\0"
"XF86WWW\0"
"XF86Xfer\0"
"XF86Yellow\0"
@ -4624,203 +4628,207 @@ static const struct name_keysym name_to_keysym[] = {
{ 0x1008ff17, 26816 }, /* XF86AudioNext */
{ 0x1008ff31, 26830 }, /* XF86AudioPause */
{ 0x1008ff14, 26845 }, /* XF86AudioPlay */
{ 0x1008ff16, 26859 }, /* XF86AudioPrev */
{ 0x1008ff13, 26873 }, /* XF86AudioRaiseVolume */
{ 0x1008ff99, 26894 }, /* XF86AudioRandomPlay */
{ 0x1008ff1c, 26914 }, /* XF86AudioRecord */
{ 0x1008ff98, 26930 }, /* XF86AudioRepeat */
{ 0x1008ff3e, 26946 }, /* XF86AudioRewind */
{ 0x1008ff15, 26962 }, /* XF86AudioStop */
{ 0x1008ff8d, 26976 }, /* XF86Away */
{ 0x1008ff26, 26985 }, /* XF86Back */
{ 0x1008ff3f, 26994 }, /* XF86BackForward */
{ 0x1008ff93, 27010 }, /* XF86Battery */
{ 0x1008ffa6, 27022 }, /* XF86Blue */
{ 0x1008ff94, 27031 }, /* XF86Bluetooth */
{ 0x1008ff52, 27045 }, /* XF86Book */
{ 0x1008ff3b, 27054 }, /* XF86BrightnessAdjust */
{ 0x1008ff54, 27075 }, /* XF86Calculater */
{ 0x1008ff1d, 27090 }, /* XF86Calculator */
{ 0x1008ff20, 27105 }, /* XF86Calendar */
{ 0x1008ff53, 27118 }, /* XF86CD */
{ 0x1008ff55, 27125 }, /* XF86Clear */
{ 0x1008fe21, 27135 }, /* XF86ClearGrab */
{ 0x1008ff56, 27149 }, /* XF86Close */
{ 0x1008ff3d, 27159 }, /* XF86Community */
{ 0x1008ff22, 27173 }, /* XF86ContrastAdjust */
{ 0x1008ff57, 27192 }, /* XF86Copy */
{ 0x1008ff58, 27201 }, /* XF86Cut */
{ 0x1008ff9c, 27209 }, /* XF86CycleAngle */
{ 0x1008ff59, 27224 }, /* XF86Display */
{ 0x1008ff5b, 27236 }, /* XF86Documents */
{ 0x1008ff5a, 27250 }, /* XF86DOS */
{ 0x1008ff2c, 27258 }, /* XF86Eject */
{ 0x1008ff5c, 27268 }, /* XF86Excel */
{ 0x1008ff5d, 27278 }, /* XF86Explorer */
{ 0x1008ff30, 27291 }, /* XF86Favorites */
{ 0x1008ff3c, 27305 }, /* XF86Finance */
{ 0x1008ff27, 27317 }, /* XF86Forward */
{ 0x1008ff9d, 27329 }, /* XF86FrameBack */
{ 0x1008ff9e, 27343 }, /* XF86FrameForward */
{ 0x1008ff5e, 27360 }, /* XF86Game */
{ 0x1008ff5f, 27369 }, /* XF86Go */
{ 0x1008ffa4, 27376 }, /* XF86Green */
{ 0x1008ffa8, 27386 }, /* XF86Hibernate */
{ 0x1008ff37, 27400 }, /* XF86History */
{ 0x1008ff18, 27412 }, /* XF86HomePage */
{ 0x1008ff3a, 27425 }, /* XF86HotLinks */
{ 0x1008ff60, 27438 }, /* XF86iTouch */
{ 0x1008ff06, 27449 }, /* XF86KbdBrightnessDown */
{ 0x1008ff05, 27471 }, /* XF86KbdBrightnessUp */
{ 0x1008ff04, 27491 }, /* XF86KbdLightOnOff */
{ 0x1008ff40, 27509 }, /* XF86Launch0 */
{ 0x1008ff41, 27521 }, /* XF86Launch1 */
{ 0x1008ff42, 27533 }, /* XF86Launch2 */
{ 0x1008ff43, 27545 }, /* XF86Launch3 */
{ 0x1008ff44, 27557 }, /* XF86Launch4 */
{ 0x1008ff45, 27569 }, /* XF86Launch5 */
{ 0x1008ff46, 27581 }, /* XF86Launch6 */
{ 0x1008ff47, 27593 }, /* XF86Launch7 */
{ 0x1008ff48, 27605 }, /* XF86Launch8 */
{ 0x1008ff49, 27617 }, /* XF86Launch9 */
{ 0x1008ff4a, 27629 }, /* XF86LaunchA */
{ 0x1008ff4b, 27641 }, /* XF86LaunchB */
{ 0x1008ff4c, 27653 }, /* XF86LaunchC */
{ 0x1008ff4d, 27665 }, /* XF86LaunchD */
{ 0x1008ff4e, 27677 }, /* XF86LaunchE */
{ 0x1008ff4f, 27689 }, /* XF86LaunchF */
{ 0x1008ff35, 27701 }, /* XF86LightBulb */
{ 0x1008fe25, 27715 }, /* XF86LogGrabInfo */
{ 0x1008ff61, 27731 }, /* XF86LogOff */
{ 0x1008fe24, 27742 }, /* XF86LogWindowTree */
{ 0x1008ff19, 27760 }, /* XF86Mail */
{ 0x1008ff90, 27769 }, /* XF86MailForward */
{ 0x1008ff62, 27785 }, /* XF86Market */
{ 0x1008ff63, 27796 }, /* XF86Meeting */
{ 0x1008ff1e, 27808 }, /* XF86Memo */
{ 0x1008ff65, 27817 }, /* XF86MenuKB */
{ 0x1008ff66, 27828 }, /* XF86MenuPB */
{ 0x1008ff8e, 27839 }, /* XF86Messenger */
{ 0x1008ff01, 27853 }, /* XF86ModeLock */
{ 0x1008ff03, 27866 }, /* XF86MonBrightnessDown */
{ 0x1008ff02, 27888 }, /* XF86MonBrightnessUp */
{ 0x1008ff92, 27908 }, /* XF86Music */
{ 0x1008ff33, 27918 }, /* XF86MyComputer */
{ 0x1008ff67, 27933 }, /* XF86MySites */
{ 0x1008ff68, 27945 }, /* XF86New */
{ 0x1008ff69, 27953 }, /* XF86News */
{ 0x1008fe22, 27962 }, /* XF86Next_VMode */
{ 0x1008ff6a, 27977 }, /* XF86OfficeHome */
{ 0x1008ff6b, 27992 }, /* XF86Open */
{ 0x1008ff38, 28001 }, /* XF86OpenURL */
{ 0x1008ff6c, 28013 }, /* XF86Option */
{ 0x1008ff6d, 28024 }, /* XF86Paste */
{ 0x1008ff6e, 28034 }, /* XF86Phone */
{ 0x1008ff91, 28044 }, /* XF86Pictures */
{ 0x1008ff21, 28057 }, /* XF86PowerDown */
{ 0x1008ff2a, 28071 }, /* XF86PowerOff */
{ 0x1008fe23, 28084 }, /* XF86Prev_VMode */
{ 0x1008ff70, 28099 }, /* XF86Q */
{ 0x1008ffa3, 28105 }, /* XF86Red */
{ 0x1008ff29, 28113 }, /* XF86Refresh */
{ 0x1008ff73, 28125 }, /* XF86Reload */
{ 0x1008ff72, 28136 }, /* XF86Reply */
{ 0x1008ff24, 28146 }, /* XF86RockerDown */
{ 0x1008ff25, 28161 }, /* XF86RockerEnter */
{ 0x1008ff23, 28177 }, /* XF86RockerUp */
{ 0x1008ff74, 28190 }, /* XF86RotateWindows */
{ 0x1008ff76, 28208 }, /* XF86RotationKB */
{ 0x1008ff75, 28223 }, /* XF86RotationPB */
{ 0x1008ff77, 28238 }, /* XF86Save */
{ 0x1008ff2d, 28247 }, /* XF86ScreenSaver */
{ 0x1008ff7a, 28263 }, /* XF86ScrollClick */
{ 0x1008ff79, 28279 }, /* XF86ScrollDown */
{ 0x1008ff78, 28294 }, /* XF86ScrollUp */
{ 0x1008ff1b, 28307 }, /* XF86Search */
{ 0x1008ffa0, 28318 }, /* XF86Select */
{ 0x1008ff7b, 28329 }, /* XF86Send */
{ 0x1008ff36, 28338 }, /* XF86Shop */
{ 0x1008ff2f, 28347 }, /* XF86Sleep */
{ 0x1008ff7c, 28357 }, /* XF86Spell */
{ 0x1008ff7d, 28367 }, /* XF86SplitScreen */
{ 0x1008ff10, 28383 }, /* XF86Standby */
{ 0x1008ff1a, 28395 }, /* XF86Start */
{ 0x1008ff28, 28405 }, /* XF86Stop */
{ 0x1008ff9a, 28414 }, /* XF86Subtitle */
{ 0x1008ff7e, 28427 }, /* XF86Support */
{ 0x1008ffa7, 28439 }, /* XF86Suspend */
{ 0x1008fe01, 28451 }, /* XF86Switch_VT_1 */
{ 0x1008fe0a, 28467 }, /* XF86Switch_VT_10 */
{ 0x1008fe0b, 28484 }, /* XF86Switch_VT_11 */
{ 0x1008fe0c, 28501 }, /* XF86Switch_VT_12 */
{ 0x1008fe02, 28518 }, /* XF86Switch_VT_2 */
{ 0x1008fe03, 28534 }, /* XF86Switch_VT_3 */
{ 0x1008fe04, 28550 }, /* XF86Switch_VT_4 */
{ 0x1008fe05, 28566 }, /* XF86Switch_VT_5 */
{ 0x1008fe06, 28582 }, /* XF86Switch_VT_6 */
{ 0x1008fe07, 28598 }, /* XF86Switch_VT_7 */
{ 0x1008fe08, 28614 }, /* XF86Switch_VT_8 */
{ 0x1008fe09, 28630 }, /* XF86Switch_VT_9 */
{ 0x1008ff7f, 28646 }, /* XF86TaskPane */
{ 0x1008ff80, 28659 }, /* XF86Terminal */
{ 0x1008ff9f, 28672 }, /* XF86Time */
{ 0x1008ff1f, 28681 }, /* XF86ToDoList */
{ 0x1008ff81, 28694 }, /* XF86Tools */
{ 0x1008ffa2, 28704 }, /* XF86TopMenu */
{ 0x1008ffb1, 28716 }, /* XF86TouchpadOff */
{ 0x1008ffb0, 28732 }, /* XF86TouchpadOn */
{ 0x1008ffa9, 28747 }, /* XF86TouchpadToggle */
{ 0x1008ff82, 28766 }, /* XF86Travel */
{ 0x1008fe20, 28777 }, /* XF86Ungrab */
{ 0x1008ff85, 28788 }, /* XF86User1KB */
{ 0x1008ff86, 28800 }, /* XF86User2KB */
{ 0x1008ff84, 28812 }, /* XF86UserPB */
{ 0x1008ff96, 28823 }, /* XF86UWB */
{ 0x1008ff34, 28831 }, /* XF86VendorHome */
{ 0x1008ff87, 28846 }, /* XF86Video */
{ 0x1008ffa1, 28856 }, /* XF86View */
{ 0x1008ff2b, 28865 }, /* XF86WakeUp */
{ 0x1008ff8f, 28876 }, /* XF86WebCam */
{ 0x1008ff88, 28887 }, /* XF86WheelButton */
{ 0x1008ff95, 28903 }, /* XF86WLAN */
{ 0x1008ff89, 28912 }, /* XF86Word */
{ 0x1008ff2e, 28921 }, /* XF86WWW */
{ 0x1008ff8a, 28929 }, /* XF86Xfer */
{ 0x1008ffa5, 28938 }, /* XF86Yellow */
{ 0x1008ff8b, 28949 }, /* XF86ZoomIn */
{ 0x1008ff8c, 28960 }, /* XF86ZoomOut */
{ 0x00000059, 28972 }, /* Y */
{ 0x00000079, 28974 }, /* y */
{ 0x000000dd, 28976 }, /* Yacute */
{ 0x000000fd, 28983 }, /* yacute */
{ 0x01001ef4, 28990 }, /* Ybelowdot */
{ 0x01001ef5, 29000 }, /* ybelowdot */
{ 0x01000176, 29010 }, /* Ycircumflex */
{ 0x01000177, 29022 }, /* ycircumflex */
{ 0x000000ff, 29034 }, /* ydiaeresis */
{ 0x000013be, 29045 }, /* Ydiaeresis */
{ 0x000000a5, 29056 }, /* yen */
{ 0x01001ef2, 29060 }, /* Ygrave */
{ 0x01001ef3, 29067 }, /* ygrave */
{ 0x01001ef6, 29074 }, /* Yhook */
{ 0x01001ef7, 29080 }, /* yhook */
{ 0x01001ef8, 29086 }, /* Ytilde */
{ 0x01001ef9, 29093 }, /* ytilde */
{ 0x0000005a, 29100 }, /* Z */
{ 0x0000007a, 29102 }, /* z */
{ 0x000001af, 29104 }, /* Zabovedot */
{ 0x000001bf, 29114 }, /* zabovedot */
{ 0x000001ac, 29124 }, /* Zacute */
{ 0x000001bc, 29131 }, /* zacute */
{ 0x000001ae, 29138 }, /* Zcaron */
{ 0x000001be, 29145 }, /* zcaron */
{ 0x0000ff3d, 29152 }, /* Zen_Koho */
{ 0x0000ff28, 29161 }, /* Zenkaku */
{ 0x0000ff2a, 29169 }, /* Zenkaku_Hankaku */
{ 0x01002080, 29185 }, /* zerosubscript */
{ 0x01002070, 29199 }, /* zerosuperior */
{ 0x010001b5, 29212 }, /* Zstroke */
{ 0x010001b6, 29220 }, /* zstroke */
{ 0x1008ffb6, 26859 }, /* XF86AudioPreset */
{ 0x1008ff16, 26875 }, /* XF86AudioPrev */
{ 0x1008ff13, 26889 }, /* XF86AudioRaiseVolume */
{ 0x1008ff99, 26910 }, /* XF86AudioRandomPlay */
{ 0x1008ff1c, 26930 }, /* XF86AudioRecord */
{ 0x1008ff98, 26946 }, /* XF86AudioRepeat */
{ 0x1008ff3e, 26962 }, /* XF86AudioRewind */
{ 0x1008ff15, 26978 }, /* XF86AudioStop */
{ 0x1008ff8d, 26992 }, /* XF86Away */
{ 0x1008ff26, 27001 }, /* XF86Back */
{ 0x1008ff3f, 27010 }, /* XF86BackForward */
{ 0x1008ff93, 27026 }, /* XF86Battery */
{ 0x1008ffa6, 27038 }, /* XF86Blue */
{ 0x1008ff94, 27047 }, /* XF86Bluetooth */
{ 0x1008ff52, 27061 }, /* XF86Book */
{ 0x1008ff3b, 27070 }, /* XF86BrightnessAdjust */
{ 0x1008ff54, 27091 }, /* XF86Calculater */
{ 0x1008ff1d, 27106 }, /* XF86Calculator */
{ 0x1008ff20, 27121 }, /* XF86Calendar */
{ 0x1008ff53, 27134 }, /* XF86CD */
{ 0x1008ff55, 27141 }, /* XF86Clear */
{ 0x1008fe21, 27151 }, /* XF86ClearGrab */
{ 0x1008ff56, 27165 }, /* XF86Close */
{ 0x1008ff3d, 27175 }, /* XF86Community */
{ 0x1008ff22, 27189 }, /* XF86ContrastAdjust */
{ 0x1008ff57, 27208 }, /* XF86Copy */
{ 0x1008ff58, 27217 }, /* XF86Cut */
{ 0x1008ff9c, 27225 }, /* XF86CycleAngle */
{ 0x1008ff59, 27240 }, /* XF86Display */
{ 0x1008ff5b, 27252 }, /* XF86Documents */
{ 0x1008ff5a, 27266 }, /* XF86DOS */
{ 0x1008ff2c, 27274 }, /* XF86Eject */
{ 0x1008ff5c, 27284 }, /* XF86Excel */
{ 0x1008ff5d, 27294 }, /* XF86Explorer */
{ 0x1008ff30, 27307 }, /* XF86Favorites */
{ 0x1008ff3c, 27321 }, /* XF86Finance */
{ 0x1008ff27, 27333 }, /* XF86Forward */
{ 0x1008ff9d, 27345 }, /* XF86FrameBack */
{ 0x1008ff9e, 27359 }, /* XF86FrameForward */
{ 0x1008ff5e, 27376 }, /* XF86Game */
{ 0x1008ff5f, 27385 }, /* XF86Go */
{ 0x1008ffa4, 27392 }, /* XF86Green */
{ 0x1008ffa8, 27402 }, /* XF86Hibernate */
{ 0x1008ff37, 27416 }, /* XF86History */
{ 0x1008ff18, 27428 }, /* XF86HomePage */
{ 0x1008ff3a, 27441 }, /* XF86HotLinks */
{ 0x1008ff60, 27454 }, /* XF86iTouch */
{ 0x1008ff06, 27465 }, /* XF86KbdBrightnessDown */
{ 0x1008ff05, 27487 }, /* XF86KbdBrightnessUp */
{ 0x1008ff04, 27507 }, /* XF86KbdLightOnOff */
{ 0x1008ffb3, 27525 }, /* XF86Keyboard */
{ 0x1008ff40, 27538 }, /* XF86Launch0 */
{ 0x1008ff41, 27550 }, /* XF86Launch1 */
{ 0x1008ff42, 27562 }, /* XF86Launch2 */
{ 0x1008ff43, 27574 }, /* XF86Launch3 */
{ 0x1008ff44, 27586 }, /* XF86Launch4 */
{ 0x1008ff45, 27598 }, /* XF86Launch5 */
{ 0x1008ff46, 27610 }, /* XF86Launch6 */
{ 0x1008ff47, 27622 }, /* XF86Launch7 */
{ 0x1008ff48, 27634 }, /* XF86Launch8 */
{ 0x1008ff49, 27646 }, /* XF86Launch9 */
{ 0x1008ff4a, 27658 }, /* XF86LaunchA */
{ 0x1008ff4b, 27670 }, /* XF86LaunchB */
{ 0x1008ff4c, 27682 }, /* XF86LaunchC */
{ 0x1008ff4d, 27694 }, /* XF86LaunchD */
{ 0x1008ff4e, 27706 }, /* XF86LaunchE */
{ 0x1008ff4f, 27718 }, /* XF86LaunchF */
{ 0x1008ff35, 27730 }, /* XF86LightBulb */
{ 0x1008fe25, 27744 }, /* XF86LogGrabInfo */
{ 0x1008ff61, 27760 }, /* XF86LogOff */
{ 0x1008fe24, 27771 }, /* XF86LogWindowTree */
{ 0x1008ff19, 27789 }, /* XF86Mail */
{ 0x1008ff90, 27798 }, /* XF86MailForward */
{ 0x1008ff62, 27814 }, /* XF86Market */
{ 0x1008ff63, 27825 }, /* XF86Meeting */
{ 0x1008ff1e, 27837 }, /* XF86Memo */
{ 0x1008ff65, 27846 }, /* XF86MenuKB */
{ 0x1008ff66, 27857 }, /* XF86MenuPB */
{ 0x1008ff8e, 27868 }, /* XF86Messenger */
{ 0x1008ff01, 27882 }, /* XF86ModeLock */
{ 0x1008ff03, 27895 }, /* XF86MonBrightnessDown */
{ 0x1008ff02, 27917 }, /* XF86MonBrightnessUp */
{ 0x1008ff92, 27937 }, /* XF86Music */
{ 0x1008ff33, 27947 }, /* XF86MyComputer */
{ 0x1008ff67, 27962 }, /* XF86MySites */
{ 0x1008ff68, 27974 }, /* XF86New */
{ 0x1008ff69, 27982 }, /* XF86News */
{ 0x1008fe22, 27991 }, /* XF86Next_VMode */
{ 0x1008ff6a, 28006 }, /* XF86OfficeHome */
{ 0x1008ff6b, 28021 }, /* XF86Open */
{ 0x1008ff38, 28030 }, /* XF86OpenURL */
{ 0x1008ff6c, 28042 }, /* XF86Option */
{ 0x1008ff6d, 28053 }, /* XF86Paste */
{ 0x1008ff6e, 28063 }, /* XF86Phone */
{ 0x1008ff91, 28073 }, /* XF86Pictures */
{ 0x1008ff21, 28086 }, /* XF86PowerDown */
{ 0x1008ff2a, 28100 }, /* XF86PowerOff */
{ 0x1008fe23, 28113 }, /* XF86Prev_VMode */
{ 0x1008ff70, 28128 }, /* XF86Q */
{ 0x1008ffa3, 28134 }, /* XF86Red */
{ 0x1008ff29, 28142 }, /* XF86Refresh */
{ 0x1008ff73, 28154 }, /* XF86Reload */
{ 0x1008ff72, 28165 }, /* XF86Reply */
{ 0x1008ffb5, 28175 }, /* XF86RFKill */
{ 0x1008ff24, 28186 }, /* XF86RockerDown */
{ 0x1008ff25, 28201 }, /* XF86RockerEnter */
{ 0x1008ff23, 28217 }, /* XF86RockerUp */
{ 0x1008ff74, 28230 }, /* XF86RotateWindows */
{ 0x1008ff76, 28248 }, /* XF86RotationKB */
{ 0x1008ff75, 28263 }, /* XF86RotationPB */
{ 0x1008ff77, 28278 }, /* XF86Save */
{ 0x1008ff2d, 28287 }, /* XF86ScreenSaver */
{ 0x1008ff7a, 28303 }, /* XF86ScrollClick */
{ 0x1008ff79, 28319 }, /* XF86ScrollDown */
{ 0x1008ff78, 28334 }, /* XF86ScrollUp */
{ 0x1008ff1b, 28347 }, /* XF86Search */
{ 0x1008ffa0, 28358 }, /* XF86Select */
{ 0x1008ff7b, 28369 }, /* XF86Send */
{ 0x1008ff36, 28378 }, /* XF86Shop */
{ 0x1008ff2f, 28387 }, /* XF86Sleep */
{ 0x1008ff7c, 28397 }, /* XF86Spell */
{ 0x1008ff7d, 28407 }, /* XF86SplitScreen */
{ 0x1008ff10, 28423 }, /* XF86Standby */
{ 0x1008ff1a, 28435 }, /* XF86Start */
{ 0x1008ff28, 28445 }, /* XF86Stop */
{ 0x1008ff9a, 28454 }, /* XF86Subtitle */
{ 0x1008ff7e, 28467 }, /* XF86Support */
{ 0x1008ffa7, 28479 }, /* XF86Suspend */
{ 0x1008fe01, 28491 }, /* XF86Switch_VT_1 */
{ 0x1008fe0a, 28507 }, /* XF86Switch_VT_10 */
{ 0x1008fe0b, 28524 }, /* XF86Switch_VT_11 */
{ 0x1008fe0c, 28541 }, /* XF86Switch_VT_12 */
{ 0x1008fe02, 28558 }, /* XF86Switch_VT_2 */
{ 0x1008fe03, 28574 }, /* XF86Switch_VT_3 */
{ 0x1008fe04, 28590 }, /* XF86Switch_VT_4 */
{ 0x1008fe05, 28606 }, /* XF86Switch_VT_5 */
{ 0x1008fe06, 28622 }, /* XF86Switch_VT_6 */
{ 0x1008fe07, 28638 }, /* XF86Switch_VT_7 */
{ 0x1008fe08, 28654 }, /* XF86Switch_VT_8 */
{ 0x1008fe09, 28670 }, /* XF86Switch_VT_9 */
{ 0x1008ff7f, 28686 }, /* XF86TaskPane */
{ 0x1008ff80, 28699 }, /* XF86Terminal */
{ 0x1008ff9f, 28712 }, /* XF86Time */
{ 0x1008ff1f, 28721 }, /* XF86ToDoList */
{ 0x1008ff81, 28734 }, /* XF86Tools */
{ 0x1008ffa2, 28744 }, /* XF86TopMenu */
{ 0x1008ffb1, 28756 }, /* XF86TouchpadOff */
{ 0x1008ffb0, 28772 }, /* XF86TouchpadOn */
{ 0x1008ffa9, 28787 }, /* XF86TouchpadToggle */
{ 0x1008ff82, 28806 }, /* XF86Travel */
{ 0x1008fe20, 28817 }, /* XF86Ungrab */
{ 0x1008ff85, 28828 }, /* XF86User1KB */
{ 0x1008ff86, 28840 }, /* XF86User2KB */
{ 0x1008ff84, 28852 }, /* XF86UserPB */
{ 0x1008ff96, 28863 }, /* XF86UWB */
{ 0x1008ff34, 28871 }, /* XF86VendorHome */
{ 0x1008ff87, 28886 }, /* XF86Video */
{ 0x1008ffa1, 28896 }, /* XF86View */
{ 0x1008ff2b, 28905 }, /* XF86WakeUp */
{ 0x1008ff8f, 28916 }, /* XF86WebCam */
{ 0x1008ff88, 28927 }, /* XF86WheelButton */
{ 0x1008ff95, 28943 }, /* XF86WLAN */
{ 0x1008ff89, 28952 }, /* XF86Word */
{ 0x1008ffb4, 28961 }, /* XF86WWAN */
{ 0x1008ff2e, 28970 }, /* XF86WWW */
{ 0x1008ff8a, 28978 }, /* XF86Xfer */
{ 0x1008ffa5, 28987 }, /* XF86Yellow */
{ 0x1008ff8b, 28998 }, /* XF86ZoomIn */
{ 0x1008ff8c, 29009 }, /* XF86ZoomOut */
{ 0x00000059, 29021 }, /* Y */
{ 0x00000079, 29023 }, /* y */
{ 0x000000dd, 29025 }, /* Yacute */
{ 0x000000fd, 29032 }, /* yacute */
{ 0x01001ef4, 29039 }, /* Ybelowdot */
{ 0x01001ef5, 29049 }, /* ybelowdot */
{ 0x01000176, 29059 }, /* Ycircumflex */
{ 0x01000177, 29071 }, /* ycircumflex */
{ 0x000000ff, 29083 }, /* ydiaeresis */
{ 0x000013be, 29094 }, /* Ydiaeresis */
{ 0x000000a5, 29105 }, /* yen */
{ 0x01001ef2, 29109 }, /* Ygrave */
{ 0x01001ef3, 29116 }, /* ygrave */
{ 0x01001ef6, 29123 }, /* Yhook */
{ 0x01001ef7, 29129 }, /* yhook */
{ 0x01001ef8, 29135 }, /* Ytilde */
{ 0x01001ef9, 29142 }, /* ytilde */
{ 0x0000005a, 29149 }, /* Z */
{ 0x0000007a, 29151 }, /* z */
{ 0x000001af, 29153 }, /* Zabovedot */
{ 0x000001bf, 29163 }, /* zabovedot */
{ 0x000001ac, 29173 }, /* Zacute */
{ 0x000001bc, 29180 }, /* zacute */
{ 0x000001ae, 29187 }, /* Zcaron */
{ 0x000001be, 29194 }, /* zcaron */
{ 0x0000ff3d, 29201 }, /* Zen_Koho */
{ 0x0000ff28, 29210 }, /* Zenkaku */
{ 0x0000ff2a, 29218 }, /* Zenkaku_Hankaku */
{ 0x01002080, 29234 }, /* zerosubscript */
{ 0x01002070, 29248 }, /* zerosuperior */
{ 0x010001b5, 29261 }, /* Zstroke */
{ 0x010001b6, 29269 }, /* zstroke */
};
static const struct name_keysym keysym_to_name[] = {
@ -4882,8 +4890,8 @@ static const struct name_keysym keysym_to_name[] = {
{ 0x00000056, 26483 }, /* V */
{ 0x00000057, 26545 }, /* W */
{ 0x00000058, 26631 }, /* X */
{ 0x00000059, 28972 }, /* Y */
{ 0x0000005a, 29100 }, /* Z */
{ 0x00000059, 29021 }, /* Y */
{ 0x0000005a, 29149 }, /* Z */
{ 0x0000005b, 3603 }, /* bracketleft */
{ 0x0000005c, 3352 }, /* backslash */
{ 0x0000005d, 3615 }, /* bracketright */
@ -4914,8 +4922,8 @@ static const struct name_keysym keysym_to_name[] = {
{ 0x00000076, 26485 }, /* v */
{ 0x00000077, 26547 }, /* w */
{ 0x00000078, 26633 }, /* x */
{ 0x00000079, 28974 }, /* y */
{ 0x0000007a, 29102 }, /* z */
{ 0x00000079, 29023 }, /* y */
{ 0x0000007a, 29151 }, /* z */
{ 0x0000007b, 3582 }, /* braceleft */
{ 0x0000007c, 3392 }, /* bar */
{ 0x0000007d, 3592 }, /* braceright */
@ -4925,7 +4933,7 @@ static const struct name_keysym keysym_to_name[] = {
{ 0x000000a2, 8589 }, /* cent */
{ 0x000000a3, 23827 }, /* sterling */
{ 0x000000a4, 8766 }, /* currency */
{ 0x000000a5, 29056 }, /* yen */
{ 0x000000a5, 29105 }, /* yen */
{ 0x000000a6, 8389 }, /* brokenbar */
{ 0x000000a7, 22719 }, /* section */
{ 0x000000a8, 11203 }, /* diaeresis */
@ -4981,7 +4989,7 @@ static const struct name_keysym keysym_to_name[] = {
{ 0x000000da, 25851 }, /* Uacute */
{ 0x000000db, 25899 }, /* Ucircumflex */
{ 0x000000dc, 25923 }, /* Udiaeresis */
{ 0x000000dd, 28976 }, /* Yacute */
{ 0x000000dd, 29025 }, /* Yacute */
{ 0x000000de, 25499 }, /* THORN */
{ 0x000000df, 23820 }, /* ssharp */
{ 0x000000e0, 861 }, /* agrave */
@ -5013,9 +5021,9 @@ static const struct name_keysym keysym_to_name[] = {
{ 0x000000fa, 25858 }, /* uacute */
{ 0x000000fb, 25911 }, /* ucircumflex */
{ 0x000000fc, 25934 }, /* udiaeresis */
{ 0x000000fd, 28983 }, /* yacute */
{ 0x000000fd, 29032 }, /* yacute */
{ 0x000000fe, 25511 }, /* thorn */
{ 0x000000ff, 29034 }, /* ydiaeresis */
{ 0x000000ff, 29083 }, /* ydiaeresis */
{ 0x000001a1, 918 }, /* Aogonek */
{ 0x000001a2, 8383 }, /* breve */
{ 0x000001a3, 19517 }, /* Lstroke */
@ -5024,9 +5032,9 @@ static const struct name_keysym keysym_to_name[] = {
{ 0x000001a9, 22617 }, /* Scaron */
{ 0x000001aa, 22631 }, /* Scedilla */
{ 0x000001ab, 24322 }, /* Tcaron */
{ 0x000001ac, 29124 }, /* Zacute */
{ 0x000001ae, 29138 }, /* Zcaron */
{ 0x000001af, 29104 }, /* Zabovedot */
{ 0x000001ac, 29173 }, /* Zacute */
{ 0x000001ae, 29187 }, /* Zcaron */
{ 0x000001af, 29153 }, /* Zabovedot */
{ 0x000001b1, 926 }, /* aogonek */
{ 0x000001b2, 20520 }, /* ogonek */
{ 0x000001b3, 19525 }, /* lstroke */
@ -5036,10 +5044,10 @@ static const struct name_keysym keysym_to_name[] = {
{ 0x000001b9, 22624 }, /* scaron */
{ 0x000001ba, 22640 }, /* scedilla */
{ 0x000001bb, 24329 }, /* tcaron */
{ 0x000001bc, 29131 }, /* zacute */
{ 0x000001bc, 29180 }, /* zacute */
{ 0x000001bd, 11283 }, /* doubleacute */
{ 0x000001be, 29145 }, /* zcaron */
{ 0x000001bf, 29114 }, /* zabovedot */
{ 0x000001be, 29194 }, /* zcaron */
{ 0x000001bf, 29163 }, /* zabovedot */
{ 0x000001c0, 22272 }, /* Racute */
{ 0x000001c3, 445 }, /* Abreve */
{ 0x000001c5, 19147 }, /* Lacute */
@ -5789,7 +5797,7 @@ static const struct name_keysym keysym_to_name[] = {
{ 0x00000eff, 18797 }, /* Korean_Won */
{ 0x000013bc, 20514 }, /* OE */
{ 0x000013bd, 20517 }, /* oe */
{ 0x000013be, 29045 }, /* Ydiaeresis */
{ 0x000013be, 29094 }, /* Ydiaeresis */
{ 0x000020ac, 12090 }, /* EuroSign */
{ 0x0000fd01, 125 }, /* 3270_Duplicate */
{ 0x0000fd02, 195 }, /* 3270_FieldMark */
@ -5978,9 +5986,9 @@ static const struct name_keysym keysym_to_name[] = {
{ 0x0000ff25, 16635 }, /* Hiragana */
{ 0x0000ff26, 18770 }, /* Katakana */
{ 0x0000ff27, 16644 }, /* Hiragana_Katakana */
{ 0x0000ff28, 29161 }, /* Zenkaku */
{ 0x0000ff28, 29210 }, /* Zenkaku */
{ 0x0000ff29, 16048 }, /* Hankaku */
{ 0x0000ff2a, 29169 }, /* Zenkaku_Hankaku */
{ 0x0000ff2a, 29218 }, /* Zenkaku_Hankaku */
{ 0x0000ff2b, 25752 }, /* Touroku */
{ 0x0000ff2c, 19698 }, /* Massyo */
{ 0x0000ff2d, 18351 }, /* Kana_Lock */
@ -6124,16 +6132,16 @@ static const struct name_keysym keysym_to_name[] = {
{ 0x0100012d, 17124 }, /* ibreve */
{ 0x01000174, 26563 }, /* Wcircumflex */
{ 0x01000175, 26575 }, /* wcircumflex */
{ 0x01000176, 29010 }, /* Ycircumflex */
{ 0x01000177, 29022 }, /* ycircumflex */
{ 0x01000176, 29059 }, /* Ycircumflex */
{ 0x01000177, 29071 }, /* ycircumflex */
{ 0x0100018f, 22649 }, /* SCHWA */
{ 0x0100019f, 20218 }, /* Obarred */
{ 0x010001a0, 20553 }, /* Ohorn */
{ 0x010001a1, 20559 }, /* ohorn */
{ 0x010001af, 25997 }, /* Uhorn */
{ 0x010001b0, 26003 }, /* uhorn */
{ 0x010001b5, 29212 }, /* Zstroke */
{ 0x010001b6, 29220 }, /* zstroke */
{ 0x010001b5, 29261 }, /* Zstroke */
{ 0x010001b6, 29269 }, /* zstroke */
{ 0x010001b7, 12147 }, /* EZH */
{ 0x010001d1, 20254 }, /* Ocaron */
{ 0x010001d2, 20261 }, /* ocaron */
@ -6521,22 +6529,22 @@ static const struct name_keysym keysym_to_name[] = {
{ 0x01001eef, 26112 }, /* uhorntilde */
{ 0x01001ef0, 26031 }, /* Uhornbelowdot */
{ 0x01001ef1, 26045 }, /* uhornbelowdot */
{ 0x01001ef2, 29060 }, /* Ygrave */
{ 0x01001ef3, 29067 }, /* ygrave */
{ 0x01001ef4, 28990 }, /* Ybelowdot */
{ 0x01001ef5, 29000 }, /* ybelowdot */
{ 0x01001ef6, 29074 }, /* Yhook */
{ 0x01001ef7, 29080 }, /* yhook */
{ 0x01001ef8, 29086 }, /* Ytilde */
{ 0x01001ef9, 29093 }, /* ytilde */
{ 0x01002070, 29199 }, /* zerosuperior */
{ 0x01001ef2, 29109 }, /* Ygrave */
{ 0x01001ef3, 29116 }, /* ygrave */
{ 0x01001ef4, 29039 }, /* Ybelowdot */
{ 0x01001ef5, 29049 }, /* ybelowdot */
{ 0x01001ef6, 29123 }, /* Yhook */
{ 0x01001ef7, 29129 }, /* yhook */
{ 0x01001ef8, 29135 }, /* Ytilde */
{ 0x01001ef9, 29142 }, /* ytilde */
{ 0x01002070, 29248 }, /* zerosuperior */
{ 0x01002074, 12632 }, /* foursuperior */
{ 0x01002075, 12594 }, /* fivesuperior */
{ 0x01002076, 23756 }, /* sixsuperior */
{ 0x01002077, 22932 }, /* sevensuperior */
{ 0x01002078, 11765 }, /* eightsuperior */
{ 0x01002079, 20062 }, /* ninesuperior */
{ 0x01002080, 29185 }, /* zerosubscript */
{ 0x01002080, 29234 }, /* zerosubscript */
{ 0x01002081, 20742 }, /* onesubscript */
{ 0x01002082, 25812 }, /* twosubscript */
{ 0x01002083, 25556 }, /* threesubscript */
@ -6924,181 +6932,185 @@ static const struct name_keysym keysym_to_name[] = {
{ 0x1005ff7b, 24215 }, /* SunVideoLowerBrightness */
{ 0x1005ff7c, 24239 }, /* SunVideoRaiseBrightness */
{ 0x1005ff7d, 24127 }, /* SunPowerSwitchShift */
{ 0x1008fe01, 28451 }, /* XF86Switch_VT_1 */
{ 0x1008fe02, 28518 }, /* XF86Switch_VT_2 */
{ 0x1008fe03, 28534 }, /* XF86Switch_VT_3 */
{ 0x1008fe04, 28550 }, /* XF86Switch_VT_4 */
{ 0x1008fe05, 28566 }, /* XF86Switch_VT_5 */
{ 0x1008fe06, 28582 }, /* XF86Switch_VT_6 */
{ 0x1008fe07, 28598 }, /* XF86Switch_VT_7 */
{ 0x1008fe08, 28614 }, /* XF86Switch_VT_8 */
{ 0x1008fe09, 28630 }, /* XF86Switch_VT_9 */
{ 0x1008fe0a, 28467 }, /* XF86Switch_VT_10 */
{ 0x1008fe0b, 28484 }, /* XF86Switch_VT_11 */
{ 0x1008fe0c, 28501 }, /* XF86Switch_VT_12 */
{ 0x1008fe20, 28777 }, /* XF86Ungrab */
{ 0x1008fe21, 27135 }, /* XF86ClearGrab */
{ 0x1008fe22, 27962 }, /* XF86Next_VMode */
{ 0x1008fe23, 28084 }, /* XF86Prev_VMode */
{ 0x1008fe24, 27742 }, /* XF86LogWindowTree */
{ 0x1008fe25, 27715 }, /* XF86LogGrabInfo */
{ 0x1008ff01, 27853 }, /* XF86ModeLock */
{ 0x1008ff02, 27888 }, /* XF86MonBrightnessUp */
{ 0x1008ff03, 27866 }, /* XF86MonBrightnessDown */
{ 0x1008ff04, 27491 }, /* XF86KbdLightOnOff */
{ 0x1008ff05, 27471 }, /* XF86KbdBrightnessUp */
{ 0x1008ff06, 27449 }, /* XF86KbdBrightnessDown */
{ 0x1008ff10, 28383 }, /* XF86Standby */
{ 0x1008fe01, 28491 }, /* XF86Switch_VT_1 */
{ 0x1008fe02, 28558 }, /* XF86Switch_VT_2 */
{ 0x1008fe03, 28574 }, /* XF86Switch_VT_3 */
{ 0x1008fe04, 28590 }, /* XF86Switch_VT_4 */
{ 0x1008fe05, 28606 }, /* XF86Switch_VT_5 */
{ 0x1008fe06, 28622 }, /* XF86Switch_VT_6 */
{ 0x1008fe07, 28638 }, /* XF86Switch_VT_7 */
{ 0x1008fe08, 28654 }, /* XF86Switch_VT_8 */
{ 0x1008fe09, 28670 }, /* XF86Switch_VT_9 */
{ 0x1008fe0a, 28507 }, /* XF86Switch_VT_10 */
{ 0x1008fe0b, 28524 }, /* XF86Switch_VT_11 */
{ 0x1008fe0c, 28541 }, /* XF86Switch_VT_12 */
{ 0x1008fe20, 28817 }, /* XF86Ungrab */
{ 0x1008fe21, 27151 }, /* XF86ClearGrab */
{ 0x1008fe22, 27991 }, /* XF86Next_VMode */
{ 0x1008fe23, 28113 }, /* XF86Prev_VMode */
{ 0x1008fe24, 27771 }, /* XF86LogWindowTree */
{ 0x1008fe25, 27744 }, /* XF86LogGrabInfo */
{ 0x1008ff01, 27882 }, /* XF86ModeLock */
{ 0x1008ff02, 27917 }, /* XF86MonBrightnessUp */
{ 0x1008ff03, 27895 }, /* XF86MonBrightnessDown */
{ 0x1008ff04, 27507 }, /* XF86KbdLightOnOff */
{ 0x1008ff05, 27487 }, /* XF86KbdBrightnessUp */
{ 0x1008ff06, 27465 }, /* XF86KbdBrightnessDown */
{ 0x1008ff10, 28423 }, /* XF86Standby */
{ 0x1008ff11, 26749 }, /* XF86AudioLowerVolume */
{ 0x1008ff12, 26802 }, /* XF86AudioMute */
{ 0x1008ff13, 26873 }, /* XF86AudioRaiseVolume */
{ 0x1008ff13, 26889 }, /* XF86AudioRaiseVolume */
{ 0x1008ff14, 26845 }, /* XF86AudioPlay */
{ 0x1008ff15, 26962 }, /* XF86AudioStop */
{ 0x1008ff16, 26859 }, /* XF86AudioPrev */
{ 0x1008ff15, 26978 }, /* XF86AudioStop */
{ 0x1008ff16, 26875 }, /* XF86AudioPrev */
{ 0x1008ff17, 26816 }, /* XF86AudioNext */
{ 0x1008ff18, 27412 }, /* XF86HomePage */
{ 0x1008ff19, 27760 }, /* XF86Mail */
{ 0x1008ff1a, 28395 }, /* XF86Start */
{ 0x1008ff1b, 28307 }, /* XF86Search */
{ 0x1008ff1c, 26914 }, /* XF86AudioRecord */
{ 0x1008ff1d, 27090 }, /* XF86Calculator */
{ 0x1008ff1e, 27808 }, /* XF86Memo */
{ 0x1008ff1f, 28681 }, /* XF86ToDoList */
{ 0x1008ff20, 27105 }, /* XF86Calendar */
{ 0x1008ff21, 28057 }, /* XF86PowerDown */
{ 0x1008ff22, 27173 }, /* XF86ContrastAdjust */
{ 0x1008ff23, 28177 }, /* XF86RockerUp */
{ 0x1008ff24, 28146 }, /* XF86RockerDown */
{ 0x1008ff25, 28161 }, /* XF86RockerEnter */
{ 0x1008ff26, 26985 }, /* XF86Back */
{ 0x1008ff27, 27317 }, /* XF86Forward */
{ 0x1008ff28, 28405 }, /* XF86Stop */
{ 0x1008ff29, 28113 }, /* XF86Refresh */
{ 0x1008ff2a, 28071 }, /* XF86PowerOff */
{ 0x1008ff2b, 28865 }, /* XF86WakeUp */
{ 0x1008ff2c, 27258 }, /* XF86Eject */
{ 0x1008ff2d, 28247 }, /* XF86ScreenSaver */
{ 0x1008ff2e, 28921 }, /* XF86WWW */
{ 0x1008ff2f, 28347 }, /* XF86Sleep */
{ 0x1008ff30, 27291 }, /* XF86Favorites */
{ 0x1008ff18, 27428 }, /* XF86HomePage */
{ 0x1008ff19, 27789 }, /* XF86Mail */
{ 0x1008ff1a, 28435 }, /* XF86Start */
{ 0x1008ff1b, 28347 }, /* XF86Search */
{ 0x1008ff1c, 26930 }, /* XF86AudioRecord */
{ 0x1008ff1d, 27106 }, /* XF86Calculator */
{ 0x1008ff1e, 27837 }, /* XF86Memo */
{ 0x1008ff1f, 28721 }, /* XF86ToDoList */
{ 0x1008ff20, 27121 }, /* XF86Calendar */
{ 0x1008ff21, 28086 }, /* XF86PowerDown */
{ 0x1008ff22, 27189 }, /* XF86ContrastAdjust */
{ 0x1008ff23, 28217 }, /* XF86RockerUp */
{ 0x1008ff24, 28186 }, /* XF86RockerDown */
{ 0x1008ff25, 28201 }, /* XF86RockerEnter */
{ 0x1008ff26, 27001 }, /* XF86Back */
{ 0x1008ff27, 27333 }, /* XF86Forward */
{ 0x1008ff28, 28445 }, /* XF86Stop */
{ 0x1008ff29, 28142 }, /* XF86Refresh */
{ 0x1008ff2a, 28100 }, /* XF86PowerOff */
{ 0x1008ff2b, 28905 }, /* XF86WakeUp */
{ 0x1008ff2c, 27274 }, /* XF86Eject */
{ 0x1008ff2d, 28287 }, /* XF86ScreenSaver */
{ 0x1008ff2e, 28970 }, /* XF86WWW */
{ 0x1008ff2f, 28387 }, /* XF86Sleep */
{ 0x1008ff30, 27307 }, /* XF86Favorites */
{ 0x1008ff31, 26830 }, /* XF86AudioPause */
{ 0x1008ff32, 26770 }, /* XF86AudioMedia */
{ 0x1008ff33, 27918 }, /* XF86MyComputer */
{ 0x1008ff34, 28831 }, /* XF86VendorHome */
{ 0x1008ff35, 27701 }, /* XF86LightBulb */
{ 0x1008ff36, 28338 }, /* XF86Shop */
{ 0x1008ff37, 27400 }, /* XF86History */
{ 0x1008ff38, 28001 }, /* XF86OpenURL */
{ 0x1008ff33, 27947 }, /* XF86MyComputer */
{ 0x1008ff34, 28871 }, /* XF86VendorHome */
{ 0x1008ff35, 27730 }, /* XF86LightBulb */
{ 0x1008ff36, 28378 }, /* XF86Shop */
{ 0x1008ff37, 27416 }, /* XF86History */
{ 0x1008ff38, 28030 }, /* XF86OpenURL */
{ 0x1008ff39, 26655 }, /* XF86AddFavorite */
{ 0x1008ff3a, 27425 }, /* XF86HotLinks */
{ 0x1008ff3b, 27054 }, /* XF86BrightnessAdjust */
{ 0x1008ff3c, 27305 }, /* XF86Finance */
{ 0x1008ff3d, 27159 }, /* XF86Community */
{ 0x1008ff3e, 26946 }, /* XF86AudioRewind */
{ 0x1008ff3f, 26994 }, /* XF86BackForward */
{ 0x1008ff40, 27509 }, /* XF86Launch0 */
{ 0x1008ff41, 27521 }, /* XF86Launch1 */
{ 0x1008ff42, 27533 }, /* XF86Launch2 */
{ 0x1008ff43, 27545 }, /* XF86Launch3 */
{ 0x1008ff44, 27557 }, /* XF86Launch4 */
{ 0x1008ff45, 27569 }, /* XF86Launch5 */
{ 0x1008ff46, 27581 }, /* XF86Launch6 */
{ 0x1008ff47, 27593 }, /* XF86Launch7 */
{ 0x1008ff48, 27605 }, /* XF86Launch8 */
{ 0x1008ff49, 27617 }, /* XF86Launch9 */
{ 0x1008ff4a, 27629 }, /* XF86LaunchA */
{ 0x1008ff4b, 27641 }, /* XF86LaunchB */
{ 0x1008ff4c, 27653 }, /* XF86LaunchC */
{ 0x1008ff4d, 27665 }, /* XF86LaunchD */
{ 0x1008ff4e, 27677 }, /* XF86LaunchE */
{ 0x1008ff4f, 27689 }, /* XF86LaunchF */
{ 0x1008ff3a, 27441 }, /* XF86HotLinks */
{ 0x1008ff3b, 27070 }, /* XF86BrightnessAdjust */
{ 0x1008ff3c, 27321 }, /* XF86Finance */
{ 0x1008ff3d, 27175 }, /* XF86Community */
{ 0x1008ff3e, 26962 }, /* XF86AudioRewind */
{ 0x1008ff3f, 27010 }, /* XF86BackForward */
{ 0x1008ff40, 27538 }, /* XF86Launch0 */
{ 0x1008ff41, 27550 }, /* XF86Launch1 */
{ 0x1008ff42, 27562 }, /* XF86Launch2 */
{ 0x1008ff43, 27574 }, /* XF86Launch3 */
{ 0x1008ff44, 27586 }, /* XF86Launch4 */
{ 0x1008ff45, 27598 }, /* XF86Launch5 */
{ 0x1008ff46, 27610 }, /* XF86Launch6 */
{ 0x1008ff47, 27622 }, /* XF86Launch7 */
{ 0x1008ff48, 27634 }, /* XF86Launch8 */
{ 0x1008ff49, 27646 }, /* XF86Launch9 */
{ 0x1008ff4a, 27658 }, /* XF86LaunchA */
{ 0x1008ff4b, 27670 }, /* XF86LaunchB */
{ 0x1008ff4c, 27682 }, /* XF86LaunchC */
{ 0x1008ff4d, 27694 }, /* XF86LaunchD */
{ 0x1008ff4e, 27706 }, /* XF86LaunchE */
{ 0x1008ff4f, 27718 }, /* XF86LaunchF */
{ 0x1008ff50, 26671 }, /* XF86ApplicationLeft */
{ 0x1008ff51, 26691 }, /* XF86ApplicationRight */
{ 0x1008ff52, 27045 }, /* XF86Book */
{ 0x1008ff53, 27118 }, /* XF86CD */
{ 0x1008ff54, 27075 }, /* XF86Calculater */
{ 0x1008ff55, 27125 }, /* XF86Clear */
{ 0x1008ff56, 27149 }, /* XF86Close */
{ 0x1008ff57, 27192 }, /* XF86Copy */
{ 0x1008ff58, 27201 }, /* XF86Cut */
{ 0x1008ff59, 27224 }, /* XF86Display */
{ 0x1008ff5a, 27250 }, /* XF86DOS */
{ 0x1008ff5b, 27236 }, /* XF86Documents */
{ 0x1008ff5c, 27268 }, /* XF86Excel */
{ 0x1008ff5d, 27278 }, /* XF86Explorer */
{ 0x1008ff5e, 27360 }, /* XF86Game */
{ 0x1008ff5f, 27369 }, /* XF86Go */
{ 0x1008ff60, 27438 }, /* XF86iTouch */
{ 0x1008ff61, 27731 }, /* XF86LogOff */
{ 0x1008ff62, 27785 }, /* XF86Market */
{ 0x1008ff63, 27796 }, /* XF86Meeting */
{ 0x1008ff65, 27817 }, /* XF86MenuKB */
{ 0x1008ff66, 27828 }, /* XF86MenuPB */
{ 0x1008ff67, 27933 }, /* XF86MySites */
{ 0x1008ff68, 27945 }, /* XF86New */
{ 0x1008ff69, 27953 }, /* XF86News */
{ 0x1008ff6a, 27977 }, /* XF86OfficeHome */
{ 0x1008ff6b, 27992 }, /* XF86Open */
{ 0x1008ff6c, 28013 }, /* XF86Option */
{ 0x1008ff6d, 28024 }, /* XF86Paste */
{ 0x1008ff6e, 28034 }, /* XF86Phone */
{ 0x1008ff70, 28099 }, /* XF86Q */
{ 0x1008ff72, 28136 }, /* XF86Reply */
{ 0x1008ff73, 28125 }, /* XF86Reload */
{ 0x1008ff74, 28190 }, /* XF86RotateWindows */
{ 0x1008ff75, 28223 }, /* XF86RotationPB */
{ 0x1008ff76, 28208 }, /* XF86RotationKB */
{ 0x1008ff77, 28238 }, /* XF86Save */
{ 0x1008ff78, 28294 }, /* XF86ScrollUp */
{ 0x1008ff79, 28279 }, /* XF86ScrollDown */
{ 0x1008ff7a, 28263 }, /* XF86ScrollClick */
{ 0x1008ff7b, 28329 }, /* XF86Send */
{ 0x1008ff7c, 28357 }, /* XF86Spell */
{ 0x1008ff7d, 28367 }, /* XF86SplitScreen */
{ 0x1008ff7e, 28427 }, /* XF86Support */
{ 0x1008ff7f, 28646 }, /* XF86TaskPane */
{ 0x1008ff80, 28659 }, /* XF86Terminal */
{ 0x1008ff81, 28694 }, /* XF86Tools */
{ 0x1008ff82, 28766 }, /* XF86Travel */
{ 0x1008ff84, 28812 }, /* XF86UserPB */
{ 0x1008ff85, 28788 }, /* XF86User1KB */
{ 0x1008ff86, 28800 }, /* XF86User2KB */
{ 0x1008ff87, 28846 }, /* XF86Video */
{ 0x1008ff88, 28887 }, /* XF86WheelButton */
{ 0x1008ff89, 28912 }, /* XF86Word */
{ 0x1008ff8a, 28929 }, /* XF86Xfer */
{ 0x1008ff8b, 28949 }, /* XF86ZoomIn */
{ 0x1008ff8c, 28960 }, /* XF86ZoomOut */
{ 0x1008ff8d, 26976 }, /* XF86Away */
{ 0x1008ff8e, 27839 }, /* XF86Messenger */
{ 0x1008ff8f, 28876 }, /* XF86WebCam */
{ 0x1008ff90, 27769 }, /* XF86MailForward */
{ 0x1008ff91, 28044 }, /* XF86Pictures */
{ 0x1008ff92, 27908 }, /* XF86Music */
{ 0x1008ff93, 27010 }, /* XF86Battery */
{ 0x1008ff94, 27031 }, /* XF86Bluetooth */
{ 0x1008ff95, 28903 }, /* XF86WLAN */
{ 0x1008ff96, 28823 }, /* XF86UWB */
{ 0x1008ff52, 27061 }, /* XF86Book */
{ 0x1008ff53, 27134 }, /* XF86CD */
{ 0x1008ff54, 27091 }, /* XF86Calculater */
{ 0x1008ff55, 27141 }, /* XF86Clear */
{ 0x1008ff56, 27165 }, /* XF86Close */
{ 0x1008ff57, 27208 }, /* XF86Copy */
{ 0x1008ff58, 27217 }, /* XF86Cut */
{ 0x1008ff59, 27240 }, /* XF86Display */
{ 0x1008ff5a, 27266 }, /* XF86DOS */
{ 0x1008ff5b, 27252 }, /* XF86Documents */
{ 0x1008ff5c, 27284 }, /* XF86Excel */
{ 0x1008ff5d, 27294 }, /* XF86Explorer */
{ 0x1008ff5e, 27376 }, /* XF86Game */
{ 0x1008ff5f, 27385 }, /* XF86Go */
{ 0x1008ff60, 27454 }, /* XF86iTouch */
{ 0x1008ff61, 27760 }, /* XF86LogOff */
{ 0x1008ff62, 27814 }, /* XF86Market */
{ 0x1008ff63, 27825 }, /* XF86Meeting */
{ 0x1008ff65, 27846 }, /* XF86MenuKB */
{ 0x1008ff66, 27857 }, /* XF86MenuPB */
{ 0x1008ff67, 27962 }, /* XF86MySites */
{ 0x1008ff68, 27974 }, /* XF86New */
{ 0x1008ff69, 27982 }, /* XF86News */
{ 0x1008ff6a, 28006 }, /* XF86OfficeHome */
{ 0x1008ff6b, 28021 }, /* XF86Open */
{ 0x1008ff6c, 28042 }, /* XF86Option */
{ 0x1008ff6d, 28053 }, /* XF86Paste */
{ 0x1008ff6e, 28063 }, /* XF86Phone */
{ 0x1008ff70, 28128 }, /* XF86Q */
{ 0x1008ff72, 28165 }, /* XF86Reply */
{ 0x1008ff73, 28154 }, /* XF86Reload */
{ 0x1008ff74, 28230 }, /* XF86RotateWindows */
{ 0x1008ff75, 28263 }, /* XF86RotationPB */
{ 0x1008ff76, 28248 }, /* XF86RotationKB */
{ 0x1008ff77, 28278 }, /* XF86Save */
{ 0x1008ff78, 28334 }, /* XF86ScrollUp */
{ 0x1008ff79, 28319 }, /* XF86ScrollDown */
{ 0x1008ff7a, 28303 }, /* XF86ScrollClick */
{ 0x1008ff7b, 28369 }, /* XF86Send */
{ 0x1008ff7c, 28397 }, /* XF86Spell */
{ 0x1008ff7d, 28407 }, /* XF86SplitScreen */
{ 0x1008ff7e, 28467 }, /* XF86Support */
{ 0x1008ff7f, 28686 }, /* XF86TaskPane */
{ 0x1008ff80, 28699 }, /* XF86Terminal */
{ 0x1008ff81, 28734 }, /* XF86Tools */
{ 0x1008ff82, 28806 }, /* XF86Travel */
{ 0x1008ff84, 28852 }, /* XF86UserPB */
{ 0x1008ff85, 28828 }, /* XF86User1KB */
{ 0x1008ff86, 28840 }, /* XF86User2KB */
{ 0x1008ff87, 28886 }, /* XF86Video */
{ 0x1008ff88, 28927 }, /* XF86WheelButton */
{ 0x1008ff89, 28952 }, /* XF86Word */
{ 0x1008ff8a, 28978 }, /* XF86Xfer */
{ 0x1008ff8b, 28998 }, /* XF86ZoomIn */
{ 0x1008ff8c, 29009 }, /* XF86ZoomOut */
{ 0x1008ff8d, 26992 }, /* XF86Away */
{ 0x1008ff8e, 27868 }, /* XF86Messenger */
{ 0x1008ff8f, 28916 }, /* XF86WebCam */
{ 0x1008ff90, 27798 }, /* XF86MailForward */
{ 0x1008ff91, 28073 }, /* XF86Pictures */
{ 0x1008ff92, 27937 }, /* XF86Music */
{ 0x1008ff93, 27026 }, /* XF86Battery */
{ 0x1008ff94, 27047 }, /* XF86Bluetooth */
{ 0x1008ff95, 28943 }, /* XF86WLAN */
{ 0x1008ff96, 28863 }, /* XF86UWB */
{ 0x1008ff97, 26732 }, /* XF86AudioForward */
{ 0x1008ff98, 26930 }, /* XF86AudioRepeat */
{ 0x1008ff99, 26894 }, /* XF86AudioRandomPlay */
{ 0x1008ff9a, 28414 }, /* XF86Subtitle */
{ 0x1008ff98, 26946 }, /* XF86AudioRepeat */
{ 0x1008ff99, 26910 }, /* XF86AudioRandomPlay */
{ 0x1008ff9a, 28454 }, /* XF86Subtitle */
{ 0x1008ff9b, 26712 }, /* XF86AudioCycleTrack */
{ 0x1008ff9c, 27209 }, /* XF86CycleAngle */
{ 0x1008ff9d, 27329 }, /* XF86FrameBack */
{ 0x1008ff9e, 27343 }, /* XF86FrameForward */
{ 0x1008ff9f, 28672 }, /* XF86Time */
{ 0x1008ffa0, 28318 }, /* XF86Select */
{ 0x1008ffa1, 28856 }, /* XF86View */
{ 0x1008ffa2, 28704 }, /* XF86TopMenu */
{ 0x1008ffa3, 28105 }, /* XF86Red */
{ 0x1008ffa4, 27376 }, /* XF86Green */
{ 0x1008ffa5, 28938 }, /* XF86Yellow */
{ 0x1008ffa6, 27022 }, /* XF86Blue */
{ 0x1008ffa7, 28439 }, /* XF86Suspend */
{ 0x1008ffa8, 27386 }, /* XF86Hibernate */
{ 0x1008ffa9, 28747 }, /* XF86TouchpadToggle */
{ 0x1008ffb0, 28732 }, /* XF86TouchpadOn */
{ 0x1008ffb1, 28716 }, /* XF86TouchpadOff */
{ 0x1008ff9c, 27225 }, /* XF86CycleAngle */
{ 0x1008ff9d, 27345 }, /* XF86FrameBack */
{ 0x1008ff9e, 27359 }, /* XF86FrameForward */
{ 0x1008ff9f, 28712 }, /* XF86Time */
{ 0x1008ffa0, 28358 }, /* XF86Select */
{ 0x1008ffa1, 28896 }, /* XF86View */
{ 0x1008ffa2, 28744 }, /* XF86TopMenu */
{ 0x1008ffa3, 28134 }, /* XF86Red */
{ 0x1008ffa4, 27392 }, /* XF86Green */
{ 0x1008ffa5, 28987 }, /* XF86Yellow */
{ 0x1008ffa6, 27038 }, /* XF86Blue */
{ 0x1008ffa7, 28479 }, /* XF86Suspend */
{ 0x1008ffa8, 27402 }, /* XF86Hibernate */
{ 0x1008ffa9, 28787 }, /* XF86TouchpadToggle */
{ 0x1008ffb0, 28772 }, /* XF86TouchpadOn */
{ 0x1008ffb1, 28756 }, /* XF86TouchpadOff */
{ 0x1008ffb2, 26785 }, /* XF86AudioMicMute */
{ 0x1008ffb3, 27525 }, /* XF86Keyboard */
{ 0x1008ffb4, 28961 }, /* XF86WWAN */
{ 0x1008ffb5, 28175 }, /* XF86RFKill */
{ 0x1008ffb6, 26859 }, /* XF86AudioPreset */
};

View File

@ -34,13 +34,13 @@ typedef darray(struct sval) darray_sval;
static inline bool
svaleq(struct sval s1, struct sval s2)
{
return s1.len == s2.len && strncmp(s1.start, s2.start, s1.len) == 0;
return s1.len == s2.len && memcmp(s1.start, s2.start, s1.len) == 0;
}
static inline bool
svaleq_prefix(struct sval s1, struct sval s2)
{
return s1.len <= s2.len && strncmp(s1.start, s2.start, s1.len) == 0;
return s1.len <= s2.len && memcmp(s1.start, s2.start, s1.len) == 0;
}
struct scanner {
@ -54,6 +54,7 @@ struct scanner {
unsigned token_line, token_column;
const char *file_name;
struct xkb_context *ctx;
void *priv;
};
#define scanner_log(scanner, level, fmt, ...) \
@ -70,7 +71,8 @@ struct scanner {
static inline void
scanner_init(struct scanner *s, struct xkb_context *ctx,
const char *string, size_t len, const char *file_name)
const char *string, size_t len, const char *file_name,
void *priv)
{
s->s = string;
s->len = len;
@ -79,6 +81,7 @@ scanner_init(struct scanner *s, struct xkb_context *ctx,
s->token_line = s->token_column = 1;
s->file_name = file_name;
s->ctx = ctx;
s->priv = priv;
}
static inline char
@ -101,6 +104,15 @@ eol(struct scanner *s)
return peek(s) == '\n';
}
static inline void
skip_to_eol(struct scanner *s)
{
const char *nl = memchr(s->s + s->pos, '\n', s->len - s->pos);
const size_t new_pos = nl ? (size_t) (nl - s->s) : s->len;
s->column += new_pos - s->pos;
s->pos = new_pos;
}
static inline char
next(struct scanner *s)
{
@ -130,7 +142,7 @@ str(struct scanner *s, const char *string, size_t len)
{
if (s->len - s->pos < len)
return false;
if (strncasecmp(s->s + s->pos, string, len) != 0)
if (memcmp(s->s + s->pos, string, len) != 0)
return false;
s->pos += len; s->column += len;
return true;
@ -147,6 +159,17 @@ buf_append(struct scanner *s, char ch)
return true;
}
static inline bool
buf_appends(struct scanner *s, const char *str)
{
int ret;
ret = snprintf(s->buf + s->buf_pos, sizeof(s->buf) - s->buf_pos, "%s", str);
if (ret < 0 || (size_t) ret >= sizeof(s->buf) - s->buf_pos)
return false;
s->buf_pos += ret;
return true;
}
static inline bool
oct(struct scanner *s, uint8_t *out)
{
@ -156,4 +179,17 @@ oct(struct scanner *s, uint8_t *out)
return i > 0;
}
static inline bool
hex(struct scanner *s, uint8_t *out)
{
int i;
for (i = 0, *out = 0; is_xdigit(peek(s)) && i < 2; i++) {
const char c = next(s);
const char offset = (c >= '0' && c <= '9' ? '0' :
c >= 'a' && c <= 'f' ? 'a' - 10 : 'A' - 10);
*out = *out * 16 + c - offset;
}
return i > 0;
}
#endif

View File

@ -116,27 +116,34 @@ struct xkb_state {
struct xkb_keymap *keymap;
};
/*
* If the virtual modifiers are not bound to anything, the entry
* is not active and should be skipped. xserver does this with
* cached entry->active field.
*/
static bool
entry_is_active(const struct xkb_key_type_entry *entry)
{
return entry->mods.mods == 0 || entry->mods.mask != 0;
}
static const struct xkb_key_type_entry *
get_entry_for_mods(const struct xkb_key_type *type, xkb_mod_mask_t mods)
{
for (unsigned i = 0; i < type->num_entries; i++)
if (entry_is_active(&type->entries[i]) &&
type->entries[i].mods.mask == mods)
return &type->entries[i];
return NULL;
}
static const struct xkb_key_type_entry *
get_entry_for_key_state(struct xkb_state *state, const struct xkb_key *key,
xkb_layout_index_t group)
{
const struct xkb_key_type *type = key->groups[group].type;
xkb_mod_mask_t active_mods = state->components.mods & type->mods.mask;
for (unsigned i = 0; i < type->num_entries; i++) {
/*
* If the virtual modifiers are not bound to anything, we're
* supposed to skip the entry (xserver does this with cached
* entry->active field).
*/
if (!type->entries[i].mods.mask)
continue;
if (type->entries[i].mods.mask == active_mods)
return &type->entries[i];
}
return NULL;
return get_entry_for_mods(type, active_mods);
}
/**
@ -162,7 +169,7 @@ xkb_state_key_get_level(struct xkb_state *state, xkb_keycode_t kc,
}
xkb_layout_index_t
wrap_group_into_range(int32_t group,
XkbWrapGroupIntoRange(int32_t group,
xkb_layout_index_t num_groups,
enum xkb_range_exceed_type out_of_range_group_action,
xkb_layout_index_t out_of_range_group_number)
@ -210,26 +217,26 @@ xkb_state_key_get_layout(struct xkb_state *state, xkb_keycode_t kc)
if (!key)
return XKB_LAYOUT_INVALID;
return wrap_group_into_range(state->components.group, key->num_groups,
return XkbWrapGroupIntoRange(state->components.group, key->num_groups,
key->out_of_range_group_action,
key->out_of_range_group_number);
}
static const union xkb_action fake = { .type = ACTION_TYPE_NONE };
static const union xkb_action *
xkb_key_get_action(struct xkb_state *state, const struct xkb_key *key)
{
static const union xkb_action dummy = { .type = ACTION_TYPE_NONE };
xkb_layout_index_t layout;
xkb_level_index_t level;
layout = xkb_state_key_get_layout(state, key->keycode);
if (layout == XKB_LAYOUT_INVALID)
return &fake;
return &dummy;
level = xkb_state_key_get_level(state, key->keycode, layout);
if (level == XKB_LEVEL_INVALID)
return &fake;
return &dummy;
return &key->groups[layout].levels[level].action;
}
@ -257,33 +264,20 @@ xkb_filter_new(struct xkb_state *state)
/***====================================================================***/
static bool
xkb_filter_group_set_func(struct xkb_state *state,
struct xkb_filter *filter,
const struct xkb_key *key,
enum xkb_key_direction direction)
{
if (key != filter->key) {
filter->action.group.flags &= ~ACTION_LOCK_CLEAR;
return true;
}
if (direction == XKB_KEY_DOWN) {
filter->refcnt++;
return false;
}
else if (--filter->refcnt > 0) {
return false;
}
state->components.base_group = filter->priv;
if (filter->action.group.flags & ACTION_LOCK_CLEAR)
state->components.locked_group = 0;
filter->func = NULL;
return true;
}
enum xkb_filter_result {
/*
* The event is consumed by the filters.
*
* An event is always processed by all filters, but any filter can
* prevent it from being processed further by consuming it.
*/
XKB_FILTER_CONSUME,
/*
* The event may continue to be processed as far as this filter is
* concerned.
*/
XKB_FILTER_CONTINUE,
};
static void
xkb_filter_group_set_new(struct xkb_state *state, struct xkb_filter *filter)
@ -296,23 +290,31 @@ xkb_filter_group_set_new(struct xkb_state *state, struct xkb_filter *filter)
}
static bool
xkb_filter_group_lock_func(struct xkb_state *state,
struct xkb_filter *filter,
const struct xkb_key *key,
enum xkb_key_direction direction)
xkb_filter_group_set_func(struct xkb_state *state,
struct xkb_filter *filter,
const struct xkb_key *key,
enum xkb_key_direction direction)
{
if (key != filter->key)
return true;
if (key != filter->key) {
filter->action.group.flags &= ~ACTION_LOCK_CLEAR;
return XKB_FILTER_CONTINUE;
}
if (direction == XKB_KEY_DOWN) {
filter->refcnt++;
return false;
return XKB_FILTER_CONSUME;
}
if (--filter->refcnt > 0)
return false;
else if (--filter->refcnt > 0) {
return XKB_FILTER_CONSUME;
}
state->components.base_group = filter->priv;
if (filter->action.group.flags & ACTION_LOCK_CLEAR)
state->components.locked_group = 0;
filter->func = NULL;
return true;
return XKB_FILTER_CONTINUE;
}
static void
@ -325,30 +327,23 @@ xkb_filter_group_lock_new(struct xkb_state *state, struct xkb_filter *filter)
}
static bool
xkb_filter_mod_set_func(struct xkb_state *state,
struct xkb_filter *filter,
const struct xkb_key *key,
enum xkb_key_direction direction)
xkb_filter_group_lock_func(struct xkb_state *state,
struct xkb_filter *filter,
const struct xkb_key *key,
enum xkb_key_direction direction)
{
if (key != filter->key) {
filter->action.mods.flags &= ~ACTION_LOCK_CLEAR;
return true;
}
if (key != filter->key)
return XKB_FILTER_CONTINUE;
if (direction == XKB_KEY_DOWN) {
filter->refcnt++;
return false;
return XKB_FILTER_CONSUME;
}
else if (--filter->refcnt > 0) {
return false;
}
state->clear_mods = filter->action.mods.mods.mask;
if (filter->action.mods.flags & ACTION_LOCK_CLEAR)
state->components.locked_mods &= ~filter->action.mods.mods.mask;
if (--filter->refcnt > 0)
return XKB_FILTER_CONSUME;
filter->func = NULL;
return true;
return XKB_FILTER_CONTINUE;
}
static void
@ -358,27 +353,30 @@ xkb_filter_mod_set_new(struct xkb_state *state, struct xkb_filter *filter)
}
static bool
xkb_filter_mod_lock_func(struct xkb_state *state,
struct xkb_filter *filter,
const struct xkb_key *key,
enum xkb_key_direction direction)
xkb_filter_mod_set_func(struct xkb_state *state,
struct xkb_filter *filter,
const struct xkb_key *key,
enum xkb_key_direction direction)
{
if (key != filter->key)
return true;
if (key != filter->key) {
filter->action.mods.flags &= ~ACTION_LOCK_CLEAR;
return XKB_FILTER_CONTINUE;
}
if (direction == XKB_KEY_DOWN) {
filter->refcnt++;
return false;
return XKB_FILTER_CONSUME;
}
else if (--filter->refcnt > 0) {
return XKB_FILTER_CONSUME;
}
if (--filter->refcnt > 0)
return false;
state->clear_mods |= filter->action.mods.mods.mask;
if (!(filter->action.mods.flags & ACTION_LOCK_NO_UNLOCK))
state->components.locked_mods &= ~filter->priv;
state->clear_mods = filter->action.mods.mods.mask;
if (filter->action.mods.flags & ACTION_LOCK_CLEAR)
state->components.locked_mods &= ~filter->action.mods.mods.mask;
filter->func = NULL;
return true;
return XKB_FILTER_CONTINUE;
}
static void
@ -391,6 +389,30 @@ xkb_filter_mod_lock_new(struct xkb_state *state, struct xkb_filter *filter)
state->components.locked_mods |= filter->action.mods.mods.mask;
}
static bool
xkb_filter_mod_lock_func(struct xkb_state *state,
struct xkb_filter *filter,
const struct xkb_key *key,
enum xkb_key_direction direction)
{
if (key != filter->key)
return XKB_FILTER_CONTINUE;
if (direction == XKB_KEY_DOWN) {
filter->refcnt++;
return XKB_FILTER_CONSUME;
}
if (--filter->refcnt > 0)
return XKB_FILTER_CONSUME;
state->clear_mods |= filter->action.mods.mods.mask;
if (!(filter->action.mods.flags & ACTION_LOCK_NO_UNLOCK))
state->components.locked_mods &= ~filter->priv;
filter->func = NULL;
return XKB_FILTER_CONTINUE;
}
enum xkb_key_latch_state {
NO_LATCH,
LATCH_KEY_DOWN,
@ -414,6 +436,13 @@ xkb_action_breaks_latch(const union xkb_action *action)
}
}
static void
xkb_filter_mod_latch_new(struct xkb_state *state, struct xkb_filter *filter)
{
filter->priv = LATCH_KEY_DOWN;
state->set_mods = filter->action.mods.mods.mask;
}
static bool
xkb_filter_mod_latch_func(struct xkb_state *state,
struct xkb_filter *filter,
@ -445,14 +474,14 @@ xkb_filter_mod_latch_func(struct xkb_state *state,
filter->key = key;
state->components.latched_mods &= ~filter->action.mods.mods.mask;
/* XXX beep beep! */
return false;
return XKB_FILTER_CONSUME;
}
else if (xkb_action_breaks_latch(action)) {
/* XXX: This may be totally broken, we might need to break the
* latch in the next run after this press? */
state->components.latched_mods &= ~filter->action.mods.mods.mask;
filter->func = NULL;
return true;
return XKB_FILTER_CONTINUE;
}
}
else if (direction == XKB_KEY_UP && key == filter->key) {
@ -492,14 +521,7 @@ xkb_filter_mod_latch_func(struct xkb_state *state,
filter->priv = latch;
return true;
}
static void
xkb_filter_mod_latch_new(struct xkb_state *state, struct xkb_filter *filter)
{
filter->priv = LATCH_KEY_DOWN;
state->set_mods = filter->action.mods.mods.mask;
return XKB_FILTER_CONTINUE;
}
static const struct {
@ -531,17 +553,19 @@ xkb_filter_apply_all(struct xkb_state *state,
{
struct xkb_filter *filter;
const union xkb_action *action;
bool send = true;
bool consumed;
/* First run through all the currently active filters and see if any of
* them have claimed this event. */
* them have consumed this event. */
consumed = false;
darray_foreach(filter, state->filters) {
if (!filter->func)
continue;
send = filter->func(state, filter, key, direction) && send;
}
if (!send || direction == XKB_KEY_UP)
if (filter->func(state, filter, key, direction) == XKB_FILTER_CONSUME)
consumed = true;
}
if (consumed || direction == XKB_KEY_UP)
return;
action = xkb_key_get_action(state, key);
@ -560,9 +584,6 @@ xkb_filter_apply_all(struct xkb_state *state,
return;
filter = xkb_filter_new(state);
if (!filter)
return; /* WSGO */
filter->key = key;
filter->func = filter_action_funcs[action->type].func;
filter->action = *action;
@ -619,7 +640,7 @@ xkb_state_led_update_all(struct xkb_state *state)
state->components.leds = 0;
darray_enumerate(idx, led, state->keymap->leds) {
xkb_leds_enumerate(idx, led, state->keymap) {
xkb_mod_mask_t mod_mask = 0;
xkb_layout_mask_t group_mask = 0;
@ -677,13 +698,13 @@ xkb_state_update_derived(struct xkb_state *state)
/* TODO: Use groups_wrap control instead of always RANGE_WRAP. */
wrapped = wrap_group_into_range(state->components.locked_group,
wrapped = XkbWrapGroupIntoRange(state->components.locked_group,
state->keymap->num_groups,
RANGE_WRAP, 0);
state->components.locked_group =
(wrapped == XKB_LAYOUT_INVALID ? 0 : wrapped);
wrapped = wrap_group_into_range(state->components.base_group +
wrapped = XkbWrapGroupIntoRange(state->components.base_group +
state->components.latched_group +
state->components.locked_group,
state->keymap->num_groups,
@ -786,25 +807,37 @@ xkb_state_update_mask(struct xkb_state *state,
xkb_layout_index_t locked_group)
{
struct state_components prev_components;
xkb_mod_index_t num_mods;
xkb_mod_index_t idx;
xkb_mod_mask_t mask;
prev_components = state->components;
state->components.base_mods = 0;
state->components.latched_mods = 0;
state->components.locked_mods = 0;
num_mods = xkb_keymap_num_mods(state->keymap);
/* Only include modifiers which exist in the keymap. */
mask = (xkb_mod_mask_t) ((1ull << xkb_keymap_num_mods(state->keymap)) - 1u);
for (idx = 0; idx < num_mods; idx++) {
xkb_mod_mask_t mod = (1u << idx);
if (base_mods & mod)
state->components.base_mods |= mod;
if (latched_mods & mod)
state->components.latched_mods |= mod;
if (locked_mods & mod)
state->components.locked_mods |= mod;
}
state->components.base_mods = base_mods & mask;
state->components.latched_mods = latched_mods & mask;
state->components.locked_mods = locked_mods & mask;
/* Make sure the mods are fully resolved - since we get arbitrary
* input, they might not be.
*
* It might seem more reasonable to do this only for components.mods
* in xkb_state_update_derived(), rather than for each component
* seperately. That would allow to distinguish between "really"
* depressed mods (would be in MODS_DEPRESSED) and indirectly
* depressed to to a mapping (would only be in MODS_EFFECTIVE).
* However, the traditional behavior of xkb_state_update_key() is that
* if a vmod is depressed, its mappings are depressed with it; so we're
* expected to do the same here. Also, LEDs (usually) look if a real
* mod is locked, not just effective; otherwise it won't be lit.
*
* We OR here because mod_mask_get_effective() drops vmods. */
state->components.base_mods |=
mod_mask_get_effective(state->keymap, state->components.base_mods);
state->components.latched_mods |=
mod_mask_get_effective(state->keymap, state->components.latched_mods);
state->components.locked_mods |=
mod_mask_get_effective(state->keymap, state->components.locked_mods);
state->components.base_group = base_group;
state->components.latched_group = latched_group;
@ -843,7 +876,7 @@ err:
}
/*
* http://www.x.org/releases/current/doc/kbproto/xkbproto.html#Interpreting_the_Lock_Modifier
* https://www.x.org/releases/current/doc/kbproto/xkbproto.html#Interpreting_the_Lock_Modifier
*/
static bool
should_do_caps_transformation(struct xkb_state *state, xkb_keycode_t kc)
@ -857,7 +890,7 @@ should_do_caps_transformation(struct xkb_state *state, xkb_keycode_t kc)
}
/*
* http://www.x.org/releases/current/doc/kbproto/xkbproto.html#Interpreting_the_Control_Modifier
* https://www.x.org/releases/current/doc/kbproto/xkbproto.html#Interpreting_the_Control_Modifier
*/
static bool
should_do_ctrl_transformation(struct xkb_state *state, xkb_keycode_t kc)
@ -1080,6 +1113,28 @@ xkb_state_serialize_layout(struct xkb_state *state,
return ret;
}
/**
* Gets a modifier mask and returns the resolved effective mask; this
* is needed because some modifiers can also map to other modifiers, e.g.
* the "NumLock" modifier usually also sets the "Mod2" modifier.
*/
xkb_mod_mask_t
mod_mask_get_effective(struct xkb_keymap *keymap, xkb_mod_mask_t mods)
{
const struct xkb_mod *mod;
xkb_mod_index_t i;
xkb_mod_mask_t mask;
/* The effective mask is only real mods for now. */
mask = mods & MOD_REAL_MASK_ALL;
xkb_mods_enumerate(i, mod, &keymap->mods)
if (mods & (1u << i))
mask |= mod->mapping;
return mask;
}
/**
* Returns 1 if the given modifier is active with the specified type(s), 0 if
* not, or -1 if the modifier is invalid.
@ -1099,7 +1154,7 @@ xkb_state_mod_index_is_active(struct xkb_state *state,
* Helper function for xkb_state_mod_indices_are_active and
* xkb_state_mod_names_are_active.
*/
static int
static bool
match_mod_masks(struct xkb_state *state,
enum xkb_state_component type,
enum xkb_state_match match,
@ -1108,14 +1163,12 @@ match_mod_masks(struct xkb_state *state,
xkb_mod_mask_t active = xkb_state_serialize_mods(state, type);
if (!(match & XKB_STATE_MATCH_NON_EXCLUSIVE) && (active & ~wanted))
return 0;
return false;
if (match & XKB_STATE_MATCH_ANY)
return !!(active & wanted);
else
return (active & wanted) == wanted;
return active & wanted;
return 0;
return (active & wanted) == wanted;
}
/**
@ -1129,14 +1182,13 @@ xkb_state_mod_indices_are_active(struct xkb_state *state,
...)
{
va_list ap;
xkb_mod_index_t idx = 0;
xkb_mod_mask_t wanted = 0;
int ret = 0;
xkb_mod_index_t num_mods = xkb_keymap_num_mods(state->keymap);
va_start(ap, match);
while (1) {
idx = va_arg(ap, xkb_mod_index_t);
xkb_mod_index_t idx = va_arg(ap, xkb_mod_index_t);
if (idx == XKB_MOD_INVALID)
break;
if (idx >= num_mods) {
@ -1180,12 +1232,12 @@ xkb_state_mod_names_are_active(struct xkb_state *state,
...)
{
va_list ap;
xkb_mod_index_t idx = 0;
xkb_mod_mask_t wanted = 0;
int ret = 0;
va_start(ap, match);
while (1) {
xkb_mod_index_t idx;
const char *str = va_arg(ap, const char *);
if (str == NULL)
break;
@ -1252,8 +1304,8 @@ xkb_state_layout_name_is_active(struct xkb_state *state, const char *name,
XKB_EXPORT int
xkb_state_led_index_is_active(struct xkb_state *state, xkb_led_index_t idx)
{
if (idx >= darray_size(state->keymap->leds) ||
darray_item(state->keymap->leds, idx).name == XKB_ATOM_NONE)
if (idx >= state->keymap->num_leds ||
state->keymap->leds[idx].name == XKB_ATOM_NONE)
return -1;
return !!(state->components.leds & (1u << idx));
@ -1273,13 +1325,20 @@ xkb_state_led_name_is_active(struct xkb_state *state, const char *name)
return xkb_state_led_index_is_active(state, idx);
}
/**
* See:
* - XkbTranslateKeyCode(3), mod_rtrn return value, from libX11.
* - MyEnhancedXkbTranslateKeyCode(), a modification of the above, from GTK+.
*/
static xkb_mod_mask_t
key_get_consumed(struct xkb_state *state, const struct xkb_key *key)
key_get_consumed(struct xkb_state *state, const struct xkb_key *key,
enum xkb_consumed_mode mode)
{
const struct xkb_key_type *type;
const struct xkb_key_type_entry *entry;
xkb_mod_mask_t preserve;
const struct xkb_key_type_entry *matching_entry;
xkb_mod_mask_t preserve = 0;
xkb_layout_index_t group;
xkb_mod_mask_t consumed = 0;
group = xkb_state_key_get_layout(state, key->keycode);
if (group == XKB_LAYOUT_INVALID)
@ -1287,47 +1346,64 @@ key_get_consumed(struct xkb_state *state, const struct xkb_key *key)
type = key->groups[group].type;
entry = get_entry_for_key_state(state, key, group);
if (entry)
preserve = entry->preserve.mask;
else
preserve = 0;
matching_entry = get_entry_for_key_state(state, key, group);
if (matching_entry)
preserve = matching_entry->preserve.mask;
return type->mods.mask & ~preserve;
switch (mode) {
case XKB_CONSUMED_MODE_XKB:
consumed = type->mods.mask;
break;
case XKB_CONSUMED_MODE_GTK: {
const struct xkb_key_type_entry *no_mods_entry;
xkb_level_index_t no_mods_leveli;
const struct xkb_level *no_mods_level, *level;
no_mods_entry = get_entry_for_mods(type, 0);
no_mods_leveli = no_mods_entry ? no_mods_entry->level : 0;
no_mods_level = &key->groups[group].levels[no_mods_leveli];
for (unsigned i = 0; i < type->num_entries; i++) {
const struct xkb_key_type_entry *entry = &type->entries[i];
if (!entry_is_active(entry))
continue;
level = &key->groups[group].levels[entry->level];
if (XkbLevelsSameSyms(level, no_mods_level))
continue;
if (entry == matching_entry || my_popcount(entry->mods.mask) == 1)
consumed |= entry->mods.mask & ~entry->preserve.mask;
}
break;
}
}
return consumed & ~preserve;
}
/**
* Tests to see if a modifier is used up by our translation of a
* keycode to keysyms, taking note of the current modifier state and
* the appropriate key type's preserve information, if any. This allows
* the user to mask out the modifier in later processing of the
* modifiers, e.g. when implementing hot keys or accelerators.
*
* See also, for example:
* - XkbTranslateKeyCode(3), mod_rtrn return value, from libX11.
* - gdk_keymap_translate_keyboard_state, consumed_modifiers return value,
* from gtk+.
*/
XKB_EXPORT int
xkb_state_mod_index_is_consumed(struct xkb_state *state, xkb_keycode_t kc,
xkb_mod_index_t idx)
xkb_state_mod_index_is_consumed2(struct xkb_state *state, xkb_keycode_t kc,
xkb_mod_index_t idx,
enum xkb_consumed_mode mode)
{
const struct xkb_key *key = XkbKey(state->keymap, kc);
if (!key || idx >= xkb_keymap_num_mods(state->keymap))
return -1;
return !!((1u << idx) & key_get_consumed(state, key));
return !!((1u << idx) & key_get_consumed(state, key, mode));
}
XKB_EXPORT int
xkb_state_mod_index_is_consumed(struct xkb_state *state, xkb_keycode_t kc,
xkb_mod_index_t idx)
{
return xkb_state_mod_index_is_consumed2(state, kc, idx,
XKB_CONSUMED_MODE_XKB);
}
/**
* Calculates which modifiers should be consumed during key processing,
* and returns the mask with all these modifiers removed. e.g. if
* given a state of Alt and Shift active for a two-level alphabetic
* key containing plus and equal on the first and second level
* respectively, will return a mask of only Alt, as Shift has been
* consumed by the type handling.
*/
XKB_EXPORT xkb_mod_mask_t
xkb_state_mod_mask_remove_consumed(struct xkb_state *state, xkb_keycode_t kc,
xkb_mod_mask_t mask)
@ -1337,16 +1413,34 @@ xkb_state_mod_mask_remove_consumed(struct xkb_state *state, xkb_keycode_t kc,
if (!key)
return 0;
return mask & ~key_get_consumed(state, key);
return mask & ~key_get_consumed(state, key, XKB_CONSUMED_MODE_XKB);
}
XKB_EXPORT xkb_mod_mask_t
xkb_state_key_get_consumed_mods2(struct xkb_state *state, xkb_keycode_t kc,
enum xkb_consumed_mode mode)
{
const struct xkb_key *key;
switch (mode) {
case XKB_CONSUMED_MODE_XKB:
case XKB_CONSUMED_MODE_GTK:
break;
default:
log_err_func(state->keymap->ctx,
"unrecognized consumed modifiers mode: %d\n", mode);
return 0;
}
key = XkbKey(state->keymap, kc);
if (!key)
return 0;
return key_get_consumed(state, key, mode);
}
XKB_EXPORT xkb_mod_mask_t
xkb_state_key_get_consumed_mods(struct xkb_state *state, xkb_keycode_t kc)
{
const struct xkb_key *key = XkbKey(state->keymap, kc);
if (!key)
return 0;
return key_get_consumed(state, key);
return xkb_state_key_get_consumed_mods2(state, kc, XKB_CONSUMED_MODE_XKB);
}

View File

@ -204,32 +204,20 @@ const LookupEntry symInterpretMatchMaskNames[] = {
{ "AnyOf", MATCH_ANY },
{ "AllOf", MATCH_ALL },
{ "Exactly", MATCH_EXACTLY },
{ NULL, 0 },
};
const char *
ModIndexText(const struct xkb_keymap *keymap, xkb_mod_index_t ndx)
ModIndexText(struct xkb_context *ctx, const struct xkb_mod_set *mods,
xkb_mod_index_t ndx)
{
if (ndx == XKB_MOD_INVALID)
return "none";
if (ndx >= darray_size(keymap->mods))
if (ndx >= mods->num_mods)
return NULL;
return xkb_atom_text(keymap->ctx, darray_item(keymap->mods, ndx).name);
}
xkb_mod_index_t
ModNameToIndex(const struct xkb_keymap *keymap, xkb_atom_t name,
enum mod_type type)
{
xkb_mod_index_t i;
const struct xkb_mod *mod;
darray_enumerate(i, mod, keymap->mods)
if ((mod->type & type) && name == mod->name)
return i;
return XKB_MOD_INVALID;
return xkb_atom_text(ctx, mods->mods[ndx].name);
}
const char *
@ -264,9 +252,10 @@ SIMatchText(enum xkb_match_operation type)
}
const char *
ModMaskText(const struct xkb_keymap *keymap, xkb_mod_mask_t mask)
ModMaskText(struct xkb_context *ctx, const struct xkb_mod_set *mods,
xkb_mod_mask_t mask)
{
char buf[1024];
char buf[1024] = {0};
size_t pos = 0;
xkb_mod_index_t i;
const struct xkb_mod *mod;
@ -277,7 +266,7 @@ ModMaskText(const struct xkb_keymap *keymap, xkb_mod_mask_t mask)
if (mask == MOD_REAL_MASK_ALL)
return "all";
darray_enumerate(i, mod, keymap->mods) {
xkb_mods_enumerate(i, mod, mods) {
int ret;
if (!(mask & (1u << i)))
@ -285,14 +274,14 @@ ModMaskText(const struct xkb_keymap *keymap, xkb_mod_mask_t mask)
ret = snprintf(buf + pos, sizeof(buf) - pos, "%s%s",
pos == 0 ? "" : "+",
xkb_atom_text(keymap->ctx, mod->name));
xkb_atom_text(ctx, mod->name));
if (ret <= 0 || pos + ret >= sizeof(buf))
break;
else
pos += ret;
}
return strcpy(xkb_context_get_buffer(keymap->ctx, pos + 1), buf);
return strcpy(xkb_context_get_buffer(ctx, pos + 1), buf);
}
const char *

View File

@ -48,14 +48,12 @@ extern const LookupEntry actionTypeNames[];
extern const LookupEntry symInterpretMatchMaskNames[];
const char *
ModMaskText(const struct xkb_keymap *keymap, xkb_mod_mask_t mask);
ModMaskText(struct xkb_context *ctx, const struct xkb_mod_set *mods,
xkb_mod_mask_t mask);
const char *
ModIndexText(const struct xkb_keymap *keymap, xkb_mod_index_t ndx);
xkb_mod_index_t
ModNameToIndex(const struct xkb_keymap *keymap, xkb_atom_t name,
enum mod_type type);
ModIndexText(struct xkb_context *ctx, const struct xkb_mod_set *mods,
xkb_mod_index_t ndx);
const char *
ActionTypeText(enum xkb_action_type type);

View File

@ -49,17 +49,13 @@ utf32_to_utf8(uint32_t unichar, char *buffer)
length = 3;
head = 0xe0;
}
else if (unichar <= 0x1fffff) {
else if (unichar <= 0x10ffff) {
length = 4;
head = 0xf0;
}
else if (unichar <= 0x3ffffff) {
length = 5;
head = 0xf8;
}
else {
length = 6;
head = 0xfc;
buffer[0] = '\0';
return 0;
}
for (count = length - 1, shift = 0; count > 0; count--, shift += 6)
@ -80,7 +76,7 @@ is_valid_utf8(const char *ss, size_t len)
/* This beauty is from:
* The Unicode Standard Version 6.2 - Core Specification, Table 3.7
* http://www.unicode.org/versions/Unicode6.2.0/ch03.pdf#G7404
* https://www.unicode.org/versions/Unicode6.2.0/ch03.pdf#G7404
* We can optimize if needed. */
while (i < len)
{

View File

@ -32,13 +32,16 @@
#include <sys/types.h>
bool
map_file(FILE *file, const char **string_out, size_t *size_out)
map_file(FILE *file, char **string_out, size_t *size_out)
{
struct stat stat_buf;
const int fd = fileno(file);
int fd;
char *string;
/* Make sure to keep the errno on failure! */
fd = fileno(file);
if (fd < 0)
return false;
if (fstat(fd, &stat_buf) != 0)
return false;
@ -53,15 +56,15 @@ map_file(FILE *file, const char **string_out, size_t *size_out)
}
void
unmap_file(const char *str, size_t size)
unmap_file(char *str, size_t size)
{
munmap(UNCONSTIFY(str), size);
munmap(str, size);
}
#else
bool
map_file(FILE *file, const char **string_out, size_t *size_out)
map_file(FILE *file, char **string_out, size_t *size_out)
{
long ret;
size_t ret_s;
@ -99,9 +102,62 @@ map_file(FILE *file, const char **string_out, size_t *size_out)
}
void
unmap_file(const char *str, size_t size)
unmap_file(char *str, size_t size)
{
free(UNCONSTIFY(str));
free(str);
}
#endif
// ASCII lower-case map.
static const unsigned char lower_map[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
59, 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122,
91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122,
123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137,
138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152,
153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182,
183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197,
198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212,
213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227,
228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242,
243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
};
// ASCII tolower (to avoid locale issues).
char
to_lower(char c)
{
return (char) lower_map[(unsigned char) c];
}
// ASCII strcasecmp (to avoid locale issues).
int
istrcmp(const char *a, const char *b)
{
for (size_t i = 0; ; i++) {
if (to_lower(a[i]) != to_lower(b[i]))
return (int) to_lower(a[i]) - (int) to_lower(b[i]);
if (!a[i])
break;
}
return 0;
}
// ASCII strncasecmp (to avoid locale issues).
int
istrncmp(const char *a, const char *b, size_t n)
{
for (size_t i = 0; i < n; i++) {
if (to_lower(a[i]) != to_lower(b[i]))
return (int) to_lower(a[i]) - (int) to_lower(b[i]);
if (!a[i])
break;
}
return 0;
}

View File

@ -29,7 +29,6 @@
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include "darray.h"
@ -40,6 +39,19 @@
*/
#define UNCONSTIFY(const_ptr) ((void *) (uintptr_t) (const_ptr))
#define STATIC_ASSERT(expr, message) do { \
switch (0) { case 0: case (expr): ; } \
} while (0)
char
to_lower(char c);
int
istrcmp(const char *a, const char *b);
int
istrncmp(const char *a, const char *b, size_t n);
static inline bool
streq(const char *s1, const char *s2)
{
@ -57,13 +69,13 @@ streq_not_null(const char *s1, const char *s2)
static inline bool
istreq(const char *s1, const char *s2)
{
return strcasecmp(s1, s2) == 0;
return istrcmp(s1, s2) == 0;
}
static inline bool
istreq_prefix(const char *s1, const char *s2)
{
return strncasecmp(s1, s2, strlen(s1)) == 0;
return istrncmp(s1, s2, strlen(s1)) == 0;
}
static inline char *
@ -99,7 +111,7 @@ strempty(const char *s)
static inline void *
memdup(const void *mem, size_t nmemb, size_t size)
{
void *p = malloc(nmemb * size);
void *p = calloc(nmemb, size);
if (p)
memcpy(p, mem, nmemb * size);
return p;
@ -174,11 +186,25 @@ msb_pos(uint32_t mask)
return pos;
}
// Avoid conflict with other popcount()s.
static inline int
my_popcount(uint32_t x)
{
int count;
#if defined(HAVE___BUILTIN_POPCOUNT)
count = __builtin_popcount(x);
#else
for (count = 0; x; count++)
x &= x - 1;
#endif
return count;
}
bool
map_file(FILE *file, const char **string_out, size_t *size_out);
map_file(FILE *file, char **string_out, size_t *size_out);
void
unmap_file(const char *str, size_t size);
unmap_file(char *string, size_t size);
#define ARRAY_SIZE(arr) ((sizeof(arr) / sizeof(*(arr))))
@ -187,6 +213,9 @@ unmap_file(const char *str, size_t size);
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MAX3(a, b, c) MAX(MAX((a), (b)), (c))
/* Round up @a so it's divisible by @b. */
#define ROUNDUP(a, b) (((a) + (b) - 1) / (b) * (b))
#if defined(HAVE_SECURE_GETENV)
# define secure_getenv secure_getenv
#elif defined(HAVE___SECURE_GETENV)

View File

@ -159,9 +159,10 @@ adopt_atoms(struct xkb_context *ctx, xcb_connection_t *conn,
{
enum { SIZE = 128 };
xcb_get_atom_name_cookie_t cookies[SIZE];
const size_t num_batches = ROUNDUP(count, SIZE) / SIZE;
/* Send and collect the atoms in batches of reasonable SIZE. */
for (size_t batch = 0; batch <= count / SIZE; batch++) {
for (size_t batch = 0; batch < num_batches; batch++) {
const size_t start = batch * SIZE;
const size_t stop = min((batch + 1) * SIZE, count);
@ -195,15 +196,12 @@ adopt_atoms(struct xkb_context *ctx, xcb_connection_t *conn,
/*
* If we don't discard the uncollected replies, they just
* sit there waiting. Sad.
* sit in the XCB queue waiting forever. Sad.
*/
err_discard:
for (size_t j = i + 1; j < stop; j++) {
if (from[j] != XCB_ATOM_NONE) {
reply = xcb_get_atom_name_reply(conn, cookies[j % SIZE], NULL);
free(reply);
}
}
for (size_t j = i + 1; j < stop; j++)
if (from[j] != XCB_ATOM_NONE)
xcb_discard_reply(conn, cookies[j % SIZE].sequence);
return false;
}
}

View File

@ -26,7 +26,7 @@
/*
* References for the lonesome traveler:
* Xkb protocol specification:
* http://www.x.org/releases/current/doc/kbproto/xkbproto.html
* https://www.x.org/releases/current/doc/kbproto/xkbproto.html
* The XCB xkb XML protocol file:
* /user/share/xcb/xkb.xml
* The XCB xkb header file:
@ -218,8 +218,8 @@ translate_action(union xkb_action *action, const xcb_xkb_action_t *wire)
case XCB_XKB_SA_TYPE_MOVE_PTR:
action->type = ACTION_TYPE_PTR_MOVE;
action->ptr.x = (wire->moveptr.xLow | (wire->moveptr.xHigh << 8));
action->ptr.y = (wire->moveptr.yLow | (wire->moveptr.yHigh << 8));
action->ptr.x = (int16_t) (wire->moveptr.xLow | ((uint16_t) wire->moveptr.xHigh << 8));
action->ptr.y = (int16_t) (wire->moveptr.yLow | ((uint16_t) wire->moveptr.yHigh << 8));
if (!(wire->moveptr.flags & XCB_XKB_SA_MOVE_PTR_FLAG_NO_ACCELERATION))
action->ptr.flags |= ACTION_ACCEL;
@ -299,6 +299,20 @@ translate_action(union xkb_action *action, const xcb_xkb_action_t *wire)
case XCB_XKB_SA_TYPE_DEVICE_VALUATOR:
action->type = ACTION_TYPE_NONE;
break;
default:
if (wire->type < ACTION_TYPE_PRIVATE) {
action->type = ACTION_TYPE_NONE;
break;
}
/* Treat high unknown actions as Private actions. */
action->priv.type = wire->noaction.type;
STATIC_ASSERT(sizeof(action->priv.data) == 7 &&
sizeof(wire->noaction.pad0) == 7,
"The private action data must be 7 bytes long!");
memcpy(action->priv.data, wire->noaction.pad0, 7);
break;
}
}
@ -434,6 +448,7 @@ get_sym_maps(struct xkb_keymap *keymap, xcb_connection_t *conn,
const xkb_layout_index_t group = j / wire_sym_map->width;
const xkb_level_index_t level = j % wire_sym_map->width;
assert(key->groups[group].type != NULL);
if (level < key->groups[group].type->num_levels &&
wire_keysym != XKB_KEY_NoSymbol) {
key->groups[group].levels[level].num_syms = 1;
@ -508,13 +523,13 @@ get_vmods(struct xkb_keymap *keymap, xcb_connection_t *conn,
{
uint8_t *iter = xcb_xkb_get_map_map_vmods_rtrn(map);
darray_resize0(keymap->mods,
NUM_REAL_MODS + msb_pos(reply->virtualMods));
keymap->mods.num_mods =
NUM_REAL_MODS + MIN(msb_pos(reply->virtualMods), NUM_VMODS);
for (unsigned i = 0; i < NUM_VMODS; i++) {
if (reply->virtualMods & (1u << i)) {
uint8_t wire = *iter;
struct xkb_mod *mod = &darray_item(keymap->mods, NUM_REAL_MODS + i);
struct xkb_mod *mod = &keymap->mods.mods[NUM_REAL_MODS + i];
mod->type = MOD_VIRT;
mod->mapping = translate_mods(wire, 0, 0);
@ -685,12 +700,12 @@ get_indicators(struct xkb_keymap *keymap, xcb_connection_t *conn,
xcb_xkb_indicator_map_iterator_t iter =
xcb_xkb_get_indicator_map_maps_iterator(reply);
darray_resize0(keymap->leds, msb_pos(reply->which));
keymap->num_leds = msb_pos(reply->which);
for (unsigned i = 0; i < NUM_INDICATORS; i++) {
if (reply->which & (1u << i)) {
xcb_xkb_indicator_map_t *wire = iter.data;
struct xkb_led *led = &darray_item(keymap->leds, i);
struct xkb_led *led = &keymap->leds[i];
if (wire->whichGroups & XCB_XKB_IM_GROUPS_WHICH_USE_BASE)
led->which_groups |= XKB_STATE_LAYOUT_DEPRESSED;
@ -789,7 +804,7 @@ get_sym_interprets(struct xkb_keymap *keymap, xcb_connection_t *conn,
}
sym_interpret->level_one_only =
!!(wire->match & XCB_XKB_SYM_INTERP_MATCH_LEVEL_ONE_ONLY);
(wire->match & XCB_XKB_SYM_INTERP_MATCH_LEVEL_ONE_ONLY);
sym_interpret->mods = wire->mods;
if (wire->virtualMod == NO_MODIFIER)
@ -797,7 +812,7 @@ get_sym_interprets(struct xkb_keymap *keymap, xcb_connection_t *conn,
else
sym_interpret->virtual_mod = NUM_REAL_MODS + wire->virtualMod;
sym_interpret->repeat = !!(wire->flags & 0x01);
sym_interpret->repeat = (wire->flags & 0x01);
translate_action(&sym_interpret->action,
(xcb_xkb_action_t *) &wire->action);
@ -887,12 +902,12 @@ get_indicator_names(struct xkb_keymap *keymap, xcb_connection_t *conn,
{
xcb_atom_t *iter = xcb_xkb_get_names_value_list_indicator_names(list);
FAIL_UNLESS(msb_pos(reply->indicators) <= darray_size(keymap->leds));
FAIL_UNLESS(msb_pos(reply->indicators) <= keymap->num_leds);
for (unsigned i = 0; i < NUM_INDICATORS; i++) {
if (reply->indicators & (1u << i)) {
xcb_atom_t wire = *iter;
struct xkb_led *led = &darray_item(keymap->leds, i);
struct xkb_led *led = &keymap->leds[i];
if (!adopt_atom(keymap->ctx, conn, wire, &led->name))
return false;
@ -919,12 +934,13 @@ get_vmod_names(struct xkb_keymap *keymap, xcb_connection_t *conn,
* tells us which vmods exist (a vmod must have a name), so we fix
* up the size here.
*/
darray_resize0(keymap->mods, NUM_REAL_MODS + msb_pos(reply->virtualMods));
keymap->mods.num_mods =
NUM_REAL_MODS + MIN(msb_pos(reply->virtualMods), NUM_VMODS);
for (unsigned i = 0; i < NUM_VMODS; i++) {
if (reply->virtualMods & (1u << i)) {
xcb_atom_t wire = *iter;
struct xkb_mod *mod = &darray_item(keymap->mods, NUM_REAL_MODS + i);
struct xkb_mod *mod = &keymap->mods.mods[NUM_REAL_MODS + i];
if (!adopt_atom(keymap->ctx, conn, wire, &mod->name))
return false;
@ -1115,7 +1131,7 @@ get_controls(struct xkb_keymap *keymap, xcb_connection_t *conn,
FAIL_UNLESS(keymap->max_key_code < XCB_XKB_CONST_PER_KEY_BIT_ARRAY_SIZE * 8);
for (xkb_keycode_t i = keymap->min_key_code; i <= keymap->max_key_code; i++)
keymap->keys[i].repeats = !!(reply->perKeyRepeat[i / 8] & (1 << (i % 8)));
keymap->keys[i].repeats = (reply->perKeyRepeat[i / 8] & (1 << (i % 8)));
free(reply);
return true;
@ -1139,7 +1155,7 @@ xkb_x11_keymap_new_from_device(struct xkb_context *ctx,
return NULL;
}
if (device_id < 0 || device_id > 255) {
if (device_id < 0 || device_id > 127) {
log_err_func(ctx, "illegal device ID: %d\n", device_id);
return NULL;
}

View File

@ -1,189 +0,0 @@
/*
* Copyright © 2012 Daniel Stone
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Author: Daniel Stone <daniel@fooishbar.org>
*/
#define _XKBCOMMON_COMPAT_H /* don't mangle our legacy names! */
#include "xkbcommon/xkbcommon.h"
#include "utils.h"
/* We don't carry any prototypes for these functions, as we #define them
* to their newer versions so people link against those. */
#pragma GCC diagnostic ignored "-Wmissing-prototypes"
XKB_EXPORT struct xkb_keymap *
xkb_map_new_from_names(struct xkb_context *context,
const struct xkb_rule_names *names,
enum xkb_keymap_compile_flags flags)
{
return xkb_keymap_new_from_names(context, names, flags);
}
XKB_EXPORT struct xkb_keymap *
xkb_map_new_from_file(struct xkb_context *context, FILE *file,
enum xkb_keymap_format format,
enum xkb_keymap_compile_flags flags)
{
return xkb_keymap_new_from_file(context, file, format, flags);
}
XKB_EXPORT struct xkb_keymap *
xkb_map_new_from_string(struct xkb_context *context, const char *string,
enum xkb_keymap_format format,
enum xkb_keymap_compile_flags flags)
{
return xkb_keymap_new_from_string(context, string, format, flags);
}
XKB_EXPORT char *
xkb_map_get_as_string(struct xkb_keymap *keymap)
{
return xkb_keymap_get_as_string(keymap, XKB_KEYMAP_FORMAT_TEXT_V1);
}
XKB_EXPORT struct xkb_keymap *
xkb_map_ref(struct xkb_keymap *keymap)
{
return xkb_keymap_ref(keymap);
}
XKB_EXPORT void
xkb_map_unref(struct xkb_keymap *keymap)
{
xkb_keymap_unref(keymap);
}
XKB_EXPORT xkb_mod_index_t
xkb_map_num_mods(struct xkb_keymap *keymap)
{
return xkb_keymap_num_mods(keymap);
}
XKB_EXPORT const char *
xkb_map_mod_get_name(struct xkb_keymap *keymap, xkb_mod_index_t idx)
{
return xkb_keymap_mod_get_name(keymap, idx);
}
XKB_EXPORT xkb_mod_index_t
xkb_map_mod_get_index(struct xkb_keymap *keymap, const char *name)
{
return xkb_keymap_mod_get_index(keymap, name);
}
XKB_EXPORT bool
xkb_key_mod_index_is_consumed(struct xkb_state *state, xkb_keycode_t kc,
xkb_mod_index_t idx)
{
return xkb_state_mod_index_is_consumed(state, kc, idx);
}
XKB_EXPORT xkb_mod_mask_t
xkb_key_mod_mask_remove_consumed(struct xkb_state *state, xkb_keycode_t kc,
xkb_mod_mask_t mask)
{
return xkb_state_mod_mask_remove_consumed(state, kc, mask);
}
XKB_EXPORT xkb_layout_index_t
xkb_map_num_groups(struct xkb_keymap *keymap)
{
return xkb_keymap_num_layouts(keymap);
}
XKB_EXPORT xkb_layout_index_t
xkb_key_num_groups(struct xkb_keymap *keymap, xkb_keycode_t kc)
{
return xkb_keymap_num_layouts_for_key(keymap, kc);
}
XKB_EXPORT const char *
xkb_map_group_get_name(struct xkb_keymap *keymap, xkb_layout_index_t idx)
{
return xkb_keymap_layout_get_name(keymap, idx);
}
XKB_EXPORT xkb_layout_index_t
xkb_map_group_get_index(struct xkb_keymap *keymap, const char *name)
{
return xkb_keymap_layout_get_index(keymap, name);
}
XKB_EXPORT xkb_led_index_t
xkb_map_num_leds(struct xkb_keymap *keymap)
{
return xkb_keymap_num_leds(keymap);
}
XKB_EXPORT const char *
xkb_map_led_get_name(struct xkb_keymap *keymap, xkb_led_index_t idx)
{
return xkb_keymap_led_get_name(keymap, idx);
}
XKB_EXPORT xkb_led_index_t
xkb_map_led_get_index(struct xkb_keymap *keymap, const char *name)
{
return xkb_keymap_led_get_index(keymap, name);
}
XKB_EXPORT bool
xkb_key_repeats(struct xkb_keymap *keymap, xkb_keycode_t kc)
{
return xkb_keymap_key_repeats(keymap, kc);
}
XKB_EXPORT int
xkb_key_get_syms(struct xkb_state *state, xkb_keycode_t kc,
const xkb_keysym_t **syms_out)
{
return xkb_state_key_get_syms(state, kc, syms_out);
}
XKB_EXPORT bool
xkb_state_group_name_is_active(struct xkb_state *state, const char *name,
enum xkb_state_component type)
{
return xkb_state_layout_name_is_active(state, name, type);
}
XKB_EXPORT bool
xkb_state_group_index_is_active(struct xkb_state *state, xkb_layout_index_t idx,
enum xkb_state_component type)
{
return xkb_state_layout_index_is_active(state, idx, type);
}
XKB_EXPORT xkb_layout_index_t
xkb_state_serialize_group(struct xkb_state *state,
enum xkb_state_component type)
{
return xkb_state_serialize_layout(state, type);
}
XKB_EXPORT struct xkb_keymap *
xkb_state_get_map(struct xkb_state *state)
{
return xkb_state_get_keymap(state);
}

View File

@ -103,7 +103,7 @@ enum action_field {
ActionsInfo *
NewActionsInfo(void)
{
unsigned type;
enum xkb_action_type type;
ActionsInfo *info;
info = calloc(1, sizeof(*info));
@ -168,7 +168,7 @@ static const LookupEntry fieldStrings[] = {
};
static bool
stringToAction(const char *str, unsigned *type_rtrn)
stringToAction(const char *str, enum xkb_action_type *type_rtrn)
{
return LookupString(actionTypeNames, str, type_rtrn);
}
@ -221,9 +221,9 @@ ReportActionNotArray(struct xkb_context *ctx, enum xkb_action_type action,
}
static bool
HandleNoAction(struct xkb_keymap *keymap, union xkb_action *action,
enum action_field field, const ExprDef *array_ndx,
const ExprDef *value)
HandleNoAction(struct xkb_context *ctx, const struct xkb_mod_set *mods,
union xkb_action *action, enum action_field field,
const ExprDef *array_ndx, const ExprDef *value)
{
return true;
@ -252,16 +252,17 @@ CheckBooleanFlag(struct xkb_context *ctx, enum xkb_action_type action,
}
static bool
CheckModifierField(struct xkb_keymap *keymap, enum xkb_action_type action,
const ExprDef *array_ndx, const ExprDef *value,
enum xkb_action_flags *flags_inout, xkb_mod_mask_t *mods_rtrn)
CheckModifierField(struct xkb_context *ctx, const struct xkb_mod_set *mods,
enum xkb_action_type action, const ExprDef *array_ndx,
const ExprDef *value, enum xkb_action_flags *flags_inout,
xkb_mod_mask_t *mods_rtrn)
{
if (array_ndx)
return ReportActionNotArray(keymap->ctx, action, ACTION_FIELD_MODIFIERS);
return ReportActionNotArray(ctx, action, ACTION_FIELD_MODIFIERS);
if (value->expr.op == EXPR_IDENT) {
const char *valStr;
valStr = xkb_atom_text(keymap->ctx, value->ident.ident);
valStr = xkb_atom_text(ctx, value->ident.ident);
if (valStr && (istreq(valStr, "usemodmapmods") ||
istreq(valStr, "modmapmods"))) {
*mods_rtrn = 0;
@ -270,8 +271,8 @@ CheckModifierField(struct xkb_keymap *keymap, enum xkb_action_type action,
}
}
if (!ExprResolveModMask(keymap, value, MOD_BOTH, mods_rtrn))
return ReportMismatch(keymap->ctx, action,
if (!ExprResolveModMask(ctx, value, MOD_BOTH, mods, mods_rtrn))
return ReportMismatch(ctx, action,
ACTION_FIELD_MODIFIERS, "modifier mask");
*flags_inout &= ~ACTION_MODS_LOOKUP_MODMAP;
@ -306,36 +307,36 @@ CheckAffectField(struct xkb_context *ctx, enum xkb_action_type action,
}
static bool
HandleSetLatchLockMods(struct xkb_keymap *keymap, union xkb_action *action,
enum action_field field, const ExprDef *array_ndx,
const ExprDef *value)
HandleSetLatchLockMods(struct xkb_context *ctx, const struct xkb_mod_set *mods,
union xkb_action *action, enum action_field field,
const ExprDef *array_ndx, const ExprDef *value)
{
struct xkb_mod_action *act = &action->mods;
const enum xkb_action_type type = action->type;
if (field == ACTION_FIELD_MODIFIERS)
return CheckModifierField(keymap, action->type, array_ndx, value,
return CheckModifierField(ctx, mods, action->type, array_ndx, value,
&act->flags, &act->mods.mods);
if ((type == ACTION_TYPE_MOD_SET || type == ACTION_TYPE_MOD_LATCH) &&
field == ACTION_FIELD_CLEAR_LOCKS)
return CheckBooleanFlag(keymap->ctx, action->type, field,
return CheckBooleanFlag(ctx, action->type, field,
ACTION_LOCK_CLEAR, array_ndx, value,
&act->flags);
if (type == ACTION_TYPE_MOD_LATCH &&
field == ACTION_FIELD_LATCH_TO_LOCK)
return CheckBooleanFlag(keymap->ctx, action->type, field,
return CheckBooleanFlag(ctx, action->type, field,
ACTION_LATCH_TO_LOCK, array_ndx, value,
&act->flags);
if (type == ACTION_TYPE_MOD_LOCK &&
field == ACTION_FIELD_AFFECT)
return CheckAffectField(keymap->ctx, action->type, array_ndx, value,
return CheckAffectField(ctx, action->type, array_ndx, value,
&act->flags);
return ReportIllegal(keymap->ctx, action->type, field);
return ReportIllegal(ctx, action->type, field);
}
static bool
CheckGroupField(struct xkb_context *ctx, unsigned action,
CheckGroupField(struct xkb_context *ctx, enum xkb_action_type action,
const ExprDef *array_ndx, const ExprDef *value,
enum xkb_action_flags *flags_inout, int32_t *group_rtrn)
{
@ -373,34 +374,34 @@ CheckGroupField(struct xkb_context *ctx, unsigned action,
}
static bool
HandleSetLatchLockGroup(struct xkb_keymap *keymap, union xkb_action *action,
enum action_field field, const ExprDef *array_ndx,
const ExprDef *value)
HandleSetLatchLockGroup(struct xkb_context *ctx, const struct xkb_mod_set *mods,
union xkb_action *action, enum action_field field,
const ExprDef *array_ndx, const ExprDef *value)
{
struct xkb_group_action *act = &action->group;
const enum xkb_action_type type = action->type;
if (field == ACTION_FIELD_GROUP)
return CheckGroupField(keymap->ctx, action->type, array_ndx, value,
return CheckGroupField(ctx, action->type, array_ndx, value,
&act->flags, &act->group);
if ((type == ACTION_TYPE_GROUP_SET || type == ACTION_TYPE_GROUP_LATCH) &&
field == ACTION_FIELD_CLEAR_LOCKS)
return CheckBooleanFlag(keymap->ctx, action->type, field,
return CheckBooleanFlag(ctx, action->type, field,
ACTION_LOCK_CLEAR, array_ndx, value,
&act->flags);
if (type == ACTION_TYPE_GROUP_LATCH &&
field == ACTION_FIELD_LATCH_TO_LOCK)
return CheckBooleanFlag(keymap->ctx, action->type, field,
return CheckBooleanFlag(ctx, action->type, field,
ACTION_LATCH_TO_LOCK, array_ndx, value,
&act->flags);
return ReportIllegal(keymap->ctx, action->type, field);
return ReportIllegal(ctx, action->type, field);
}
static bool
HandleMovePtr(struct xkb_keymap *keymap, union xkb_action *action,
enum action_field field, const ExprDef *array_ndx,
const ExprDef *value)
HandleMovePtr(struct xkb_context *ctx, const struct xkb_mod_set *mods,
union xkb_action *action, enum action_field field,
const ExprDef *array_ndx, const ExprDef *value)
{
struct xkb_pointer_action *act = &action->ptr;
@ -410,13 +411,13 @@ HandleMovePtr(struct xkb_keymap *keymap, union xkb_action *action,
value->expr.op != EXPR_UNARY_PLUS);
if (array_ndx)
return ReportActionNotArray(keymap->ctx, action->type, field);
return ReportActionNotArray(ctx, action->type, field);
if (!ExprResolveInteger(keymap->ctx, value, &val))
return ReportMismatch(keymap->ctx, action->type, field, "integer");
if (!ExprResolveInteger(ctx, value, &val))
return ReportMismatch(ctx, action->type, field, "integer");
if (val < INT16_MIN || val > INT16_MAX) {
log_err(keymap->ctx,
log_err(ctx,
"The %s field in the %s action must be in range %d..%d; "
"Action definition ignored\n",
fieldText(field), ActionTypeText(action->type),
@ -438,17 +439,17 @@ HandleMovePtr(struct xkb_keymap *keymap, union xkb_action *action,
return true;
}
else if (field == ACTION_FIELD_ACCEL) {
return CheckBooleanFlag(keymap->ctx, action->type, field,
return CheckBooleanFlag(ctx, action->type, field,
ACTION_ACCEL, array_ndx, value, &act->flags);
}
return ReportIllegal(keymap->ctx, action->type, field);
return ReportIllegal(ctx, action->type, field);
}
static bool
HandlePtrBtn(struct xkb_keymap *keymap, union xkb_action *action,
enum action_field field, const ExprDef *array_ndx,
const ExprDef *value)
HandlePtrBtn(struct xkb_context *ctx, const struct xkb_mod_set *mods,
union xkb_action *action, enum action_field field,
const ExprDef *array_ndx, const ExprDef *value)
{
struct xkb_pointer_button_action *act = &action->btn;
@ -456,14 +457,14 @@ HandlePtrBtn(struct xkb_keymap *keymap, union xkb_action *action,
int btn;
if (array_ndx)
return ReportActionNotArray(keymap->ctx, action->type, field);
return ReportActionNotArray(ctx, action->type, field);
if (!ExprResolveButton(keymap->ctx, value, &btn))
return ReportMismatch(keymap->ctx, action->type, field,
if (!ExprResolveButton(ctx, value, &btn))
return ReportMismatch(ctx, action->type, field,
"integer (range 1..5)");
if (btn < 0 || btn > 5) {
log_err(keymap->ctx,
log_err(ctx,
"Button must specify default or be in the range 1..5; "
"Illegal button value %d ignored\n", btn);
return false;
@ -474,20 +475,20 @@ HandlePtrBtn(struct xkb_keymap *keymap, union xkb_action *action,
}
else if (action->type == ACTION_TYPE_PTR_LOCK &&
field == ACTION_FIELD_AFFECT) {
return CheckAffectField(keymap->ctx, action->type, array_ndx, value,
return CheckAffectField(ctx, action->type, array_ndx, value,
&act->flags);
}
else if (field == ACTION_FIELD_COUNT) {
int val;
if (array_ndx)
return ReportActionNotArray(keymap->ctx, action->type, field);
return ReportActionNotArray(ctx, action->type, field);
if (!ExprResolveInteger(keymap->ctx, value, &val))
return ReportMismatch(keymap->ctx, action->type, field, "integer");
if (!ExprResolveInteger(ctx, value, &val))
return ReportMismatch(ctx, action->type, field, "integer");
if (val < 0 || val > 255) {
log_err(keymap->ctx,
log_err(ctx,
"The count field must have a value in the range 0..255; "
"Illegal count %d ignored\n", val);
return false;
@ -497,7 +498,7 @@ HandlePtrBtn(struct xkb_keymap *keymap, union xkb_action *action,
return true;
}
return ReportIllegal(keymap->ctx, action->type, field);
return ReportIllegal(ctx, action->type, field);
}
static const LookupEntry ptrDflts[] = {
@ -508,9 +509,9 @@ static const LookupEntry ptrDflts[] = {
};
static bool
HandleSetPtrDflt(struct xkb_keymap *keymap, union xkb_action *action,
enum action_field field, const ExprDef *array_ndx,
const ExprDef *value)
HandleSetPtrDflt(struct xkb_context *ctx, const struct xkb_mod_set *mods,
union xkb_action *action, enum action_field field,
const ExprDef *array_ndx, const ExprDef *value)
{
struct xkb_pointer_default_action *act = &action->dflt;
@ -518,10 +519,10 @@ HandleSetPtrDflt(struct xkb_keymap *keymap, union xkb_action *action,
unsigned int val;
if (array_ndx)
return ReportActionNotArray(keymap->ctx, action->type, field);
return ReportActionNotArray(ctx, action->type, field);
if (!ExprResolveEnum(keymap->ctx, value, &val, ptrDflts))
return ReportMismatch(keymap->ctx, action->type, field,
if (!ExprResolveEnum(ctx, value, &val, ptrDflts))
return ReportMismatch(ctx, action->type, field,
"pointer component");
return true;
}
@ -530,7 +531,7 @@ HandleSetPtrDflt(struct xkb_keymap *keymap, union xkb_action *action,
int btn;
if (array_ndx)
return ReportActionNotArray(keymap->ctx, action->type, field);
return ReportActionNotArray(ctx, action->type, field);
if (value->expr.op == EXPR_NEGATE ||
value->expr.op == EXPR_UNARY_PLUS) {
@ -542,18 +543,18 @@ HandleSetPtrDflt(struct xkb_keymap *keymap, union xkb_action *action,
button = value;
}
if (!ExprResolveButton(keymap->ctx, button, &btn))
return ReportMismatch(keymap->ctx, action->type, field,
if (!ExprResolveButton(ctx, button, &btn))
return ReportMismatch(ctx, action->type, field,
"integer (range 1..5)");
if (btn < 0 || btn > 5) {
log_err(keymap->ctx,
log_err(ctx,
"New default button value must be in the range 1..5; "
"Illegal default button value %d ignored\n", btn);
return false;
}
if (btn == 0) {
log_err(keymap->ctx,
log_err(ctx,
"Cannot set default pointer button to \"default\"; "
"Illegal default button setting ignored\n");
return false;
@ -563,13 +564,13 @@ HandleSetPtrDflt(struct xkb_keymap *keymap, union xkb_action *action,
return true;
}
return ReportIllegal(keymap->ctx, action->type, field);
return ReportIllegal(ctx, action->type, field);
}
static bool
HandleSwitchScreen(struct xkb_keymap *keymap, union xkb_action *action,
enum action_field field, const ExprDef *array_ndx,
const ExprDef *value)
HandleSwitchScreen(struct xkb_context *ctx, const struct xkb_mod_set *mods,
union xkb_action *action, enum action_field field,
const ExprDef *array_ndx, const ExprDef *value)
{
struct xkb_switch_screen_action *act = &action->screen;
@ -578,7 +579,7 @@ HandleSwitchScreen(struct xkb_keymap *keymap, union xkb_action *action,
int val;
if (array_ndx)
return ReportActionNotArray(keymap->ctx, action->type, field);
return ReportActionNotArray(ctx, action->type, field);
if (value->expr.op == EXPR_NEGATE ||
value->expr.op == EXPR_UNARY_PLUS) {
@ -590,12 +591,12 @@ HandleSwitchScreen(struct xkb_keymap *keymap, union xkb_action *action,
scrn = value;
}
if (!ExprResolveInteger(keymap->ctx, scrn, &val))
return ReportMismatch(keymap->ctx, action->type, field,
if (!ExprResolveInteger(ctx, scrn, &val))
return ReportMismatch(ctx, action->type, field,
"integer (0..255)");
if (val < 0 || val > 255) {
log_err(keymap->ctx,
log_err(ctx,
"Screen index must be in the range 1..255; "
"Illegal screen value %d ignored\n", val);
return false;
@ -605,46 +606,46 @@ HandleSwitchScreen(struct xkb_keymap *keymap, union xkb_action *action,
return true;
}
else if (field == ACTION_FIELD_SAME) {
return CheckBooleanFlag(keymap->ctx, action->type, field,
return CheckBooleanFlag(ctx, action->type, field,
ACTION_SAME_SCREEN, array_ndx, value,
&act->flags);
}
return ReportIllegal(keymap->ctx, action->type, field);
return ReportIllegal(ctx, action->type, field);
}
static bool
HandleSetLockControls(struct xkb_keymap *keymap, union xkb_action *action,
enum action_field field, const ExprDef *array_ndx,
const ExprDef *value)
HandleSetLockControls(struct xkb_context *ctx, const struct xkb_mod_set *mods,
union xkb_action *action, enum action_field field,
const ExprDef *array_ndx, const ExprDef *value)
{
struct xkb_controls_action *act = &action->ctrls;
if (field == ACTION_FIELD_CONTROLS) {
unsigned int mask;
enum xkb_action_controls mask;
if (array_ndx)
return ReportActionNotArray(keymap->ctx, action->type, field);
return ReportActionNotArray(ctx, action->type, field);
if (!ExprResolveMask(keymap->ctx, value, &mask, ctrlMaskNames))
return ReportMismatch(keymap->ctx, action->type, field,
if (!ExprResolveMask(ctx, value, &mask, ctrlMaskNames))
return ReportMismatch(ctx, action->type, field,
"controls mask");
act->ctrls = mask;
return true;
}
else if (field == ACTION_FIELD_AFFECT) {
return CheckAffectField(keymap->ctx, action->type, array_ndx, value,
return CheckAffectField(ctx, action->type, array_ndx, value,
&act->flags);
}
return ReportIllegal(keymap->ctx, action->type, field);
return ReportIllegal(ctx, action->type, field);
}
static bool
HandlePrivate(struct xkb_keymap *keymap, union xkb_action *action,
enum action_field field, const ExprDef *array_ndx,
const ExprDef *value)
HandlePrivate(struct xkb_context *ctx, const struct xkb_mod_set *mods,
union xkb_action *action, enum action_field field,
const ExprDef *array_ndx, const ExprDef *value)
{
struct xkb_private_action *act = &action->priv;
@ -652,13 +653,13 @@ HandlePrivate(struct xkb_keymap *keymap, union xkb_action *action,
int type;
if (array_ndx)
return ReportActionNotArray(keymap->ctx, action->type, field);
return ReportActionNotArray(ctx, action->type, field);
if (!ExprResolveInteger(keymap->ctx, value, &type))
return ReportMismatch(keymap->ctx, ACTION_TYPE_PRIVATE, field, "integer");
if (!ExprResolveInteger(ctx, value, &type))
return ReportMismatch(ctx, ACTION_TYPE_PRIVATE, field, "integer");
if (type < 0 || type > 255) {
log_err(keymap->ctx,
log_err(ctx,
"Private action type must be in the range 0..255; "
"Illegal type %d ignored\n", type);
return false;
@ -675,7 +676,7 @@ HandlePrivate(struct xkb_keymap *keymap, union xkb_action *action,
* make actions like these no-ops for now.
*/
if (type < ACTION_TYPE_PRIVATE) {
log_info(keymap->ctx,
log_info(ctx,
"Private actions of type %s are not supported; Ignored\n",
ActionTypeText(type));
act->type = ACTION_TYPE_NONE;
@ -692,44 +693,45 @@ HandlePrivate(struct xkb_keymap *keymap, union xkb_action *action,
const char *str;
size_t len;
if (!ExprResolveString(keymap->ctx, value, &val))
return ReportMismatch(keymap->ctx, action->type, field, "string");
if (!ExprResolveString(ctx, value, &val))
return ReportMismatch(ctx, action->type, field, "string");
str = xkb_atom_text(keymap->ctx, val);
str = xkb_atom_text(ctx, val);
len = strlen(str);
if (len < 1 || len > 7) {
log_warn(keymap->ctx,
log_warn(ctx,
"A private action has 7 data bytes; "
"Illegal data ignored\n");
return false;
}
/* act->data may not be null-terminated, this is intentional */
strncpy((char *) act->data, str, sizeof(act->data));
return true;
}
else {
int ndx, datum;
if (!ExprResolveInteger(keymap->ctx, array_ndx, &ndx)) {
log_err(keymap->ctx,
if (!ExprResolveInteger(ctx, array_ndx, &ndx)) {
log_err(ctx,
"Array subscript must be integer; "
"Illegal subscript ignored\n");
return false;
}
if (ndx < 0 || (size_t) ndx >= sizeof(act->data)) {
log_err(keymap->ctx,
log_err(ctx,
"The data for a private action is %lu bytes long; "
"Attempt to use data[%d] ignored\n",
(unsigned long) sizeof(act->data), ndx);
return false;
}
if (!ExprResolveInteger(keymap->ctx, value, &datum))
return ReportMismatch(keymap->ctx, act->type, field, "integer");
if (!ExprResolveInteger(ctx, value, &datum))
return ReportMismatch(ctx, act->type, field, "integer");
if (datum < 0 || datum > 255) {
log_err(keymap->ctx,
log_err(ctx,
"All data for a private action must be 0..255; "
"Illegal datum %d ignored\n", datum);
return false;
@ -740,10 +742,11 @@ HandlePrivate(struct xkb_keymap *keymap, union xkb_action *action,
}
}
return ReportIllegal(keymap->ctx, ACTION_TYPE_NONE, field);
return ReportIllegal(ctx, ACTION_TYPE_NONE, field);
}
typedef bool (*actionHandler)(struct xkb_keymap *keymap,
typedef bool (*actionHandler)(struct xkb_context *ctx,
const struct xkb_mod_set *mods,
union xkb_action *action,
enum action_field field,
const ExprDef *array_ndx,
@ -771,22 +774,23 @@ static const actionHandler handleAction[_ACTION_TYPE_NUM_ENTRIES] = {
/***====================================================================***/
bool
HandleActionDef(ExprDef *def, struct xkb_keymap *keymap,
union xkb_action *action, ActionsInfo *info)
HandleActionDef(struct xkb_context *ctx, ActionsInfo *info,
const struct xkb_mod_set *mods, ExprDef *def,
union xkb_action *action)
{
ExprDef *arg;
const char *str;
unsigned handler_type;
enum xkb_action_type handler_type;
if (def->expr.op != EXPR_ACTION_DECL) {
log_err(keymap->ctx, "Expected an action definition, found %s\n",
log_err(ctx, "Expected an action definition, found %s\n",
expr_op_type_to_string(def->expr.op));
return false;
}
str = xkb_atom_text(keymap->ctx, def->action.name);
str = xkb_atom_text(ctx, def->action.name);
if (!stringToAction(str, &handler_type)) {
log_err(keymap->ctx, "Unknown action %s\n", str);
log_err(ctx, "Unknown action %s\n", str);
return false;
}
@ -822,12 +826,11 @@ HandleActionDef(ExprDef *def, struct xkb_keymap *keymap,
value = (const ExprDef *) &constTrue;
}
if (!ExprResolveLhs(keymap->ctx, field, &elemRtrn, &fieldRtrn,
&arrayRtrn))
if (!ExprResolveLhs(ctx, field, &elemRtrn, &fieldRtrn, &arrayRtrn))
return false;
if (elemRtrn) {
log_err(keymap->ctx,
log_err(ctx,
"Cannot change defaults in an action definition; "
"Ignoring attempt to change %s.%s\n",
elemRtrn, fieldRtrn);
@ -835,12 +838,12 @@ HandleActionDef(ExprDef *def, struct xkb_keymap *keymap,
}
if (!stringToField(fieldRtrn, &fieldNdx)) {
log_err(keymap->ctx, "Unknown field name %s\n", fieldRtrn);
log_err(ctx, "Unknown field name %s\n", fieldRtrn);
return false;
}
if (!handleAction[handler_type](keymap, action, fieldNdx, arrayRtrn,
value))
if (!handleAction[handler_type](ctx, mods, action, fieldNdx,
arrayRtrn, value))
return false;
}
@ -848,20 +851,21 @@ HandleActionDef(ExprDef *def, struct xkb_keymap *keymap,
}
bool
SetActionField(struct xkb_keymap *keymap, const char *elem, const char *field,
ExprDef *array_ndx, ExprDef *value, ActionsInfo *info)
SetActionField(struct xkb_context *ctx, ActionsInfo *info,
struct xkb_mod_set *mods, const char *elem,
const char *field, ExprDef *array_ndx, ExprDef *value)
{
unsigned action;
enum xkb_action_type action;
enum action_field action_field;
if (!stringToAction(elem, &action))
return false;
if (!stringToField(field, &action_field)) {
log_err(keymap->ctx, "\"%s\" is not a legal field name\n", field);
log_err(ctx, "\"%s\" is not a legal field name\n", field);
return false;
}
return handleAction[action](keymap, &info->actions[action],
return handleAction[action](ctx, mods, &info->actions[action],
action_field, array_ndx, value);
}

View File

@ -43,11 +43,14 @@ void
FreeActionsInfo(ActionsInfo *info);
bool
HandleActionDef(ExprDef *def, struct xkb_keymap *keymap,
union xkb_action *action, ActionsInfo *info);
HandleActionDef(struct xkb_context *ctx, ActionsInfo *info,
const struct xkb_mod_set *mods, ExprDef *def,
union xkb_action *action);
bool
SetActionField(struct xkb_keymap *keymap, const char *elem, const char *field,
ExprDef *array_ndx, ExprDef *value, ActionsInfo *info);
SetActionField(struct xkb_context *ctx, ActionsInfo *info,
struct xkb_mod_set *mods, const char *elem,
const char *field, ExprDef *array_ndx, ExprDef *value);
#endif

View File

@ -105,6 +105,13 @@ ExprCreateInteger(int ival)
return expr;
}
ExprDef *
ExprCreateFloat(void)
{
EXPR_CREATE(ExprFloat, expr, EXPR_VALUE, EXPR_TYPE_FLOAT);
return expr;
}
ExprDef *
ExprCreateBoolean(bool set)
{
@ -231,11 +238,9 @@ ExprAppendMultiKeysymList(ExprDef *expr, ExprDef *append)
darray_append(expr->keysym_list.symsMapIndex, nSyms);
darray_append(expr->keysym_list.symsNumEntries, numEntries);
darray_append_items(expr->keysym_list.syms,
darray_mem(append->keysym_list.syms, 0), numEntries);
darray_concat(expr->keysym_list.syms, append->keysym_list.syms);
darray_resize(append->keysym_list.syms, 0);
FreeStmt(&append->common);
FreeStmt((ParseCommon *) append);
return expr;
}
@ -303,8 +308,21 @@ VarCreate(ExprDef *name, ExprDef *value)
VarDef *
BoolVarCreate(xkb_atom_t ident, bool set)
{
return VarCreate((ExprDef *) ExprCreateIdent(ident),
(ExprDef *) ExprCreateBoolean(set));
ExprDef *name, *value;
VarDef *def;
if (!(name = ExprCreateIdent(ident))) {
return NULL;
}
if (!(value = ExprCreateBoolean(set))) {
FreeStmt((ParseCommon *) name);
return NULL;
}
if (!(def = VarCreate(name, value))) {
FreeStmt((ParseCommon *) name);
FreeStmt((ParseCommon *) value);
return NULL;
}
return def;
}
InterpDef *
@ -318,6 +336,7 @@ InterpCreate(xkb_keysym_t sym, ExprDef *match)
def->common.next = NULL;
def->sym = sym;
def->match = match;
def->def = NULL;
return def;
}
@ -458,12 +477,8 @@ IncludeCreate(struct xkb_context *ctx, char *str, enum merge_mode merge)
incl = incl->next_incl;
}
if (!incl) {
log_wsgo(ctx,
"Allocation failure in IncludeCreate; "
"Using only part of the include\n");
if (!incl)
break;
}
incl->common.type = STMT_INCLUDE;
incl->common.next = NULL;
@ -506,8 +521,7 @@ XkbFileCreate(enum xkb_file_type type, char *name, ParseCommon *defs,
XkbEscapeMapName(name);
file->file_type = type;
file->topName = strdup_safe(name);
file->name = name;
file->name = name ? name : strdup("(unnamed)");
file->defs = defs;
file->flags = flags;
@ -697,7 +711,6 @@ FreeXkbFile(XkbFile *file)
}
free(file->name);
free(file->topName);
free(file);
file = next;
}
@ -716,7 +729,7 @@ static const char *xkb_file_type_strings[_FILE_TYPE_NUM_ENTRIES] = {
const char *
xkb_file_type_to_string(enum xkb_file_type type)
{
if (type > _FILE_TYPE_NUM_ENTRIES)
if (type >= _FILE_TYPE_NUM_ENTRIES)
return "unknown";
return xkb_file_type_strings[type];
}
@ -777,6 +790,7 @@ static const char *expr_value_type_strings[_EXPR_TYPE_NUM_VALUES] = {
[EXPR_TYPE_UNKNOWN] = "unknown",
[EXPR_TYPE_BOOLEAN] = "boolean",
[EXPR_TYPE_INT] = "int",
[EXPR_TYPE_FLOAT] = "float",
[EXPR_TYPE_STRING] = "string",
[EXPR_TYPE_ACTION] = "action",
[EXPR_TYPE_KEYNAME] = "keyname",

View File

@ -36,6 +36,9 @@ ExprCreateString(xkb_atom_t str);
ExprDef *
ExprCreateInteger(int ival);
ExprDef *
ExprCreateFloat(void);
ExprDef *
ExprCreateBoolean(bool set);

View File

@ -95,6 +95,7 @@ enum expr_value_type {
EXPR_TYPE_UNKNOWN = 0,
EXPR_TYPE_BOOLEAN,
EXPR_TYPE_INT,
EXPR_TYPE_FLOAT,
EXPR_TYPE_STRING,
EXPR_TYPE_ACTION,
EXPR_TYPE_KEYNAME,
@ -186,6 +187,12 @@ typedef struct {
int ival;
} ExprInteger;
typedef struct {
ExprCommon expr;
/* We don't support floats, but we still represnt them in the AST, in
* order to provide proper error messages. */
} ExprFloat;
typedef struct {
ExprCommon expr;
xkb_atom_t key_name;
@ -338,7 +345,6 @@ enum xkb_map_flags {
typedef struct {
ParseCommon common;
enum xkb_file_type file_type;
char *topName;
char *name;
ParseCommon *defs;
enum xkb_map_flags flags;

View File

@ -55,9 +55,9 @@
#include "include.h"
enum si_field {
SI_FIELD_VIRTUAL_MOD = (1 << 0),
SI_FIELD_ACTION = (1 << 1),
SI_FIELD_AUTO_REPEAT = (1 << 2),
SI_FIELD_VIRTUAL_MOD = (1 << 0),
SI_FIELD_ACTION = (1 << 1),
SI_FIELD_AUTO_REPEAT = (1 << 2),
SI_FIELD_LEVEL_ONE_ONLY = (1 << 3),
};
@ -69,9 +69,9 @@ typedef struct {
} SymInterpInfo;
enum led_field {
LED_FIELD_MODS = (1 << 0),
LED_FIELD_GROUPS = (1 << 1),
LED_FIELD_CTRLS = (1 << 2),
LED_FIELD_MODS = (1 << 0),
LED_FIELD_GROUPS = (1 << 1),
LED_FIELD_CTRLS = (1 << 2),
};
typedef struct {
@ -87,23 +87,26 @@ typedef struct {
SymInterpInfo default_interp;
darray(SymInterpInfo) interps;
LedInfo default_led;
darray(LedInfo) leds;
LedInfo leds[XKB_MAX_LEDS];
unsigned int num_leds;
ActionsInfo *actions;
struct xkb_keymap *keymap;
struct xkb_mod_set mods;
struct xkb_context *ctx;
} CompatInfo;
static const char *
siText(SymInterpInfo *si, CompatInfo *info)
{
char *buf = xkb_context_get_buffer(info->keymap->ctx, 128);
char *buf = xkb_context_get_buffer(info->ctx, 128);
if (si == &info->default_interp)
return "default";
snprintf(buf, 128, "%s+%s(%s)",
KeysymText(info->keymap->ctx, si->interp.sym),
KeysymText(info->ctx, si->interp.sym),
SIMatchText(si->interp.match),
ModMaskText(info->keymap, si->interp.mods));
ModMaskText(info->ctx, &info->mods, si->interp.mods));
return buf;
}
@ -111,7 +114,7 @@ siText(SymInterpInfo *si, CompatInfo *info)
static inline bool
ReportSINotArray(CompatInfo *info, SymInterpInfo *si, const char *field)
{
return ReportNotArray(info->keymap->ctx, "symbol interpretation", field,
return ReportNotArray(info->ctx, "symbol interpretation", field,
siText(si, info));
}
@ -119,7 +122,7 @@ static inline bool
ReportSIBadType(CompatInfo *info, SymInterpInfo *si, const char *field,
const char *wanted)
{
return ReportBadType(info->keymap->ctx, "symbol interpretation", field,
return ReportBadType(info->ctx, "symbol interpretation", field,
siText(si, info), wanted);
}
@ -127,25 +130,26 @@ static inline bool
ReportLedBadType(CompatInfo *info, LedInfo *ledi, const char *field,
const char *wanted)
{
return ReportBadType(info->keymap->ctx, "indicator map", field,
xkb_atom_text(info->keymap->ctx, ledi->led.name),
return ReportBadType(info->ctx, "indicator map", field,
xkb_atom_text(info->ctx, ledi->led.name),
wanted);
}
static inline bool
ReportLedNotArray(CompatInfo *info, LedInfo *ledi, const char *field)
{
return ReportNotArray(info->keymap->ctx, "indicator map", field,
xkb_atom_text(info->keymap->ctx, ledi->led.name));
return ReportNotArray(info->ctx, "indicator map", field,
xkb_atom_text(info->ctx, ledi->led.name));
}
static void
InitCompatInfo(CompatInfo *info, struct xkb_keymap *keymap,
ActionsInfo *actions)
InitCompatInfo(CompatInfo *info, struct xkb_context *ctx,
ActionsInfo *actions, const struct xkb_mod_set *mods)
{
memset(info, 0, sizeof(*info));
info->keymap = keymap;
info->ctx = ctx;
info->actions = actions;
info->mods = *mods;
info->default_interp.merge = MERGE_OVERRIDE;
info->default_interp.interp.virtual_mod = XKB_MOD_INVALID;
info->default_led.merge = MERGE_OVERRIDE;
@ -156,7 +160,6 @@ ClearCompatInfo(CompatInfo *info)
{
free(info->name);
darray_free(info->interps);
darray_free(info->leds);
}
static SymInterpInfo *
@ -196,13 +199,13 @@ AddInterp(CompatInfo *info, SymInterpInfo *new, bool same_file)
{
SymInterpInfo *old = FindMatchingInterp(info, new);
if (old) {
const int verbosity = xkb_context_get_log_verbosity(info->keymap->ctx);
const int verbosity = xkb_context_get_log_verbosity(info->ctx);
const bool report = (same_file && verbosity > 0) || verbosity > 9;
enum si_field collide = 0;
if (new->merge == MERGE_REPLACE) {
if (report)
log_warn(info->keymap->ctx,
log_warn(info->ctx,
"Multiple definitions for \"%s\"; "
"Earlier interpretation ignored\n",
siText(new, info));
@ -232,7 +235,7 @@ AddInterp(CompatInfo *info, SymInterpInfo *new, bool same_file)
}
if (collide) {
log_warn(info->keymap->ctx,
log_warn(info->ctx,
"Multiple interpretations of \"%s\"; "
"Using %s definition for duplicate fields\n",
siText(new, info),
@ -260,18 +263,17 @@ ResolveStateAndPredicate(ExprDef *expr, enum xkb_match_operation *pred_rtrn,
*pred_rtrn = MATCH_EXACTLY;
if (expr->expr.op == EXPR_ACTION_DECL) {
const char *pred_txt = xkb_atom_text(info->keymap->ctx,
expr->action.name);
if (!LookupString(symInterpretMatchMaskNames, pred_txt, pred_rtrn)) {
log_err(info->keymap->ctx,
const char *pred_txt = xkb_atom_text(info->ctx, expr->action.name);
if (!LookupString(symInterpretMatchMaskNames, pred_txt, pred_rtrn) ||
!expr->action.args) {
log_err(info->ctx,
"Illegal modifier predicate \"%s\"; Ignored\n", pred_txt);
return false;
}
expr = expr->action.args;
}
else if (expr->expr.op == EXPR_IDENT) {
const char *pred_txt = xkb_atom_text(info->keymap->ctx,
expr->ident.ident);
const char *pred_txt = xkb_atom_text(info->ctx, expr->ident.ident);
if (pred_txt && istreq(pred_txt, "any")) {
*pred_rtrn = MATCH_ANY;
*mods_rtrn = MOD_REAL_MASK_ALL;
@ -279,7 +281,8 @@ ResolveStateAndPredicate(ExprDef *expr, enum xkb_match_operation *pred_rtrn,
}
}
return ExprResolveModMask(info->keymap, expr, MOD_REAL, mods_rtrn);
return ExprResolveModMask(info->ctx, expr, MOD_REAL, &info->mods,
mods_rtrn);
}
/***====================================================================***/
@ -305,13 +308,13 @@ UseNewLEDField(enum led_field field, LedInfo *old, LedInfo *new,
static bool
AddLedMap(CompatInfo *info, LedInfo *new, bool same_file)
{
LedInfo *old;
enum led_field collide;
struct xkb_context *ctx = info->keymap->ctx;
const int verbosity = xkb_context_get_log_verbosity(ctx);
const int verbosity = xkb_context_get_log_verbosity(info->ctx);
const bool report = (same_file && verbosity > 0) || verbosity > 9;
darray_foreach(old, info->leds) {
for (xkb_led_index_t i = 0; i < info->num_leds; i++) {
LedInfo *old = &info->leds[i];
if (old->led.name != new->led.name)
continue;
@ -326,10 +329,10 @@ AddLedMap(CompatInfo *info, LedInfo *new, bool same_file)
if (new->merge == MERGE_REPLACE) {
if (report)
log_warn(info->keymap->ctx,
log_warn(info->ctx,
"Map for indicator %s redefined; "
"Earlier definition ignored\n",
xkb_atom_text(ctx, old->led.name));
xkb_atom_text(info->ctx, old->led.name));
*old = *new;
return true;
}
@ -351,17 +354,23 @@ AddLedMap(CompatInfo *info, LedInfo *new, bool same_file)
}
if (collide) {
log_warn(info->keymap->ctx,
log_warn(info->ctx,
"Map for indicator %s redefined; "
"Using %s definition for duplicate fields\n",
xkb_atom_text(ctx, old->led.name),
xkb_atom_text(info->ctx, old->led.name),
(new->merge == MERGE_AUGMENT ? "first" : "last"));
}
return true;
}
darray_append(info->leds, *new);
if (info->num_leds >= XKB_MAX_LEDS) {
log_err(info->ctx,
"Too many LEDs defined (maximum %d)\n",
XKB_MAX_LEDS);
return false;
}
info->leds[info->num_leds++] = *new;
return true;
}
@ -369,14 +378,13 @@ static void
MergeIncludedCompatMaps(CompatInfo *into, CompatInfo *from,
enum merge_mode merge)
{
SymInterpInfo *si;
LedInfo *ledi;
if (from->errorCount > 0) {
into->errorCount += from->errorCount;
return;
}
into->mods = from->mods;
if (into->name == NULL) {
into->name = from->name;
from->name = NULL;
@ -387,6 +395,7 @@ MergeIncludedCompatMaps(CompatInfo *into, CompatInfo *from,
darray_init(from->interps);
}
else {
SymInterpInfo *si;
darray_foreach(si, from->interps) {
si->merge = (merge == MERGE_DEFAULT ? si->merge : merge);
if (!AddInterp(into, si, false))
@ -394,12 +403,14 @@ MergeIncludedCompatMaps(CompatInfo *into, CompatInfo *from,
}
}
if (darray_empty(into->leds)) {
into->leds = from->leds;
darray_init(from->leds);
if (into->num_leds == 0) {
memcpy(into->leds, from->leds, sizeof(*from->leds) * from->num_leds);
into->num_leds = from->num_leds;
from->num_leds = 0;
}
else {
darray_foreach(ledi, from->leds) {
for (xkb_led_index_t i = 0; i < from->num_leds; i++) {
LedInfo *ledi = &from->leds[i];
ledi->merge = (merge == MERGE_DEFAULT ? ledi->merge : merge);
if (!AddLedMap(into, ledi, false))
into->errorCount++;
@ -415,7 +426,7 @@ HandleIncludeCompatMap(CompatInfo *info, IncludeStmt *include)
{
CompatInfo included;
InitCompatInfo(&included, info->keymap, info->actions);
InitCompatInfo(&included, info->ctx, info->actions, &info->mods);
included.name = include->stmt;
include->stmt = NULL;
@ -423,14 +434,14 @@ HandleIncludeCompatMap(CompatInfo *info, IncludeStmt *include)
CompatInfo next_incl;
XkbFile *file;
file = ProcessIncludeFile(info->keymap->ctx, stmt, FILE_TYPE_COMPAT);
file = ProcessIncludeFile(info->ctx, stmt, FILE_TYPE_COMPAT);
if (!file) {
info->errorCount += 10;
ClearCompatInfo(&included);
return false;
}
InitCompatInfo(&next_incl, info->keymap, info->actions);
InitCompatInfo(&next_incl, info->ctx, info->actions, &included.mods);
next_incl.default_interp = info->default_interp;
next_incl.default_interp.merge = stmt->merge;
next_incl.default_led = info->default_led;
@ -454,14 +465,14 @@ static bool
SetInterpField(CompatInfo *info, SymInterpInfo *si, const char *field,
ExprDef *arrayNdx, ExprDef *value)
{
struct xkb_keymap *keymap = info->keymap;
xkb_mod_index_t ndx;
if (istreq(field, "action")) {
if (arrayNdx)
return ReportSINotArray(info, si, field);
if (!HandleActionDef(value, keymap, &si->interp.action, info->actions))
if (!HandleActionDef(info->ctx, info->actions, &info->mods,
value, &si->interp.action))
return false;
si->defined |= SI_FIELD_ACTION;
@ -471,7 +482,7 @@ SetInterpField(CompatInfo *info, SymInterpInfo *si, const char *field,
if (arrayNdx)
return ReportSINotArray(info, si, field);
if (!ExprResolveMod(keymap, value, MOD_VIRT, &ndx))
if (!ExprResolveMod(info->ctx, value, MOD_VIRT, &info->mods, &ndx))
return ReportSIBadType(info, si, field, "virtual modifier");
si->interp.virtual_mod = ndx;
@ -483,7 +494,7 @@ SetInterpField(CompatInfo *info, SymInterpInfo *si, const char *field,
if (arrayNdx)
return ReportSINotArray(info, si, field);
if (!ExprResolveBoolean(keymap->ctx, value, &set))
if (!ExprResolveBoolean(info->ctx, value, &set))
return ReportSIBadType(info, si, field, "boolean");
si->interp.repeat = set;
@ -491,7 +502,7 @@ SetInterpField(CompatInfo *info, SymInterpInfo *si, const char *field,
si->defined |= SI_FIELD_AUTO_REPEAT;
}
else if (istreq(field, "locking")) {
log_dbg(info->keymap->ctx,
log_dbg(info->ctx,
"The \"locking\" field in symbol interpretation is unsupported; "
"Ignored\n");
}
@ -502,14 +513,14 @@ SetInterpField(CompatInfo *info, SymInterpInfo *si, const char *field,
if (arrayNdx)
return ReportSINotArray(info, si, field);
if (!ExprResolveEnum(keymap->ctx, value, &val, useModMapValueNames))
if (!ExprResolveEnum(info->ctx, value, &val, useModMapValueNames))
return ReportSIBadType(info, si, field, "level specification");
si->interp.level_one_only = !!val;
si->interp.level_one_only = val;
si->defined |= SI_FIELD_LEVEL_ONE_ONLY;
}
else {
return ReportBadField(keymap->ctx, "symbol interpretation", field,
return ReportBadField(info->ctx, "symbol interpretation", field,
siText(si, info));
}
@ -521,13 +532,13 @@ SetLedMapField(CompatInfo *info, LedInfo *ledi, const char *field,
ExprDef *arrayNdx, ExprDef *value)
{
bool ok = true;
struct xkb_keymap *keymap = info->keymap;
if (istreq(field, "modifiers") || istreq(field, "mods")) {
if (arrayNdx)
return ReportLedNotArray(info, ledi, field);
if (!ExprResolveModMask(keymap, value, MOD_BOTH, &ledi->led.mods.mods))
if (!ExprResolveModMask(info->ctx, value, MOD_BOTH,
&info->mods, &ledi->led.mods.mods))
return ReportLedBadType(info, ledi, field, "modifier mask");
ledi->defined |= LED_FIELD_MODS;
@ -538,7 +549,7 @@ SetLedMapField(CompatInfo *info, LedInfo *ledi, const char *field,
if (arrayNdx)
return ReportLedNotArray(info, ledi, field);
if (!ExprResolveMask(keymap->ctx, value, &mask, groupMaskNames))
if (!ExprResolveMask(info->ctx, value, &mask, groupMaskNames))
return ReportLedBadType(info, ledi, field, "group mask");
ledi->led.groups = mask;
@ -550,14 +561,14 @@ SetLedMapField(CompatInfo *info, LedInfo *ledi, const char *field,
if (arrayNdx)
return ReportLedNotArray(info, ledi, field);
if (!ExprResolveMask(keymap->ctx, value, &mask, ctrlMaskNames))
if (!ExprResolveMask(info->ctx, value, &mask, ctrlMaskNames))
return ReportLedBadType(info, ledi, field, "controls mask");
ledi->led.ctrls = mask;
ledi->defined |= LED_FIELD_CTRLS;
}
else if (istreq(field, "allowexplicit")) {
log_dbg(info->keymap->ctx,
log_dbg(info->ctx,
"The \"allowExplicit\" field in indicator statements is unsupported; "
"Ignored\n");
}
@ -568,7 +579,7 @@ SetLedMapField(CompatInfo *info, LedInfo *ledi, const char *field,
if (arrayNdx)
return ReportLedNotArray(info, ledi, field);
if (!ExprResolveMask(keymap->ctx, value, &mask,
if (!ExprResolveMask(info->ctx, value, &mask,
modComponentMaskNames))
return ReportLedBadType(info, ledi, field,
"mask of modifier state components");
@ -581,7 +592,7 @@ SetLedMapField(CompatInfo *info, LedInfo *ledi, const char *field,
if (arrayNdx)
return ReportLedNotArray(info, ledi, field);
if (!ExprResolveMask(keymap->ctx, value, &mask,
if (!ExprResolveMask(info->ctx, value, &mask,
groupComponentMaskNames))
return ReportLedBadType(info, ledi, field,
"mask of group state components");
@ -594,21 +605,21 @@ SetLedMapField(CompatInfo *info, LedInfo *ledi, const char *field,
istreq(field, "leddriveskeyboard") ||
istreq(field, "indicatordriveskbd") ||
istreq(field, "indicatordriveskeyboard")) {
log_dbg(info->keymap->ctx,
log_dbg(info->ctx,
"The \"%s\" field in indicator statements is unsupported; "
"Ignored\n", field);
}
else if (istreq(field, "index")) {
/* Users should see this, it might cause unexpected behavior. */
log_err(info->keymap->ctx,
log_err(info->ctx,
"The \"index\" field in indicator statements is unsupported; "
"Ignored\n");
}
else {
log_err(info->keymap->ctx,
log_err(info->ctx,
"Unknown field %s in map for %s indicator; "
"Definition ignored\n",
field, xkb_atom_text(keymap->ctx, ledi->led.name));
field, xkb_atom_text(info->ctx, ledi->led.name));
ok = false;
}
@ -622,7 +633,7 @@ HandleGlobalVar(CompatInfo *info, VarDef *stmt)
ExprDef *ndx;
bool ret;
if (!ExprResolveLhs(info->keymap->ctx, stmt->name, &elem, &field, &ndx))
if (!ExprResolveLhs(info->ctx, stmt->name, &elem, &field, &ndx))
ret = false;
else if (elem && istreq(elem, "interpret"))
ret = SetInterpField(info, &info->default_interp, field, ndx,
@ -631,8 +642,8 @@ HandleGlobalVar(CompatInfo *info, VarDef *stmt)
ret = SetLedMapField(info, &info->default_led, field, ndx,
stmt->value);
else
ret = SetActionField(info->keymap, elem, field, ndx, stmt->value,
info->actions);
ret = SetActionField(info->ctx, info->actions, &info->mods,
elem, field, ndx, stmt->value);
return ret;
}
@ -645,15 +656,14 @@ HandleInterpBody(CompatInfo *info, VarDef *def, SymInterpInfo *si)
for (; def; def = (VarDef *) def->common.next) {
if (def->name && def->name->expr.op == EXPR_FIELD_REF) {
log_err(info->keymap->ctx,
log_err(info->ctx,
"Cannot set a global default value from within an interpret statement; "
"Move statements to the global file scope\n");
ok = false;
continue;
}
ok = ExprResolveLhs(info->keymap->ctx, def->name, &elem, &field,
&arrayNdx);
ok = ExprResolveLhs(info->ctx, def->name, &elem, &field, &arrayNdx);
if (!ok)
continue;
@ -671,7 +681,7 @@ HandleInterpDef(CompatInfo *info, InterpDef *def, enum merge_mode merge)
SymInterpInfo si;
if (!ResolveStateAndPredicate(def->match, &pred, &mods, info)) {
log_err(info->keymap->ctx,
log_err(info->ctx,
"Couldn't determine matching modifiers; "
"Symbol interpretation ignored\n");
return false;
@ -714,14 +724,13 @@ HandleLedMapDef(CompatInfo *info, LedMapDef *def, enum merge_mode merge)
for (var = def->body; var != NULL; var = (VarDef *) var->common.next) {
const char *elem, *field;
ExprDef *arrayNdx;
if (!ExprResolveLhs(info->keymap->ctx, var->name, &elem, &field,
&arrayNdx)) {
if (!ExprResolveLhs(info->ctx, var->name, &elem, &field, &arrayNdx)) {
ok = false;
continue;
}
if (elem) {
log_err(info->keymap->ctx,
log_err(info->ctx,
"Cannot set defaults for \"%s\" element in indicator map; "
"Assignment to %s.%s ignored\n", elem, elem, field);
ok = false;
@ -756,7 +765,7 @@ HandleCompatMapFile(CompatInfo *info, XkbFile *file, enum merge_mode merge)
ok = HandleInterpDef(info, (InterpDef *) stmt, merge);
break;
case STMT_GROUP_COMPAT:
log_dbg(info->keymap->ctx,
log_dbg(info->ctx,
"The \"group\" statement in compat is unsupported; "
"Ignored\n");
ok = true;
@ -768,10 +777,10 @@ HandleCompatMapFile(CompatInfo *info, XkbFile *file, enum merge_mode merge)
ok = HandleGlobalVar(info, (VarDef *) stmt);
break;
case STMT_VMOD:
ok = HandleVModDef(info->keymap, (VModDef *) stmt, merge);
ok = HandleVModDef(info->ctx, &info->mods, (VModDef *) stmt, merge);
break;
default:
log_err(info->keymap->ctx,
log_err(info->ctx,
"Compat files may not include other types; "
"Ignoring %s\n", stmt_type_to_string(stmt->type));
ok = false;
@ -782,8 +791,8 @@ HandleCompatMapFile(CompatInfo *info, XkbFile *file, enum merge_mode merge)
info->errorCount++;
if (info->errorCount > 10) {
log_err(info->keymap->ctx,
"Abandoning compatibility map \"%s\"\n", file->topName);
log_err(info->ctx,
"Abandoning compatibility map \"%s\"\n", file->name);
break;
}
}
@ -807,34 +816,33 @@ CopyInterps(CompatInfo *info, bool needSymbol, enum xkb_match_operation pred,
}
static void
CopyLedMapDefs(CompatInfo *info)
CopyLedMapDefsToKeymap(struct xkb_keymap *keymap, CompatInfo *info)
{
LedInfo *ledi;
xkb_led_index_t i;
struct xkb_led *led;
struct xkb_keymap *keymap = info->keymap;
for (xkb_led_index_t idx = 0; idx < info->num_leds; idx++) {
LedInfo *ledi = &info->leds[idx];
xkb_led_index_t i;
struct xkb_led *led;
darray_foreach(ledi, info->leds) {
/*
* Find the LED with the given name, if it was already declared
* in keycodes.
*/
darray_enumerate(i, led, keymap->leds)
xkb_leds_enumerate(i, led, keymap)
if (led->name == ledi->led.name)
break;
/* Not previously declared; create it with next free index. */
if (i >= darray_size(keymap->leds)) {
if (i >= keymap->num_leds) {
log_dbg(keymap->ctx,
"Indicator name \"%s\" was not declared in the keycodes section; "
"Adding new indicator\n",
xkb_atom_text(keymap->ctx, ledi->led.name));
darray_enumerate(i, led, keymap->leds)
xkb_leds_enumerate(i, led, keymap)
if (led->name == XKB_ATOM_NONE)
break;
if (i >= darray_size(keymap->leds)) {
if (i >= keymap->num_leds) {
/* Not place to put it; ignore. */
if (i >= XKB_MAX_LEDS) {
log_err(keymap->ctx,
@ -844,9 +852,9 @@ CopyLedMapDefs(CompatInfo *info)
xkb_atom_text(keymap->ctx, ledi->led.name));
continue;
}
/* Add a new LED. */
darray_resize(keymap->leds, i + 1);
led = &darray_item(keymap->leds, i);
led = &keymap->leds[keymap->num_leds++];
}
}
@ -864,6 +872,8 @@ CopyCompatToKeymap(struct xkb_keymap *keymap, CompatInfo *info)
keymap->compat_section_name = strdup_safe(info->name);
XkbEscapeMapName(keymap->compat_section_name);
keymap->mods = info->mods;
if (!darray_empty(info->interps)) {
struct collect collect;
darray_init(collect.sym_interprets);
@ -880,11 +890,11 @@ CopyCompatToKeymap(struct xkb_keymap *keymap, CompatInfo *info)
CopyInterps(info, false, MATCH_ANY, &collect);
CopyInterps(info, false, MATCH_ANY_OR_NONE, &collect);
keymap->num_sym_interprets = darray_size(collect.sym_interprets);
keymap->sym_interprets = darray_mem(collect.sym_interprets, 0);
darray_steal(collect.sym_interprets,
&keymap->sym_interprets, &keymap->num_sym_interprets);
}
CopyLedMapDefs(info);
CopyLedMapDefsToKeymap(keymap, info);
return true;
}
@ -900,7 +910,7 @@ CompileCompatMap(XkbFile *file, struct xkb_keymap *keymap,
if (!actions)
return false;
InitCompatInfo(&info, keymap, actions);
InitCompatInfo(&info, keymap->ctx, actions, &keymap->mods);
info.default_interp.merge = merge;
info.default_led.merge = merge;

View File

@ -42,16 +42,20 @@ ExprResolveLhs(struct xkb_context *ctx, const ExprDef *expr,
*elem_rtrn = NULL;
*field_rtrn = xkb_atom_text(ctx, expr->ident.ident);
*index_rtrn = NULL;
return true;
return (*field_rtrn != NULL);
case EXPR_FIELD_REF:
*elem_rtrn = xkb_atom_text(ctx, expr->field_ref.element);
*field_rtrn = xkb_atom_text(ctx, expr->field_ref.field);
*index_rtrn = NULL;
return true;
return (*elem_rtrn != NULL && *field_rtrn != NULL);
case EXPR_ARRAY_REF:
*elem_rtrn = xkb_atom_text(ctx, expr->array_ref.element);
*field_rtrn = xkb_atom_text(ctx, expr->array_ref.field);
*index_rtrn = expr->array_ref.entry;
if (expr->array_ref.element != XKB_ATOM_NONE && *elem_rtrn == NULL)
return false;
if (*field_rtrn == NULL)
return false;
return true;
default:
break;
@ -83,7 +87,7 @@ SimpleLookup(struct xkb_context *ctx, const void *priv, xkb_atom_t field,
/* Data passed in the *priv argument for LookupModMask. */
typedef struct {
const struct xkb_keymap *keymap;
const struct xkb_mod_set *mods;
enum mod_type mod_type;
} LookupModMaskPriv;
@ -94,13 +98,15 @@ LookupModMask(struct xkb_context *ctx, const void *priv, xkb_atom_t field,
const char *str;
xkb_mod_index_t ndx;
const LookupModMaskPriv *arg = priv;
const struct xkb_keymap *keymap = arg->keymap;
const struct xkb_mod_set *mods = arg->mods;
enum mod_type mod_type = arg->mod_type;
if (type != EXPR_TYPE_INT)
return false;
str = xkb_atom_text(ctx, field);
if (!str)
return false;
if (istreq(str, "all")) {
*val_rtrn = MOD_REAL_MASK_ALL;
@ -112,7 +118,7 @@ LookupModMask(struct xkb_context *ctx, const void *priv, xkb_atom_t field,
return true;
}
ndx = ModNameToIndex(keymap, field, mod_type);
ndx = XkbModNameToIndex(mods, field, mod_type);
if (ndx == XKB_MOD_INVALID)
return false;
@ -165,7 +171,7 @@ ExprResolveBoolean(struct xkb_context *ctx, const ExprDef *expr,
case EXPR_INVERT:
case EXPR_NOT:
ok = ExprResolveBoolean(ctx, expr, set_rtrn);
ok = ExprResolveBoolean(ctx, expr->unary.child, set_rtrn);
if (ok)
*set_rtrn = !*set_rtrn;
return ok;
@ -337,7 +343,9 @@ ExprResolveIntegerLookup(struct xkb_context *ctx, const ExprDef *expr,
*val_rtrn = l / r;
break;
default:
break;
log_err(ctx, "%s of integers not permitted\n",
expr_op_type_to_string(expr->expr.op));
return false;
}
return true;
@ -508,8 +516,8 @@ ExprResolveMaskLookup(struct xkb_context *ctx, const ExprDef *expr,
unsigned int *val_rtrn, IdentLookupFunc lookup,
const void *lookupPriv)
{
bool ok = 0;
unsigned int l, r;
bool ok = false;
unsigned int l = 0, r = 0;
int v;
ExprDef *left, *right;
const char *bogus = NULL;
@ -541,7 +549,7 @@ ExprResolveMaskLookup(struct xkb_context *ctx, const ExprDef *expr,
case EXPR_ARRAY_REF:
bogus = "array reference";
/* fallthrough */
case EXPR_ACTION_DECL:
if (bogus == NULL)
bogus = "function use";
@ -616,12 +624,12 @@ ExprResolveMask(struct xkb_context *ctx, const ExprDef *expr,
}
bool
ExprResolveModMask(struct xkb_keymap *keymap, const ExprDef *expr,
enum mod_type mod_type, xkb_mod_mask_t *mask_rtrn)
ExprResolveModMask(struct xkb_context *ctx, const ExprDef *expr,
enum mod_type mod_type, const struct xkb_mod_set *mods,
xkb_mod_mask_t *mask_rtrn)
{
LookupModMaskPriv priv = { .keymap = keymap, .mod_type = mod_type };
return ExprResolveMaskLookup(keymap->ctx, expr, mask_rtrn, LookupModMask,
&priv);
LookupModMaskPriv priv = { .mods = mods, .mod_type = mod_type };
return ExprResolveMaskLookup(ctx, expr, mask_rtrn, LookupModMask, &priv);
}
bool
@ -648,14 +656,15 @@ ExprResolveKeySym(struct xkb_context *ctx, const ExprDef *expr,
}
bool
ExprResolveMod(struct xkb_keymap *keymap, const ExprDef *def,
enum mod_type mod_type, xkb_mod_index_t *ndx_rtrn)
ExprResolveMod(struct xkb_context *ctx, const ExprDef *def,
enum mod_type mod_type, const struct xkb_mod_set *mods,
xkb_mod_index_t *ndx_rtrn)
{
xkb_mod_index_t ndx;
xkb_atom_t name;
if (def->expr.op != EXPR_IDENT) {
log_err(keymap->ctx,
log_err(ctx,
"Cannot resolve virtual modifier: "
"found %s where a virtual modifier name was expected\n",
expr_op_type_to_string(def->expr.op));
@ -663,12 +672,12 @@ ExprResolveMod(struct xkb_keymap *keymap, const ExprDef *def,
}
name = def->ident.ident;
ndx = ModNameToIndex(keymap, name, mod_type);
ndx = XkbModNameToIndex(mods, name, mod_type);
if (ndx == XKB_MOD_INVALID) {
log_err(keymap->ctx,
log_err(ctx,
"Cannot resolve virtual modifier: "
"\"%s\" was not previously declared\n",
xkb_atom_text(keymap->ctx, name));
xkb_atom_text(ctx, name));
return false;
}

View File

@ -33,12 +33,14 @@ ExprResolveLhs(struct xkb_context *ctx, const ExprDef *expr,
ExprDef **index_rtrn);
bool
ExprResolveModMask(struct xkb_keymap *keymap, const ExprDef *expr,
enum mod_type mod_type, xkb_mod_mask_t *mask_rtrn);
ExprResolveModMask(struct xkb_context *ctx, const ExprDef *expr,
enum mod_type mod_type, const struct xkb_mod_set *mods,
xkb_mod_mask_t *mask_rtrn);
bool
ExprResolveMod(struct xkb_keymap *keymap, const ExprDef *def,
enum mod_type mod_type, xkb_mod_index_t *ndx_rtrn);
ExprResolveMod(struct xkb_context *ctx, const ExprDef *def,
enum mod_type mod_type, const struct xkb_mod_set *mods,
xkb_mod_index_t *ndx_rtrn);
bool
ExprResolveBoolean(struct xkb_context *ctx, const ExprDef *expr,

View File

@ -49,7 +49,8 @@ typedef struct {
xkb_keycode_t min_key_code;
xkb_keycode_t max_key_code;
darray(xkb_atom_t) key_names;
darray(LedNameInfo) led_names;
LedNameInfo led_names[XKB_MAX_LEDS];
unsigned int num_led_names;
darray(AliasInfo) aliases;
struct xkb_context *ctx;
@ -71,10 +72,8 @@ static LedNameInfo *
FindLedByName(KeyNamesInfo *info, xkb_atom_t name,
xkb_led_index_t *idx_out)
{
LedNameInfo *ledi;
xkb_led_index_t idx;
darray_enumerate(idx, ledi, info->led_names) {
for (xkb_led_index_t idx = 0; idx < info->num_led_names; idx++) {
LedNameInfo *ledi = &info->led_names[idx];
if (ledi->name == name) {
*idx_out = idx;
return ledi;
@ -119,11 +118,11 @@ AddLedName(KeyNamesInfo *info, enum merge_mode merge, bool same_file,
return true;
}
if (new_idx >= darray_size(info->led_names))
darray_resize0(info->led_names, new_idx + 1);
if (new_idx >= info->num_led_names)
info->num_led_names = new_idx + 1;
/* LED with the same index already exists. */
old = &darray_item(info->led_names, new_idx);
old = &info->led_names[new_idx];
if (old->name != XKB_ATOM_NONE) {
if (report) {
const xkb_atom_t use = (replace ? new->name : old->name);
@ -140,7 +139,7 @@ AddLedName(KeyNamesInfo *info, enum merge_mode merge, bool same_file,
return true;
}
darray_item(info->led_names, new_idx) = *new;
*old = *new;
return true;
}
@ -150,7 +149,6 @@ ClearKeyNamesInfo(KeyNamesInfo *info)
free(info->name);
darray_free(info->key_names);
darray_free(info->aliases);
darray_free(info->led_names);
}
static void
@ -308,15 +306,16 @@ MergeIncludedKeycodes(KeyNamesInfo *into, KeyNamesInfo *from,
}
/* Merge LED names. */
if (darray_empty(into->led_names)) {
into->led_names = from->led_names;
darray_init(from->led_names);
if (into->num_led_names == 0) {
memcpy(into->led_names, from->led_names,
sizeof(*from->led_names) * from->num_led_names);
into->num_led_names = from->num_led_names;
from->num_led_names = 0;
}
else {
xkb_led_index_t idx;
LedNameInfo *ledi;
for (xkb_led_index_t idx = 0; idx < from->num_led_names; idx++) {
LedNameInfo *ledi = &from->led_names[idx];
darray_enumerate(idx, ledi, from->led_names) {
if (ledi->name == XKB_ATOM_NONE)
continue;
@ -468,7 +467,7 @@ HandleLedNameDef(KeyNamesInfo *info, LedNameDef *def,
if (!ExprResolveString(info->ctx, def->name, &name)) {
char buf[20];
snprintf(buf, sizeof(buf), "%d", def->ndx);
snprintf(buf, sizeof(buf), "%u", def->ndx);
info->errorCount++;
return ReportBadType(info->ctx, "indicator", "name", buf, "string");
}
@ -516,7 +515,7 @@ HandleKeycodesFile(KeyNamesInfo *info, XkbFile *file, enum merge_mode merge)
if (info->errorCount > 10) {
log_err(info->ctx, "Abandoning keycodes file \"%s\"\n",
file->topName);
file->name);
break;
}
}
@ -527,41 +526,45 @@ HandleKeycodesFile(KeyNamesInfo *info, XkbFile *file, enum merge_mode merge)
static bool
CopyKeyNamesToKeymap(struct xkb_keymap *keymap, KeyNamesInfo *info)
{
xkb_keycode_t kc;
xkb_led_index_t idx;
LedNameInfo *ledi;
AliasInfo *alias;
unsigned i;
struct xkb_key *keys;
xkb_keycode_t min_key_code, max_key_code, kc;
keymap->keycodes_section_name = strdup_safe(info->name);
XkbEscapeMapName(keymap->keycodes_section_name);
if (info->min_key_code != XKB_KEYCODE_INVALID) {
keymap->min_key_code = info->min_key_code;
keymap->max_key_code = info->max_key_code;
}
else {
/*
* If the keymap has no keys, let's just use the safest pair
* we know.
*/
keymap->min_key_code = 8;
keymap->max_key_code = 255;
min_key_code = info->min_key_code;
max_key_code = info->max_key_code;
/* If the keymap has no keys, let's just use the safest pair we know. */
if (min_key_code == XKB_KEYCODE_INVALID) {
min_key_code = 8;
max_key_code = 255;
}
keymap->keys = calloc(keymap->max_key_code + 1, sizeof(*keymap->keys));
for (kc = keymap->min_key_code; kc <= keymap->max_key_code; kc++)
keymap->keys[kc].keycode = kc;
keys = calloc(max_key_code + 1, sizeof(*keys));
if (!keys)
return false;
for (kc = min_key_code; kc <= max_key_code; kc++)
keys[kc].keycode = kc;
/* Copy key names. */
for (kc = info->min_key_code; kc <= info->max_key_code; kc++)
keymap->keys[kc].name = darray_item(info->key_names, kc);
keys[kc].name = darray_item(info->key_names, kc);
keymap->min_key_code = min_key_code;
keymap->max_key_code = max_key_code;
keymap->keys = keys;
return true;
}
static bool
CopyKeyAliasesToKeymap(struct xkb_keymap *keymap, KeyNamesInfo *info)
{
AliasInfo *alias;
unsigned i, num_key_aliases;
struct xkb_key_alias *key_aliases;
/*
* Do some sanity checking on the aliases. We can't do it before
* because keys and their aliases may be added out-of-order.
*/
keymap->num_key_aliases = 0;
num_key_aliases = 0;
darray_foreach(alias, info->aliases) {
/* Check that ->real is a key. */
if (!XkbKeyByName(keymap, alias->real, false)) {
@ -584,27 +587,58 @@ CopyKeyNamesToKeymap(struct xkb_keymap *keymap, KeyNamesInfo *info)
continue;
}
keymap->num_key_aliases++;
num_key_aliases++;
}
/* Copy key aliases. */
keymap->key_aliases = calloc(keymap->num_key_aliases,
sizeof(*keymap->key_aliases));
i = 0;
darray_foreach(alias, info->aliases) {
if (alias->real != XKB_ATOM_NONE) {
keymap->key_aliases[i].alias = alias->alias;
keymap->key_aliases[i].real = alias->real;
i++;
key_aliases = NULL;
if (num_key_aliases > 0) {
key_aliases = calloc(num_key_aliases, sizeof(*key_aliases));
if (!key_aliases)
return false;
i = 0;
darray_foreach(alias, info->aliases) {
if (alias->real != XKB_ATOM_NONE) {
key_aliases[i].alias = alias->alias;
key_aliases[i].real = alias->real;
i++;
}
}
}
/* Copy LED names. */
darray_resize0(keymap->leds, darray_size(info->led_names));
darray_enumerate(idx, ledi, info->led_names)
if (ledi->name != XKB_ATOM_NONE)
darray_item(keymap->leds, idx).name = ledi->name;
keymap->num_key_aliases = num_key_aliases;
keymap->key_aliases = key_aliases;
return true;
}
static bool
CopyLedNamesToKeymap(struct xkb_keymap *keymap, KeyNamesInfo *info)
{
keymap->num_leds = info->num_led_names;
for (xkb_led_index_t idx = 0; idx < info->num_led_names; idx++) {
LedNameInfo *ledi = &info->led_names[idx];
if (ledi->name == XKB_ATOM_NONE)
continue;
keymap->leds[idx].name = ledi->name;
}
return true;
}
static bool
CopyKeyNamesInfoToKeymap(struct xkb_keymap *keymap, KeyNamesInfo *info)
{
/* This function trashes keymap on error, but that's OK. */
if (!CopyKeyNamesToKeymap(keymap, info) ||
!CopyKeyAliasesToKeymap(keymap, info) ||
!CopyLedNamesToKeymap(keymap, info))
return false;
keymap->keycodes_section_name = strdup_safe(info->name);
XkbEscapeMapName(keymap->keycodes_section_name);
return true;
}
@ -622,7 +656,7 @@ CompileKeycodes(XkbFile *file, struct xkb_keymap *keymap,
if (info.errorCount != 0)
goto err_info;
if (!CopyKeyNamesToKeymap(keymap, &info))
if (!CopyKeyNamesInfoToKeymap(keymap, &info))
goto err_info;
ClearKeyNamesInfo(&info);

View File

@ -126,7 +126,7 @@ write_vmods(struct xkb_keymap *keymap, struct buf *buf)
const struct xkb_mod *mod;
xkb_mod_index_t num_vmods = 0;
darray_foreach(mod, keymap->mods) {
xkb_mods_foreach(mod, &keymap->mods) {
if (mod->type != MOD_VIRT)
continue;
@ -164,7 +164,7 @@ write_keycodes(struct xkb_keymap *keymap, struct buf *buf)
write_buf(buf, "\tminimum = %u;\n", min(keymap->min_key_code, 8));
write_buf(buf, "\tmaximum = %u;\n", max(keymap->max_key_code, 255));
xkb_foreach_key(key, keymap) {
xkb_keys_foreach(key, keymap) {
if (key->name == XKB_ATOM_NONE)
continue;
@ -172,7 +172,7 @@ write_keycodes(struct xkb_keymap *keymap, struct buf *buf)
KeyNameText(keymap->ctx, key->name), key->keycode);
}
darray_enumerate(idx, led, keymap->leds)
xkb_leds_enumerate(idx, led, keymap)
if (led->name != XKB_ATOM_NONE)
write_buf(buf, "\tindicator %u = \"%s\";\n",
idx + 1, xkb_atom_text(keymap->ctx, led->name));
@ -205,7 +205,7 @@ write_types(struct xkb_keymap *keymap, struct buf *buf)
xkb_atom_text(keymap->ctx, type->name));
write_buf(buf, "\t\tmodifiers= %s;\n",
ModMaskText(keymap, type->mods.mods));
ModMaskText(keymap->ctx, &keymap->mods, type->mods.mods));
for (unsigned j = 0; j < type->num_entries; j++) {
const char *str;
@ -218,16 +218,17 @@ write_types(struct xkb_keymap *keymap, struct buf *buf)
if (entry->level == 0 && entry->preserve.mods == 0)
continue;
str = ModMaskText(keymap, entry->mods.mods);
str = ModMaskText(keymap->ctx, &keymap->mods, entry->mods.mods);
write_buf(buf, "\t\tmap[%s]= Level%u;\n",
str, entry->level + 1);
if (entry->preserve.mods)
write_buf(buf, "\t\tpreserve[%s]= %s;\n",
str, ModMaskText(keymap, entry->preserve.mods));
str, ModMaskText(keymap->ctx, &keymap->mods,
entry->preserve.mods));
}
for (xkb_level_index_t n = 0; n < type->num_levels; n++)
for (xkb_level_index_t n = 0; n < type->num_level_names; n++)
if (type->level_names[n])
write_buf(buf, "\t\tlevel_name[Level%u]= \"%s\";\n", n + 1,
xkb_atom_text(keymap->ctx, type->level_names[n]));
@ -261,7 +262,7 @@ write_led_map(struct xkb_keymap *keymap, struct buf *buf,
LedStateMaskText(keymap->ctx, led->which_mods));
}
write_buf(buf, "\t\tmodifiers= %s;\n",
ModMaskText(keymap, led->mods.mods));
ModMaskText(keymap->ctx, &keymap->mods, led->mods.mods));
}
if (led->ctrls) {
@ -303,13 +304,14 @@ write_action(struct xkb_keymap *keymap, struct buf *buf,
type = ActionTypeText(action->type);
switch (action->type) {
case ACTION_TYPE_MOD_LOCK:
case ACTION_TYPE_MOD_SET:
case ACTION_TYPE_MOD_LATCH:
case ACTION_TYPE_MOD_LOCK:
if (action->mods.flags & ACTION_MODS_LOOKUP_MODMAP)
args = "modMapMods";
else
args = ModMaskText(keymap, action->mods.mods.mods);
args = ModMaskText(keymap->ctx, &keymap->mods,
action->mods.mods.mods);
write_buf(buf, "%s%s(modifiers=%s%s%s%s)%s", prefix, type, args,
(action->type != ACTION_TYPE_MOD_LOCK && (action->mods.flags & ACTION_LOCK_CLEAR)) ? ",clearLocks" : "",
(action->type != ACTION_TYPE_MOD_LOCK && (action->mods.flags & ACTION_LATCH_TO_LOCK)) ? ",latchToLock" : "",
@ -422,11 +424,12 @@ write_compat(struct xkb_keymap *keymap, struct buf *buf)
write_buf(buf, "\tinterpret %s+%s(%s) {\n",
si->sym ? KeysymText(keymap->ctx, si->sym) : "Any",
SIMatchText(si->match),
ModMaskText(keymap, si->mods));
ModMaskText(keymap->ctx, &keymap->mods, si->mods));
if (si->virtual_mod != XKB_MOD_INVALID)
write_buf(buf, "\t\tvirtualModifier= %s;\n",
ModIndexText(keymap, si->virtual_mod));
ModIndexText(keymap->ctx, &keymap->mods,
si->virtual_mod));
if (si->level_one_only)
write_buf(buf, "\t\tuseModMapMods=level1;\n");
@ -438,7 +441,7 @@ write_compat(struct xkb_keymap *keymap, struct buf *buf)
write_buf(buf, "\t};\n");
}
darray_foreach(led, keymap->leds)
xkb_leds_foreach(led, keymap)
if (led->which_groups || led->groups || led->which_mods ||
led->mods.mods || led->ctrls)
write_led_map(keymap, buf, led);
@ -452,7 +455,7 @@ static bool
write_keysyms(struct xkb_keymap *keymap, struct buf *buf,
const struct xkb_key *key, xkb_layout_index_t group)
{
for (xkb_level_index_t level = 0; level < XkbKeyGroupWidth(key, group);
for (xkb_level_index_t level = 0; level < XkbKeyNumLevels(key, group);
level++) {
const xkb_keysym_t *syms;
int num_syms;
@ -534,7 +537,7 @@ write_key(struct xkb_keymap *keymap, struct buf *buf,
if (key->vmodmap && (key->explicit & EXPLICIT_VMODMAP))
write_buf(buf, "\n\t\tvirtualMods= %s,",
ModMaskText(keymap, key->vmodmap));
ModMaskText(keymap->ctx, &keymap->mods, key->vmodmap));
switch (key->out_of_range_group_action) {
case RANGE_SATURATE:
@ -550,7 +553,7 @@ write_key(struct xkb_keymap *keymap, struct buf *buf,
break;
}
show_actions = !!(key->explicit & EXPLICIT_INTERP);
show_actions = (key->explicit & EXPLICIT_INTERP);
if (key->num_groups > 1 || show_actions)
simple = false;
@ -573,8 +576,7 @@ write_key(struct xkb_keymap *keymap, struct buf *buf,
write_buf(buf, " ]");
if (show_actions) {
write_buf(buf, ",\n\t\tactions[Group%u]= [ ", group + 1);
for (level = 0;
level < XkbKeyGroupWidth(key, group); level++) {
for (level = 0; level < XkbKeyNumLevels(key, group); level++) {
if (level != 0)
write_buf(buf, ", ");
write_action(keymap, buf,
@ -595,6 +597,8 @@ write_symbols(struct xkb_keymap *keymap, struct buf *buf)
{
const struct xkb_key *key;
xkb_layout_index_t group;
xkb_mod_index_t i;
const struct xkb_mod *mod;
if (keymap->symbols_section_name)
write_buf(buf, "xkb_symbols \"%s\" {\n",
@ -610,22 +614,25 @@ write_symbols(struct xkb_keymap *keymap, struct buf *buf)
if (group > 0)
write_buf(buf, "\n");
xkb_foreach_key(key, keymap)
xkb_keys_foreach(key, keymap)
if (key->num_groups > 0)
write_key(keymap, buf, key);
xkb_foreach_key(key, keymap) {
xkb_mod_index_t i;
const struct xkb_mod *mod;
if (key->modmap == 0)
continue;
darray_enumerate(i, mod, keymap->mods)
if (key->modmap & (1u << i))
write_buf(buf, "\tmodifier_map %s { %s };\n",
xkb_atom_text(keymap->ctx, mod->name),
xkb_mods_enumerate(i, mod, &keymap->mods) {
bool had_any = false;
xkb_keys_foreach(key, keymap) {
if (key->modmap & (1u << i)) {
if (!had_any)
write_buf(buf, "\tmodifier_map %s { ",
xkb_atom_text(keymap->ctx, mod->name));
write_buf(buf, "%s%s",
had_any ? ", " : "",
KeyNameText(keymap->ctx, key->name));
had_any = true;
}
}
if (had_any)
write_buf(buf, " };\n");
}
write_buf(buf, "};\n\n");

View File

@ -28,8 +28,8 @@
#define XKBCOMP_PARSER_PRIV_H
struct parser_param;
struct scanner;
#include "scanner-utils.h"
#include "parser.h"
int

View File

@ -1,19 +1,19 @@
/* A Bison parser, made by GNU Bison 2.5. */
/* A Bison parser, made by GNU Bison 3.0.4. */
/* Bison interface for Yacc-like parsers in C
Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
@ -26,162 +26,103 @@
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
#ifndef YY__XKBCOMMON_XKBCOMMON_INTERNAL_STA_PARSER_H_INCLUDED
# define YY__XKBCOMMON_XKBCOMMON_INTERNAL_STA_PARSER_H_INCLUDED
/* Debug traces. */
#ifndef YYDEBUG
# define YYDEBUG 0
#endif
#if YYDEBUG
extern int _xkbcommon_debug;
#endif
/* Tokens. */
/* Token type. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
/* Put the tokens into the symbol table, so that GDB and other debuggers
know about them. */
enum yytokentype {
END_OF_FILE = 0,
ERROR_TOK = 255,
XKB_KEYMAP = 1,
XKB_KEYCODES = 2,
XKB_TYPES = 3,
XKB_SYMBOLS = 4,
XKB_COMPATMAP = 5,
XKB_GEOMETRY = 6,
XKB_SEMANTICS = 7,
XKB_LAYOUT = 8,
INCLUDE = 10,
OVERRIDE = 11,
AUGMENT = 12,
REPLACE = 13,
ALTERNATE = 14,
VIRTUAL_MODS = 20,
TYPE = 21,
INTERPRET = 22,
ACTION_TOK = 23,
KEY = 24,
ALIAS = 25,
GROUP = 26,
MODIFIER_MAP = 27,
INDICATOR = 28,
SHAPE = 29,
KEYS = 30,
ROW = 31,
SECTION = 32,
OVERLAY = 33,
TEXT = 34,
OUTLINE = 35,
SOLID = 36,
LOGO = 37,
VIRTUAL = 38,
EQUALS = 40,
PLUS = 41,
MINUS = 42,
DIVIDE = 43,
TIMES = 44,
OBRACE = 45,
CBRACE = 46,
OPAREN = 47,
CPAREN = 48,
OBRACKET = 49,
CBRACKET = 50,
DOT = 51,
COMMA = 52,
SEMI = 53,
EXCLAM = 54,
INVERT = 55,
STRING = 60,
INTEGER = 61,
FLOAT = 62,
IDENT = 63,
KEYNAME = 64,
PARTIAL = 70,
DEFAULT = 71,
HIDDEN = 72,
ALPHANUMERIC_KEYS = 73,
MODIFIER_KEYS = 74,
KEYPAD_KEYS = 75,
FUNCTION_KEYS = 76,
ALTERNATE_GROUP = 77
};
enum yytokentype
{
END_OF_FILE = 0,
ERROR_TOK = 255,
XKB_KEYMAP = 1,
XKB_KEYCODES = 2,
XKB_TYPES = 3,
XKB_SYMBOLS = 4,
XKB_COMPATMAP = 5,
XKB_GEOMETRY = 6,
XKB_SEMANTICS = 7,
XKB_LAYOUT = 8,
INCLUDE = 10,
OVERRIDE = 11,
AUGMENT = 12,
REPLACE = 13,
ALTERNATE = 14,
VIRTUAL_MODS = 20,
TYPE = 21,
INTERPRET = 22,
ACTION_TOK = 23,
KEY = 24,
ALIAS = 25,
GROUP = 26,
MODIFIER_MAP = 27,
INDICATOR = 28,
SHAPE = 29,
KEYS = 30,
ROW = 31,
SECTION = 32,
OVERLAY = 33,
TEXT = 34,
OUTLINE = 35,
SOLID = 36,
LOGO = 37,
VIRTUAL = 38,
EQUALS = 40,
PLUS = 41,
MINUS = 42,
DIVIDE = 43,
TIMES = 44,
OBRACE = 45,
CBRACE = 46,
OPAREN = 47,
CPAREN = 48,
OBRACKET = 49,
CBRACKET = 50,
DOT = 51,
COMMA = 52,
SEMI = 53,
EXCLAM = 54,
INVERT = 55,
STRING = 60,
INTEGER = 61,
FLOAT = 62,
IDENT = 63,
KEYNAME = 64,
PARTIAL = 70,
DEFAULT = 71,
HIDDEN = 72,
ALPHANUMERIC_KEYS = 73,
MODIFIER_KEYS = 74,
KEYPAD_KEYS = 75,
FUNCTION_KEYS = 76,
ALTERNATE_GROUP = 77
};
#endif
/* Tokens. */
#define END_OF_FILE 0
#define ERROR_TOK 255
#define XKB_KEYMAP 1
#define XKB_KEYCODES 2
#define XKB_TYPES 3
#define XKB_SYMBOLS 4
#define XKB_COMPATMAP 5
#define XKB_GEOMETRY 6
#define XKB_SEMANTICS 7
#define XKB_LAYOUT 8
#define INCLUDE 10
#define OVERRIDE 11
#define AUGMENT 12
#define REPLACE 13
#define ALTERNATE 14
#define VIRTUAL_MODS 20
#define TYPE 21
#define INTERPRET 22
#define ACTION_TOK 23
#define KEY 24
#define ALIAS 25
#define GROUP 26
#define MODIFIER_MAP 27
#define INDICATOR 28
#define SHAPE 29
#define KEYS 30
#define ROW 31
#define SECTION 32
#define OVERLAY 33
#define TEXT 34
#define OUTLINE 35
#define SOLID 36
#define LOGO 37
#define VIRTUAL 38
#define EQUALS 40
#define PLUS 41
#define MINUS 42
#define DIVIDE 43
#define TIMES 44
#define OBRACE 45
#define CBRACE 46
#define OPAREN 47
#define CPAREN 48
#define OBRACKET 49
#define CBRACKET 50
#define DOT 51
#define COMMA 52
#define SEMI 53
#define EXCLAM 54
#define INVERT 55
#define STRING 60
#define INTEGER 61
#define FLOAT 62
#define IDENT 63
#define KEYNAME 64
#define PARTIAL 70
#define DEFAULT 71
#define HIDDEN 72
#define ALPHANUMERIC_KEYS 73
#define MODIFIER_KEYS 74
#define KEYPAD_KEYS 75
#define FUNCTION_KEYS 76
#define ALTERNATE_GROUP 77
/* Value type. */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
{
/* Line 2068 of yacc.c */
#line 161 "parser.y"
union YYSTYPE
{
#line 162 "../src/xkbcomp/parser.y" /* yacc.c:1909 */
int ival;
int64_t num;
enum xkb_file_type file_type;
char *str;
xkb_atom_t sval;
xkb_atom_t atom;
enum merge_mode merge;
enum xkb_map_flags mapFlags;
xkb_keysym_t keysym;
@ -201,16 +142,16 @@ typedef union YYSTYPE
void *geom;
XkbFile *file;
#line 146 "xkbcommon-internal@sta/parser.h" /* yacc.c:1909 */
};
/* Line 2068 of yacc.c */
#line 208 "src/xkbcomp/parser.h"
} YYSTYPE;
typedef union YYSTYPE YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
#endif
int _xkbcommon_parse (struct parser_param *param);
#endif /* !YY__XKBCOMMON_XKBCOMMON_INTERNAL_STA_PARSER_H_INCLUDED */

View File

@ -85,7 +85,7 @@ skip_more_whitespace_and_comments:
/* Skip comments. */
if (lit(s, "//")) {
while (!eof(s) && !eol(s)) next(s);
skip_to_eol(s);
}
/* New line. */
@ -182,15 +182,23 @@ static const struct sval rules_kccgst_svals[_KCCGST_NUM_ENTRIES] = {
[KCCGST_GEOMETRY] = SVAL_LIT("geometry"),
};
/* We use this to keep score whether an mlvo was matched or not; if not,
* we warn the user that his preference was ignored. */
struct matched_sval {
struct sval sval;
bool matched;
};
typedef darray(struct matched_sval) darray_matched_sval;
/*
* A broken-down version of xkb_rule_names (without the rules,
* obviously).
*/
struct rule_names {
struct sval model;
darray_sval layouts;
darray_sval variants;
darray_sval options;
struct matched_sval model;
darray_matched_sval layouts;
darray_matched_sval variants;
darray_matched_sval options;
};
struct group {
@ -253,10 +261,10 @@ strip_spaces(struct sval v)
return v;
}
static darray_sval
split_comma_separated_string(const char *s)
static darray_matched_sval
split_comma_separated_mlvo(const char *s)
{
darray_sval arr = darray_new();
darray_matched_sval arr = darray_new();
/*
* Make sure the array returned by this function always includes at
@ -264,15 +272,16 @@ split_comma_separated_string(const char *s)
*/
if (!s) {
struct sval val = { NULL, 0 };
struct matched_sval val = { .sval = { NULL, 0 } };
darray_append(arr, val);
return arr;
}
while (true) {
struct sval val = { s, 0 };
while (*s != '\0' && *s != ',') { s++; val.len++; }
darray_append(arr, strip_spaces(val));
struct matched_sval val = { .sval = { s, 0 } };
while (*s != '\0' && *s != ',') { s++; val.sval.len++; }
val.sval = strip_spaces(val.sval);
darray_append(arr, val);
if (*s == '\0') break;
if (*s == ',') s++;
}
@ -289,11 +298,11 @@ matcher_new(struct xkb_context *ctx,
return NULL;
m->ctx = ctx;
m->rmlvo.model.start = rmlvo->model;
m->rmlvo.model.len = strlen_safe(rmlvo->model);
m->rmlvo.layouts = split_comma_separated_string(rmlvo->layout);
m->rmlvo.variants = split_comma_separated_string(rmlvo->variant);
m->rmlvo.options = split_comma_separated_string(rmlvo->options);
m->rmlvo.model.sval.start = rmlvo->model;
m->rmlvo.model.sval.len = strlen_safe(rmlvo->model);
m->rmlvo.layouts = split_comma_separated_mlvo(rmlvo->layout);
m->rmlvo.variants = split_comma_separated_mlvo(rmlvo->variant);
m->rmlvo.options = split_comma_separated_mlvo(rmlvo->options);
return m;
}
@ -309,6 +318,8 @@ matcher_free(struct matcher *m)
darray_free(m->rmlvo.options);
darray_foreach(group, m->groups)
darray_free(group->elements);
for (int i = 0; i < _KCCGST_NUM_ENTRIES; i++)
darray_free(m->kccgst[i]);
darray_free(m->groups);
free(m);
}
@ -584,7 +595,7 @@ match_group(struct matcher *m, struct sval group_name, struct sval to)
static bool
match_value(struct matcher *m, struct sval val, struct sval to,
enum mlvo_match_type match_type)
enum mlvo_match_type match_type)
{
if (match_type == MLVO_MATCH_WILDCARD)
return true;
@ -593,6 +604,16 @@ match_value(struct matcher *m, struct sval val, struct sval to,
return svaleq(val, to);
}
static bool
match_value_and_mark(struct matcher *m, struct sval val,
struct matched_sval *to, enum mlvo_match_type match_type)
{
bool matched = match_value(m, val, to->sval, match_type);
if (matched)
to->matched = true;
return matched;
}
/*
* This function performs %-expansion on @value (see overview above),
* and appends the result to @to.
@ -614,7 +635,7 @@ append_expanded_kccgst_value(struct matcher *m, darray_char *to,
enum rules_mlvo mlv;
xkb_layout_index_t idx;
char pfx, sfx;
struct sval expanded_value;
struct matched_sval *expanded_value;
/* Check if that's a start of an expansion. */
if (s[i] != '%') {
@ -664,40 +685,42 @@ append_expanded_kccgst_value(struct matcher *m, darray_char *to,
}
/* Get the expanded value. */
expanded_value.len = 0;
expanded_value = NULL;
if (mlv == MLVO_LAYOUT) {
if (idx != XKB_LAYOUT_INVALID &&
idx < darray_size(m->rmlvo.layouts) &&
darray_size(m->rmlvo.layouts) > 1)
expanded_value = darray_item(m->rmlvo.layouts, idx);
expanded_value = &darray_item(m->rmlvo.layouts, idx);
else if (idx == XKB_LAYOUT_INVALID &&
darray_size(m->rmlvo.layouts) == 1)
expanded_value = darray_item(m->rmlvo.layouts, 0);
expanded_value = &darray_item(m->rmlvo.layouts, 0);
}
else if (mlv == MLVO_VARIANT) {
if (idx != XKB_LAYOUT_INVALID &&
idx < darray_size(m->rmlvo.variants) &&
darray_size(m->rmlvo.variants) > 1)
expanded_value = darray_item(m->rmlvo.variants, idx);
expanded_value = &darray_item(m->rmlvo.variants, idx);
else if (idx == XKB_LAYOUT_INVALID &&
darray_size(m->rmlvo.variants) == 1)
expanded_value = darray_item(m->rmlvo.variants, 0);
expanded_value = &darray_item(m->rmlvo.variants, 0);
}
else if (mlv == MLVO_MODEL) {
expanded_value = m->rmlvo.model;
expanded_value = &m->rmlvo.model;
}
/* If we didn't get one, skip silently. */
if (expanded_value.len <= 0)
if (!expanded_value || expanded_value->sval.len == 0)
continue;
if (pfx != 0)
darray_appends_nullterminate(expanded, &pfx, 1);
darray_appends_nullterminate(expanded,
expanded_value.start, expanded_value.len);
expanded_value->sval.start,
expanded_value->sval.len);
if (sfx != 0)
darray_appends_nullterminate(expanded, &sfx, 1);
expanded_value->matched = true;
}
/*
@ -743,29 +766,28 @@ matcher_rule_apply_if_matches(struct matcher *m)
enum rules_mlvo mlvo = m->mapping.mlvo_at_pos[i];
struct sval value = m->rule.mlvo_value_at_pos[i];
enum mlvo_match_type match_type = m->rule.match_type_at_pos[i];
struct matched_sval *to;
bool matched = false;
if (mlvo == MLVO_MODEL) {
matched = match_value(m, value, m->rmlvo.model, match_type);
to = &m->rmlvo.model;
matched = match_value_and_mark(m, value, to, match_type);
}
else if (mlvo == MLVO_LAYOUT) {
xkb_layout_index_t idx = m->mapping.layout_idx;
idx = (idx == XKB_LAYOUT_INVALID ? 0 : idx);
matched = match_value(m, value,
darray_item(m->rmlvo.layouts, idx),
match_type);
to = &darray_item(m->rmlvo.layouts, idx);
matched = match_value_and_mark(m, value, to, match_type);
}
else if (mlvo == MLVO_VARIANT) {
xkb_layout_index_t idx = m->mapping.layout_idx;
idx = (idx == XKB_LAYOUT_INVALID ? 0 : idx);
matched = match_value(m, value,
darray_item(m->rmlvo.variants, idx),
match_type);
to = &darray_item(m->rmlvo.variants, idx);
matched = match_value_and_mark(m, value, to, match_type);
}
else if (mlvo == MLVO_OPTION) {
struct sval *option;
darray_foreach(option, m->rmlvo.options) {
matched = match_value(m, value, *option, match_type);
darray_foreach(to, m->rmlvo.options) {
matched = match_value_and_mark(m, value, to, match_type);
if (matched)
break;
}
@ -801,11 +823,12 @@ matcher_match(struct matcher *m, const char *string, size_t len,
const char *file_name, struct xkb_component_names *out)
{
enum rules_token tok;
struct matched_sval *mval;
if (!m)
return false;
scanner_init(&m->scanner, m->ctx, string, len, file_name);
scanner_init(&m->scanner, m->ctx, string, len, file_name, NULL);
initial:
switch (tok = gettok(m)) {
@ -944,12 +967,29 @@ finish:
darray_empty(m->kccgst[KCCGST_SYMBOLS]))
goto error;
out->keycodes = darray_mem(m->kccgst[KCCGST_KEYCODES], 0);
out->types = darray_mem(m->kccgst[KCCGST_TYPES], 0);
out->compat = darray_mem(m->kccgst[KCCGST_COMPAT], 0);
/* out->geometry = darray_mem(m->kccgst[KCCGST_GEOMETRY], 0); */
darray_steal(m->kccgst[KCCGST_KEYCODES], &out->keycodes, NULL);
darray_steal(m->kccgst[KCCGST_TYPES], &out->types, NULL);
darray_steal(m->kccgst[KCCGST_COMPAT], &out->compat, NULL);
darray_steal(m->kccgst[KCCGST_SYMBOLS], &out->symbols, NULL);
darray_free(m->kccgst[KCCGST_GEOMETRY]);
out->symbols = darray_mem(m->kccgst[KCCGST_SYMBOLS], 0);
mval = &m->rmlvo.model;
if (!mval->matched && mval->sval.len > 0)
log_err(m->ctx, "Unrecognized RMLVO model \"%.*s\" was ignored\n",
mval->sval.len, mval->sval.start);
darray_foreach(mval, m->rmlvo.layouts)
if (!mval->matched && mval->sval.len > 0)
log_err(m->ctx, "Unrecognized RMLVO layout \"%.*s\" was ignored\n",
mval->sval.len, mval->sval.start);
darray_foreach(mval, m->rmlvo.variants)
if (!mval->matched && mval->sval.len > 0)
log_err(m->ctx, "Unrecognized RMLVO variant \"%.*s\" was ignored\n",
mval->sval.len, mval->sval.start);
darray_foreach(mval, m->rmlvo.options)
if (!mval->matched && mval->sval.len > 0)
log_err(m->ctx, "Unrecognized RMLVO option \"%.*s\" was ignored\n",
mval->sval.len, mval->sval.start);
return true;
@ -967,7 +1007,7 @@ xkb_components_from_rules(struct xkb_context *ctx,
bool ret = false;
FILE *file;
char *path;
const char *string;
char *string;
size_t size;
struct matcher *matcher;

View File

@ -23,6 +23,7 @@
#include "xkbcomp-priv.h"
#include "parser-priv.h"
#include "scanner-utils.h"
static bool
number(struct scanner *s, int64_t *out, int *out_tok)
@ -68,7 +69,7 @@ skip_more_whitespace_and_comments:
/* Skip comments. */
if (lit(s, "//") || chr(s, '#')) {
while (!eof(s) && !eol(s)) next(s);
skip_to_eol(s);
goto skip_more_whitespace_and_comments;
}
@ -121,7 +122,7 @@ skip_more_whitespace_and_comments:
return ERROR_TOK;
}
/* Empty key name literals are allowed. */
yylval->sval = xkb_atom_intern(s->ctx, s->buf, s->buf_pos - 1);
yylval->atom = xkb_atom_intern(s->ctx, s->buf, s->buf_pos - 1);
return KEYNAME;
}
@ -181,7 +182,7 @@ XkbParseString(struct xkb_context *ctx, const char *string, size_t len,
const char *file_name, const char *map)
{
struct scanner scanner;
scanner_init(&scanner, ctx, string, len, file_name);
scanner_init(&scanner, ctx, string, len, file_name, NULL);
return parse(ctx, &scanner, map);
}
@ -191,7 +192,7 @@ XkbParseFile(struct xkb_context *ctx, FILE *file,
{
bool ok;
XkbFile *xkb_file;
const char *string;
char *string;
size_t size;
ok = map_file(file, &string, &size);

View File

@ -72,10 +72,10 @@ enum group_field {
};
enum key_field {
KEY_FIELD_REPEAT = (1 << 0),
KEY_FIELD_REPEAT = (1 << 0),
KEY_FIELD_DEFAULT_TYPE = (1 << 1),
KEY_FIELD_GROUPINFO = (1 << 2),
KEY_FIELD_VMODMAP = (1 << 3),
KEY_FIELD_VMODMAP = (1 << 3),
};
typedef struct {
@ -177,19 +177,24 @@ typedef struct {
ActionsInfo *actions;
darray(xkb_atom_t) group_names;
darray(ModMapEntry) modmaps;
struct xkb_mod_set mods;
struct xkb_keymap *keymap;
struct xkb_context *ctx;
/* Needed for AddKeySymbols. */
const struct xkb_keymap *keymap;
} SymbolsInfo;
static void
InitSymbolsInfo(SymbolsInfo *info, struct xkb_keymap *keymap,
ActionsInfo *actions)
InitSymbolsInfo(SymbolsInfo *info, const struct xkb_keymap *keymap,
ActionsInfo *actions, const struct xkb_mod_set *mods)
{
memset(info, 0, sizeof(*info));
info->ctx = keymap->ctx;
info->keymap = keymap;
info->merge = MERGE_OVERRIDE;
InitKeyInfo(keymap->ctx, &info->default_key);
info->actions = actions;
info->mods = *mods;
info->explicit_group = XKB_LAYOUT_INVALID;
}
@ -209,7 +214,7 @@ ClearSymbolsInfo(SymbolsInfo *info)
static const char *
KeyInfoText(SymbolsInfo *info, KeyInfo *keyi)
{
return KeyNameText(info->keymap->ctx, keyi->name);
return KeyNameText(info->ctx, keyi->name);
}
static bool
@ -217,7 +222,7 @@ MergeGroups(SymbolsInfo *info, GroupInfo *into, GroupInfo *from, bool clobber,
bool report, xkb_layout_index_t group, xkb_atom_t key_name)
{
xkb_level_index_t i, levels_in_both;
struct xkb_context *ctx = info->keymap->ctx;
struct xkb_level *level;
/* First find the type of the merged group. */
if (into->type != from->type) {
@ -231,11 +236,12 @@ MergeGroups(SymbolsInfo *info, GroupInfo *into, GroupInfo *from, bool clobber,
xkb_atom_t ignore = (clobber ? into->type : from->type);
if (report)
log_warn(info->keymap->ctx,
log_warn(info->ctx,
"Multiple definitions for group %d type of key %s; "
"Using %s, ignoring %s\n",
group + 1, KeyNameText(ctx, key_name),
xkb_atom_text(ctx, use), xkb_atom_text(ctx, ignore));
group + 1, KeyNameText(info->ctx, key_name),
xkb_atom_text(info->ctx, use),
xkb_atom_text(info->ctx, ignore));
into->type = use;
}
@ -273,10 +279,10 @@ MergeGroups(SymbolsInfo *info, GroupInfo *into, GroupInfo *from, bool clobber,
ignore = (clobber ? &intoLevel->action : &fromLevel->action);
if (report)
log_warn(ctx,
log_warn(info->ctx,
"Multiple actions for level %d/group %u on key %s; "
"Using %s, ignoring %s\n",
i + 1, group + 1, KeyNameText(ctx, key_name),
i + 1, group + 1, KeyNameText(info->ctx, key_name),
ActionTypeText(use->type),
ActionTypeText(ignore->type));
@ -293,12 +299,12 @@ MergeGroups(SymbolsInfo *info, GroupInfo *into, GroupInfo *from, bool clobber,
intoLevel->u.sym = fromLevel->u.sym;
fromLevel->num_syms = 0;
}
else {
else if (!XkbLevelsSameSyms(fromLevel, intoLevel)) {
if (report)
log_warn(ctx,
log_warn(info->ctx,
"Multiple symbols for level %d/group %u on key %s; "
"Using %s, ignoring %s\n",
i + 1, group + 1, KeyNameText(ctx, key_name),
i + 1, group + 1, KeyNameText(info->ctx, key_name),
(clobber ? "from" : "to"),
(clobber ? "to" : "from"));
@ -314,9 +320,9 @@ MergeGroups(SymbolsInfo *info, GroupInfo *into, GroupInfo *from, bool clobber,
}
}
/* If @from has extra levels, get them as well. */
for (i = levels_in_both; i < darray_size(from->levels); i++) {
darray_append(into->levels, darray_item(from->levels, i));
darray_item(from->levels, i).num_syms = 0;
darray_foreach_from(level, from->levels, levels_in_both) {
darray_append(into->levels, *level);
level->num_syms = 0;
}
into->defined |= (from->defined & GROUP_FIELD_ACTS);
into->defined |= (from->defined & GROUP_FIELD_SYMS);
@ -348,14 +354,14 @@ MergeKeys(SymbolsInfo *info, KeyInfo *into, KeyInfo *from, bool same_file)
xkb_layout_index_t i;
xkb_layout_index_t groups_in_both;
enum key_field collide = 0;
const int verbosity = xkb_context_get_log_verbosity(info->keymap->ctx);
const int verbosity = xkb_context_get_log_verbosity(info->ctx);
const bool clobber = (from->merge != MERGE_AUGMENT);
const bool report = (same_file && verbosity > 0) || verbosity > 9;
if (from->merge == MERGE_REPLACE) {
ClearKeyInfo(into);
*into = *from;
InitKeyInfo(info->keymap->ctx, from);
InitKeyInfo(info->ctx, from);
return true;
}
@ -394,17 +400,18 @@ MergeKeys(SymbolsInfo *info, KeyInfo *into, KeyInfo *from, bool same_file)
}
if (collide)
log_warn(info->keymap->ctx,
log_warn(info->ctx,
"Symbol map for key %s redefined; "
"Using %s definition for conflicting fields\n",
KeyNameText(info->keymap->ctx, into->name),
KeyNameText(info->ctx, into->name),
(clobber ? "first" : "last"));
ClearKeyInfo(from);
InitKeyInfo(info->keymap->ctx, from);
InitKeyInfo(info->ctx, from);
return true;
}
/* TODO: Make it so this function doesn't need the entire keymap. */
static bool
AddKeySymbols(SymbolsInfo *info, KeyInfo *keyi, bool same_file)
{
@ -426,7 +433,7 @@ AddKeySymbols(SymbolsInfo *info, KeyInfo *keyi, bool same_file)
return MergeKeys(info, iter, keyi, same_file);
darray_append(info->keys, *keyi);
InitKeyInfo(info->keymap->ctx, keyi);
InitKeyInfo(info->ctx, keyi);
return true;
}
@ -451,19 +458,19 @@ AddModMapEntry(SymbolsInfo *info, ModMapEntry *new)
ignore = (clobber ? old->modifier : new->modifier);
if (new->haveSymbol)
log_err(info->keymap->ctx,
log_err(info->ctx,
"Symbol \"%s\" added to modifier map for multiple modifiers; "
"Using %s, ignoring %s\n",
KeysymText(info->keymap->ctx, new->u.keySym),
ModIndexText(info->keymap, use),
ModIndexText(info->keymap, ignore));
KeysymText(info->ctx, new->u.keySym),
ModIndexText(info->ctx, &info->mods, use),
ModIndexText(info->ctx, &info->mods, ignore));
else
log_err(info->keymap->ctx,
log_err(info->ctx,
"Key \"%s\" added to modifier map for multiple modifiers; "
"Using %s, ignoring %s\n",
KeyNameText(info->keymap->ctx, new->u.keyName),
ModIndexText(info->keymap, use),
ModIndexText(info->keymap, ignore));
KeyNameText(info->ctx, new->u.keyName),
ModIndexText(info->ctx, &info->mods, use),
ModIndexText(info->ctx, &info->mods, ignore));
old->modifier = use;
return true;
@ -479,8 +486,6 @@ static void
MergeIncludedSymbols(SymbolsInfo *into, SymbolsInfo *from,
enum merge_mode merge)
{
KeyInfo *keyi;
ModMapEntry *mm;
xkb_atom_t *group_name;
xkb_layout_index_t group_names_in_both;
@ -489,6 +494,8 @@ MergeIncludedSymbols(SymbolsInfo *into, SymbolsInfo *from,
return;
}
into->mods = from->mods;
if (into->name == NULL) {
into->name = from->name;
from->name = NULL;
@ -514,6 +521,7 @@ MergeIncludedSymbols(SymbolsInfo *into, SymbolsInfo *from,
darray_init(from->keys);
}
else {
KeyInfo *keyi;
darray_foreach(keyi, from->keys) {
keyi->merge = (merge == MERGE_DEFAULT ? keyi->merge : merge);
if (!AddKeySymbols(into, keyi, false))
@ -526,6 +534,7 @@ MergeIncludedSymbols(SymbolsInfo *into, SymbolsInfo *from,
darray_init(from->modmaps);
}
else {
ModMapEntry *mm;
darray_foreach(mm, from->modmaps) {
mm->merge = (merge == MERGE_DEFAULT ? mm->merge : merge);
if (!AddModMapEntry(into, mm))
@ -542,7 +551,7 @@ HandleIncludeSymbols(SymbolsInfo *info, IncludeStmt *include)
{
SymbolsInfo included;
InitSymbolsInfo(&included, info->keymap, info->actions);
InitSymbolsInfo(&included, info->keymap, info->actions, &info->mods);
included.name = include->stmt;
include->stmt = NULL;
@ -550,18 +559,19 @@ HandleIncludeSymbols(SymbolsInfo *info, IncludeStmt *include)
SymbolsInfo next_incl;
XkbFile *file;
file = ProcessIncludeFile(info->keymap->ctx, stmt, FILE_TYPE_SYMBOLS);
file = ProcessIncludeFile(info->ctx, stmt, FILE_TYPE_SYMBOLS);
if (!file) {
info->errorCount += 10;
ClearSymbolsInfo(&included);
return false;
}
InitSymbolsInfo(&next_incl, info->keymap, info->actions);
InitSymbolsInfo(&next_incl, info->keymap, info->actions,
&included.mods);
if (stmt->modifier) {
next_incl.explicit_group = atoi(stmt->modifier) - 1;
if (next_incl.explicit_group >= XKB_MAX_GROUPS) {
log_err(info->keymap->ctx,
log_err(info->ctx,
"Cannot set explicit group to %d - must be between 1..%d; "
"Ignoring group number\n",
next_incl.explicit_group + 1, XKB_MAX_GROUPS);
@ -609,7 +619,7 @@ GetGroupIndex(SymbolsInfo *info, KeyInfo *keyi, ExprDef *arrayNdx,
}
if (i >= XKB_MAX_GROUPS) {
log_err(info->keymap->ctx,
log_err(info->ctx,
"Too many groups of %s for key %s (max %u); "
"Ignoring %s defined for extra groups\n",
name, KeyInfoText(info, keyi), XKB_MAX_GROUPS, name);
@ -621,8 +631,8 @@ GetGroupIndex(SymbolsInfo *info, KeyInfo *keyi, ExprDef *arrayNdx,
return true;
}
if (!ExprResolveGroup(info->keymap->ctx, arrayNdx, ndx_rtrn)) {
log_err(info->keymap->ctx,
if (!ExprResolveGroup(info->ctx, arrayNdx, ndx_rtrn)) {
log_err(info->ctx,
"Illegal group index for %s of key %s\n"
"Definition with non-integer array index ignored\n",
name, KeyInfoText(info, keyi));
@ -655,7 +665,7 @@ AddSymbolsToKey(SymbolsInfo *info, KeyInfo *keyi, ExprDef *arrayNdx,
}
if (value->expr.op != EXPR_KEYSYM_LIST) {
log_err(info->keymap->ctx,
log_err(info->ctx,
"Expected a list of symbols, found %s; "
"Ignoring symbols for group %u of %s\n",
expr_op_type_to_string(value->expr.op), ndx + 1,
@ -664,7 +674,7 @@ AddSymbolsToKey(SymbolsInfo *info, KeyInfo *keyi, ExprDef *arrayNdx,
}
if (groupi->defined & GROUP_FIELD_SYMS) {
log_err(info->keymap->ctx,
log_err(info->ctx,
"Symbols for key %s, group %u already defined; "
"Ignoring duplicate definition\n",
KeyInfoText(info, keyi), ndx + 1);
@ -725,7 +735,7 @@ AddActionsToKey(SymbolsInfo *info, KeyInfo *keyi, ExprDef *arrayNdx,
}
if (value->expr.op != EXPR_ACTION_LIST) {
log_wsgo(info->keymap->ctx,
log_wsgo(info->ctx,
"Bad expression type (%d) for action list value; "
"Ignoring actions for group %u of %s\n",
value->expr.op, ndx, KeyInfoText(info, keyi));
@ -733,7 +743,7 @@ AddActionsToKey(SymbolsInfo *info, KeyInfo *keyi, ExprDef *arrayNdx,
}
if (groupi->defined & GROUP_FIELD_ACTS) {
log_wsgo(info->keymap->ctx,
log_wsgo(info->ctx,
"Actions for key %s, group %u already defined\n",
KeyInfoText(info, keyi), ndx);
return false;
@ -752,8 +762,8 @@ AddActionsToKey(SymbolsInfo *info, KeyInfo *keyi, ExprDef *arrayNdx,
for (unsigned i = 0; i < nActs; i++) {
union xkb_action *toAct = &darray_item(groupi->levels, i).action;
if (!HandleActionDef(act, info->keymap, toAct, info->actions))
log_err(info->keymap->ctx,
if (!HandleActionDef(info->ctx, info->actions, &info->mods, act, toAct))
log_err(info->ctx,
"Illegal action definition for %s; "
"Action for group %u/level %u ignored\n",
KeyInfoText(info, keyi), ndx + 1, i + 1);
@ -779,14 +789,12 @@ static bool
SetSymbolsField(SymbolsInfo *info, KeyInfo *keyi, const char *field,
ExprDef *arrayNdx, ExprDef *value)
{
struct xkb_context *ctx = info->keymap->ctx;
if (istreq(field, "type")) {
xkb_layout_index_t ndx;
xkb_atom_t val;
if (!ExprResolveString(ctx, value, &val)) {
log_err(ctx,
if (!ExprResolveString(info->ctx, value, &val)) {
log_err(info->ctx,
"The type field of a key symbol map must be a string; "
"Ignoring illegal type definition\n");
return false;
@ -796,8 +804,8 @@ SetSymbolsField(SymbolsInfo *info, KeyInfo *keyi, const char *field,
keyi->default_type = val;
keyi->defined |= KEY_FIELD_DEFAULT_TYPE;
}
else if (!ExprResolveGroup(ctx, arrayNdx, &ndx)) {
log_err(ctx,
else if (!ExprResolveGroup(info->ctx, arrayNdx, &ndx)) {
log_err(info->ctx,
"Illegal group index for type of key %s; "
"Definition with non-integer array index ignored\n",
KeyInfoText(info, keyi));
@ -822,8 +830,9 @@ SetSymbolsField(SymbolsInfo *info, KeyInfo *keyi, const char *field,
istreq(field, "virtualmodifiers")) {
xkb_mod_mask_t mask;
if (!ExprResolveModMask(info->keymap, value, MOD_VIRT, &mask)) {
log_err(ctx,
if (!ExprResolveModMask(info->ctx, value, MOD_VIRT, &info->mods,
&mask)) {
log_err(info->ctx,
"Expected a virtual modifier mask, found %s; "
"Ignoring virtual modifiers definition for key %s\n",
expr_op_type_to_string(value->expr.op),
@ -837,7 +846,7 @@ SetSymbolsField(SymbolsInfo *info, KeyInfo *keyi, const char *field,
else if (istreq(field, "locking") ||
istreq(field, "lock") ||
istreq(field, "locks")) {
log_vrb(ctx, 1,
log_vrb(info->ctx, 1,
"Key behaviors not supported; "
"Ignoring locking specification for key %s\n",
KeyInfoText(info, keyi));
@ -845,14 +854,14 @@ SetSymbolsField(SymbolsInfo *info, KeyInfo *keyi, const char *field,
else if (istreq(field, "radiogroup") ||
istreq(field, "permanentradiogroup") ||
istreq(field, "allownone")) {
log_vrb(ctx, 1,
log_vrb(info->ctx, 1,
"Radio groups not supported; "
"Ignoring radio group specification for key %s\n",
KeyInfoText(info, keyi));
}
else if (istreq_prefix("overlay", field) ||
istreq_prefix("permanentoverlay", field)) {
log_vrb(ctx, 1,
log_vrb(info->ctx, 1,
"Overlays not supported; "
"Ignoring overlay specification for key %s\n",
KeyInfoText(info, keyi));
@ -862,8 +871,8 @@ SetSymbolsField(SymbolsInfo *info, KeyInfo *keyi, const char *field,
istreq(field, "repeat")) {
unsigned int val;
if (!ExprResolveEnum(ctx, value, &val, repeatEntries)) {
log_err(ctx,
if (!ExprResolveEnum(info->ctx, value, &val, repeatEntries)) {
log_err(info->ctx,
"Illegal repeat setting for %s; "
"Non-boolean repeat setting ignored\n",
KeyInfoText(info, keyi));
@ -877,8 +886,8 @@ SetSymbolsField(SymbolsInfo *info, KeyInfo *keyi, const char *field,
istreq(field, "wrapgroups")) {
bool set;
if (!ExprResolveBoolean(ctx, value, &set)) {
log_err(ctx,
if (!ExprResolveBoolean(info->ctx, value, &set)) {
log_err(info->ctx,
"Illegal groupsWrap setting for %s; "
"Non-boolean value ignored\n",
KeyInfoText(info, keyi));
@ -892,8 +901,8 @@ SetSymbolsField(SymbolsInfo *info, KeyInfo *keyi, const char *field,
istreq(field, "clampgroups")) {
bool set;
if (!ExprResolveBoolean(ctx, value, &set)) {
log_err(ctx,
if (!ExprResolveBoolean(info->ctx, value, &set)) {
log_err(info->ctx,
"Illegal groupsClamp setting for %s; "
"Non-boolean value ignored\n",
KeyInfoText(info, keyi));
@ -907,8 +916,8 @@ SetSymbolsField(SymbolsInfo *info, KeyInfo *keyi, const char *field,
istreq(field, "redirectgroups")) {
xkb_layout_index_t grp;
if (!ExprResolveGroup(ctx, value, &grp)) {
log_err(ctx,
if (!ExprResolveGroup(info->ctx, value, &grp)) {
log_err(info->ctx,
"Illegal group index for redirect of key %s; "
"Definition with non-integer group ignored\n",
KeyInfoText(info, keyi));
@ -920,7 +929,7 @@ SetSymbolsField(SymbolsInfo *info, KeyInfo *keyi, const char *field,
keyi->defined |= KEY_FIELD_GROUPINFO;
}
else {
log_err(ctx,
log_err(info->ctx,
"Unknown field %s in a symbol interpretation; "
"Definition ignored\n",
field);
@ -937,21 +946,21 @@ SetGroupName(SymbolsInfo *info, ExprDef *arrayNdx, ExprDef *value)
xkb_atom_t name;
if (!arrayNdx) {
log_vrb(info->keymap->ctx, 1,
log_vrb(info->ctx, 1,
"You must specify an index when specifying a group name; "
"Group name definition without array subscript ignored\n");
return false;
}
if (!ExprResolveGroup(info->keymap->ctx, arrayNdx, &group)) {
log_err(info->keymap->ctx,
if (!ExprResolveGroup(info->ctx, arrayNdx, &group)) {
log_err(info->ctx,
"Illegal index in group name definition; "
"Definition with non-integer array index ignored\n");
return false;
}
if (!ExprResolveString(info->keymap->ctx, value, &name)) {
log_err(info->keymap->ctx,
if (!ExprResolveString(info->ctx, value, &name)) {
log_err(info->ctx,
"Group name must be a string; "
"Illegal name for group %d ignored\n", group);
return false;
@ -964,12 +973,12 @@ SetGroupName(SymbolsInfo *info, ExprDef *arrayNdx, ExprDef *value)
group_to_use = info->explicit_group;
}
else {
log_warn(info->keymap->ctx,
log_warn(info->ctx,
"An explicit group was specified for the '%s' map, "
"but it provides a name for a group other than Group1 (%d); "
"Ignoring group name '%s'\n",
info->name, group,
xkb_atom_text(info->keymap->ctx, name));
xkb_atom_text(info->ctx, name));
return false;
}
@ -987,7 +996,7 @@ HandleGlobalVar(SymbolsInfo *info, VarDef *stmt)
ExprDef *arrayNdx;
bool ret;
if (!ExprResolveLhs(info->keymap->ctx, stmt->name, &elem, &field, &arrayNdx))
if (!ExprResolveLhs(info->ctx, stmt->name, &elem, &field, &arrayNdx))
return false;
if (elem && istreq(elem, "key")) {
@ -1000,31 +1009,31 @@ HandleGlobalVar(SymbolsInfo *info, VarDef *stmt)
}
else if (!elem && (istreq(field, "groupswrap") ||
istreq(field, "wrapgroups"))) {
log_err(info->keymap->ctx,
log_err(info->ctx,
"Global \"groupswrap\" not supported; Ignored\n");
ret = true;
}
else if (!elem && (istreq(field, "groupsclamp") ||
istreq(field, "clampgroups"))) {
log_err(info->keymap->ctx,
log_err(info->ctx,
"Global \"groupsclamp\" not supported; Ignored\n");
ret = true;
}
else if (!elem && (istreq(field, "groupsredirect") ||
istreq(field, "redirectgroups"))) {
log_err(info->keymap->ctx,
log_err(info->ctx,
"Global \"groupsredirect\" not supported; Ignored\n");
ret = true;
}
else if (!elem && istreq(field, "allownone")) {
log_err(info->keymap->ctx,
log_err(info->ctx,
"Radio groups not supported; "
"Ignoring \"allownone\" specification\n");
ret = true;
}
else {
ret = SetActionField(info->keymap, elem, field, arrayNdx, stmt->value,
info->actions);
ret = SetActionField(info->ctx, info->actions, &info->mods,
elem, field, arrayNdx, stmt->value);
}
return ret;
@ -1039,7 +1048,7 @@ HandleSymbolsBody(SymbolsInfo *info, VarDef *def, KeyInfo *keyi)
for (; def; def = (VarDef *) def->common.next) {
if (def->name && def->name->expr.op == EXPR_FIELD_REF) {
log_err(info->keymap->ctx,
log_err(info->ctx,
"Cannot set a global default value from within a key statement; "
"Move statements to the global file scope\n");
continue;
@ -1053,7 +1062,7 @@ HandleSymbolsBody(SymbolsInfo *info, VarDef *def, KeyInfo *keyi)
arrayNdx = NULL;
}
else {
ok = ExprResolveLhs(info->keymap->ctx, def->name, &elem, &field,
ok = ExprResolveLhs(info->ctx, def->name, &elem, &field,
&arrayNdx);
}
@ -1083,7 +1092,7 @@ SetExplicitGroup(SymbolsInfo *info, KeyInfo *keyi)
}
if (warn)
log_warn(info->keymap->ctx,
log_warn(info->ctx,
"For the map %s an explicit group specified, "
"but key %s has more than one group defined; "
"All groups except first one will be ignored\n",
@ -1137,11 +1146,11 @@ HandleModMapDef(SymbolsInfo *info, ModMapDef *def)
ModMapEntry tmp;
xkb_mod_index_t ndx;
bool ok;
struct xkb_context *ctx = info->keymap->ctx;
struct xkb_context *ctx = info->ctx;
ndx = ModNameToIndex(info->keymap, def->modifier, MOD_REAL);
ndx = XkbModNameToIndex(&info->mods, def->modifier, MOD_REAL);
if (ndx == XKB_MOD_INVALID) {
log_err(info->keymap->ctx,
log_err(info->ctx,
"Illegal modifier map definition; "
"Ignoring map for non-modifier \"%s\"\n",
xkb_atom_text(ctx, def->modifier));
@ -1165,10 +1174,10 @@ HandleModMapDef(SymbolsInfo *info, ModMapDef *def)
tmp.u.keySym = sym;
}
else {
log_err(info->keymap->ctx,
log_err(info->ctx,
"Modmap entries may contain only key names or keysyms; "
"Illegal definition for %s modifier ignored\n",
ModIndexText(info->keymap, tmp.modifier));
ModIndexText(info->ctx, &info->mods, tmp.modifier));
continue;
}
@ -1197,13 +1206,13 @@ HandleSymbolsFile(SymbolsInfo *info, XkbFile *file, enum merge_mode merge)
ok = HandleGlobalVar(info, (VarDef *) stmt);
break;
case STMT_VMOD:
ok = HandleVModDef(info->keymap, (VModDef *) stmt, merge);
ok = HandleVModDef(info->ctx, &info->mods, (VModDef *) stmt, merge);
break;
case STMT_MODMAP:
ok = HandleModMapDef(info, (ModMapDef *) stmt);
break;
default:
log_err(info->keymap->ctx,
log_err(info->ctx,
"Symbols files may not include other types; "
"Ignoring %s\n", stmt_type_to_string(stmt->type));
ok = false;
@ -1214,8 +1223,8 @@ HandleSymbolsFile(SymbolsInfo *info, XkbFile *file, enum merge_mode merge)
info->errorCount++;
if (info->errorCount > 10) {
log_err(info->keymap->ctx, "Abandoning symbols file \"%s\"\n",
file->topName);
log_err(info->ctx, "Abandoning symbols file \"%s\"\n",
file->name);
break;
}
}
@ -1234,38 +1243,31 @@ HandleSymbolsFile(SymbolsInfo *info, XkbFile *file, enum merge_mode merge)
static struct xkb_key *
FindKeyForSymbol(struct xkb_keymap *keymap, xkb_keysym_t sym)
{
struct xkb_key *key, *ret = NULL;
xkb_layout_index_t group, min_group = UINT32_MAX;
xkb_level_index_t level, min_level = UINT16_MAX;
struct xkb_key *key;
xkb_layout_index_t group;
bool got_one_group, got_one_level;
xkb_foreach_key(key, keymap) {
for (group = 0; group < key->num_groups; group++) {
for (level = 0; level < XkbKeyGroupWidth(key, group); level++) {
if (key->groups[group].levels[level].num_syms != 1 ||
key->groups[group].levels[level].u.sym != sym)
continue;
/*
* If the keysym was found in a group or level > 0, we must
* keep looking since we might find a key in which the keysym
* is in a lower group or level.
*/
if (group < min_group ||
(group == min_group && level < min_level)) {
ret = key;
if (group == 0 && level == 0) {
return ret;
}
else {
min_group = group;
min_level = level;
}
group = 0;
do {
xkb_level_index_t level = 0;
got_one_group = false;
do {
got_one_level = false;
xkb_keys_foreach(key, keymap) {
if (group < key->num_groups &&
level < XkbKeyNumLevels(key, group)) {
got_one_group = got_one_level = true;
if (key->groups[group].levels[level].num_syms == 1 &&
key->groups[group].levels[level].u.sym == sym)
return key;
}
}
}
}
level++;
} while (got_one_level);
group++;
} while (got_one_group);
return ret;
return NULL;
}
/*
@ -1283,8 +1285,8 @@ FindKeyForSymbol(struct xkb_keymap *keymap, xkb_keysym_t sym)
static xkb_atom_t
FindAutomaticType(struct xkb_context *ctx, GroupInfo *groupi)
{
xkb_keysym_t sym0, sym1, sym2, sym3;
xkb_level_index_t width = darray_size(groupi->levels);
xkb_keysym_t sym0, sym1;
const xkb_level_index_t width = darray_size(groupi->levels);
#define GET_SYM(level) \
(darray_item(groupi->levels, level).num_syms == 0 ? \
@ -1312,6 +1314,7 @@ FindAutomaticType(struct xkb_context *ctx, GroupInfo *groupi)
if (width <= 4) {
if (xkb_keysym_is_lower(sym0) && xkb_keysym_is_upper(sym1)) {
xkb_keysym_t sym2, sym3;
sym2 = GET_SYM(2);
sym3 = (width == 4 ? GET_SYM(3) : XKB_KEY_NoSymbol);
@ -1386,9 +1389,9 @@ use_default:
}
static bool
CopySymbolsDef(SymbolsInfo *info, KeyInfo *keyi)
CopySymbolsDefToKeymap(struct xkb_keymap *keymap, SymbolsInfo *info,
KeyInfo *keyi)
{
struct xkb_keymap *keymap = info->keymap;
struct xkb_key *key;
GroupInfo *groupi;
const GroupInfo *group0;
@ -1400,7 +1403,7 @@ CopySymbolsDef(SymbolsInfo *info, KeyInfo *keyi)
*/
key = XkbKeyByName(keymap, keyi->name, false);
if (!key) {
log_vrb(info->keymap->ctx, 5,
log_vrb(info->ctx, 5,
"Key %s not found in keycodes; Symbols ignored\n",
KeyInfoText(info, keyi));
return false;
@ -1443,7 +1446,7 @@ CopySymbolsDef(SymbolsInfo *info, KeyInfo *keyi)
if (type->num_levels < darray_size(groupi->levels)) {
struct xkb_level *leveli;
log_vrb(info->keymap->ctx, 1,
log_vrb(info->ctx, 1,
"Type \"%s\" has %d levels, but %s has %d levels; "
"Ignoring extra symbols\n",
xkb_atom_text(keymap->ctx, type->name), type->num_levels,
@ -1460,10 +1463,8 @@ CopySymbolsDef(SymbolsInfo *info, KeyInfo *keyi)
}
/* Copy levels. */
darray_enumerate(i, groupi, keyi->groups) {
key->groups[i].levels = darray_mem(groupi->levels, 0);
darray_init(groupi->levels);
}
darray_enumerate(i, groupi, keyi->groups)
darray_steal(groupi->levels, &key->groups[i].levels, NULL);
key->out_of_range_group_number = keyi->out_of_range_group_number;
key->out_of_range_group_action = keyi->out_of_range_group_action;
@ -1489,30 +1490,30 @@ CopySymbolsDef(SymbolsInfo *info, KeyInfo *keyi)
}
static bool
CopyModMapDef(SymbolsInfo *info, ModMapEntry *entry)
CopyModMapDefToKeymap(struct xkb_keymap *keymap, SymbolsInfo *info,
ModMapEntry *entry)
{
struct xkb_key *key;
struct xkb_keymap *keymap = info->keymap;
if (!entry->haveSymbol) {
key = XkbKeyByName(keymap, entry->u.keyName, true);
if (!key) {
log_vrb(info->keymap->ctx, 5,
log_vrb(info->ctx, 5,
"Key %s not found in keycodes; "
"Modifier map entry for %s not updated\n",
KeyNameText(keymap->ctx, entry->u.keyName),
ModIndexText(info->keymap, entry->modifier));
KeyNameText(info->ctx, entry->u.keyName),
ModIndexText(info->ctx, &info->mods, entry->modifier));
return false;
}
}
else {
key = FindKeyForSymbol(keymap, entry->u.keySym);
if (!key) {
log_vrb(info->keymap->ctx, 5,
log_vrb(info->ctx, 5,
"Key \"%s\" not found in symbol map; "
"Modifier map entry for %s not updated\n",
KeysymText(info->keymap->ctx, entry->u.keySym),
ModIndexText(info->keymap, entry->modifier));
KeysymText(info->ctx, entry->u.keySym),
ModIndexText(info->ctx, &info->mods, entry->modifier));
return false;
}
}
@ -1530,30 +1531,31 @@ CopySymbolsToKeymap(struct xkb_keymap *keymap, SymbolsInfo *info)
keymap->symbols_section_name = strdup_safe(info->name);
XkbEscapeMapName(keymap->symbols_section_name);
keymap->num_group_names = darray_size(info->group_names);
keymap->group_names = darray_mem(info->group_names, 0);
darray_init(info->group_names);
keymap->mods = info->mods;
darray_steal(info->group_names,
&keymap->group_names, &keymap->num_group_names);
darray_foreach(keyi, info->keys)
if (!CopySymbolsDef(info, keyi))
if (!CopySymbolsDefToKeymap(keymap, info, keyi))
info->errorCount++;
if (xkb_context_get_log_verbosity(keymap->ctx) > 3) {
struct xkb_key *key;
xkb_foreach_key(key, keymap) {
xkb_keys_foreach(key, keymap) {
if (key->name == XKB_ATOM_NONE)
continue;
if (key->num_groups < 1)
log_info(keymap->ctx,
log_info(info->ctx,
"No symbols defined for %s\n",
KeyNameText(keymap->ctx, key->name));
KeyNameText(info->ctx, key->name));
}
}
darray_foreach(mm, info->modmaps)
if (!CopyModMapDef(info, mm))
if (!CopyModMapDefToKeymap(keymap, info, mm))
info->errorCount++;
/* XXX: If we don't ignore errorCount, things break. */
@ -1571,7 +1573,7 @@ CompileSymbols(XkbFile *file, struct xkb_keymap *keymap,
if (!actions)
return false;
InitSymbolsInfo(&info, keymap, actions);
InitSymbolsInfo(&info, keymap, actions, &keymap->mods);
info.default_key.merge = merge;
HandleSymbolsFile(&info, file, merge);

View File

@ -31,9 +31,9 @@
#include "include.h"
enum type_field {
TYPE_FIELD_MASK = (1 << 0),
TYPE_FIELD_MAP = (1 << 1),
TYPE_FIELD_PRESERVE = (1 << 2),
TYPE_FIELD_MASK = (1 << 0),
TYPE_FIELD_MAP = (1 << 1),
TYPE_FIELD_PRESERVE = (1 << 2),
TYPE_FIELD_LEVEL_NAME = (1 << 3),
};
@ -53,7 +53,9 @@ typedef struct {
int errorCount;
darray(KeyTypeInfo) types;
struct xkb_keymap *keymap;
struct xkb_mod_set mods;
struct xkb_context *ctx;
} KeyTypesInfo;
/***====================================================================***/
@ -61,26 +63,26 @@ typedef struct {
static inline const char *
MapEntryTxt(KeyTypesInfo *info, struct xkb_key_type_entry *entry)
{
return ModMaskText(info->keymap, entry->mods.mods);
return ModMaskText(info->ctx, &info->mods, entry->mods.mods);
}
static inline const char *
TypeTxt(KeyTypesInfo *info, KeyTypeInfo *type)
{
return xkb_atom_text(info->keymap->ctx, type->name);
return xkb_atom_text(info->ctx, type->name);
}
static inline const char *
TypeMaskTxt(KeyTypesInfo *info, KeyTypeInfo *type)
{
return ModMaskText(info->keymap, type->mods);
return ModMaskText(info->ctx, &info->mods, type->mods);
}
static inline bool
ReportTypeShouldBeArray(KeyTypesInfo *info, KeyTypeInfo *type,
const char *field)
{
return ReportShouldBeArray(info->keymap->ctx, "key type", field,
return ReportShouldBeArray(info->ctx, "key type", field,
TypeTxt(info, type));
}
@ -88,17 +90,19 @@ static inline bool
ReportTypeBadType(KeyTypesInfo *info, KeyTypeInfo *type,
const char *field, const char *wanted)
{
return ReportBadType(info->keymap->ctx, "key type", field,
return ReportBadType(info->ctx, "key type", field,
TypeTxt(info, type), wanted);
}
/***====================================================================***/
static void
InitKeyTypesInfo(KeyTypesInfo *info, struct xkb_keymap *keymap)
InitKeyTypesInfo(KeyTypesInfo *info, struct xkb_context *ctx,
const struct xkb_mod_set *mods)
{
memset(info, 0, sizeof(*info));
info->keymap = keymap;
info->ctx = ctx;
info->mods = *mods;
}
static void
@ -131,16 +135,16 @@ static bool
AddKeyType(KeyTypesInfo *info, KeyTypeInfo *new, bool same_file)
{
KeyTypeInfo *old;
const int verbosity = xkb_context_get_log_verbosity(info->keymap->ctx);
const int verbosity = xkb_context_get_log_verbosity(info->ctx);
old = FindMatchingKeyType(info, new->name);
if (old) {
if (new->merge == MERGE_REPLACE || new->merge == MERGE_OVERRIDE) {
if ((same_file && verbosity > 0) || verbosity > 9) {
log_warn(info->keymap->ctx,
log_warn(info->ctx,
"Multiple definitions of the %s key type; "
"Earlier definition ignored\n",
xkb_atom_text(info->keymap->ctx, new->name));
xkb_atom_text(info->ctx, new->name));
}
ClearKeyTypeInfo(old);
@ -151,10 +155,10 @@ AddKeyType(KeyTypesInfo *info, KeyTypeInfo *new, bool same_file)
}
if (same_file)
log_vrb(info->keymap->ctx, 4,
log_vrb(info->ctx, 4,
"Multiple definitions of the %s key type; "
"Later definition ignored\n",
xkb_atom_text(info->keymap->ctx, new->name));
xkb_atom_text(info->ctx, new->name));
ClearKeyTypeInfo(new);
return true;
@ -170,13 +174,13 @@ static void
MergeIncludedKeyTypes(KeyTypesInfo *into, KeyTypesInfo *from,
enum merge_mode merge)
{
KeyTypeInfo *type;
if (from->errorCount > 0) {
into->errorCount += from->errorCount;
return;
}
into->mods = from->mods;
if (into->name == NULL) {
into->name = from->name;
from->name = NULL;
@ -187,6 +191,7 @@ MergeIncludedKeyTypes(KeyTypesInfo *into, KeyTypesInfo *from,
darray_init(from->types);
}
else {
KeyTypeInfo *type;
darray_foreach(type, from->types) {
type->merge = (merge == MERGE_DEFAULT ? type->merge : merge);
if (!AddKeyType(into, type, false))
@ -203,7 +208,7 @@ HandleIncludeKeyTypes(KeyTypesInfo *info, IncludeStmt *include)
{
KeyTypesInfo included;
InitKeyTypesInfo(&included, info->keymap);
InitKeyTypesInfo(&included, info->ctx, &info->mods);
included.name = include->stmt;
include->stmt = NULL;
@ -211,14 +216,14 @@ HandleIncludeKeyTypes(KeyTypesInfo *info, IncludeStmt *include)
KeyTypesInfo next_incl;
XkbFile *file;
file = ProcessIncludeFile(info->keymap->ctx, stmt, FILE_TYPE_TYPES);
file = ProcessIncludeFile(info->ctx, stmt, FILE_TYPE_TYPES);
if (!file) {
info->errorCount += 10;
ClearKeyTypesInfo(&included);
return false;
}
InitKeyTypesInfo(&next_incl, info->keymap);
InitKeyTypesInfo(&next_incl, info->ctx, &included.mods);
HandleKeyTypesFile(&next_incl, file, stmt->merge);
@ -243,24 +248,24 @@ SetModifiers(KeyTypesInfo *info, KeyTypeInfo *type, ExprDef *arrayNdx,
xkb_mod_mask_t mods;
if (arrayNdx)
log_warn(info->keymap->ctx,
log_warn(info->ctx,
"The modifiers field of a key type is not an array; "
"Illegal array subscript ignored\n");
if (!ExprResolveModMask(info->keymap, value, MOD_BOTH, &mods)) {
log_err(info->keymap->ctx,
if (!ExprResolveModMask(info->ctx, value, MOD_BOTH, &info->mods, &mods)) {
log_err(info->ctx,
"Key type mask field must be a modifier mask; "
"Key type definition ignored\n");
return false;
}
if (type->defined & TYPE_FIELD_MASK) {
log_warn(info->keymap->ctx,
log_warn(info->ctx,
"Multiple modifier mask definitions for key type %s; "
"Using %s, ignoring %s\n",
xkb_atom_text(info->keymap->ctx, type->name),
xkb_atom_text(info->ctx, type->name),
TypeMaskTxt(info, type),
ModMaskText(info->keymap, mods));
ModMaskText(info->ctx, &info->mods, mods));
return false;
}
@ -291,7 +296,7 @@ AddMapEntry(KeyTypesInfo *info, KeyTypeInfo *type,
old = FindMatchingMapEntry(type, new->mods.mods);
if (old) {
if (report && old->level != new->level) {
log_warn(info->keymap->ctx,
log_warn(info->ctx,
"Multiple map entries for %s in %s; "
"Using %d, ignoring %d\n",
MapEntryTxt(info, new), TypeTxt(info, type),
@ -299,7 +304,7 @@ AddMapEntry(KeyTypesInfo *info, KeyTypeInfo *type,
(clobber ? old->level : new->level) + 1);
}
else {
log_vrb(info->keymap->ctx, 10,
log_vrb(info->ctx, 10,
"Multiple occurrences of map[%s]= %d in %s; Ignored\n",
MapEntryTxt(info, new), new->level + 1,
TypeTxt(info, type));
@ -331,21 +336,23 @@ SetMapEntry(KeyTypesInfo *info, KeyTypeInfo *type, ExprDef *arrayNdx,
if (arrayNdx == NULL)
return ReportTypeShouldBeArray(info, type, "map entry");
if (!ExprResolveModMask(info->keymap, arrayNdx, MOD_BOTH, &entry.mods.mods))
if (!ExprResolveModMask(info->ctx, arrayNdx, MOD_BOTH, &info->mods,
&entry.mods.mods))
return ReportTypeBadType(info, type, "map entry", "modifier mask");
if (entry.mods.mods & (~type->mods)) {
log_vrb(info->keymap->ctx, 1,
log_vrb(info->ctx, 1,
"Map entry for unused modifiers in %s; "
"Using %s instead of %s\n",
TypeTxt(info, type),
ModMaskText(info->keymap, entry.mods.mods & type->mods),
ModMaskText(info->ctx, &info->mods,
entry.mods.mods & type->mods),
MapEntryTxt(info, &entry));
entry.mods.mods &= type->mods;
}
if (!ExprResolveLevel(info->keymap->ctx, value, &entry.level)) {
log_err(info->keymap->ctx,
if (!ExprResolveLevel(info->ctx, value, &entry.level)) {
log_err(info->ctx,
"Level specifications in a key type must be integer; "
"Ignoring malformed level specification\n");
return false;
@ -377,22 +384,22 @@ AddPreserve(KeyTypesInfo *info, KeyTypeInfo *type,
/* Map exists with same preserve; do nothing. */
if (entry->preserve.mods == preserve_mods) {
log_vrb(info->keymap->ctx, 10,
log_vrb(info->ctx, 10,
"Identical definitions for preserve[%s] in %s; "
"Ignored\n",
ModMaskText(info->keymap, mods),
ModMaskText(info->ctx, &info->mods, mods),
TypeTxt(info, type));
return true;
}
/* Map exists with different preserve; latter wins. */
log_vrb(info->keymap->ctx, 1,
log_vrb(info->ctx, 1,
"Multiple definitions for preserve[%s] in %s; "
"Using %s, ignoring %s\n",
ModMaskText(info->keymap, mods),
ModMaskText(info->ctx, &info->mods, mods),
TypeTxt(info, type),
ModMaskText(info->keymap, preserve_mods),
ModMaskText(info->keymap, entry->preserve.mods));
ModMaskText(info->ctx, &info->mods, preserve_mods),
ModMaskText(info->ctx, &info->mods, entry->preserve.mods));
entry->preserve.mods = preserve_mods;
return true;
@ -419,28 +426,29 @@ SetPreserve(KeyTypesInfo *info, KeyTypeInfo *type, ExprDef *arrayNdx,
if (arrayNdx == NULL)
return ReportTypeShouldBeArray(info, type, "preserve entry");
if (!ExprResolveModMask(info->keymap, arrayNdx, MOD_BOTH, &mods))
if (!ExprResolveModMask(info->ctx, arrayNdx, MOD_BOTH, &info->mods, &mods))
return ReportTypeBadType(info, type, "preserve entry",
"modifier mask");
if (mods & ~type->mods) {
const char *before, *after;
before = ModMaskText(info->keymap, mods);
before = ModMaskText(info->ctx, &info->mods, mods);
mods &= type->mods;
after = ModMaskText(info->keymap, mods);
after = ModMaskText(info->ctx, &info->mods, mods);
log_vrb(info->keymap->ctx, 1,
log_vrb(info->ctx, 1,
"Preserve for modifiers not used by the %s type; "
"Index %s converted to %s\n",
TypeTxt(info, type), before, after);
}
if (!ExprResolveModMask(info->keymap, value, MOD_BOTH, &preserve_mods)) {
log_err(info->keymap->ctx,
if (!ExprResolveModMask(info->ctx, value, MOD_BOTH, &info->mods,
&preserve_mods)) {
log_err(info->ctx,
"Preserve value in a key type is not a modifier mask; "
"Ignoring preserve[%s] in type %s\n",
ModMaskText(info->keymap, mods),
ModMaskText(info->ctx, &info->mods, mods),
TypeTxt(info, type));
return false;
}
@ -448,14 +456,14 @@ SetPreserve(KeyTypesInfo *info, KeyTypeInfo *type, ExprDef *arrayNdx,
if (preserve_mods & ~mods) {
const char *before, *after;
before = ModMaskText(info->keymap, preserve_mods);
before = ModMaskText(info->ctx, &info->mods, preserve_mods);
preserve_mods &= mods;
after = ModMaskText(info->keymap, preserve_mods);
after = ModMaskText(info->ctx, &info->mods, preserve_mods);
log_vrb(info->keymap->ctx, 1,
log_vrb(info->ctx, 1,
"Illegal value for preserve[%s] in type %s; "
"Converted %s to %s\n",
ModMaskText(info->keymap, mods),
ModMaskText(info->ctx, &info->mods, mods),
TypeTxt(info, type), before, after);
}
@ -476,7 +484,7 @@ AddLevelName(KeyTypesInfo *info, KeyTypeInfo *type,
/* Same level, same name. */
if (darray_item(type->level_names, level) == name) {
log_vrb(info->keymap->ctx, 10,
log_vrb(info->ctx, 10,
"Duplicate names for level %d of key type %s; Ignored\n",
level + 1, TypeTxt(info, type));
return true;
@ -485,10 +493,10 @@ AddLevelName(KeyTypesInfo *info, KeyTypeInfo *type,
/* Same level, different name. */
if (darray_item(type->level_names, level) != XKB_ATOM_NONE) {
const char *old, *new;
old = xkb_atom_text(info->keymap->ctx,
old = xkb_atom_text(info->ctx,
darray_item(type->level_names, level));
new = xkb_atom_text(info->keymap->ctx, name);
log_vrb(info->keymap->ctx, 1,
new = xkb_atom_text(info->ctx, name);
log_vrb(info->ctx, 1,
"Multiple names for level %d of key type %s; "
"Using %s, ignoring %s\n",
level + 1, TypeTxt(info, type),
@ -511,19 +519,18 @@ SetLevelName(KeyTypesInfo *info, KeyTypeInfo *type, ExprDef *arrayNdx,
{
xkb_level_index_t level;
xkb_atom_t level_name;
struct xkb_context *ctx = info->keymap->ctx;
if (arrayNdx == NULL)
return ReportTypeShouldBeArray(info, type, "level name");
if (!ExprResolveLevel(ctx, arrayNdx, &level))
if (!ExprResolveLevel(info->ctx, arrayNdx, &level))
return ReportTypeBadType(info, type, "level name", "integer");
if (!ExprResolveString(ctx, value, &level_name)) {
log_err(info->keymap->ctx,
if (!ExprResolveString(info->ctx, value, &level_name)) {
log_err(info->ctx,
"Non-string name for level %d in key type %s; "
"Ignoring illegal level name definition\n",
level + 1, xkb_atom_text(ctx, type->name));
level + 1, xkb_atom_text(info->ctx, type->name));
return false;
}
@ -555,7 +562,7 @@ SetKeyTypeField(KeyTypesInfo *info, KeyTypeInfo *type,
type_field = TYPE_FIELD_LEVEL_NAME;
ok = SetLevelName(info, type, arrayNdx, value);
} else {
log_err(info->keymap->ctx,
log_err(info->ctx,
"Unknown field %s in key type %s; Definition ignored\n",
field, TypeTxt(info, type));
}
@ -572,13 +579,13 @@ HandleKeyTypeBody(KeyTypesInfo *info, VarDef *def, KeyTypeInfo *type)
ExprDef *arrayNdx;
for (; def; def = (VarDef *) def->common.next) {
ok = ExprResolveLhs(info->keymap->ctx, def->name, &elem, &field,
ok = ExprResolveLhs(info->ctx, def->name, &elem, &field,
&arrayNdx);
if (!ok)
continue;
if (elem && istreq(elem, "type")) {
log_err(info->keymap->ctx,
log_err(info->ctx,
"Support for changing the default type has been removed; "
"Statement ignored\n");
continue;
@ -633,16 +640,16 @@ HandleKeyTypesFile(KeyTypesInfo *info, XkbFile *file, enum merge_mode merge)
ok = HandleKeyTypeDef(info, (KeyTypeDef *) stmt, merge);
break;
case STMT_VAR:
log_err(info->keymap->ctx,
log_err(info->ctx,
"Support for changing the default type has been removed; "
"Statement ignored\n");
ok = true;
break;
case STMT_VMOD:
ok = HandleVModDef(info->keymap, (VModDef *) stmt, merge);
ok = HandleVModDef(info->ctx, &info->mods, (VModDef *) stmt, merge);
break;
default:
log_err(info->keymap->ctx,
log_err(info->ctx,
"Key type files may not include other declarations; "
"Ignoring %s\n", stmt_type_to_string(stmt->type));
ok = false;
@ -653,8 +660,8 @@ HandleKeyTypesFile(KeyTypesInfo *info, XkbFile *file, enum merge_mode merge)
info->errorCount++;
if (info->errorCount > 10) {
log_err(info->keymap->ctx,
"Abandoning keytypes file \"%s\"\n", file->topName);
log_err(info->ctx,
"Abandoning keytypes file \"%s\"\n", file->name);
break;
}
}
@ -665,21 +672,20 @@ HandleKeyTypesFile(KeyTypesInfo *info, XkbFile *file, enum merge_mode merge)
static bool
CopyKeyTypesToKeymap(struct xkb_keymap *keymap, KeyTypesInfo *info)
{
keymap->types_section_name = strdup_safe(info->name);
XkbEscapeMapName(keymap->types_section_name);
unsigned num_types;
struct xkb_key_type *types;
keymap->num_types = darray_size(info->types);
if (keymap->num_types == 0)
keymap->num_types = 1;
keymap->types = calloc(keymap->num_types, sizeof(*keymap->types));
num_types = darray_empty(info->types) ? 1 : darray_size(info->types);
types = calloc(num_types, sizeof(*types));
if (!types)
return false;
/*
* If no types were specified, a default unnamed one-level type is
* used for all keys.
*/
if (darray_empty(info->types)) {
struct xkb_key_type *type = &keymap->types[0];
struct xkb_key_type *type = &types[0];
type->mods.mods = 0;
type->num_levels = 1;
@ -687,24 +693,26 @@ CopyKeyTypesToKeymap(struct xkb_keymap *keymap, KeyTypesInfo *info)
type->num_entries = 0;
type->name = xkb_atom_intern_literal(keymap->ctx, "default");
type->level_names = NULL;
type->num_level_names = 0;
}
else {
for (unsigned i = 0; i < num_types; i++) {
KeyTypeInfo *def = &darray_item(info->types, i);
struct xkb_key_type *type = &types[i];
return true;
}
for (unsigned i = 0; i < keymap->num_types; i++) {
KeyTypeInfo *def = &darray_item(info->types, i);
struct xkb_key_type *type = &keymap->types[i];
type->mods.mods = def->mods;
type->num_levels = def->num_levels;
type->entries = darray_mem(def->entries, 0);
type->num_entries = darray_size(def->entries);
darray_init(def->entries);
type->name = def->name;
type->level_names = darray_mem(def->level_names, 0);
darray_init(def->level_names);
type->name = def->name;
type->mods.mods = def->mods;
type->num_levels = def->num_levels;
darray_steal(def->level_names, &type->level_names, &type->num_level_names);
darray_steal(def->entries, &type->entries, &type->num_entries);
}
}
keymap->types_section_name = strdup_safe(info->name);
XkbEscapeMapName(keymap->types_section_name);
keymap->num_types = num_types;
keymap->types = types;
keymap->mods = info->mods;
return true;
}
@ -716,7 +724,7 @@ CompileKeyTypes(XkbFile *file, struct xkb_keymap *keymap,
{
KeyTypesInfo info;
InitKeyTypesInfo(&info, keymap);
InitKeyTypesInfo(&info, keymap->ctx, &keymap->mods);
HandleKeyTypesFile(&info, file, merge);
if (info.errorCount != 0)

View File

@ -30,13 +30,12 @@
#include "vmod.h"
bool
HandleVModDef(struct xkb_keymap *keymap, VModDef *stmt,
enum merge_mode merge)
HandleVModDef(struct xkb_context *ctx, struct xkb_mod_set *mods,
VModDef *stmt, enum merge_mode merge)
{
xkb_mod_index_t i;
struct xkb_mod *mod;
xkb_mod_mask_t mapping;
struct xkb_mod new;
merge = (merge == MERGE_DEFAULT ? stmt->merge : merge);
@ -46,10 +45,10 @@ HandleVModDef(struct xkb_keymap *keymap, VModDef *stmt,
* it sets the vmod-to-real-mod[s] mapping directly instead of going
* through modifier_map or some such.
*/
if (!ExprResolveModMask(keymap, stmt->value, MOD_REAL, &mapping)) {
log_err(keymap->ctx,
if (!ExprResolveModMask(ctx, stmt->value, MOD_REAL, mods, &mapping)) {
log_err(ctx,
"Declaration of %s ignored\n",
xkb_atom_text(keymap->ctx, stmt->name));
xkb_atom_text(ctx, stmt->name));
return false;
}
}
@ -57,13 +56,13 @@ HandleVModDef(struct xkb_keymap *keymap, VModDef *stmt,
mapping = 0;
}
darray_enumerate(i, mod, keymap->mods) {
xkb_mods_enumerate(i, mod, mods) {
if (mod->name == stmt->name) {
if (mod->type != MOD_VIRT) {
log_err(keymap->ctx,
log_err(ctx,
"Can't add a virtual modifier named \"%s\"; "
"there is already a non-virtual modifier with this name! Ignored\n",
xkb_atom_text(keymap->ctx, mod->name));
xkb_atom_text(ctx, mod->name));
return false;
}
@ -76,12 +75,12 @@ HandleVModDef(struct xkb_keymap *keymap, VModDef *stmt,
use = (merge == MERGE_OVERRIDE ? mapping : mod->mapping);
ignore = (merge == MERGE_OVERRIDE ? mod->mapping : mapping);
log_warn(keymap->ctx,
log_warn(ctx,
"Virtual modifier %s defined multiple times; "
"Using %s, ignoring %s\n",
xkb_atom_text(keymap->ctx, stmt->name),
ModMaskText(keymap, use),
ModMaskText(keymap, ignore));
xkb_atom_text(ctx, stmt->name),
ModMaskText(ctx, mods, use),
ModMaskText(ctx, mods, ignore));
mapping = use;
}
@ -91,16 +90,16 @@ HandleVModDef(struct xkb_keymap *keymap, VModDef *stmt,
}
}
if (darray_size(keymap->mods) >= XKB_MAX_MODS) {
log_err(keymap->ctx,
if (mods->num_mods >= XKB_MAX_MODS) {
log_err(ctx,
"Too many modifiers defined (maximum %d)\n",
XKB_MAX_MODS);
return false;
}
new.name = stmt->name;
new.mapping = mapping;
new.type = MOD_VIRT;
darray_append(keymap->mods, new);
mods->mods[mods->num_mods].name = stmt->name;
mods->mods[mods->num_mods].type = MOD_VIRT;
mods->mods[mods->num_mods].mapping = mapping;
mods->num_mods++;
return true;
}

View File

@ -28,7 +28,7 @@
#define XKBCOMP_VMOD_H
bool
HandleVModDef(struct xkb_keymap *keymap, VModDef *stmt,
enum merge_mode merge);
HandleVModDef(struct xkb_context *ctx, struct xkb_mod_set *mods,
VModDef *stmt, enum merge_mode merge);
#endif

View File

@ -32,15 +32,7 @@
static void
ComputeEffectiveMask(struct xkb_keymap *keymap, struct xkb_mods *mods)
{
const struct xkb_mod *mod;
xkb_mod_index_t i;
/* The effective mask is only real mods for now. */
mods->mask = mods->mods & MOD_REAL_MASK_ALL;
darray_enumerate(i, mod, keymap->mods)
if (mods->mods & (1u << i))
mods->mask |= mod->mapping;
mods->mask = mod_mask_get_effective(keymap, mods->mods);
}
static void
@ -115,7 +107,7 @@ FindInterpForKey(struct xkb_keymap *keymap, const struct xkb_key *key,
found = (!mods || (interp->mods & mods));
break;
case MATCH_ANY:
found = !!(interp->mods & mods);
found = (interp->mods & mods);
break;
case MATCH_ALL:
found = ((interp->mods & mods) == interp->mods);
@ -144,7 +136,7 @@ ApplyInterpsToKey(struct xkb_keymap *keymap, struct xkb_key *key)
return true;
for (group = 0; group < key->num_groups; group++) {
for (level = 0; level < XkbKeyGroupWidth(key, group); level++) {
for (level = 0; level < XkbKeyNumLevels(key, group); level++) {
const struct xkb_sym_interpret *interp;
interp = FindInterpForKey(keymap, key, group, level);
@ -180,20 +172,20 @@ ApplyInterpsToKey(struct xkb_keymap *keymap, struct xkb_key *key)
static bool
UpdateDerivedKeymapFields(struct xkb_keymap *keymap)
{
struct xkb_key *key;
struct xkb_mod *mod;
struct xkb_led *led;
unsigned int i, j;
struct xkb_key *key;
/* Find all the interprets for the key and bind them to actions,
* which will also update the vmodmap. */
xkb_foreach_key(key, keymap)
xkb_keys_foreach(key, keymap)
if (!ApplyInterpsToKey(keymap, key))
return false;
/* Update keymap->mods, the virtual -> real mod mapping. */
xkb_foreach_key(key, keymap)
darray_enumerate(i, mod, keymap->mods)
xkb_keys_foreach(key, keymap)
xkb_mods_enumerate(i, mod, &keymap->mods)
if (key->vmodmap & (1u << i))
mod->mapping |= key->modmap;
@ -208,18 +200,18 @@ UpdateDerivedKeymapFields(struct xkb_keymap *keymap)
}
/* Update action modifiers. */
xkb_foreach_key(key, keymap)
xkb_keys_foreach(key, keymap)
for (i = 0; i < key->num_groups; i++)
for (j = 0; j < XkbKeyGroupWidth(key, i); j++)
for (j = 0; j < XkbKeyNumLevels(key, i); j++)
UpdateActionMods(keymap, &key->groups[i].levels[j].action,
key->modmap);
/* Update vmod -> led maps. */
darray_foreach(led, keymap->leds)
xkb_leds_foreach(led, keymap)
ComputeEffectiveMask(keymap, &led->mods);
/* Find maximum number of groups out of all keys in the keymap. */
xkb_foreach_key(key, keymap)
xkb_keys_foreach(key, keymap)
keymap->num_groups = MAX(keymap->num_groups, key->num_groups);
return true;
@ -240,20 +232,22 @@ bool
CompileKeymap(XkbFile *file, struct xkb_keymap *keymap, enum merge_mode merge)
{
bool ok;
const char *main_name;
XkbFile *files[LAST_KEYMAP_FILE_TYPE + 1] = { NULL };
enum xkb_file_type type;
struct xkb_context *ctx = keymap->ctx;
main_name = file->name ? file->name : "(unnamed)";
/* Collect section files and check for duplicates. */
for (file = (XkbFile *) file->defs; file;
file = (XkbFile *) file->common.next) {
if (file->file_type < FIRST_KEYMAP_FILE_TYPE ||
file->file_type > LAST_KEYMAP_FILE_TYPE) {
log_err(ctx, "Cannot define %s in a keymap file\n",
xkb_file_type_to_string(file->file_type));
if (file->file_type == FILE_TYPE_GEOMETRY) {
log_vrb(ctx, 1,
"Geometry sections are not supported; ignoring\n");
} else {
log_err(ctx, "Cannot define %s in a keymap file\n",
xkb_file_type_to_string(file->file_type));
}
continue;
}
@ -265,11 +259,6 @@ CompileKeymap(XkbFile *file, struct xkb_keymap *keymap, enum merge_mode merge)
continue;
}
if (!file->topName) {
free(file->topName);
file->topName = strdup(main_name);
}
files[file->file_type] = file;
}
@ -295,7 +284,7 @@ CompileKeymap(XkbFile *file, struct xkb_keymap *keymap, enum merge_mode merge)
type <= LAST_KEYMAP_FILE_TYPE;
type++) {
log_dbg(ctx, "Compiling %s \"%s\"\n",
xkb_file_type_to_string(type), files[type]->topName);
xkb_file_type_to_string(type), files[type]->name);
ok = compile_file_fns[type](files[type], keymap, merge);
if (!ok) {

View File

@ -0,0 +1,493 @@
/*
* Copyright © 2013 Ran Benita
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef _XKBCOMMON_COMPOSE_H
#define _XKBCOMMON_COMPOSE_H
#include <xkbcommon/xkbcommon.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file
* libxkbcommon Compose API - support for Compose and dead-keys.
*/
/**
* @defgroup compose Compose and dead-keys support
* Support for Compose and dead-keys.
* @since 0.5.0
*
* @{
*/
/**
* @page compose-overview Overview
* @parblock
*
* Compose and dead-keys are a common feature of many keyboard input
* systems. They extend the range of the keysysm that can be produced
* directly from a keyboard by using a sequence of key strokes, instead
* of just one.
*
* Here are some example sequences, in the libX11 Compose file format:
*
* <dead_acute> <a> : "á" aacute # LATIN SMALL LETTER A WITH ACUTE
* <Multi_key> <A> <T> : "@" at # COMMERCIAL AT
*
* When the user presses a key which produces the `<dead_acute>` keysym,
* nothing initially happens (thus the key is dubbed a "dead-key"). But
* when the user enters `<a>`, "á" is "composed", in place of "a". If
* instead the user had entered a keysym which does not follow
* `<dead_acute>` in any compose sequence, the sequence is said to be
* "cancelled".
*
* Compose files define many such sequences. For a description of the
* common file format for Compose files, see the Compose(5) man page.
*
* A successfuly-composed sequence has two results: a keysym and a UTF-8
* string. At least one of the two is defined for each sequence. If only
* a keysym is given, the keysym's string representation is used for the
* result string (using xkb_keysym_to_utf8()).
*
* This library provides low-level support for Compose file parsing and
* processing. Higher-level APIs (such as libX11's `Xutf8LookupString`(3))
* may be built upon it, or it can be used directly.
*
* @endparblock
*/
/**
* @page compose-conflicting Conflicting Sequences
* @parblock
*
* To avoid ambiguity, a sequence is not allowed to be a prefix of another.
* In such a case, the conflict is resolved thus:
*
* 1. A longer sequence overrides a shorter one.
* 2. An equal sequence overrides an existing one.
* 3. A shorter sequence does not override a longer one.
*
* Sequences of length 1 are allowed.
*
* @endparblock
*/
/**
* @page compose-cancellation Cancellation Behavior
* @parblock
*
* What should happen when a sequence is cancelled? For example, consider
* there are only the above sequences, and the input keysyms are
* `<dead_acute> <b>`. There are a few approaches:
*
* 1. Swallow the cancelling keysym; that is, no keysym is produced.
* This is the approach taken by libX11.
* 2. Let the cancelling keysym through; that is, `<b>` is produced.
* 3. Replay the entire sequence; that is, `<dead_acute> <b>` is produced.
* This is the approach taken by Microsoft Windows (approximately;
* instead of `<dead_acute>`, the underlying key is used. This is
* difficult to simulate with XKB keymaps).
*
* You can program whichever approach best fits users' expectations.
*
* @endparblock
*/
/**
* @struct xkb_compose_table
* Opaque Compose table object.
*
* The compose table holds the definitions of the Compose sequences, as
* gathered from Compose files. It is immutable.
*/
struct xkb_compose_table;
/**
* @struct xkb_compose_state
* Opaque Compose state object.
*
* The compose state maintains state for compose sequence matching, such
* as which possible sequences are being matched, and the position within
* these sequences. It acts as a simple state machine wherein keysyms are
* the input, and composed keysyms and strings are the output.
*
* The compose state is usually associated with a keyboard device.
*/
struct xkb_compose_state;
/** Flags affecting Compose file compilation. */
enum xkb_compose_compile_flags {
/** Do not apply any flags. */
XKB_COMPOSE_COMPILE_NO_FLAGS = 0
};
/** The recognized Compose file formats. */
enum xkb_compose_format {
/** The classic libX11 Compose text format, described in Compose(5). */
XKB_COMPOSE_FORMAT_TEXT_V1 = 1
};
/**
* @page compose-locale Compose Locale
* @parblock
*
* Compose files are locale dependent:
* - Compose files are written for a locale, and the locale is used when
* searching for the appropriate file to use.
* - Compose files may reference the locale internally, with directives
* such as \%L.
*
* As such, functions like xkb_compose_table_new_from_locale() require
* a `locale` parameter. This will usually be the current locale (see
* locale(7) for more details). You may also want to allow the user to
* explicitly configure it, so he can use the Compose file of a given
* locale, but not use that locale for other things.
*
* You may query the current locale as follows:
* @code
* const char *locale;
* locale = setlocale(LC_CTYPE, NULL);
* @endcode
*
* This will only give useful results if the program had previously set
* the current locale using setlocale(3), with `LC_CTYPE` or `LC_ALL`
* and a non-NULL argument.
*
* If you prefer not to use the locale system of the C runtime library,
* you may nevertheless obtain the user's locale directly using
* environment variables, as described in locale(7). For example,
* @code
* const char *locale;
* locale = getenv("LC_ALL");
* if (!locale || !*locale)
* locale = getenv("LC_CTYPE");
* if (!locale || !*locale)
* locale = getenv("LANG");
* if (!locale || !*locale)
* locale = "C";
* @endcode
*
* Note that some locales supported by the C standard library may not
* have a Compose file assigned.
*
* @endparblock
*/
/**
* Create a compose table for a given locale.
*
* The locale is used for searching the file-system for an appropriate
* Compose file. The search order is described in Compose(5). It is
* affected by the following environment variables:
*
* 1. `XCOMPOSEFILE` - see Compose(5).
* 2. `HOME` - see Compose(5).
* 3. `XLOCALEDIR` - if set, used as the base directory for the system's
* X locale files, e.g. `/usr/share/X11/locale`, instead of the
* preconfigured directory.
*
* @param context
* The library context in which to create the compose table.
* @param locale
* The current locale. See @ref compose-locale.\n
*
* The value is copied, so it is safe to pass the result of getenv(3)
* (or similar) without fear of it being invalidated by a subsequent
* setenv(3) (or similar).
* @param flags
* Optional flags for the compose table, or 0.
*
* @returns A compose table for the given locale, or NULL if the
* compilation failed or a Compose file was not found.
*
* @memberof xkb_compose_table
*/
struct xkb_compose_table *
xkb_compose_table_new_from_locale(struct xkb_context *context,
const char *locale,
enum xkb_compose_compile_flags flags);
/**
* Create a new compose table from a Compose file.
*
* @param context
* The library context in which to create the compose table.
* @param file
* The Compose file to compile.
* @param locale
* The current locale. See @ref compose-locale.
* @param format
* The text format of the Compose file to compile.
* @param flags
* Optional flags for the compose table, or 0.
*
* @returns A compose table compiled from the given file, or NULL if
* the compilation failed.
*
* @memberof xkb_compose_table
*/
struct xkb_compose_table *
xkb_compose_table_new_from_file(struct xkb_context *context,
FILE *file,
const char *locale,
enum xkb_compose_format format,
enum xkb_compose_compile_flags flags);
/**
* Create a new compose table from a memory buffer.
*
* This is just like xkb_compose_table_new_from_file(), but instead of
* a file, gets the table as one enormous string.
*
* @see xkb_compose_table_new_from_file()
* @memberof xkb_compose_table
*/
struct xkb_compose_table *
xkb_compose_table_new_from_buffer(struct xkb_context *context,
const char *buffer, size_t length,
const char *locale,
enum xkb_compose_format format,
enum xkb_compose_compile_flags flags);
/**
* Take a new reference on a compose table.
*
* @returns The passed in object.
*
* @memberof xkb_compose_table
*/
struct xkb_compose_table *
xkb_compose_table_ref(struct xkb_compose_table *table);
/**
* Release a reference on a compose table, and possibly free it.
*
* @param table The object. If it is NULL, this function does nothing.
*
* @memberof xkb_compose_table
*/
void
xkb_compose_table_unref(struct xkb_compose_table *table);
/** Flags for compose state creation. */
enum xkb_compose_state_flags {
/** Do not apply any flags. */
XKB_COMPOSE_STATE_NO_FLAGS = 0
};
/**
* Create a new compose state object.
*
* @param table
* The compose table the state will use.
* @param flags
* Optional flags for the compose state, or 0.
*
* @returns A new compose state, or NULL on failure.
*
* @memberof xkb_compose_state
*/
struct xkb_compose_state *
xkb_compose_state_new(struct xkb_compose_table *table,
enum xkb_compose_state_flags flags);
/**
* Take a new reference on a compose state object.
*
* @returns The passed in object.
*
* @memberof xkb_compose_state
*/
struct xkb_compose_state *
xkb_compose_state_ref(struct xkb_compose_state *state);
/**
* Release a reference on a compose state object, and possibly free it.
*
* @param state The object. If NULL, do nothing.
*
* @memberof xkb_compose_state
*/
void
xkb_compose_state_unref(struct xkb_compose_state *state);
/**
* Get the compose table which a compose state object is using.
*
* @returns The compose table which was passed to xkb_compose_state_new()
* when creating this state object.
*
* This function does not take a new reference on the compose table; you
* must explicitly reference it yourself if you plan to use it beyond the
* lifetime of the state.
*
* @memberof xkb_compose_state
*/
struct xkb_compose_table *
xkb_compose_state_get_compose_table(struct xkb_compose_state *state);
/** Status of the Compose sequence state machine. */
enum xkb_compose_status {
/** The initial state; no sequence has started yet. */
XKB_COMPOSE_NOTHING,
/** In the middle of a sequence. */
XKB_COMPOSE_COMPOSING,
/** A complete sequence has been matched. */
XKB_COMPOSE_COMPOSED,
/** The last sequence was cancelled due to an unmatched keysym. */
XKB_COMPOSE_CANCELLED
};
/** The effect of a keysym fed to xkb_compose_state_feed(). */
enum xkb_compose_feed_result {
/** The keysym had no effect - it did not affect the status. */
XKB_COMPOSE_FEED_IGNORED,
/** The keysym started, advanced or cancelled a sequence. */
XKB_COMPOSE_FEED_ACCEPTED
};
/**
* Feed one keysym to the Compose sequence state machine.
*
* This function can advance into a compose sequence, cancel a sequence,
* start a new sequence, or do nothing in particular. The resulting
* status may be observed with xkb_compose_state_get_status().
*
* Some keysyms, such as keysyms for modifier keys, are ignored - they
* have no effect on the status or otherwise.
*
* The following is a description of the possible status transitions, in
* the format CURRENT STATUS => NEXT STATUS, given a non-ignored input
* keysym `keysym`:
*
@verbatim
NOTHING or CANCELLED or COMPOSED =>
NOTHING if keysym does not start a sequence.
COMPOSING if keysym starts a sequence.
COMPOSED if keysym starts and terminates a single-keysym sequence.
COMPOSING =>
COMPOSING if keysym advances any of the currently possible
sequences but does not terminate any of them.
COMPOSED if keysym terminates one of the currently possible
sequences.
CANCELLED if keysym does not advance any of the currently
possible sequences.
@endverbatim
*
* The current Compose formats do not support multiple-keysyms.
* Therefore, if you are using a function such as xkb_state_key_get_syms()
* and it returns more than one keysym, consider feeding XKB_KEY_NoSymbol
* instead.
*
* @param state
* The compose state object.
* @param keysym
* A keysym, usually obtained after a key-press event, with a
* function such as xkb_state_key_get_one_sym().
*
* @returns Whether the keysym was ignored. This is useful, for example,
* if you want to keep a record of the sequence matched thus far.
*
* @memberof xkb_compose_state
*/
enum xkb_compose_feed_result
xkb_compose_state_feed(struct xkb_compose_state *state,
xkb_keysym_t keysym);
/**
* Reset the Compose sequence state machine.
*
* The status is set to XKB_COMPOSE_NOTHING, and the current sequence
* is discarded.
*
* @memberof xkb_compose_state
*/
void
xkb_compose_state_reset(struct xkb_compose_state *state);
/**
* Get the current status of the compose state machine.
*
* @see xkb_compose_status
* @memberof xkb_compose_state
**/
enum xkb_compose_status
xkb_compose_state_get_status(struct xkb_compose_state *state);
/**
* Get the result Unicode/UTF-8 string for a composed sequence.
*
* See @ref compose-overview for more details. This function is only
* useful when the status is XKB_COMPOSE_COMPOSED.
*
* @param[in] state
* The compose state.
* @param[out] buffer
* A buffer to write the string into.
* @param[in] size
* Size of the buffer.
*
* @warning If the buffer passed is too small, the string is truncated
* (though still NUL-terminated).
*
* @returns
* The number of bytes required for the string, excluding the NUL byte.
* If the sequence is not complete, or does not have a viable result
* string, returns 0, and sets `buffer` to the empty string (if possible).
* @returns
* You may check if truncation has occurred by comparing the return value
* with the size of `buffer`, similarly to the `snprintf`(3) function.
* You may safely pass NULL and 0 to `buffer` and `size` to find the
* required size (without the NUL-byte).
*
* @memberof xkb_compose_state
**/
int
xkb_compose_state_get_utf8(struct xkb_compose_state *state,
char *buffer, size_t size);
/**
* Get the result keysym for a composed sequence.
*
* See @ref compose-overview for more details. This function is only
* useful when the status is XKB_COMPOSE_COMPOSED.
*
* @returns The result keysym. If the sequence is not complete, or does
* not specify a result keysym, returns XKB_KEY_NoSymbol.
*
* @memberof xkb_compose_state
**/
xkb_keysym_t
xkb_compose_state_get_one_sym(struct xkb_compose_state *state);
/** @} */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* _XKBCOMMON_COMPOSE_H */

View File

@ -1,7 +1,7 @@
#ifndef _XKBCOMMON_KEYSYMS_H
#define _XKBCOMMON_KEYSYMS_H
/* This file is autogenerated from Makefile.am; please do not commit directly. */
/* This file is autogenerated; please do not commit directly. */
#define XKB_KEY_NoSymbol 0x000000 /* Special KeySym */
@ -2451,29 +2451,6 @@ SOFTWARE.
*
* The XFree86 keysym range is 0x10080001 - 0x1008FFFF.
*
* When adding new entries, the xc/lib/XKeysymDB file should also be
* updated to make the new entries visible to Xlib.
*/
/*
* ModeLock
*
* This one is old, and not really used any more since XKB offers this
* functionality.
*/
#define XKB_KEY_XF86ModeLock 0x1008FF01 /* Mode Switch Lock */
/*
* Note, 0x1008FF07 - 0x1008FF0F are free and should be used for misc new
* keysyms that don't fit into any of the groups below.
*
* 0x1008FF64, 0x1008FF6F, 0x1008FF71, 0x1008FF83 are no longer used,
* and should be used first for new keysyms.
*
* Check in keysymdef.h for generic symbols before adding new XFree86-specific
* symbols here.
*
* X.Org will not be adding to the XF86 set of keysyms, though they have
* been adopted and are considered a "standard" part of X keysym definitions.
* XFree86 never properly commented these keysyms, so we have done our
@ -2484,6 +2461,14 @@ SOFTWARE.
* these archives, these are from memory and usage.
*/
/*
* ModeLock
*
* This one is old, and not really used any more since XKB offers this
* functionality.
*/
#define XKB_KEY_XF86ModeLock 0x1008FF01 /* Mode Switch Lock */
/* Backlight controls. */
#define XKB_KEY_XF86MonBrightnessUp 0x1008FF02 /* Monitor/panel brightness */
@ -2660,6 +2645,13 @@ SOFTWARE.
#define XKB_KEY_XF86AudioMicMute 0x1008FFB2 /* Mute the Mic from the system */
#define XKB_KEY_XF86Keyboard 0x1008FFB3 /* User defined keyboard related action */
#define XKB_KEY_XF86WWAN 0x1008FFB4 /* Toggle WWAN (LTE, UMTS, etc.) radio */
#define XKB_KEY_XF86RFKill 0x1008FFB5 /* Toggle radios on/off */
#define XKB_KEY_XF86AudioPreset 0x1008FFB6 /* Select equalizer preset, e.g. theatre-mode */
/* Keys for special action keys (hot keys) */
/* Virtual terminals on some operating systems */
#define XKB_KEY_XF86Switch_VT_1 0x1008FE01

View File

@ -39,10 +39,75 @@ extern "C" {
/**
* @defgroup x11 X11 support
* Additional X11 support for xkbcommon.
* @since 0.4.0
*
* @{
*/
/**
* @page x11-overview Overview
* @parblock
*
* The xkbcommon-x11 module provides a means for creating an xkb_keymap
* corresponding to the currently active keymap on the X server. To do
* so, it queries the XKB X11 extension using the xcb-xkb library. It
* can be used as a replacement for Xlib's keyboard handling.
*
* Following is an example workflow using xkbcommon-x11. A complete
* example may be found in the test/interactive-x11.c file in the
* xkbcommon source repository. On startup:
*
* 1. Connect to the X server using xcb_connect().
* 2. Setup the XKB X11 extension. You can do this either by using the
* xcb_xkb_use_extension() request directly, or by using the
* xkb_x11_setup_xkb_extension() helper function.
*
* The XKB extension supports using separate keymaps and states for
* different keyboard devices. The devices are identified by an integer
* device ID and are managed by another X11 extension, XInput. The
* original X11 protocol only had one keyboard device, called the "core
* keyboard", which is still supported as a "virtual device".
*
* 3. We will use the core keyboard as an example. To get its device ID,
* use either the xcb_xkb_get_device_info() request directly, or the
* xkb_x11_get_core_keyboard_device_id() helper function.
* 4. Create an initial xkb_keymap for this device, using the
* xkb_x11_keymap_new_from_device() function.
* 5. Create an initial xkb_state for this device, using the
* xkb_x11_state_new_from_device() function.
*
* @note At this point, you may consider setting various XKB controls and
* XKB per-client flags. For example, enabling detectable autorepeat: \n
* https://www.x.org/releases/current/doc/kbproto/xkbproto.html#Detectable_Autorepeat
*
* Next, you need to react to state changes (e.g. a modifier was pressed,
* the layout was changed) and to keymap changes (e.g. a tool like xkbcomp,
* setxkbmap or xmodmap was used):
*
* 6. Select to listen to at least the following XKB events:
* NewKeyboardNotify, MapNotify, StateNotify; using the
* xcb_xkb_select_events_aux() request.
* 7. When NewKeyboardNotify or MapNotify are received, recreate the
* xkb_keymap and xkb_state as described above.
* 8. When StateNotify is received, update the xkb_state accordingly
* using the xkb_state_update_mask() function.
*
* @note It is also possible to use the KeyPress/KeyRelease @p state
* field to find the effective modifier and layout state, instead of
* using XkbStateNotify: \n
* https://www.x.org/releases/current/doc/kbproto/xkbproto.html#Computing_A_State_Field_from_an_XKB_State
* \n However, XkbStateNotify is more accurate.
*
* @note There is no need to call xkb_state_update_key(); the state is
* already synchronized.
*
* Finally, when a key event is received, you can use ordinary xkbcommon
* functions, like xkb_state_key_get_one_sym() and xkb_state_key_get_utf8(),
* as you normally would.
*
* @endparblock
*/
/**
* The minimal compatible major version of the XKB X11 extension which
* this library can use.
@ -75,14 +140,18 @@ enum xkb_x11_setup_xkb_extension_flags {
*
* @param connection
* An XCB connection to the X server.
* @param major_xkb_version, minor_xkb_version
* @param major_xkb_version
* See @p minor_xkb_version.
* @param minor_xkb_version
* The XKB extension version to request. To operate correctly, you
* must have (major_xkb_version, minor_xkb_version) >=
* (XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION),
* though this is not enforced.
* @param flags
* Optional flags, or 0.
* @param[out] major_xkb_version_out, minor_xkb_version_out
* @param[out] major_xkb_version_out
* See @p minor_xkb_version_out.
* @param[out] minor_xkb_version_out
* Backfilled with the compatible XKB extension version numbers picked
* by the server. Can be NULL.
* @param[out] base_event_out
@ -127,8 +196,9 @@ xkb_x11_get_core_keyboard_device_id(xcb_connection_t *connection);
* @param connection
* An XCB connection to the X server.
* @param device_id
* An XInput 1 device ID (in the range 0-255) with input class KEY.
* Passing values outside of this range is an error.
* An XInput device ID (in the range 0-127) with input class KEY.
* Passing values outside of this range is an error (the XKB protocol
* predates the XInput2 protocol, which first allowed IDs > 127).
* @param flags
* Optional flags for the keymap, or 0.
*

View File

@ -152,6 +152,10 @@ struct xkb_state;
* underlying input system. For example, with an X11-compatible keymap
* and Linux evdev scan codes (see linux/input.h), a fixed offset is used:
*
* The keymap defines a canonical name for each key, plus possible aliases.
* Historically, the XKB protocol restricts these names to at most 4 (ASCII)
* characters, but this library does not share this limit.
*
* @code
* xkb_keycode_t keycode_A = KEY_A + 8;
* @endcode
@ -173,7 +177,7 @@ typedef uint32_t xkb_keycode_t;
* somewhat more general, in that they can also represent some "function",
* such as "Left" or "Right" for the arrow keys. For more information,
* see:
* http://www.x.org/releases/X11R7.7/doc/xproto/x11protocol.html#keysym_encoding
* https://www.x.org/releases/current/doc/xproto/x11protocol.html#keysym_encoding
*
* Specifically named keysyms can be found in the
* xkbcommon/xkbcommon-keysyms.h header file. Their name does not include
@ -369,6 +373,35 @@ struct xkb_rule_names {
* @{
*/
/**
* @page keysym-transformations Keysym Transformations
*
* Keysym translation is subject to several "keysym transformations",
* as described in the XKB specification. These are:
*
* - Capitalization transformation. If the Caps Lock modifier is
* active and was not consumed by the translation process, a single
* keysym is transformed to its upper-case form (if applicable).
* Similarly, the UTF-8/UTF-32 string produced is capitalized.
*
* This is described in:
* https://www.x.org/releases/current/doc/kbproto/xkbproto.html#Interpreting_the_Lock_Modifier
*
* - Control transformation. If the Control modifier is active and
* was not consumed by the translation process, the string produced
* is transformed to its matching ASCII control character (if
* applicable). Keysyms are not affected.
*
* This is described in:
* https://www.x.org/releases/current/doc/kbproto/xkbproto.html#Interpreting_the_Control_Modifier
*
* Each relevant function discusses which transformations it performs.
*
* These transformations are not applicable when a key produces multiple
* keysyms.
*/
/**
* Get the name of a keysym.
*
@ -416,6 +449,9 @@ enum xkb_keysym_flags {
* fails, only then to try with this flag, while possibly warning the user
* he had misspelled the name, and might get wrong results.
*
* Case folding is done according to the C locale; the current locale is not
* consulted.
*
* @returns The keysym. If the name is invalid, returns XKB_KEY_NoSymbol.
*
* @sa xkb_keysym_t
@ -434,8 +470,8 @@ xkb_keysym_from_name(const char *name, enum xkb_keysym_flags flags);
* terminating byte). If the keysym does not have a Unicode
* representation, returns 0. If the buffer is too small, returns -1.
*
* Prefer not to use this function on keysyms obtained from an
* xkb_state. In this case, use xkb_state_key_get_utf8() instead.
* This function does not perform any @ref keysym-transformations.
* Therefore, prefer to use xkb_state_key_get_utf8() if possible.
*
* @sa xkb_state_key_get_utf8()
*/
@ -449,14 +485,34 @@ xkb_keysym_to_utf8(xkb_keysym_t keysym, char *buffer, size_t size);
* compatible with UCS-4. If the keysym does not have a Unicode
* representation, returns 0.
*
* Prefer not to use this function on keysyms obtained from an
* xkb_state. In this case, use xkb_state_key_get_utf32() instead.
* This function does not perform any @ref keysym-transformations.
* Therefore, prefer to use xkb_state_key_get_utf32() if possible.
*
* @sa xkb_state_key_get_utf32()
*/
uint32_t
xkb_keysym_to_utf32(xkb_keysym_t keysym);
/**
* Convert a keysym to its uppercase form.
*
* If there is no such form, the keysym is returned unchanged.
*
* The conversion rules may be incomplete; prefer to work with the Unicode
* representation instead, when possible.
*/
xkb_keysym_t
xkb_keysym_to_upper(xkb_keysym_t ks);
/**
* Convert a keysym to its lowercase form.
*
* The conversion rules may be incomplete; prefer to work with the Unicode
* representation instead, when possible.
*/
xkb_keysym_t
xkb_keysym_to_lower(xkb_keysym_t ks);
/** @} */
/**
@ -469,14 +525,29 @@ xkb_keysym_to_utf32(xkb_keysym_t keysym);
* @{
*/
/**
* @page envvars Environment Variables
*
* The user may set some environment variables which affect the library:
*
* - `XKB_CONFIG_ROOT`, `HOME` - see @ref include-path.
* - `XKB_LOG_LEVEL` - see xkb_context_set_log_level().
* - `XKB_LOG_VERBOSITY` - see xkb_context_set_log_verbosity().
* - `XKB_DEFAULT_RULES`, `XKB_DEFAULT_MODEL`, `XKB_DEFAULT_LAYOUT`,
* `XKB_DEFAULT_VARIANT`, `XKB_DEFAULT_OPTIONS` - see xkb_rule_names.
*/
/** Flags for context creation. */
enum xkb_context_flags {
/** Do not apply any context flags. */
XKB_CONTEXT_NO_FLAGS = 0,
/** Create this context with an empty include path. */
XKB_CONTEXT_NO_DEFAULT_INCLUDES = (1 << 0),
/** Don't take RMLVO names from the environment. */
XKB_CONTEXT_NO_ENVIRONMENT_NAMES = (1 << 1),
/**
* Don't take RMLVO names from the environment.
* @since 0.3.0
*/
XKB_CONTEXT_NO_ENVIRONMENT_NAMES = (1 << 1)
};
/**
@ -486,10 +557,6 @@ enum xkb_context_flags {
*
* @returns A new context, or NULL on failure.
*
* The user may set some environment variables to affect default values in
* the context. See e.g. xkb_context_set_log_level() and
* xkb_context_set_log_verbosity().
*
* @memberof xkb_context
*/
struct xkb_context *
@ -548,7 +615,12 @@ xkb_context_get_user_data(struct xkb_context *context);
*
* The include paths are the file-system paths that are searched when an
* include statement is encountered during keymap compilation.
* In most cases, the default include paths are sufficient.
*
* The default include paths are:
* - The system XKB root, defined at library configuration time.
* If * the `XKB_CONFIG_ROOT` environment is defined, it is used instead.
* - The path `$HOME/.xkb`, where $HOME is the value of the environment
* variable `HOME`.
*
* @{
*/
@ -784,7 +856,7 @@ xkb_keymap_new_from_file(struct xkb_context *context, FILE *file,
* This is just like xkb_keymap_new_from_file(), but instead of a file, gets
* the keymap as one enormous string.
*
* @see xkb_keymap_new_from_string()
* @see xkb_keymap_new_from_file()
* @memberof xkb_keymap
*/
struct xkb_keymap *
@ -800,6 +872,7 @@ xkb_keymap_new_from_string(struct xkb_context *context, const char *string,
*
* @see xkb_keymap_new_from_string()
* @memberof xkb_keymap
* @since 0.3.0
*/
struct xkb_keymap *
xkb_keymap_new_from_buffer(struct xkb_context *context, const char *buffer,
@ -842,7 +915,7 @@ xkb_keymap_unref(struct xkb_keymap *keymap);
*
* @returns The keymap as a NUL-terminated string, or NULL if unsuccessful.
*
* The returned string may be fed back into xkb_map_new_from_string() to get
* The returned string may be fed back into xkb_keymap_new_from_string() to get
* the exact same keymap (possibly in another process, etc.).
*
* The returned string is dynamically allocated and should be freed by the
@ -868,6 +941,7 @@ xkb_keymap_get_as_string(struct xkb_keymap *keymap,
*
* @sa xkb_keycode_t
* @memberof xkb_keymap
* @since 0.3.1
*/
xkb_keycode_t
xkb_keymap_min_keycode(struct xkb_keymap *keymap);
@ -877,6 +951,7 @@ xkb_keymap_min_keycode(struct xkb_keymap *keymap);
*
* @sa xkb_keycode_t
* @memberof xkb_keymap
* @since 0.3.1
*/
xkb_keycode_t
xkb_keymap_max_keycode(struct xkb_keymap *keymap);
@ -886,6 +961,7 @@ xkb_keymap_max_keycode(struct xkb_keymap *keymap);
*
* @sa xkb_keymap_key_for_each
* @memberof xkb_keymap
* @since 0.3.1
*/
typedef void
(*xkb_keymap_key_iter_t)(struct xkb_keymap *keymap, xkb_keycode_t key,
@ -898,11 +974,43 @@ typedef void
*
* @sa xkb_keymap_min_keycode() xkb_keymap_max_keycode() xkb_keycode_t
* @memberof xkb_keymap
* @since 0.3.1
*/
void
xkb_keymap_key_for_each(struct xkb_keymap *keymap, xkb_keymap_key_iter_t iter,
void *data);
/**
* Find the name of the key with the given keycode.
*
* This function always returns the canonical name of the key (see
* description in xkb_keycode_t).
*
* @returns The key name. If no key with this keycode exists,
* returns NULL.
*
* @sa xkb_keycode_t
* @memberof xkb_keymap
* @since 0.6.0
*/
const char *
xkb_keymap_key_get_name(struct xkb_keymap *keymap, xkb_keycode_t key);
/**
* Find the keycode of the key with the given name.
*
* The name can be either a canonical name or an alias.
*
* @returns The keycode. If no key with this name exists,
* returns XKB_KEYCODE_INVALID.
*
* @sa xkb_keycode_t
* @memberof xkb_keymap
* @since 0.6.0
*/
xkb_keycode_t
xkb_keymap_key_by_name(struct xkb_keymap *keymap, const char *name);
/**
* Get the number of modifiers in the keymap.
*
@ -968,6 +1076,41 @@ xkb_keymap_layout_get_name(struct xkb_keymap *keymap, xkb_layout_index_t idx);
xkb_layout_index_t
xkb_keymap_layout_get_index(struct xkb_keymap *keymap, const char *name);
/**
* Get the number of LEDs in the keymap.
*
* @warning The range [ 0...xkb_keymap_num_leds() ) includes all of the LEDs
* in the keymap, but may also contain inactive LEDs. When iterating over
* this range, you need the handle this case when calling functions such as
* xkb_keymap_led_get_name() or xkb_state_led_index_is_active().
*
* @sa xkb_led_index_t
* @memberof xkb_keymap
*/
xkb_led_index_t
xkb_keymap_num_leds(struct xkb_keymap *keymap);
/**
* Get the name of a LED by index.
*
* @returns The name. If the index is invalid, returns NULL.
*
* @memberof xkb_keymap
*/
const char *
xkb_keymap_led_get_name(struct xkb_keymap *keymap, xkb_led_index_t idx);
/**
* Get the index of a LED by name.
*
* @returns The index. If no LED with this name exists, returns
* XKB_LED_INVALID.
*
* @memberof xkb_keymap
*/
xkb_led_index_t
xkb_keymap_led_get_index(struct xkb_keymap *keymap, const char *name);
/**
* Get the number of layouts for a specific key.
*
@ -1008,8 +1151,8 @@ xkb_keymap_num_levels_for_key(struct xkb_keymap *keymap, xkb_keycode_t key,
* @param[in] layout The layout for which to get the keysyms.
* @param[in] level The shift level in the layout for which to get the
* keysyms. This must be smaller than:
* @code xkb_keymap_num_layouts_for_key(keymap, key) @endcode
* @param[out] syms_out An immutible array of keysyms corresponding to the
* @code xkb_keymap_num_levels_for_key(keymap, key) @endcode
* @param[out] syms_out An immutable array of keysyms corresponding to the
* key in the given layout and shift level.
*
* If @c layout is out of range for this key (that is, larger or equal to
@ -1030,41 +1173,6 @@ xkb_keymap_key_get_syms_by_level(struct xkb_keymap *keymap,
xkb_level_index_t level,
const xkb_keysym_t **syms_out);
/**
* Get the number of LEDs in the keymap.
*
* @warning The range [ 0...xkb_keymap_num_leds() ) includes all of the LEDs
* in the keymap, but may also contain inactive LEDs. When iterating over
* this range, you need the handle this case when calling functions such as
* xkb_keymap_led_get_name() or xkb_state_led_index_is_active().
*
* @sa xkb_led_index_t
* @memberof xkb_keymap
*/
xkb_led_index_t
xkb_keymap_num_leds(struct xkb_keymap *keymap);
/**
* Get the name of a LED by index.
*
* @returns The name. If the index is invalid, returns NULL.
*
* @memberof xkb_keymap
*/
const char *
xkb_keymap_led_get_name(struct xkb_keymap *keymap, xkb_led_index_t idx);
/**
* Get the index of a LED by name.
*
* @returns The index. If no LED with this name exists, returns
* XKB_LED_INVALID.
*
* @memberof xkb_keymap
*/
xkb_led_index_t
xkb_keymap_led_get_index(struct xkb_keymap *keymap, const char *name);
/**
* Determine whether a key should repeat or not.
*
@ -1264,9 +1372,11 @@ xkb_state_update_mask(struct xkb_state *state,
* key in the given keyboard state.
*
* As an extension to XKB, this function can return more than one keysym.
* If you do not want to handle this case, you should use
* xkb_state_key_get_one_sym(), which additionally performs transformations
* which are specific to the one-keysym case.
* If you do not want to handle this case, you can use
* xkb_state_key_get_one_sym() for a simpler interface.
*
* This function does not perform any @ref keysym-transformations.
* (This might change).
*
* @returns The number of keysyms in the syms_out array. If no keysyms
* are produced by the key in the given keyboard state, returns 0 and sets
@ -1298,7 +1408,11 @@ xkb_state_key_get_syms(struct xkb_state *state, xkb_keycode_t key,
* You may safely pass NULL and 0 to @p buffer and @p size to find the
* required size (without the NUL-byte).
*
* This function performs Capitalization and Control @ref
* keysym-transformations.
*
* @memberof xkb_state
* @since 0.4.1
*/
int
xkb_state_key_get_utf8(struct xkb_state *state, xkb_keycode_t key,
@ -1311,7 +1425,11 @@ xkb_state_key_get_utf8(struct xkb_state *state, xkb_keycode_t key,
* @returns The UTF-32 representation for the key, if it consists of only
* a single codepoint. Otherwise, returns 0.
*
* This function performs Capitalization and Control @ref
* keysym-transformations.
*
* @memberof xkb_state
* @since 0.4.1
*/
uint32_t
xkb_state_key_get_utf32(struct xkb_state *state, xkb_keycode_t key);
@ -1328,6 +1446,8 @@ xkb_state_key_get_utf32(struct xkb_state *state, xkb_keycode_t key);
* @returns The keysym. If the key does not have exactly one keysym,
* returns XKB_KEY_NoSymbol
*
* This function performs Capitalization @ref keysym-transformations.
*
* @sa xkb_state_key_get_syms()
* @memberof xkb_state
*/
@ -1378,8 +1498,8 @@ xkb_state_key_get_level(struct xkb_state *state, xkb_keycode_t key,
xkb_layout_index_t layout);
/**
* Match flags for xkb_state_mod_indices_are_active and
* xkb_state_mod_names_are_active, specifying how the conditions for a
* Match flags for xkb_state_mod_indices_are_active() and
* xkb_state_mod_names_are_active(), specifying the conditions for a
* successful match. XKB_STATE_MATCH_NON_EXCLUSIVE is bitmaskable with
* the other modes.
*/
@ -1508,67 +1628,160 @@ xkb_state_mod_indices_are_active(struct xkb_state *state,
...);
/**
* Test whether a modifier is consumed by keyboard state translation for
* a key.
* @page consumed-modifiers Consumed Modifiers
* @parblock
*
* Some functions, like xkb_state_key_get_syms(), look at the state of
* the modifiers in the keymap and derive from it the correct shift level
* to use for the key. For example, in a US layout, pressing the key
* labeled \<A\> while the Shift modifier is active, generates the keysym 'A'.
* In this case, the Shift modifier is said to be consumed. However, the
* Num Lock modifier does not affect this translation at all, even if it
* active, so it is not consumed by this translation.
* labeled \<A\> while the Shift modifier is active, generates the keysym
* 'A'. In this case, the Shift modifier is said to be "consumed".
* However, the Num Lock modifier does not affect this translation at all,
* even if it is active, so it is not consumed by this translation.
*
* It may be desirable for some application to not reuse consumed modifiers
* for further processing, e.g. for hotkeys or keyboard shortcuts. To
* for further processing, e.g. for hotkeys or keyboard shortcuts. To
* understand why, consider some requirements from a standard shortcut
* mechanism, and how they are implemented:
*
* 1. The shortcut's modifiers must match exactly to the state. For example,
* it is possible to bind separate actions to \<Alt\>\<Tab\> and to
* \<Alt\>\<Shift\>\<Tab\>. Further, if only \<Alt\>\<Tab\> is bound to
* an action, pressing \<Alt\>\<Shift\>\<Tab\> should not trigger the
* shortcut.
* 1. The shortcut's modifiers must match exactly to the state. For
* example, it is possible to bind separate actions to \<Alt\>\<Tab\>
* and to \<Alt\>\<Shift\>\<Tab\>. Further, if only \<Alt\>\<Tab\> is
* bound to an action, pressing \<Alt\>\<Shift\>\<Tab\> should not
* trigger the shortcut.
* Effectively, this means that the modifiers are compared using the
* equality operator (==).
* 2. Only relevant modifiers are considered for the matching. For example,
*
* 2. Only relevant modifiers are considered for the matching. For example,
* Caps Lock and Num Lock should not generally affect the matching, e.g.
* when matching \<Alt\>\<Tab\> against the state, it does not matter
* whether Num Lock is active or not. These relevant, or significant,
* whether Num Lock is active or not. These relevant, or "significant",
* modifiers usually include Alt, Control, Shift, Super and similar.
* Effectively, this means that non-significant modifiers are masked out,
* before doing the comparison as described above.
* 3. The matching must be independent of the layout/keymap. For example,
*
* 3. The matching must be independent of the layout/keymap. For example,
* the \<Plus\> (+) symbol is found on the first level on some layouts,
* and requires holding Shift on others. If you simply bind the action
* but requires holding Shift on others. If you simply bind the action
* to the \<Plus\> keysym, it would work for the unshifted kind, but
* not for the others, because the match against Shift would fail. If
* not for the others, because the match against Shift would fail. If
* you bind the action to \<Shift\>\<Plus\>, only the shifted kind would
* work. So what is needed is to recognize that Shift is used up in the
* work. So what is needed is to recognize that Shift is used up in the
* translation of the keysym itself, and therefore should not be included
* in the matching.
* Effectively, this means that consumed modifiers (Shift in this example)
* are masked out as well, before doing the comparison.
*
* To summarize, this is how the matching would be performed:
* In summary, this is approximately how the matching would be performed:
* @code
* (keysym == shortcut_keysym) &&
* ((state_modifiers & ~consumed_modifiers & significant_modifiers) == shortcut_modifiers)
* ((state_mods & ~consumed_mods & significant_mods) == shortcut_mods)
* @endcode
*
* @c state_modifiers are the modifiers reported by
* @c state_mods are the modifiers reported by
* xkb_state_mod_index_is_active() and similar functions.
* @c consumed_modifiers are the modifiers reported by
* xkb_state_mod_index_is_consumed().
* @c significant_modifiers are decided upon by the application/toolkit/user;
* @c consumed_mods are the modifiers reported by
* xkb_state_mod_index_is_consumed() and similar functions.
* @c significant_mods are decided upon by the application/toolkit/user;
* it is up to them to decide whether these are configurable or hard-coded.
*
* @endparblock
*/
/**
* Consumed modifiers mode.
*
* There are several possible methods for deciding which modifiers are
* consumed and which are not, each applicable for different systems or
* situations. The mode selects the method to use.
*
* Keep in mind that in all methods, the keymap may decide to "preserve"
* a modifier, meaning it is not reported as consumed even if it would
* have otherwise.
*/
enum xkb_consumed_mode {
/**
* This is the mode defined in the XKB specification and used by libX11.
*
* A modifier is consumed if and only if it *may affect* key translation.
*
* For example, if `Control+Alt+<Backspace>` produces some assigned keysym,
* then when pressing just `<Backspace>`, `Control` and `Alt` are consumed,
* even though they are not active, since if they *were* active they would
* have affected key translation.
*/
XKB_CONSUMED_MODE_XKB,
/**
* This is the mode used by the GTK+ toolkit.
*
* The mode consists of the following two independent heuristics:
*
* - The currently active set of modifiers, excluding modifiers which do
* not affect the key (as described for @ref XKB_CONSUMED_MODE_XKB), are
* considered consumed, if the keysyms produced when all of them are
* active are different from the keysyms produced when no modifiers are
* active.
*
* - A single modifier is considered consumed if the keysyms produced for
* the key when it is the only active modifier are different from the
* keysyms produced when no modifiers are active.
*/
XKB_CONSUMED_MODE_GTK
};
/**
* Get the mask of modifiers consumed by translating a given key.
*
* @param state The keyboard state.
* @param key The keycode of the key.
* @param mode The consumed modifiers mode to use; see enum description.
*
* @returns a mask of the consumed modifiers.
*
* @memberof xkb_state
* @since 0.7.0
*/
xkb_mod_mask_t
xkb_state_key_get_consumed_mods2(struct xkb_state *state, xkb_keycode_t key,
enum xkb_consumed_mode mode);
/**
* Same as xkb_state_key_get_consumed_mods2() with mode XKB_CONSUMED_MODE_XKB.
*
* @memberof xkb_state
* @since 0.4.1
*/
xkb_mod_mask_t
xkb_state_key_get_consumed_mods(struct xkb_state *state, xkb_keycode_t key);
/**
* Test whether a modifier is consumed by keyboard state translation for
* a key.
*
* @param state The keyboard state.
* @param key The keycode of the key.
* @param idx The index of the modifier to check.
* @param mode The consumed modifiers mode to use; see enum description.
*
* @returns 1 if the modifier is consumed, 0 if it is not. If the modifier
* index is not valid in the keymap, returns -1.
*
* @sa xkb_state_mod_mask_remove_consumed()
* @sa xkb_state_key_get_consumed_mods()
* @memberof xkb_state
* @since 0.7.0
*/
int
xkb_state_mod_index_is_consumed2(struct xkb_state *state,
xkb_keycode_t key,
xkb_mod_index_t idx,
enum xkb_consumed_mode mode);
/**
* Same as xkb_state_mod_index_is_consumed2() with mode XKB_CONSUMED_MOD_XKB.
*
* @memberof xkb_state
* @since 0.4.1
*/
int
xkb_state_mod_index_is_consumed(struct xkb_state *state, xkb_keycode_t key,
@ -1577,6 +1790,8 @@ xkb_state_mod_index_is_consumed(struct xkb_state *state, xkb_keycode_t key,
/**
* Remove consumed modifiers from a modifier mask for a key.
*
* @deprecated Use xkb_state_key_get_consumed_mods2() instead.
*
* Takes the given modifier mask, and removes all modifiers which are
* consumed for that particular key (as in xkb_state_mod_index_is_consumed()).
*
@ -1587,17 +1802,6 @@ xkb_mod_mask_t
xkb_state_mod_mask_remove_consumed(struct xkb_state *state, xkb_keycode_t key,
xkb_mod_mask_t mask);
/**
* Get the mask of modifiers consumed by translating a given key.
*
* @returns a mask of the consumed modifiers.
*
* @sa xkb_state_mod_index_is_consumed()
* @memberof xkb_state
*/
xkb_mod_mask_t
xkb_state_key_get_consumed_mods(struct xkb_state *state, xkb_keycode_t key);
/**
* Test whether a layout is active in a given keyboard state by name.
*