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
parent
aa633ff276
commit
76c762558a
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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/*
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 *
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -36,6 +36,9 @@ ExprCreateString(xkb_atom_t str);
|
|||
ExprDef *
|
||||
ExprCreateInteger(int ival);
|
||||
|
||||
ExprDef *
|
||||
ExprCreateFloat(void);
|
||||
|
||||
ExprDef *
|
||||
ExprCreateBoolean(bool set);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@
|
|||
#define XKBCOMP_PARSER_PRIV_H
|
||||
|
||||
struct parser_param;
|
||||
struct scanner;
|
||||
|
||||
#include "scanner-utils.h"
|
||||
#include "parser.h"
|
||||
|
||||
int
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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 */
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in New Issue