wip: remove libxkbcommon and xkeyboard-config (moved to local/recipes/)
This commit is contained in:
@@ -1,19 +0,0 @@
|
||||
#TODO: needs xkeyboard-config data installed; Wayland helper tools stay disabled for now
|
||||
[source]
|
||||
tar = "https://xkbcommon.org/download/libxkbcommon-1.7.0.tar.xz"
|
||||
blake3 = "5001ca0b8562feeef2010bf16c05657e3875fda3ed5fdedbf48b9135e5cdfcbc"
|
||||
|
||||
[build]
|
||||
template = "meson"
|
||||
mesonflags = [
|
||||
"-Denable-wayland=false",
|
||||
"-Denable-x11=false",
|
||||
"-Denable-tools=false",
|
||||
"-Denable-docs=false",
|
||||
"-Denable-xkbregistry=false",
|
||||
"-Dxkb-config-root=/usr/share/X11/xkb",
|
||||
"-Dx-locale-root=/usr/share/X11/locale",
|
||||
]
|
||||
dependencies = [
|
||||
"xkeyboard-config",
|
||||
]
|
||||
@@ -1,14 +0,0 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
max_line_length = 80
|
||||
|
||||
[*.yml,*.md]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
name: github-release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'xkbcommon-*'
|
||||
|
||||
# Set permissions at the job level.
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Automatically create GitHub release for tag
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: ${{ github.ref }}
|
||||
body: |
|
||||
See the [NEWS](https://github.com/xkbcommon/libxkbcommon/blob/master/NEWS) file for the changes.
|
||||
|
||||
Official tarball: https://xkbcommon.org/download/lib${{ github.ref_name }}.tar.xz
|
||||
@@ -1,83 +0,0 @@
|
||||
name: linux
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
# Set permissions at the job level.
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
linux:
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
contents: read
|
||||
strategy:
|
||||
matrix:
|
||||
compiler: [clang, gcc]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade meson PyYAML
|
||||
sudo apt update
|
||||
sudo apt install -y \
|
||||
doxygen libxcb-xkb-dev valgrind ninja-build \
|
||||
libwayland-dev wayland-protocols bison graphviz libicu-dev
|
||||
- name: Install xkeyboard-config
|
||||
run: |
|
||||
# Install master version of xkeyboard-config, in order to ensure
|
||||
# its latest version works well with xkbcommon.
|
||||
# HACK: We use meson to install, while it would be cleaner
|
||||
# to create a proper package to install or use some PPA.
|
||||
pushd ~
|
||||
git clone --depth=1 https://gitlab.freedesktop.org/xkeyboard-config/xkeyboard-config.git
|
||||
cd "xkeyboard-config"
|
||||
BUILDDIR=build
|
||||
meson setup $BUILDDIR -Dprefix=/usr
|
||||
meson install -C $BUILDDIR
|
||||
popd
|
||||
- name: Setup
|
||||
run: |
|
||||
# -gdwarf-4 - see https://github.com/llvm/llvm-project/issues/56550.
|
||||
CFLAGS='-gdwarf-4' meson setup build -Denable-docs=true -Denable-cool-uris=true
|
||||
env:
|
||||
CC: ${{ matrix.compiler }}
|
||||
- name: Build
|
||||
run: |
|
||||
meson compile -C build
|
||||
- name: Test
|
||||
run:
|
||||
meson test -C build --print-errorlogs --no-suite python-tests
|
||||
- name: Test with valgrind
|
||||
run:
|
||||
meson test -C build --print-errorlogs --setup=valgrind --no-suite python-tests
|
||||
- name: Upload test logs
|
||||
uses: actions/upload-artifact@v3
|
||||
if: failure()
|
||||
with:
|
||||
name: test logs
|
||||
path: |
|
||||
build/meson-logs/
|
||||
- name: Ensure doxygen version is correct
|
||||
run: |
|
||||
doxygen --version > version.txt
|
||||
echo "1.9.6" >> version.txt
|
||||
if [ $(sort -V version.txt | tail -n1) != "1.9.6" ]; then
|
||||
echo "Doxygen version 1.9.6 or earlier expected, see #347"
|
||||
exit 1
|
||||
fi
|
||||
- name: Store doxygen docs for use by the pages workflow
|
||||
uses: actions/upload-artifact@v3
|
||||
if: success()
|
||||
with:
|
||||
name: doxygen-docs
|
||||
path: |
|
||||
build/html/
|
||||
@@ -1,45 +0,0 @@
|
||||
name: macos
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
# Set permissions at the job level.
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
macos:
|
||||
runs-on: macos-12
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
brew install bison libxml2 meson ninja pyyaml xkeyboardconfig xorg-server
|
||||
brew link bison --force
|
||||
env:
|
||||
HOMEBREW_NO_AUTO_UPDATE: 1
|
||||
HOMEBREW_NO_INSTALL_CLEANUP: 1
|
||||
- name: Setup
|
||||
run: |
|
||||
PATH="/usr/local/opt/bison/bin:${PATH}" \
|
||||
meson setup \
|
||||
-Denable-wayland=false \
|
||||
-Denable-x11=true \
|
||||
-Dxkb-config-root="$(brew --prefix xkeyboardconfig)/share/X11/xkb" \
|
||||
-Dx-locale-root="$(brew --prefix xorg-server)/share/X11/locale" \
|
||||
build
|
||||
- name: Build
|
||||
run: |
|
||||
PATH="/usr/local/opt/bison/bin:${PATH}" meson compile -C build
|
||||
- name: Test
|
||||
run: |
|
||||
meson test -C build --print-errorlogs
|
||||
@@ -1,55 +0,0 @@
|
||||
name: Deploy to GitHub pages
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["master"]
|
||||
|
||||
# Allow running this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
# Allow only one concurrent deployment
|
||||
concurrency:
|
||||
group: "pages"
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-22.04
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
|
||||
steps:
|
||||
- name: Set up directory tree
|
||||
run: mkdir -p public_html/doc/
|
||||
- name: Download doxygen from Linux build
|
||||
uses: dawidd6/action-download-artifact@v2
|
||||
with:
|
||||
workflow: linux.yml
|
||||
workflow_conclusion: success
|
||||
name: doxygen-docs
|
||||
path: doxygen/
|
||||
- name: Move doxygen to target directory
|
||||
run: mv doxygen/ public_html/doc/current/
|
||||
- name: Check out the static website
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: xkbcommon/website
|
||||
persist-credentials: false
|
||||
path: website
|
||||
- name: Move static website to target directory
|
||||
run: mv website/* public_html/
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v3
|
||||
- name: Upload pages artifact
|
||||
uses: actions/upload-pages-artifact@v1
|
||||
with:
|
||||
path: public_html/
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v2
|
||||
@@ -1,43 +0,0 @@
|
||||
name: windows
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
# Set permissions at the job level.
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
windows:
|
||||
runs-on: windows-2022
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
- name: Install dependencies
|
||||
shell: powershell
|
||||
run: |
|
||||
python -m pip install --upgrade meson
|
||||
Invoke-WebRequest -Uri https://github.com/lexxmark/winflexbison/releases/download/v2.5.23/win_flex_bison-2.5.23.zip -OutFile win_flex_bison.zip
|
||||
Expand-Archive -Path win_flex_bison.zip -DestinationPath bin
|
||||
Write-Output ((Get-Location).ToString() + "./bin") | Out-File -Append -FilePath $env:GITHUB_PATH -Encoding utf8
|
||||
- name: Setup
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||
meson setup --backend=vs -Denable-wayland=false -Denable-x11=false -Denable-docs=false -Denable-xkbregistry=false build
|
||||
- name: Build
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||
meson compile -C build
|
||||
- name: Test
|
||||
run:
|
||||
meson test -C build --print-errorlogs
|
||||
@@ -1,28 +0,0 @@
|
||||
# See https://pre-commit.com for more information
|
||||
# See https://pre-commit.com/hooks.html for more hooks
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.5.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: end-of-file-fixer
|
||||
- id: check-yaml
|
||||
- id: check-added-large-files
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 24.2.0
|
||||
hooks:
|
||||
- id: black
|
||||
args: ['--check', '--diff', '.']
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
rev: v0.2.2
|
||||
hooks:
|
||||
- id: ruff
|
||||
# ambiguous-variable-name (E741), line-too-long (E501)
|
||||
args: ['--ignore=E741,E501', '.']
|
||||
# [TODO] C linter/formatter
|
||||
# Note: There is an old config file for uncrustify (https://uncrustify.sourceforge.net)
|
||||
# in the repo, but we may want to migrate to other modern style.
|
||||
# - repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
# rev: v16.0.6
|
||||
# hooks:
|
||||
# - id: clang-format
|
||||
@@ -1,228 +0,0 @@
|
||||
tok_split_gte=false
|
||||
utf8_byte=true
|
||||
utf8_force=true
|
||||
indent_cmt_with_tabs=false
|
||||
indent_align_string=false
|
||||
indent_braces=false
|
||||
indent_braces_no_func=false
|
||||
indent_braces_no_class=false
|
||||
indent_braces_no_struct=false
|
||||
indent_brace_parent=false
|
||||
indent_namespace=false
|
||||
indent_extern=false
|
||||
indent_class=false
|
||||
indent_class_colon=false
|
||||
indent_else_if=false
|
||||
indent_var_def_cont=false
|
||||
indent_func_call_param=false
|
||||
indent_func_def_param=false
|
||||
indent_func_proto_param=false
|
||||
indent_func_class_param=false
|
||||
indent_func_ctor_var_param=false
|
||||
indent_template_param=false
|
||||
indent_func_param_double=false
|
||||
indent_relative_single_line_comments=false
|
||||
indent_col1_comment=false
|
||||
indent_access_spec_body=false
|
||||
indent_paren_nl=false
|
||||
indent_comma_paren=false
|
||||
indent_bool_paren=false
|
||||
indent_first_bool_expr=false
|
||||
indent_square_nl=false
|
||||
indent_preserve_sql=false
|
||||
indent_align_assign=true
|
||||
sp_balance_nested_parens=false
|
||||
align_keep_tabs=false
|
||||
align_with_tabs=false
|
||||
align_on_tabstop=false
|
||||
align_number_left=false
|
||||
align_func_params=false
|
||||
align_same_func_call_params=false
|
||||
align_var_def_colon=true
|
||||
align_var_def_attribute=true
|
||||
align_var_def_inline=true
|
||||
align_right_cmt_mix=false
|
||||
align_on_operator=false
|
||||
align_mix_var_proto=false
|
||||
align_single_line_func=false
|
||||
align_single_line_brace=false
|
||||
align_nl_cont=false
|
||||
align_left_shift=true
|
||||
align_oc_decl_colon=true
|
||||
nl_collapse_empty_body=true
|
||||
nl_assign_leave_one_liners=true
|
||||
nl_class_leave_one_liners=true
|
||||
nl_enum_leave_one_liners=true
|
||||
nl_getset_leave_one_liners=true
|
||||
nl_func_leave_one_liners=true
|
||||
nl_if_leave_one_liners=true
|
||||
nl_multi_line_cond=false
|
||||
nl_multi_line_define=false
|
||||
nl_before_case=true
|
||||
nl_after_case=true
|
||||
nl_after_return=false
|
||||
nl_after_semicolon=true
|
||||
nl_after_brace_open=true
|
||||
nl_after_brace_open_cmt=false
|
||||
nl_after_vbrace_open=false
|
||||
nl_after_vbrace_open_empty=false
|
||||
nl_after_brace_close=false
|
||||
nl_after_vbrace_close=false
|
||||
nl_define_macro=false
|
||||
nl_squeeze_ifdef=false
|
||||
nl_ds_struct_enum_cmt=false
|
||||
nl_ds_struct_enum_close_brace=false
|
||||
nl_create_if_one_liner=false
|
||||
nl_create_for_one_liner=false
|
||||
nl_create_while_one_liner=false
|
||||
ls_for_split_full=false
|
||||
ls_func_split_full=false
|
||||
nl_after_multiline_comment=false
|
||||
eat_blanks_after_open_brace=false
|
||||
eat_blanks_before_close_brace=false
|
||||
mod_full_brace_if_chain=false
|
||||
mod_pawn_semicolon=false
|
||||
mod_full_paren_if_bool=false
|
||||
mod_remove_extra_semicolon=false
|
||||
mod_sort_import=false
|
||||
mod_sort_using=false
|
||||
mod_sort_include=false
|
||||
mod_move_case_break=false
|
||||
mod_remove_empty_return=false
|
||||
cmt_indent_multi=true
|
||||
cmt_c_group=false
|
||||
cmt_c_nl_start=false
|
||||
cmt_c_nl_end=false
|
||||
cmt_cpp_group=false
|
||||
cmt_cpp_nl_start=false
|
||||
cmt_cpp_nl_end=false
|
||||
cmt_cpp_to_c=true
|
||||
cmt_star_cont=true
|
||||
cmt_multi_check_last=true
|
||||
cmt_insert_before_preproc=false
|
||||
pp_indent_at_level=false
|
||||
pp_region_indent_code=false
|
||||
pp_if_indent_code=false
|
||||
pp_define_at_level=false
|
||||
indent_columns=4
|
||||
indent_brace=0
|
||||
indent_switch_case=0
|
||||
align_struct_init_span=2
|
||||
align_pp_define_gap=0
|
||||
align_pp_define_span=2
|
||||
align_oc_msg_colon_span=16
|
||||
nl_end_of_file_min=1
|
||||
nl_func_var_def_blk=0
|
||||
code_width=78
|
||||
nl_max=2
|
||||
newlines=auto
|
||||
indent_with_tabs=0
|
||||
sp_arith=force
|
||||
sp_assign=force
|
||||
sp_assign_default=force
|
||||
sp_before_assign=force
|
||||
sp_after_assign=force
|
||||
sp_enum_assign=force
|
||||
sp_enum_before_assign=force
|
||||
sp_enum_after_assign=force
|
||||
sp_pp_stringify=add
|
||||
sp_bool=force
|
||||
sp_compare=force
|
||||
sp_inside_paren=remove
|
||||
sp_paren_paren=remove
|
||||
sp_paren_brace=force
|
||||
sp_before_ptr_star=ignore
|
||||
sp_before_unnamed_ptr_star=force
|
||||
sp_before_byref=force
|
||||
sp_before_unnamed_byref=force
|
||||
sp_after_byref=remove
|
||||
sp_after_type=force
|
||||
sp_before_sparen=force
|
||||
sp_inside_sparen=remove
|
||||
sp_inside_sparen_close=remove
|
||||
sp_after_sparen=force
|
||||
sp_sparen_brace=force
|
||||
sp_special_semi=force
|
||||
sp_before_semi=remove
|
||||
sp_after_semi=force
|
||||
sp_after_semi_for=force
|
||||
sp_after_semi_for_empty=force
|
||||
sp_before_square=remove
|
||||
sp_inside_square=remove
|
||||
sp_after_comma=force
|
||||
sp_before_comma=remove
|
||||
sp_paren_comma=force
|
||||
sp_before_ellipsis=force
|
||||
sp_after_class_colon=force
|
||||
sp_before_class_colon=force
|
||||
sp_before_case_colon=remove
|
||||
sp_after_cast=force
|
||||
sp_inside_paren_cast=remove
|
||||
sp_sizeof_paren=remove
|
||||
sp_inside_braces_enum=force
|
||||
sp_inside_braces_struct=force
|
||||
sp_inside_braces=force
|
||||
sp_inside_braces_empty=force
|
||||
sp_func_proto_paren=remove
|
||||
sp_func_def_paren=remove
|
||||
sp_inside_fparens=remove
|
||||
sp_inside_fparen=remove
|
||||
sp_square_fparen=remove
|
||||
sp_fparen_brace=force
|
||||
sp_func_call_paren=remove
|
||||
sp_func_call_paren_empty=remove
|
||||
sp_return_paren=force
|
||||
sp_attribute_paren=remove
|
||||
sp_defined_paren=remove
|
||||
sp_macro=force
|
||||
sp_macro_func=force
|
||||
sp_else_brace=force
|
||||
sp_brace_else=force
|
||||
sp_brace_typedef=force
|
||||
sp_not=remove
|
||||
sp_inv=remove
|
||||
nl_start_of_file=remove
|
||||
nl_end_of_file=force
|
||||
nl_assign_square=remove
|
||||
nl_after_square_assign=remove
|
||||
nl_fcall_brace=remove
|
||||
nl_enum_brace=remove
|
||||
nl_struct_brace=remove
|
||||
nl_union_brace=remove
|
||||
nl_if_brace=remove
|
||||
nl_brace_else=force
|
||||
nl_elseif_brace=remove
|
||||
nl_else_brace=remove
|
||||
nl_else_if=remove
|
||||
nl_for_brace=remove
|
||||
nl_do_brace=remove
|
||||
nl_brace_while=remove
|
||||
nl_switch_brace=remove
|
||||
nl_case_colon_brace=force
|
||||
nl_func_type_name=force
|
||||
nl_func_type_name_class=force
|
||||
nl_func_proto_type_name=force
|
||||
nl_func_paren=remove
|
||||
nl_func_def_paren=remove
|
||||
nl_func_decl_start=remove
|
||||
nl_func_def_start=remove
|
||||
nl_func_decl_args=remove
|
||||
nl_func_decl_end=remove
|
||||
nl_func_def_end=remove
|
||||
nl_func_decl_end_single=remove
|
||||
nl_func_def_end_single=remove
|
||||
nl_func_decl_empty=remove
|
||||
nl_func_def_empty=remove
|
||||
nl_fdef_brace=force
|
||||
nl_return_expr=remove
|
||||
nl_before_if=ignore
|
||||
nl_after_if=ignore
|
||||
nl_before_for=ignore
|
||||
nl_after_for=ignore
|
||||
nl_before_while=ignore
|
||||
nl_after_while=ignore
|
||||
nl_before_switch=ignore
|
||||
nl_after_switch=ignore
|
||||
nl_before_do=ignore
|
||||
nl_after_do=ignore
|
||||
pp_space=remove
|
||||
@@ -1,215 +0,0 @@
|
||||
The following is a list of all copyright notices and license statements which
|
||||
appear in the xkbcommon source tree.
|
||||
|
||||
If making new contributions, the first form (i.e. Daniel Stone, Ran Benita,
|
||||
etc) is vastly preferred.
|
||||
|
||||
All licenses are derivative of the MIT/X11 license, mostly identical other
|
||||
than no-endorsement clauses (e.g. paragraph 4 of The Open Group's license).
|
||||
|
||||
These statements are split into two sections: one for the code compiled and
|
||||
distributed as part of the libxkbcommon shared library and the code
|
||||
component of all tests (i.e. everything under src/ and xkbcommon/, plus the
|
||||
.c and .h files under test/), and another for the test data under test/data,
|
||||
which is distributed with the xkbcommon source tarball, but not installed to
|
||||
the system.
|
||||
|
||||
|
||||
BEGINNING OF SOFTWARE COPYRIGHT/LICENSE STATEMENTS:
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
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>
|
||||
|
||||
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 1985, 1987, 1988, 1990, 1998 The Open Group
|
||||
|
||||
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 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 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.
|
||||
|
||||
Except as contained in this notice, the names of the authors or their
|
||||
institutions shall not be used in advertising or otherwise to promote the
|
||||
sale, use or other dealings in this Software without prior written
|
||||
authorization from the authors.
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
Copyright (c) 1993, 1994, 1995, 1996 by Silicon Graphics Computer Systems, Inc.
|
||||
|
||||
Permission to use, copy, modify, and distribute this
|
||||
software and its documentation for any purpose and without
|
||||
fee is hereby granted, 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 Silicon Graphics not be
|
||||
used in advertising or publicity pertaining to distribution
|
||||
of the software without specific prior written permission.
|
||||
Silicon Graphics makes no representation about the suitability
|
||||
of this software for any purpose. It is provided "as is"
|
||||
without any express or implied warranty.
|
||||
|
||||
SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
||||
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
|
||||
GRAPHICS 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.
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
|
||||
|
||||
All Rights Reserved
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and its
|
||||
documentation for any purpose and without fee is hereby granted,
|
||||
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 Digital not be
|
||||
used in advertising or publicity pertaining to distribution of the
|
||||
software without specific, written prior permission.
|
||||
|
||||
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
|
||||
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
|
||||
DIGITAL 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.
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
Copyright (C) 2011 Joseph Adams <joeyadams3.14159@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 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.
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
END OF SOFTWARE COPYRIGHT/LICENSE STATEMENTS
|
||||
|
||||
|
||||
BEGINNING OF LICENSE STATEMENTS FOR UNDISTRIBUTED DATA FILES IN test/data,
|
||||
derived from xkeyboard-config:
|
||||
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Copyright 1996 by Joseph Moss
|
||||
Copyright (C) 2002-2007 Free Software Foundation, Inc.
|
||||
Copyright (C) Dmitry Golubev <lastguru@mail.ru>, 2003-2004
|
||||
Copyright (C) 2004, Gregory Mokhin <mokhin@bog.msu.ru>
|
||||
Copyright (C) 2006 Erdal Ronahî
|
||||
|
||||
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 the copyright holder(s) not be used in
|
||||
advertising or publicity pertaining to distribution of the software without
|
||||
specific, written prior permission. The copyright holder(s) makes no
|
||||
representations about the suitability of this software for any purpose. It
|
||||
is provided "as is" without express or implied warranty.
|
||||
|
||||
THE COPYRIGHT HOLDER(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
EVENT SHALL THE COPYRIGHT HOLDER(S) 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.
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
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.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,76 +0,0 @@
|
||||
libxkbcommon consists of three shared libraries, libxkbcommon (the main
|
||||
library), libxkbcommon-x11 (an addon library for XCB clients) and libxkbregistry
|
||||
(a library to list available RMLVO options).
|
||||
|
||||
The files for libxkbcommon-x11 are:
|
||||
libxkbcommon-x11.a libxkbcommon-x11.so* xkbcommon/xkbcommon-x11.h
|
||||
xkbcommon-x11.map xkbcommon-x11.pc
|
||||
|
||||
libxkbcommon-x11 can be disabled with -Denable-x11=false (see
|
||||
`meson configure build` for other options/variables).
|
||||
|
||||
The files for libxkbregistry are:
|
||||
libxkbregistry.a libxkbregistry.so* xkbcommon/xkbregistry.h
|
||||
xkbregistry.map xkbregistry.pc
|
||||
|
||||
libxkbregistry can be disabled with -Denable-xkbregistry=false (see
|
||||
`meson configure build` for other options/variables).
|
||||
|
||||
Dependencies for libxkbcommon:
|
||||
- C compiler, meson, pkg-config, libc.
|
||||
|
||||
- (build) bison (preferred), win_bison or byacc>=20141006.
|
||||
byacc must be configured with --enable-btyacc.
|
||||
|
||||
- (build optional, runtime required) xkeyboard-config.
|
||||
During build, for automatically detecting the value of
|
||||
-Dxkb-config-root instead of guessing (/usr/share/X11/xkb).
|
||||
During runtime, not strictly needed, but most users of the library
|
||||
would need it.
|
||||
|
||||
- (runtime) libX11.
|
||||
Contains the dataset for Compose support (/usr/share/X11/locale).
|
||||
Please don't depend on it explicitly.
|
||||
|
||||
- (build optional) doxygen.
|
||||
For generating the HTML documentation.
|
||||
To disable, use -Denable-docs=false.
|
||||
|
||||
- (build optional) gperf.
|
||||
Output included in git and tarball. To regenerate, use
|
||||
`./scripts/update-keywords`.
|
||||
|
||||
Dependencies for xkbcli:
|
||||
- libxkbcommon.
|
||||
|
||||
Dependencies for libxkbcommon-x11:
|
||||
- libxkbcommon.
|
||||
|
||||
- libxcb>=1.10 with libxcb-xkb.
|
||||
|
||||
Dependencies for libxkbcommon-x11 tests:
|
||||
- xkbcomp, Xvfb.
|
||||
If they are not available, the relevant tests are skipped.
|
||||
|
||||
Dependencies for libxkbregistry:
|
||||
- libxkbregistry is a sublibrary of libxkbcommon and cannot be built without
|
||||
building libxbkcommon. The files produced are otherwise independent.
|
||||
|
||||
- libxml2
|
||||
|
||||
- (build optional, runtime requirement) xkeyboard-config
|
||||
During build, for automatically detecting the value of
|
||||
-Dxkb-config-root instead of guessing (/usr/share/X11/xkb).
|
||||
|
||||
Dependencies for Wayland tests:
|
||||
- wayland-client>=1.2.0, wayland-scanner, wayland-protocols>=1.0.
|
||||
To disable, use -Denable-wayland=false.
|
||||
|
||||
Unless libxcb is always available as part of the system, it is preferred
|
||||
that libxkbcommon and libxkbcommon-x11 be split into separate packages,
|
||||
such that the main library does not depend on libxcb. This avoids a
|
||||
transitive dependency of Wayland clients on X libraries.
|
||||
|
||||
It is perferred that libxkbregistry be split into a separate packages as most
|
||||
clients that require libxkbcommon do not require libxkbregistry and clients
|
||||
requiring libxkbregistry may not need libxkbcommon.
|
||||
@@ -1,79 +0,0 @@
|
||||
# libxkbcommon
|
||||
|
||||
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 and a separate library for listing available keyboard layouts.
|
||||
|
||||
[XKB]: doc/introduction-to-xkb.md
|
||||
|
||||
## Quick Guide
|
||||
|
||||
- [Introduction to XKB][XKB]: to learn the essentials of XKB.
|
||||
- [User-configuration](doc/user-configuration.md): instructions to add
|
||||
a *custom layout* or option.
|
||||
- [Quick Guide](doc/quick-guide.md): introduction on how to use this library.
|
||||
|
||||
## Building
|
||||
|
||||
libxkbcommon is built with [Meson](http://mesonbuild.com/):
|
||||
|
||||
meson setup build
|
||||
meson compile -C build
|
||||
meson test -C build # Run the tests.
|
||||
|
||||
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
|
||||
meson compile -C build
|
||||
|
||||
## API
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
See [Compatibility](doc/compatibility.md) notes.
|
||||
|
||||
## Development
|
||||
|
||||
An extremely rudimentary homepage can be found at
|
||||
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 in a [GitHub](https://github.com/xkbcommon/libxkbcommon) pull request.
|
||||
|
||||
Bug reports (and usage questions) are also welcome, and may be filed at
|
||||
[GitHub](https://github.com/xkbcommon/libxkbcommon/issues).
|
||||
|
||||
The maintainers are
|
||||
- Daniel Stone <daniel@fooishbar.org>
|
||||
- Ran Benita <ran@unusedvar.com>
|
||||
|
||||
## Credits
|
||||
|
||||
Many thanks are due to Dan Nicholson for his heroic work in getting xkbcommon
|
||||
off the ground initially.
|
||||
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2021 Ran Benita <ran@unusedvar.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 "config.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "atom.h"
|
||||
#include "bench.h"
|
||||
#include "darray.h"
|
||||
|
||||
#define BENCHMARK_ITERATIONS 100
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
FILE *file;
|
||||
char wordbuf[1024];
|
||||
darray(char *) words;
|
||||
char **worditer;
|
||||
struct atom_table *table;
|
||||
xkb_atom_t atom;
|
||||
const char *text;
|
||||
struct bench bench;
|
||||
char *elapsed;
|
||||
|
||||
darray_init(words);
|
||||
file = fopen("/usr/share/dict/words", "rb");
|
||||
if (file == NULL) {
|
||||
perror("/usr/share/dict/words");
|
||||
return -1;
|
||||
}
|
||||
while (fgets(wordbuf, sizeof(wordbuf), file)) {
|
||||
size_t len = strlen(wordbuf);
|
||||
if (len > 0 && wordbuf[len - 1] == '\n')
|
||||
wordbuf[len - 1] = '\0';
|
||||
darray_append(words, strdup(wordbuf));
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
bench_start(&bench);
|
||||
for (int i = 0; i < BENCHMARK_ITERATIONS; i++) {
|
||||
table = atom_table_new();
|
||||
assert(table);
|
||||
|
||||
darray_foreach(worditer, words) {
|
||||
atom = atom_intern(table, *worditer, strlen(*worditer) - 1, true);
|
||||
assert(atom != XKB_ATOM_NONE);
|
||||
|
||||
text = atom_text(table, atom);
|
||||
assert(text != NULL);
|
||||
}
|
||||
|
||||
atom_table_free(table);
|
||||
}
|
||||
bench_stop(&bench);
|
||||
|
||||
elapsed = bench_elapsed_str(&bench);
|
||||
fprintf(stderr, "%d iterations in %ss\n",
|
||||
BENCHMARK_ITERATIONS, elapsed);
|
||||
free(elapsed);
|
||||
|
||||
darray_foreach(worditer, words) {
|
||||
free(*worditer);
|
||||
}
|
||||
darray_free(words);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2015 Kazunobu Kuriyama <kazunobu.kuriyama@nifty.com>
|
||||
* 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 "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "bench.h"
|
||||
#include "../src/utils.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct timeval {
|
||||
long tv_sec, tv_usec;
|
||||
};
|
||||
|
||||
static int
|
||||
gettimeofday(struct timeval *tv, void *unused)
|
||||
{
|
||||
static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL);
|
||||
|
||||
SYSTEMTIME system_time;
|
||||
FILETIME file_time;
|
||||
uint64_t t;
|
||||
|
||||
GetSystemTime(&system_time);
|
||||
SystemTimeToFileTime(&system_time, &file_time);
|
||||
t = (uint64_t) file_time.dwLowDateTime;
|
||||
t += ((uint64_t) file_time.dwHighDateTime) << 32;
|
||||
|
||||
tv->tv_sec = (long) ((t - EPOCH) / 10000000L);
|
||||
tv->tv_usec = (long) (system_time.wMilliseconds * 1000);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
bench_start(struct bench *bench)
|
||||
{
|
||||
struct timeval val;
|
||||
(void) gettimeofday(&val, NULL);
|
||||
bench->start = (struct bench_time) {
|
||||
.seconds = val.tv_sec,
|
||||
.microseconds = val.tv_usec,
|
||||
};
|
||||
}
|
||||
|
||||
void
|
||||
bench_stop(struct bench *bench)
|
||||
{
|
||||
struct timeval val;
|
||||
(void) gettimeofday(&val, NULL);
|
||||
bench->stop = (struct bench_time) {
|
||||
.seconds = val.tv_sec,
|
||||
.microseconds = val.tv_usec,
|
||||
};
|
||||
}
|
||||
|
||||
void
|
||||
bench_elapsed(const struct bench *bench, struct bench_time *result)
|
||||
{
|
||||
result->seconds = bench->stop.seconds - bench->start.seconds;
|
||||
result->microseconds = bench->stop.microseconds - bench->start.microseconds;
|
||||
if (result->microseconds < 0) {
|
||||
result->microseconds += 1000000;
|
||||
result->seconds--;
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
bench_elapsed_str(const struct bench *bench)
|
||||
{
|
||||
struct bench_time elapsed;
|
||||
char *buf;
|
||||
int ret;
|
||||
|
||||
bench_elapsed(bench, &elapsed);
|
||||
ret = asprintf(&buf, "%ld.%06ld", elapsed.seconds, elapsed.microseconds);
|
||||
assert(ret >= 0);
|
||||
|
||||
return buf;
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2015 Kazunobu Kuriyama <kazunobu.kuriyama@nifty.com>
|
||||
* 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 LIBXKBCOMMON_BENCH_H
|
||||
#define LIBXKBCOMMON_BENCH_H
|
||||
|
||||
struct bench_time {
|
||||
long seconds;
|
||||
long microseconds;
|
||||
};
|
||||
|
||||
struct bench {
|
||||
struct bench_time start;
|
||||
struct bench_time stop;
|
||||
};
|
||||
|
||||
void
|
||||
bench_start(struct bench *bench);
|
||||
void
|
||||
bench_stop(struct bench *bench);
|
||||
|
||||
void
|
||||
bench_elapsed(const struct bench *bench, struct bench_time *result);
|
||||
/* The caller is responsibile to free() the returned string. */
|
||||
char *
|
||||
bench_elapsed_str(const struct bench *bench);
|
||||
|
||||
#endif /* LIBXKBCOMMON_BENCH_H */
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2023 Pierre Le Marre
|
||||
*
|
||||
* 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 "config.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "xkbcommon/xkbcommon-compose.h"
|
||||
|
||||
#include "../test/test.h"
|
||||
#include "bench.h"
|
||||
|
||||
#define BENCHMARK_ITERATIONS 1000
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
struct xkb_context *ctx;
|
||||
char *path;
|
||||
FILE *file;
|
||||
struct xkb_compose_table *table;
|
||||
struct xkb_compose_table_iterator *iter;
|
||||
struct xkb_compose_table_entry *entry;
|
||||
struct bench bench;
|
||||
char *elapsed;
|
||||
|
||||
ctx = test_get_context(CONTEXT_NO_FLAG);
|
||||
assert(ctx);
|
||||
|
||||
path = test_get_path("locale/en_US.UTF-8/Compose");
|
||||
file = fopen(path, "rb");
|
||||
if (file == NULL) {
|
||||
perror(path);
|
||||
free(path);
|
||||
xkb_context_unref(ctx);
|
||||
return -1;
|
||||
}
|
||||
free(path);
|
||||
|
||||
xkb_context_set_log_level(ctx, XKB_LOG_LEVEL_CRITICAL);
|
||||
xkb_context_set_log_verbosity(ctx, 0);
|
||||
|
||||
table = xkb_compose_table_new_from_file(ctx, file, "",
|
||||
XKB_COMPOSE_FORMAT_TEXT_V1,
|
||||
XKB_COMPOSE_COMPILE_NO_FLAGS);
|
||||
fclose(file);
|
||||
assert(table);
|
||||
|
||||
bench_start(&bench);
|
||||
for (int i = 0; i < BENCHMARK_ITERATIONS; i++) {
|
||||
iter = xkb_compose_table_iterator_new(table);
|
||||
while ((entry = xkb_compose_table_iterator_next(iter))) {
|
||||
assert (entry);
|
||||
}
|
||||
xkb_compose_table_iterator_free(iter);
|
||||
}
|
||||
bench_stop(&bench);
|
||||
|
||||
xkb_compose_table_unref(table);
|
||||
|
||||
elapsed = bench_elapsed_str(&bench);
|
||||
fprintf(stderr, "traversed %d compose tables in %ss\n",
|
||||
BENCHMARK_ITERATIONS, elapsed);
|
||||
free(elapsed);
|
||||
|
||||
xkb_context_unref(ctx);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* 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 "config.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "xkbcommon/xkbcommon-compose.h"
|
||||
|
||||
#include "../test/test.h"
|
||||
#include "bench.h"
|
||||
|
||||
#define BENCHMARK_ITERATIONS 1000
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
struct xkb_context *ctx;
|
||||
char *path;
|
||||
FILE *file;
|
||||
struct xkb_compose_table *table;
|
||||
struct bench bench;
|
||||
char *elapsed;
|
||||
|
||||
ctx = test_get_context(CONTEXT_NO_FLAG);
|
||||
assert(ctx);
|
||||
|
||||
path = test_get_path("locale/en_US.UTF-8/Compose");
|
||||
file = fopen(path, "rb");
|
||||
if (file == NULL) {
|
||||
perror(path);
|
||||
free(path);
|
||||
xkb_context_unref(ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
xkb_context_set_log_level(ctx, XKB_LOG_LEVEL_CRITICAL);
|
||||
xkb_context_set_log_verbosity(ctx, 0);
|
||||
|
||||
bench_start(&bench);
|
||||
for (int i = 0; i < BENCHMARK_ITERATIONS; i++) {
|
||||
rewind(file);
|
||||
table = xkb_compose_table_new_from_file(ctx, file, "",
|
||||
XKB_COMPOSE_FORMAT_TEXT_V1,
|
||||
XKB_COMPOSE_COMPILE_NO_FLAGS);
|
||||
assert(table);
|
||||
xkb_compose_table_unref(table);
|
||||
}
|
||||
bench_stop(&bench);
|
||||
|
||||
fclose(file);
|
||||
free(path);
|
||||
|
||||
elapsed = bench_elapsed_str(&bench);
|
||||
fprintf(stderr, "compiled %d compose tables in %ss\n",
|
||||
BENCHMARK_ITERATIONS, elapsed);
|
||||
free(elapsed);
|
||||
|
||||
xkb_context_unref(ctx);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2012 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 "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "../test/test.h"
|
||||
#include "bench.h"
|
||||
|
||||
#define BENCHMARK_ITERATIONS 20000000
|
||||
|
||||
static void
|
||||
bench_key_proc(struct xkb_state *state)
|
||||
{
|
||||
int8_t keys[256] = { 0 };
|
||||
xkb_keycode_t keycode;
|
||||
xkb_keysym_t keysym;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
|
||||
keycode = (rand() % (255 - 9)) + 9;
|
||||
if (keys[keycode]) {
|
||||
xkb_state_update_key(state, keycode, XKB_KEY_UP);
|
||||
keys[keycode] = 0;
|
||||
keysym = xkb_state_key_get_one_sym(state, keycode);
|
||||
(void) keysym;
|
||||
} else {
|
||||
xkb_state_update_key(state, keycode, XKB_KEY_DOWN);
|
||||
keys[keycode] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
struct xkb_context *ctx;
|
||||
struct xkb_keymap *keymap;
|
||||
struct xkb_state *state;
|
||||
struct bench bench;
|
||||
char *elapsed;
|
||||
|
||||
ctx = test_get_context(0);
|
||||
assert(ctx);
|
||||
|
||||
keymap = test_compile_rules(ctx, "evdev", "pc104", "us,ru,il,de",
|
||||
",,,neo", "grp:menu_toggle");
|
||||
assert(keymap);
|
||||
|
||||
state = xkb_state_new(keymap);
|
||||
assert(state);
|
||||
|
||||
xkb_context_set_log_level(ctx, XKB_LOG_LEVEL_CRITICAL);
|
||||
xkb_context_set_log_verbosity(ctx, 0);
|
||||
|
||||
srand((unsigned) time(NULL));
|
||||
|
||||
bench_start(&bench);
|
||||
bench_key_proc(state);
|
||||
bench_stop(&bench);
|
||||
|
||||
elapsed = bench_elapsed_str(&bench);
|
||||
fprintf(stderr, "ran %d iterations in %ss\n",
|
||||
BENCHMARK_ITERATIONS, elapsed);
|
||||
free(elapsed);
|
||||
|
||||
xkb_state_unref(state);
|
||||
xkb_keymap_unref(keymap);
|
||||
xkb_context_unref(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2012 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 "config.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "../test/test.h"
|
||||
#include "xkbcomp/xkbcomp-priv.h"
|
||||
#include "xkbcomp/rules.h"
|
||||
#include "bench.h"
|
||||
|
||||
#define BENCHMARK_ITERATIONS 20000
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct xkb_context *ctx;
|
||||
int i;
|
||||
struct xkb_rule_names rmlvo = {
|
||||
"evdev", "pc105", "us,il", ",", "ctrl:nocaps,grp:menu_toggle",
|
||||
};
|
||||
struct bench bench;
|
||||
char *elapsed;
|
||||
|
||||
ctx = test_get_context(0);
|
||||
assert(ctx);
|
||||
|
||||
xkb_context_set_log_level(ctx, XKB_LOG_LEVEL_CRITICAL);
|
||||
xkb_context_set_log_verbosity(ctx, 0);
|
||||
|
||||
bench_start(&bench);
|
||||
for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
|
||||
struct xkb_component_names kccgst;
|
||||
|
||||
assert(xkb_components_from_rules(ctx, &rmlvo, &kccgst));
|
||||
free(kccgst.keycodes);
|
||||
free(kccgst.types);
|
||||
free(kccgst.compat);
|
||||
free(kccgst.symbols);
|
||||
}
|
||||
bench_stop(&bench);
|
||||
|
||||
elapsed = bench_elapsed_str(&bench);
|
||||
fprintf(stderr, "processed %d rule files in %ss\n",
|
||||
BENCHMARK_ITERATIONS, elapsed);
|
||||
free(elapsed);
|
||||
|
||||
xkb_context_unref(ctx);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2009 Dan Nicholson
|
||||
*
|
||||
* 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 "config.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "../test/test.h"
|
||||
#include "bench.h"
|
||||
|
||||
#define BENCHMARK_ITERATIONS 1000
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct xkb_context *ctx;
|
||||
struct xkb_keymap *keymap;
|
||||
struct bench bench;
|
||||
char *elapsed;
|
||||
int i;
|
||||
|
||||
ctx = test_get_context(0);
|
||||
assert(ctx);
|
||||
|
||||
xkb_context_set_log_level(ctx, XKB_LOG_LEVEL_CRITICAL);
|
||||
xkb_context_set_log_verbosity(ctx, 0);
|
||||
|
||||
bench_start(&bench);
|
||||
for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
|
||||
keymap = test_compile_rules(ctx, "evdev", "evdev", "us", "", "");
|
||||
assert(keymap);
|
||||
xkb_keymap_unref(keymap);
|
||||
}
|
||||
bench_stop(&bench);
|
||||
|
||||
elapsed = bench_elapsed_str(&bench);
|
||||
fprintf(stderr, "compiled %d keymaps in %ss\n",
|
||||
BENCHMARK_ITERATIONS, elapsed);
|
||||
free(elapsed);
|
||||
|
||||
xkb_context_unref(ctx);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2020 Ran Benita <ran@unusedvar.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 "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <xcb/xkb.h>
|
||||
|
||||
#include "xkbcommon/xkbcommon.h"
|
||||
#include "xkbcommon/xkbcommon-x11.h"
|
||||
|
||||
#include "bench.h"
|
||||
|
||||
#define BENCHMARK_ITERATIONS 2500
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int ret;
|
||||
xcb_connection_t *conn;
|
||||
int32_t device_id;
|
||||
struct xkb_context *ctx;
|
||||
struct bench bench;
|
||||
char *elapsed;
|
||||
|
||||
conn = xcb_connect(NULL, NULL);
|
||||
if (!conn || xcb_connection_has_error(conn)) {
|
||||
fprintf(stderr, "Couldn't connect to X server: error code %d\n",
|
||||
conn ? xcb_connection_has_error(conn) : -1);
|
||||
ret = -1;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
ret = xkb_x11_setup_xkb_extension(conn,
|
||||
XKB_X11_MIN_MAJOR_XKB_VERSION,
|
||||
XKB_X11_MIN_MINOR_XKB_VERSION,
|
||||
XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS,
|
||||
NULL, NULL, NULL, NULL);
|
||||
if (!ret) {
|
||||
fprintf(stderr, "Couldn't setup XKB extension\n");
|
||||
goto err_conn;
|
||||
}
|
||||
|
||||
device_id = xkb_x11_get_core_keyboard_device_id(conn);
|
||||
if (device_id == -1) {
|
||||
ret = -1;
|
||||
fprintf(stderr, "Couldn't find core keyboard device\n");
|
||||
goto err_conn;
|
||||
}
|
||||
|
||||
ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||
if (!ctx) {
|
||||
ret = -1;
|
||||
fprintf(stderr, "Couldn't create xkb context\n");
|
||||
goto err_conn;
|
||||
}
|
||||
|
||||
bench_start(&bench);
|
||||
for (int i = 0; i < BENCHMARK_ITERATIONS; i++) {
|
||||
struct xkb_keymap *keymap;
|
||||
struct xkb_state *state;
|
||||
|
||||
keymap = xkb_x11_keymap_new_from_device(ctx, conn, device_id,
|
||||
XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
assert(keymap);
|
||||
|
||||
state = xkb_x11_state_new_from_device(keymap, conn, device_id);
|
||||
assert(state);
|
||||
|
||||
xkb_state_unref(state);
|
||||
xkb_keymap_unref(keymap);
|
||||
}
|
||||
bench_stop(&bench);
|
||||
ret = 0;
|
||||
|
||||
elapsed = bench_elapsed_str(&bench);
|
||||
fprintf(stderr, "retrieved %d keymaps from X in %ss\n",
|
||||
BENCHMARK_ITERATIONS, elapsed);
|
||||
free(elapsed);
|
||||
|
||||
xkb_context_unref(ctx);
|
||||
err_conn:
|
||||
xcb_disconnect(conn);
|
||||
err_out:
|
||||
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
# Fragments for the changelog
|
||||
|
||||
This directory contains fragments for the future [NEWS](../NEWS.md) file.
|
||||
|
||||
## Introduction
|
||||
|
||||
We use <code>[towncrier]</code> to produce useful, summarized news files.
|
||||
|
||||
There are 3 sections types:
|
||||
|
||||
- API: `changes/api`
|
||||
- Tools: `changes/tools`
|
||||
- Build System: `changes/build`
|
||||
|
||||
There are 3 news fragments types:
|
||||
|
||||
- Breaking changes: `.breaking`
|
||||
- New: `.feature`
|
||||
- Fixes: `.bugfix`
|
||||
|
||||
[towncrier]: https://pypi.org/project/towncrier/
|
||||
|
||||
## Adding a fragment
|
||||
|
||||
Add a short description of the change in a file `changes/SECTION/ID.FRAGMENT.md`,
|
||||
where:
|
||||
|
||||
- `SECTION` and `FRAGMENT` values are described in the [previous section](#introduction).
|
||||
- `ID` is the corresponding issue identifier on Github, if relevant. If there is
|
||||
no such issue, then `ID` should start with `+` and some identifier that make
|
||||
the file unique in the directory.
|
||||
|
||||
Examples:
|
||||
- A _bug fix_ for the _issue #463_ is an _API_ change, so the corresponding file
|
||||
should be named `changes/api/463.bugfix.md`.
|
||||
- A _new feature_ for _tools_ like #448 corresponds to e.g.
|
||||
`changes/tools/+add-verbose-opt.feature.md`.
|
||||
|
||||
Guidelines for the fragment files:
|
||||
|
||||
- Use the [Markdown] markup.
|
||||
- Use past tense, e.g. “Fixed a segfault”.
|
||||
- Look at the previous releases [NEWS](../NEWS.md) file for further examples.
|
||||
|
||||
[Markdown]: https://daringfireball.net/projects/markdown/
|
||||
|
||||
## Build the changelog
|
||||
|
||||
Install <code>[towncrier]</code> from Pypi:
|
||||
|
||||
```bash
|
||||
python3 -m pip install towncrier
|
||||
```
|
||||
|
||||
Then build the changelog:
|
||||
|
||||
```bash
|
||||
# Only check the result. Useful after adding a new fragment.
|
||||
towncrier build --draft --version 1.8.0
|
||||
# Write the changelog & delete the news fragments
|
||||
towncrier build --yes --version 1.8.0
|
||||
```
|
||||
@@ -1,60 +0,0 @@
|
||||
PROJECT_NAME = @PACKAGE_NAME@
|
||||
|
||||
PROJECT_NUMBER = @PACKAGE_VERSION@
|
||||
|
||||
OUTPUT_DIRECTORY = @OUTPUT_DIRECTORY@
|
||||
|
||||
BRIEF_MEMBER_DESC = NO
|
||||
|
||||
JAVADOC_AUTOBRIEF = YES
|
||||
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
|
||||
EXTENSION_MAPPING = no_extension=md
|
||||
|
||||
SORT_MEMBER_DOCS = NO
|
||||
|
||||
QUIET = $(DOXYGEN_QUIET)
|
||||
|
||||
WARN_IF_UNDOCUMENTED = NO
|
||||
|
||||
WARN_AS_ERROR = $(DOXYGEN_WARN_AS_ERROR)
|
||||
|
||||
INPUT = @INPUT@
|
||||
|
||||
FILE_PATTERNS = *.c \
|
||||
*.h
|
||||
|
||||
RECURSIVE = YES
|
||||
|
||||
USE_MDFILE_AS_MAINPAGE = README.md
|
||||
|
||||
VERBATIM_HEADERS = NO
|
||||
|
||||
ALPHABETICAL_INDEX = NO
|
||||
|
||||
IGNORE_PREFIX = xkb_ \
|
||||
XKB_ \
|
||||
rxkb_ \
|
||||
RXKB_
|
||||
|
||||
HTML_EXTRA_STYLESHEET = doc/doxygen-extra.css
|
||||
|
||||
TIMESTAMP = NO
|
||||
|
||||
ENUM_VALUES_PER_LINE = 1
|
||||
|
||||
SEARCHENGINE = NO
|
||||
|
||||
GENERATE_LATEX = NO
|
||||
|
||||
HAVE_DOT = YES
|
||||
|
||||
DOTFILE_DIRS = doc/diagrams
|
||||
|
||||
DOT_IMAGE_FORMAT = svg
|
||||
|
||||
ALIASES += figure="@htmlonly[block]<figure>@endhtmlonly"
|
||||
ALIASES += endfigure="@htmlonly[block]</figure>@endhtmlonly"
|
||||
ALIASES += figcaption="@htmlonly[block]<figcaption>@endhtmlonly"
|
||||
ALIASES += endfigcaption="@htmlonly[block]</figcaption>@endhtmlonly"
|
||||
@@ -1,64 +0,0 @@
|
||||
# Compatibility {#xkbcommon-compatibility}
|
||||
|
||||
@tableofcontents{html:2}
|
||||
|
||||
## XKB support {#xkb-v1-compatibility}
|
||||
|
||||
Relative to the XKB 1.0 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 @anchor geometry
|
||||
@anchor 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
|
||||
@anchor KcCGST-support
|
||||
+ 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
|
||||
|
||||
On the other hand, some features and extensions were added.
|
||||
|
||||
### Notable additions
|
||||
|
||||
- 32-bit keycodes
|
||||
- extended number of modifiers (planned)
|
||||
- extended number of groups (planned)
|
||||
- multiple keysyms per level
|
||||
+ such levels are ignored by x11/xkbcomp.
|
||||
- key names (e.g. `<AE11>`) can be longer than 4 characters.
|
||||
|
||||
## Compose support {#compose-support}
|
||||
|
||||
Relative to the standard implementation in libX11 (described in the
|
||||
Compose(5) man-page), some features are not supported:
|
||||
|
||||
- the (! MODIFIER) syntax
|
||||
+ parsed correctly but ignored.
|
||||
- using modifier keysyms in Compose sequences
|
||||
- several interactions with Braille keysyms
|
||||
@@ -1,67 +0,0 @@
|
||||
# WARNING: This file is autogenerated by: scripts/ensure-stable-doc-urls.py
|
||||
# Do not edit manually.
|
||||
annotated.html: []
|
||||
classes.html: []
|
||||
deprecated.html: []
|
||||
dir_63ce773eee1f9b680e6e312b48cc99ca.html: []
|
||||
dir_891596f32582d3133e8915e72908625f.html: []
|
||||
dir_d44c64559bbebec7f509842c48db8b23.html: []
|
||||
dir_e68e8157741866f444e17edd764ebbae.html: []
|
||||
error-index.html: []
|
||||
files.html: []
|
||||
functions.html: []
|
||||
functions_func.html: []
|
||||
functions_type.html: []
|
||||
functions_vars.html: []
|
||||
globals.html: []
|
||||
globals_defs.html: []
|
||||
globals_enum.html: []
|
||||
globals_eval.html: []
|
||||
globals_func.html: []
|
||||
globals_type.html: []
|
||||
graph_legend.html: []
|
||||
group__components.html: []
|
||||
group__compose.html: []
|
||||
group__context.html: []
|
||||
group__include-path.html: []
|
||||
group__keymap.html: []
|
||||
group__keysyms.html: []
|
||||
group__logging.html: []
|
||||
group__registry.html: []
|
||||
group__state.html: []
|
||||
group__x11.html: []
|
||||
index.html: []
|
||||
keymap-text-format-v1.html:
|
||||
- md_doc_keymap_format_text_v1.html
|
||||
md_doc_quick_guide.html: []
|
||||
modules.html: []
|
||||
pages.html: []
|
||||
rule-file-format.html:
|
||||
- md_doc_rules_format.html
|
||||
structrxkb__context.html: []
|
||||
structrxkb__iso3166__code.html: []
|
||||
structrxkb__iso639__code.html: []
|
||||
structrxkb__layout.html: []
|
||||
structrxkb__model.html: []
|
||||
structrxkb__option.html: []
|
||||
structrxkb__option__group.html: []
|
||||
structxkb__compose__state.html: []
|
||||
structxkb__compose__table.html: []
|
||||
structxkb__compose__table__entry.html: []
|
||||
structxkb__compose__table__iterator.html: []
|
||||
structxkb__context.html: []
|
||||
structxkb__keymap.html: []
|
||||
structxkb__rule__names.html: []
|
||||
structxkb__state.html: []
|
||||
todo.html: []
|
||||
user-configuration.html:
|
||||
- md_doc_user_configuration.html
|
||||
xkb-intro.html: []
|
||||
xkbcommon-compatibility.html:
|
||||
- md_doc_compat.html
|
||||
xkbcommon-compose_8h.html: []
|
||||
xkbcommon-keysyms_8h.html: []
|
||||
xkbcommon-names_8h.html: []
|
||||
xkbcommon-x11_8h.html: []
|
||||
xkbcommon_8h.html: []
|
||||
xkbregistry_8h.html: []
|
||||
@@ -1,75 +0,0 @@
|
||||
digraph {
|
||||
|
||||
node [shape=box]
|
||||
|
||||
subgraph process {
|
||||
RMLVO [
|
||||
label=<<i>End user configuration</i><br/><b>RMLVO:</b> <b>R</b>ules, <b>M</b>odel, <b>L</b>ayout, <b>V</b>ariant, <b>O</b>ptions>,
|
||||
penwidth=3,
|
||||
href="@ref RMLVO-intro",
|
||||
];
|
||||
RMLVO_resolution [
|
||||
label=<<i>RMLVO resolution</i><br/>Determine KcCGST using the specified rules file:<br/>match the given model, layout, variant and options fields>,
|
||||
style=rounded,
|
||||
color=blue
|
||||
];
|
||||
KcCGST [
|
||||
label=<<i>Layout database configuration</i><br/><b>KcCGST:</b> <b>K</b>ey<b>c</b>odes, <b>C</b>ompat, <b>G</b>eometry, <b>S</b>ymbols, <b>T</b>ypes>,
|
||||
penwidth=3,
|
||||
href="@ref KcCGST-intro"
|
||||
];
|
||||
KcCGST_resolution [
|
||||
label=<<i>KcCGST resolution</i><br/>Construct the keymap from its components>,
|
||||
style=rounded,
|
||||
color=blue
|
||||
];
|
||||
Keymap [
|
||||
label=<<i>Window server configuration</i><br/><b>Complete keymap</b>>,
|
||||
penwidth=3,
|
||||
href="@ref keymap-intro"
|
||||
];
|
||||
}
|
||||
|
||||
database [shape=none, label=<
|
||||
<table border="0" cellborder="1" cellspacing="0" cellpadding="4">
|
||||
<tr><td><b>Layout Database</b></td></tr>
|
||||
<hr/>
|
||||
<tr><td port="rules">Rules files</td></tr>
|
||||
<tr><td port="keycodes">Keycodes files</td></tr>
|
||||
<tr><td port="compat">Compat files</td></tr>
|
||||
<tr><td port="geometry">(Geometry files)</td></tr>
|
||||
<tr><td port="symbols">Symbols files</td></tr>
|
||||
<tr><td port="types">Types files</td></tr>
|
||||
</table>
|
||||
>];
|
||||
|
||||
{ rank = same; KcCGST; database }
|
||||
|
||||
edge [
|
||||
color=blue,
|
||||
arrowhead=normal,
|
||||
style=bold
|
||||
]
|
||||
{
|
||||
rankdir="TB";
|
||||
RMLVO -> RMLVO_resolution -> KcCGST -> KcCGST_resolution -> Keymap
|
||||
}
|
||||
|
||||
|
||||
edge [
|
||||
color=dimgrey,
|
||||
arrowhead=vee,
|
||||
style=solid
|
||||
]
|
||||
RMLVO:e -> database:rules:e [constraint=false];
|
||||
KcCGST:e -> database:keycodes:w [constraint=false];
|
||||
KcCGST:e -> database:compat:w [constraint=false];
|
||||
KcCGST:e -> database:symbols:w [constraint=false];
|
||||
KcCGST:e -> database:types:w [constraint=false];
|
||||
|
||||
database:rules:w -> RMLVO_resolution:e [constraint=false];
|
||||
database:keycodes:e -> KcCGST_resolution [constraint=false];
|
||||
database:compat:e -> KcCGST_resolution [constraint=false];
|
||||
database:symbols:e -> KcCGST_resolution [constraint=false];
|
||||
database:types:e -> KcCGST_resolution [constraint=false];
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
digraph {
|
||||
node [shape=box]
|
||||
|
||||
database [shape=none, label=<
|
||||
<table border="0" cellborder="1" cellspacing="0" cellpadding="4">
|
||||
<tr><td><b>Layout Database</b></td></tr>
|
||||
<hr/>
|
||||
<tr><td port="rules" href="@ref rule-file-format">Rules files</td></tr>
|
||||
<tr><td port="keycodes" href="@ref keycode-def">Keycodes files</td></tr>
|
||||
<tr><td port="compat" href="@ref key-action-def">Compat files</td></tr>
|
||||
<tr><td port="geometry">(Geometry files)</td></tr>
|
||||
<tr><td port="symbols" href="@ref keysym-def">Symbols files</td></tr>
|
||||
<tr><td port="types" href="@ref key-type-def">Key types files</td></tr>
|
||||
</table>
|
||||
>];
|
||||
|
||||
server [
|
||||
label=<<b>Server</b>>,
|
||||
style=rounded
|
||||
];
|
||||
|
||||
client [
|
||||
label=<<b>Client</b>>,
|
||||
style=rounded
|
||||
];
|
||||
|
||||
{ rank="same"; database; server; client }
|
||||
|
||||
database:keycodes -> server [
|
||||
label=<<i>xkb_keycodes</i> section>,
|
||||
labelhref="@ref the-xkb_keycodes-section"
|
||||
];
|
||||
database:compat -> server [
|
||||
label=<<i>xkb_compat</i> section>,
|
||||
labelhref="@ref the-xkb_compat-section"
|
||||
];
|
||||
database:symbols -> server [
|
||||
label=<<i>xkb_symbols</i> section>,
|
||||
labelhref="@ref the-xkb_symbols-section"
|
||||
];
|
||||
database:types -> server [
|
||||
label=<<i>xkb_types</i> section>,
|
||||
labelhref="@ref the-xkb_types-section"
|
||||
];
|
||||
|
||||
server:n -> database:rules [
|
||||
label=<RMLVO>,
|
||||
labelhref="@ref RMLVO-intro",
|
||||
labeltooltip="Rules, Model, Layout, Variant, Options"
|
||||
];
|
||||
server -> client [
|
||||
label=<complete keymap:<br/><i>xkb_keymap</i> block =<br/><i>xkb_keycodes</i> +<br/><i>xkb_compat</i> +<br/><i>xkb_symbols</i> +<br/><i>xkb_types</i>>,
|
||||
labelhref="@ref the-xkb_keymap-block"
|
||||
];
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
digraph
|
||||
{
|
||||
active_modifiers [
|
||||
label="Active modifiers",
|
||||
href="@ref xkb_state::xkb_state_mod_index_is_active"
|
||||
];
|
||||
modifiers_filter [
|
||||
shape=box,
|
||||
label=<<b>Filter modifiers</b><br/>Keep only meaningful modifiers for the key type>,
|
||||
style=rounded
|
||||
];
|
||||
filtered_modifiers [label="Filtered modifiers"];
|
||||
level_match [
|
||||
shape=box,
|
||||
label=<<b>Lookup modifiers combination</b><br/>Find the shift level<br/>matching exactly the modifiers,<br/>defaulting to the base level>,
|
||||
style=rounded
|
||||
];
|
||||
shift_level [
|
||||
label="Shift level",
|
||||
href="@ref level-def"
|
||||
];
|
||||
consume_modifiers [
|
||||
shape=box,
|
||||
label=<<b>Consume modifiers</b>>,
|
||||
style=rounded
|
||||
];
|
||||
consumed_modifiers [
|
||||
label="Consumed modifiers",
|
||||
href="@ref consumed-modifiers"
|
||||
];
|
||||
symbols_table_lookup [
|
||||
shape=box,
|
||||
label=<<b>Symbols table lookup</b>>,
|
||||
style=rounded
|
||||
];
|
||||
symbols_table [
|
||||
shape=box,
|
||||
label=<<b>Symbols table</b>>,
|
||||
href="@ref key-symbols-table",
|
||||
penwidth=2
|
||||
];
|
||||
keysym_pre_transformation [
|
||||
label="Raw keysym"
|
||||
];
|
||||
keysyms_transformations [
|
||||
shape=box,
|
||||
label=<<b>Keysyms transformations</b>>,
|
||||
href="@ref keysym-transformations",
|
||||
style=rounded
|
||||
];
|
||||
keysym_post_transformation [
|
||||
label="Final keysym"
|
||||
];
|
||||
|
||||
key_type [shape=none, label=<
|
||||
<table border="2" cellborder="1" cellspacing="0" cellpadding="4">
|
||||
<tr><td href="@ref the-xkb_types-section"><b>Key type</b></td></tr>
|
||||
<hr/>
|
||||
<tr><td port="modifiers" href="@ref key-type-modifiers">modifiers</td></tr>
|
||||
<tr><td port="map" href="@ref key-type-map">map</td></tr>
|
||||
<tr><td port="preserve" href="@ref key-type-preserve">preserve</td></tr>
|
||||
</table>
|
||||
>];
|
||||
|
||||
{ rank="same"; key_type; filtered_modifiers }
|
||||
{ rank="same"; level_match; consume_modifiers }
|
||||
{ rank="same"; symbols_table_lookup; symbols_table }
|
||||
|
||||
active_modifiers -> modifiers_filter;
|
||||
key_type:modifiers -> modifiers_filter
|
||||
// [
|
||||
// label=<<i>xkb_compat</i> section>,
|
||||
// labelhref="@ref the-xkb_compat-section"
|
||||
// ];
|
||||
//active_modifiers -> filtered_modifiers [label=""];
|
||||
modifiers_filter -> filtered_modifiers;
|
||||
filtered_modifiers -> level_match;
|
||||
key_type:map -> level_match;
|
||||
level_match -> shift_level;
|
||||
shift_level -> symbols_table_lookup;
|
||||
symbols_table -> symbols_table_lookup;
|
||||
symbols_table_lookup -> keysym_pre_transformation;
|
||||
keysym_pre_transformation -> keysyms_transformations;
|
||||
keysyms_transformations -> keysym_post_transformation;
|
||||
filtered_modifiers -> consume_modifiers;
|
||||
key_type:preserve -> consume_modifiers;
|
||||
consume_modifiers -> consumed_modifiers;
|
||||
consumed_modifiers -> keysyms_transformations;
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
div#top, div.header, div.contents {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 960px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
dl.todo dt::before {
|
||||
content: '🚧 ';
|
||||
}
|
||||
|
||||
span.todo::before {
|
||||
content: '🚧 ';
|
||||
}
|
||||
|
||||
/* Append external links with a distinctive icon */
|
||||
a[href^="http://"]::after,
|
||||
a[href^="https://"]::after
|
||||
{
|
||||
content: "";
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
margin-left: 4px;
|
||||
/* Bootstrap icon: https://icons.getbootstrap.com/icons/box-arrow-up-right/ */
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' class='bi bi-box-arrow-up-right' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5z'/%3E%3Cpath fill-rule='evenodd' d='M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0v-5z'/%3E%3C/svg%3E");
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Error index
|
||||
******************************************************************************/
|
||||
|
||||
div.example-container {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
justify-content: space-between;
|
||||
gap: 1em;
|
||||
}
|
||||
|
||||
div.example {
|
||||
flex-grow: 1;
|
||||
overflow-x: auto;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
div.example-inner {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
div.example-title {
|
||||
padding: 0 0 1em 0;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
div.example table code {
|
||||
/* Allow to keep 2 examples side by side */
|
||||
font-size: 0.72rem;
|
||||
}
|
||||
|
||||
div.example figure {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
figcaption {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
figcaption p {
|
||||
margin: 0;
|
||||
}
|
||||
@@ -1,207 +0,0 @@
|
||||
# Introduction to XKB {#xkb-intro}
|
||||
|
||||
__XKB__ stands for “X Keyboard Extension”. It may refer to either:
|
||||
|
||||
- a [protocol](@ref xkb-the-protocol)
|
||||
- a [keyboard layout configuration](@ref xkb-the-config)
|
||||
- a [text format](@ref xkb-the-text-format)
|
||||
|
||||
## XKB the protocol {#xkb-the-protocol}
|
||||
|
||||
A __protocol__ for the [X Windows System], that extends the core protocol.
|
||||
|
||||
_xkbcommon’s_ API is somehow derived from this API, but has been
|
||||
substantially reworked to function as a library instead of a protocol,
|
||||
and exposes fewer internal details to clients.
|
||||
|
||||
_xkbcommon_ does not depend on a particular windows system; for instance
|
||||
it is used by the [Wayland] protocol.
|
||||
|
||||
_xkbcommon_ provides the <code>[xkbcommon-x11]</code> module to interface
|
||||
a client with an X server using the XKB protocol. Relevant links:
|
||||
|
||||
- [The X Window System Protocol][X Protocol]
|
||||
- [The X Keyboard Extension: Protocol Specification][XKB Protocol]
|
||||
- [xkbcommon-x11]
|
||||
|
||||
|
||||
## XKB the keyboard keymap configuration {#xkb-the-config}
|
||||
|
||||
In order to use [the protocol](@ref xkb-the-protocol), one must first load a
|
||||
[complete keymap]. The keymap usually comes from the OS _layout database_,
|
||||
which is commonly [xkeyboard-config]. Since keymaps may have definitions in
|
||||
common, the database actually stores their basic components separately to allow
|
||||
maximum composability and coherence. A recipe to compose a keymap from its
|
||||
components is called a _keymap configuration_.
|
||||
|
||||
In XKB, there are several ways to define a keymap configuration. They all aim to
|
||||
produce a [complete keymap]. The following diagram presents an overview.
|
||||
Then they are presented hereinafter, ordered from end user to low-level
|
||||
implementation.
|
||||
|
||||
@dotfile xkb-configuration "XKB keymap configurations"
|
||||
<dl>
|
||||
<dt>
|
||||
RMLVO: <u>R</u>ules, <u>M</u>odel, <u>L</u>ayout, <u>V</u>ariant,
|
||||
<u>O</u>ptions @anchor RMLVO-intro
|
||||
</dt>
|
||||
<dd>
|
||||
This is the configuration the end user usually faces in the UI.
|
||||
The idea is to expose high level concepts such as [keyboard model] and
|
||||
[keyboard layout] to the user, then to _map_ them to the corresponding set
|
||||
of low-level configuration files (see [KcCGST]).
|
||||
|
||||
@note The RMLVO configurations actually available to the end user is managed
|
||||
by the `xkbregistry`. It uses an XML file, the _registry_, which exposes and
|
||||
documents the set of RMLVO settings in the layout database.
|
||||
|
||||
The RMLVO configuration consists of the following components:
|
||||
|
||||
<dl>
|
||||
<dt>Rules</dt>
|
||||
<dd>
|
||||
The rules define the _mapping_ from high to low level components.
|
||||
The rules _component_ is the file containing the set of rules to use.
|
||||
It is usually implicit and set by the system.
|
||||
|
||||
See the [rules file format](doc/rules-format.md) for further details.
|
||||
</dd>
|
||||
<dt>Model</dt>
|
||||
<dd>
|
||||
The name of the model of the keyboard hardware in use.
|
||||
It may depend on:
|
||||
|
||||
- The _location_ and _language_ of the user, because languages may
|
||||
require [specific keys][language input keys] for their input methods,
|
||||
such as the _muhenkan_ key on Japanese keyboard and the _Hanja_ key
|
||||
for Korean keyboards. The keyboard are usually classified by the
|
||||
[standard][keyboard standard] it is based on, e.g. ANSI, ISO, JIS,
|
||||
ABNT.
|
||||
- The keyboard _vendor:_ keyboard may have a set of keys that are not
|
||||
standard, or may be specific to an OS.
|
||||
</dd>
|
||||
<dt>Layout</dt>
|
||||
<dd>
|
||||
The identifier of the general layout to use. It usually refers to a
|
||||
country or a language.
|
||||
</dd>
|
||||
<dt>Variant</dt>
|
||||
<dd>
|
||||
Any minor variants on the general layout. It may be national variants
|
||||
</dd>
|
||||
<dt>Options</dt>
|
||||
<dd>
|
||||
Set of extra options to customize the standard layouts.
|
||||
|
||||
Examples: switch modifiers keys, location of the compose key, etc.
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>
|
||||
KcCGST: <u>K</u>ey<u>c</u>odes, <u>C</u>ompat, <u>G</u>eometry,
|
||||
<u>S</u>ymbols, <u>T</u>ypes @anchor KcCGST-intro
|
||||
</dt>
|
||||
<dd>
|
||||
This is the low-level configuration of XKB and how the files are actually
|
||||
organized in the _layout database_.
|
||||
It is not really intuitive or straight-forward for the uninitiated.
|
||||
|
||||
@note _xkbcommon_ [does not offer an API for KcCGST](@ref KcCGST-support):
|
||||
it is considered an implementation detail.
|
||||
Instead, [RMLVO] is the preferred way for the user to configure XKB.
|
||||
|
||||
The KcCGST configuration consists of the following components:
|
||||
|
||||
<dl>
|
||||
<dt>Key codes</dt>
|
||||
<dd>
|
||||
A translation of the raw [key codes] from the keyboard into
|
||||
symbolic names.
|
||||
</dd>
|
||||
<dt>Compatibility</dt>
|
||||
<dd>
|
||||
A specification of what internal actions modifiers and various
|
||||
special-purpose keys produce.
|
||||
</dd>
|
||||
<dt>Geometry</dt>
|
||||
<dd>
|
||||
A description of the physical layout of a keyboard.
|
||||
|
||||
@attention This legacy feature is [not supported](@ref geometry-support)
|
||||
by _xkbcommon_.
|
||||
</dd>
|
||||
<dt>Key symbols</dt>
|
||||
<dd>
|
||||
A translation of symbolic key codes into actual [key symbols] \(keysyms).
|
||||
</dd>
|
||||
<dt>Key types</dt>
|
||||
<dd>
|
||||
Types describe how a pressed key is affected by active [modifiers]
|
||||
such as Shift, Control, Alt, etc.
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>Complete Keymap @anchor keymap-intro</dt>
|
||||
<dd>
|
||||
A complete keymap is a _self-contained_ text file with all the [KcCGST]
|
||||
components needed to configure a keyboard. This is the result of the
|
||||
_resolution_ of the [RMLVO] and [KcCGST] configurations. This is also the
|
||||
format used by X11 and Wayland when prompted to _serialize_ the keymap in use.
|
||||
|
||||
@note This is a low-level configuration. [RMLVO] is the preferred way for the
|
||||
end user to configure XKB, but some _power users_ may need it for _avanced_
|
||||
configurations.
|
||||
|
||||
See the [XKB text format] for further details.
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
@note Layout making use of dead keys require a [Compose](@ref compose) file. The
|
||||
same applies when if using a [Compose key].
|
||||
|
||||
[key codes]: @ref keycode-def
|
||||
[key symbols]: @ref keysym-def
|
||||
[levels]: @ref level-def
|
||||
[modifiers]: @ref modifier-def
|
||||
[RMLVO]: @ref RMLVO-intro
|
||||
[KcCGST]: @ref KcCGST-intro
|
||||
[complete keymap]: @ref keymap-intro
|
||||
[Compose key]: https://en.wikipedia.org/wiki/Compose_key
|
||||
[XKB text format]: @ref xkb-the-text-format
|
||||
|
||||
|
||||
## XKB the text format {#xkb-the-text-format}
|
||||
|
||||
A __text format__ to define keyboard keymaps. XKB 1.0 is the specification
|
||||
implemented in current X servers. The format supported by _xkbcommon_
|
||||
is very close to XKB 1.0, with some removals and additions. See the
|
||||
[compatibility] page for further details.
|
||||
|
||||
The format supported by _xkbcommon_ is documented at the page
|
||||
“[The XKB keymap text format, V1][keymap-format-text-v1]”.
|
||||
|
||||
The documentation of the _original_ XKB 1.0 format is much more scarce than
|
||||
for the protocol. Some priceless resources are:
|
||||
|
||||
- [Ivan Pascal's XKB documentation][ivan-pascal]
|
||||
- [An Unreliable Guide to XKB Configuration][unreliable-guide]
|
||||
- [ArchWiki XKB page][arch-wiki]
|
||||
|
||||
[X Windows System]: https://en.wikipedia.org/wiki/X_Window_System
|
||||
[X Protocol]: https://www.x.org/releases/current/doc/xproto/x11protocol.html#Keyboards
|
||||
[XKB Protocol]: https://www.x.org/releases/current/doc/kbproto/xkbproto.html
|
||||
[xkbcommon-x11]: @ref x11-overview
|
||||
[Wayland]: https://wayland.freedesktop.org/docs/html/apa.html#protocol-spec-wl_keyboard
|
||||
[compatibility]: @ref xkb-v1-compatibility
|
||||
[keymap-format-text-v1]: doc/keymap-format-text-v1.md
|
||||
[ivan-pascal]: https://web.archive.org/web/20190724015820/http://pascal.tsu.ru/en/xkb/
|
||||
[unreliable-guide]: https://www.charvolant.org/doug/xkb/html/index.html
|
||||
[arch-wiki]: https://wiki.archlinux.org/index.php/X_keyboard_extension
|
||||
[keyboard model]: https://en.wikipedia.org/wiki/Computer_keyboard
|
||||
[keymap]: https://en.wikipedia.org/wiki/Keyboard_layout
|
||||
[keyboard layout]: https://en.wikipedia.org/wiki/Keyboard_layout
|
||||
[xkeyboard-config]: https://gitlab.freedesktop.org/xkeyboard-config/xkeyboard-config
|
||||
[keyboard standard]: https://en.wikipedia.org/wiki/Computer_keyboard#Types_and_standards
|
||||
[language input keys]: https://en.wikipedia.org/wiki/Language_input_keys
|
||||
|
||||
@todo Explain how to configure XKB, with examples
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,742 +0,0 @@
|
||||
# Error index {#error-index}
|
||||
|
||||
<!--
|
||||
NOTE: This file has been generated automatically by “update-message-registry.py”.
|
||||
Do not edit manually!
|
||||
-->
|
||||
|
||||
This page lists the warnings and errors generated by xkbcommon.
|
||||
There are currently 55 entries.
|
||||
|
||||
@todo The documentation of the log messages is a work in progress.
|
||||
|
||||
## Index
|
||||
|
||||
| Code | Identifier | Description | Type |
|
||||
| --------- | ---------------------------- | ----------- | ---- |
|
||||
| [XKB-034] | `malformed-number-literal` | Warn on malformed number literals | Error |
|
||||
| [XKB-043] | `conflicting-key-type-preserve-entries` | Conflicting “preserve” entries in a key type | Warning |
|
||||
| [XKB-060] | `unsupported-modifier-mask` | Warn on unsupported modifier mask | Error |
|
||||
| [XKB-077] | `expected-array-entry` | Expected an array entry, but the index is missing | Error |
|
||||
| [XKB-101] | `illegal-keycode-alias` | Illegal keycode alias with the name of a real key | Warning |
|
||||
| [XKB-107] | `unrecognized-keysym` | Warn on unrecognized keysyms | Warning |
|
||||
| [XKB-123] | `undeclared-virtual-modifier` | A virtual modifier is used before being declared | Error |
|
||||
| [XKB-134] | `insufficient-buffer-size` | A buffer has an insufficient size | Error |
|
||||
| [XKB-150] | `wrong-statement-type` | The type of the statement is not allowed in the context | Error |
|
||||
| [XKB-172] | `unsupported-geometry-section` | Geometry sections are not supported | Warning |
|
||||
| [XKB-183] | `cannot-infer-key-type` | Warn if no key type can be inferred | Warning |
|
||||
| [XKB-193] | `invalid-escape-sequence` | Invalid escape sequence in a string | Warning |
|
||||
| [XKB-195] | `illegal-key-type-preserve-result` | The result of a key type “preserve” entry must be a subset of its input modifiers. | Warning |
|
||||
| [XKB-203] | `invalid-include-statement` | Syntax error in the include statement | Error |
|
||||
| [XKB-206] | `invalid-modmap-entry` | A modmap entry is invalid | Error |
|
||||
| [XKB-237] | `unsupported-group-index` | Warn when a group index is not supported | Error |
|
||||
| [XKB-239] | `conflicting-key-type-level-names` | The name of a key type level is defined multiple times. | Warning |
|
||||
| [XKB-254] | `invalid-set-default-statement` | Invalid statement setting default values | Error |
|
||||
| [XKB-266] | `conflicting-key-type-map-entry` | Conflicting “map” entries in type definition | Warning |
|
||||
| [XKB-286] | `undefined-key-type` | Warn if using an undefined key type | Warning |
|
||||
| [XKB-305] | `non-base-group-name` | Warn if a group name was defined for group other than the first one | Warning |
|
||||
| [XKB-312] | `unsupported-shift-level` | Warn when a shift level is not supported | Error |
|
||||
| [XKB-338] | `included-file-not-found` | Could not find a file used in an include statement | Error |
|
||||
| [XKB-345] | `unknown-operator` | Use of an operator that is unknown and thus unsupported | Error |
|
||||
| [XKB-378] | `duplicate-entry` | An entry is duplicated and will be ignored | Warning |
|
||||
| [XKB-386] | `recursive-include` | Included files form cycle | Error |
|
||||
| [XKB-407] | `conflicting-key-type-definitions` | Conflicting definitions of a key type | Warning |
|
||||
| [XKB-428] | `global-defaults-wrong-scope` | A global defaults statement is in a wrong scope and should be moved | Error |
|
||||
| [XKB-433] | `missing-default-section` | Missing default section in included file | Warning |
|
||||
| [XKB-461] | `conflicting-key-symbol` | Warn if there are conflicting keysyms while merging keys | Warning |
|
||||
| [XKB-478] | `invalid-operation` | The operation is invalid in the context | Error |
|
||||
| [XKB-489] | `numeric-keysym` | Warn on numeric keysym (other than 0-9) | Warning |
|
||||
| [XKB-516] | `extra-symbols-ignored` | <span class="todo">TODO:</span> add description | Warning |
|
||||
| [XKB-523] | `conflicting-key-name` | Conflicting definitions of a key name or alias | Warning |
|
||||
| [XKB-550] | `allocation-error` | Cannot allocate memory | Error |
|
||||
| [XKB-578] | `wrong-field-type` | Warn when a field has not the expected type | Error |
|
||||
| [XKB-623] | `invalid-real-modifier` | Invalid _real_ modifier | Error |
|
||||
| [XKB-645] | `unknown-char-escape-sequence` | Warn on unknown escape sequence in string literal | Warning |
|
||||
| [XKB-661] | `invalid-included-file` | The target file of an include statement could not be processed | Error |
|
||||
| [XKB-700] | `multiple-groups-at-once` | Warn if a key defines multiple groups at once | Warning |
|
||||
| [XKB-711] | `unsupported-symbols-field` | A legacy X11 symbol field is not supported | Warning |
|
||||
| [XKB-769] | `invalid-syntax` | The syntax is invalid and the file cannot be parsed | Error |
|
||||
| [XKB-770] | `undefined-keycode` | Reference to an undefined keycode | Warning |
|
||||
| [XKB-784] | `invalid-expression-type` | An expression has not the expected type | Error |
|
||||
| [XKB-796] | `invalid-value` | A value is invalid and will be ignored | Error |
|
||||
| [XKB-800] | `conflicting-modmap` | Warn if there are conflicting modmap definitions | Warning |
|
||||
| [XKB-812] | `unknown-field` | A field is unknown and will be ignored | Error |
|
||||
| [XKB-883] | `conflicting-key-action` | Warn if there are conflicting actions while merging keys | Warning |
|
||||
| [XKB-893] | `conflicting-key-type-merging-groups` | Warn if there are conflicting key types while merging groups | Warning |
|
||||
| [XKB-901] | `conflicting-key-symbols-entry` | Conflicting symbols entry for a key | Error |
|
||||
| [XKB-903] | `missing-symbols-group-name-index` | Missing group index in a group name entry | Warning |
|
||||
| [XKB-935] | `conflicting-key-fields` | Warn if there are conflicting fields while merging keys | Warning |
|
||||
| [XKB-949] | `invalid-identifier` | An identifier is used but is not built-in | Error |
|
||||
| [XKB-965] | `unresolved-keymap-symbol` | Warn if using a symbol not defined in the keymap | Warning |
|
||||
| [XKB-971] | `undeclared-modifiers-in-key-type` | Some modifiers used in a key type “map” or “preserve” entry are not declared | Warning |
|
||||
|
||||
## Details
|
||||
|
||||
### XKB-034 – Malformed number literal {#XKB-034}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Error</dd>
|
||||
<dt>Summary</dt><dd>Warn on malformed number literals</dd>
|
||||
</dl>
|
||||
|
||||
xkbcommon can parse the following number literal formats:
|
||||
|
||||
- *decimal integer:* 1, 123, etc.
|
||||
- *decimal floating-point number:* 1.23, etc.
|
||||
- *hexadecimal integer:* prefixed with “0x”: 0x123, 0xff, 0xAB, etc.
|
||||
|
||||
|
||||
### XKB-043 – Conflicting key type preserve entries {#XKB-043}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Warning</dd>
|
||||
<dt>Summary</dt><dd>Conflicting “preserve” entries in a key type</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-060 – Unsupported modifier mask {#XKB-060}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Error</dd>
|
||||
<dt>Summary</dt><dd>Warn on unsupported modifier mask</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-077 – Expected array entry {#XKB-077}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Error</dd>
|
||||
<dt>Summary</dt><dd>Expected an array entry, but the index is missing</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-101 – Illegal keycode alias {#XKB-101}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Warning</dd>
|
||||
<dt>Summary</dt><dd>Illegal keycode alias with the name of a real key</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-107 – Unrecognized keysym {#XKB-107}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Warning</dd>
|
||||
<dt>Summary</dt><dd>Warn on unrecognized keysyms</dd>
|
||||
</dl>
|
||||
|
||||
xkbcommon replaces keysyms it does not recognize by the keysym `NoSymbol`.
|
||||
|
||||
You may find the list of supported keysyms in
|
||||
`include/xkbcommon/xkbcommon-keysyms.h`.
|
||||
|
||||
|
||||
#### Examples
|
||||
|
||||
<details>
|
||||
<summary>Unrecognized keysym “`coma`”</summary>
|
||||
|
||||
**Error message:**
|
||||
|
||||
```
|
||||
xkbcommon: WARNING: [XKB-107] de:31:20: unrecognized keysym "coma"
|
||||
```
|
||||
|
||||
xkbcommon does not recognize the keysym “`coma`”. It is most probably
|
||||
a typo for “<code>com<em>m</em>a</code>”.
|
||||
See: `XKB_KEY_comma` in `include/xkbcommon/xkbcommon-keysyms.h`.
|
||||
|
||||
**Fix:**
|
||||
<div class="example-container">
|
||||
<div class="example">
|
||||
<div class="example-inner">
|
||||
<div class="example-title">Before</div>
|
||||
```c
|
||||
key <AB08> {[ coma, semicolon, periodcentered, multiply ]};
|
||||
```
|
||||
</div>
|
||||
</div>
|
||||
<div class="example">
|
||||
<div class="example-inner">
|
||||
<div class="example-title">After</div>
|
||||
```c
|
||||
key <AB08> {[ comma, semicolon, periodcentered, multiply ]};
|
||||
```
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
### XKB-123 – Undeclared virtual modifier {#XKB-123}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Error</dd>
|
||||
<dt>Summary</dt><dd>A virtual modifier is used before being declared</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-134 – Insufficient buffer size {#XKB-134}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Error</dd>
|
||||
<dt>Summary</dt><dd>A buffer has an insufficient size</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-150 – Wrong statement type {#XKB-150}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Error</dd>
|
||||
<dt>Summary</dt><dd>The type of the statement is not allowed in the context</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-172 – Unsupported geometry section {#XKB-172}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Warning</dd>
|
||||
<dt>Summary</dt><dd>Geometry sections are not supported</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-183 – Cannot infer key type {#XKB-183}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Warning</dd>
|
||||
<dt>Summary</dt><dd>Warn if no key type can be inferred</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-193 – Invalid escape sequence {#XKB-193}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Warning</dd>
|
||||
<dt>Summary</dt><dd>Invalid escape sequence in a string</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-195 – Illegal key type preserve result {#XKB-195}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Warning</dd>
|
||||
<dt>Summary</dt><dd>The result of a key type “preserve” entry must be a subset of its input modifiers.</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-203 – Invalid include statement {#XKB-203}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Error</dd>
|
||||
<dt>Summary</dt><dd>Syntax error in the include statement</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-206 – Invalid modmap entry {#XKB-206}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Error</dd>
|
||||
<dt>Summary</dt><dd>A modmap entry is invalid</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-237 – Unsupported group index {#XKB-237}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Error</dd>
|
||||
<dt>Summary</dt><dd>Warn when a group index is not supported</dd>
|
||||
</dl>
|
||||
|
||||
xkbcommon supports group index in the range (1..4).
|
||||
|
||||
|
||||
### XKB-239 – Conflicting key type level names {#XKB-239}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Warning</dd>
|
||||
<dt>Summary</dt><dd>The name of a key type level is defined multiple times.</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-254 – Invalid set default statement {#XKB-254}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Error</dd>
|
||||
<dt>Summary</dt><dd>Invalid statement setting default values</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-266 – Conflicting key type map entry {#XKB-266}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Warning</dd>
|
||||
<dt>Summary</dt><dd>Conflicting “map” entries in type definition</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-286 – Undefined key type {#XKB-286}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Warning</dd>
|
||||
<dt>Summary</dt><dd>Warn if using an undefined key type</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-305 – Non base group name {#XKB-305}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Warning</dd>
|
||||
<dt>Summary</dt><dd>Warn if a group name was defined for group other than the first one</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-312 – Unsupported shift level {#XKB-312}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Error</dd>
|
||||
<dt>Summary</dt><dd>Warn when a shift level is not supported</dd>
|
||||
</dl>
|
||||
|
||||
Shift levels are _one_-indexed. xkbcommon supports two formats of shift levels:
|
||||
as numbers and as identifiers `LevelN`, where `N` is in the range (1..8).
|
||||
|
||||
|
||||
### XKB-338 – Included file not found {#XKB-338}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Error</dd>
|
||||
<dt>Summary</dt><dd>Could not find a file used in an include statement</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-345 – Unknown operator {#XKB-345}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Error</dd>
|
||||
<dt>Summary</dt><dd>Use of an operator that is unknown and thus unsupported</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-378 – Duplicate entry {#XKB-378}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Warning</dd>
|
||||
<dt>Summary</dt><dd>An entry is duplicated and will be ignored</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-386 – Recursive include {#XKB-386}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.7.0</dd>
|
||||
<dt>Type</dt><dd>Error</dd>
|
||||
<dt>Summary</dt><dd>Included files form cycle</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-407 – Conflicting key type definitions {#XKB-407}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Warning</dd>
|
||||
<dt>Summary</dt><dd>Conflicting definitions of a key type</dd>
|
||||
</dl>
|
||||
|
||||
The given key type is defined multiple times, but only one definition is kept.
|
||||
|
||||
|
||||
### XKB-428 – Global defaults wrong scope {#XKB-428}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Error</dd>
|
||||
<dt>Summary</dt><dd>A global defaults statement is in a wrong scope and should be moved</dd>
|
||||
</dl>
|
||||
|
||||
#### Examples
|
||||
|
||||
<details>
|
||||
<summary>Default key type in key statement</summary>
|
||||
|
||||
**Error message:**
|
||||
|
||||
```
|
||||
xkbcommon: ERROR: [XKB-428] Cannot set global defaults for "type" element
|
||||
within a key statement: move statements to the global file scope.
|
||||
Assignment to "key.type" ignored.
|
||||
```
|
||||
|
||||
**Fix:**
|
||||
<div class="example-container">
|
||||
<div class="example">
|
||||
<div class="example-inner">
|
||||
<div class="example-title">Before</div>
|
||||
```c
|
||||
key <AE01> {
|
||||
key.type = "FOUR_LEVEL_SEMIALPHABETIC",
|
||||
symbols = [q, Q, at]
|
||||
};
|
||||
```
|
||||
</div>
|
||||
</div>
|
||||
<div class="example">
|
||||
<div class="example-inner">
|
||||
<div class="example-title">After</div>
|
||||
```c
|
||||
// Either put default key type in global file scope
|
||||
key.type = "FOUR_LEVEL_SEMIALPHABETIC";
|
||||
key <AE01> { [q, Q, at] };
|
||||
// or use a local setting (unqualified, i.e. without `key.`)
|
||||
key <AE01> {
|
||||
type = "FOUR_LEVEL_SEMIALPHABETIC",
|
||||
symbols = [ q, Q, at ]
|
||||
};
|
||||
```
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
### XKB-433 – Missing default section {#XKB-433}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Warning</dd>
|
||||
<dt>Summary</dt><dd>Missing default section in included file</dd>
|
||||
</dl>
|
||||
|
||||
When using an include statement, the included file may contains multiple sections.
|
||||
The include statement may specify the name of the section to include, or leave it
|
||||
unspecified. In the latter case, the included file must then define a *default* section.
|
||||
The present warning is shown when no default section is defined.
|
||||
|
||||
To solve this, either fix the include statement by specifying the exact section to
|
||||
include, or declare a default section in the included file.
|
||||
|
||||
|
||||
### XKB-461 – Conflicting key symbol {#XKB-461}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Warning</dd>
|
||||
<dt>Summary</dt><dd>Warn if there are conflicting keysyms while merging keys</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-478 – Invalid operation {#XKB-478}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Error</dd>
|
||||
<dt>Summary</dt><dd>The operation is invalid in the context</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-489 – Numeric keysym {#XKB-489}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.6.0</dd>
|
||||
<dt>Type</dt><dd>Warning</dd>
|
||||
<dt>Summary</dt><dd>Warn on numeric keysym (other than 0-9)</dd>
|
||||
</dl>
|
||||
|
||||
Numeric keysyms are not human-friendly. Use the corresponding named keysym
|
||||
or Unicode keysym, if available.
|
||||
|
||||
|
||||
#### Examples
|
||||
|
||||
<details>
|
||||
<summary>Hexadecimal keysym `0x1001ed0`</summary>
|
||||
|
||||
**Error message:**
|
||||
|
||||
```
|
||||
xkbcommon: WARNING: [XKB-489] numeric keysym "0x1001ed0"
|
||||
```
|
||||
|
||||
**Fix:**
|
||||
<div class="example-container">
|
||||
<div class="example">
|
||||
<div class="example-inner">
|
||||
<div class="example-title">Before</div>
|
||||
```c
|
||||
key <AE01> { [ 0x1001ed0] };
|
||||
```
|
||||
</div>
|
||||
</div>
|
||||
<div class="example">
|
||||
<div class="example-inner">
|
||||
<div class="example-title">After</div>
|
||||
```c
|
||||
// Preferred form: human-friendly
|
||||
key <AE01> { [ Ocircumflexacute ] };
|
||||
// or
|
||||
key <AE01> { [ U1ED0 ] };
|
||||
```
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
### XKB-516 – Extra symbols ignored {#XKB-516}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Warning</dd>
|
||||
<dt>Summary</dt><dd><span class="todo">TODO:</span> add description</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-523 – Conflicting key name {#XKB-523}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Warning</dd>
|
||||
<dt>Summary</dt><dd>Conflicting definitions of a key name or alias</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-550 – Allocation error {#XKB-550}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Error</dd>
|
||||
<dt>Summary</dt><dd>Cannot allocate memory</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-578 – Wrong field type {#XKB-578}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Error</dd>
|
||||
<dt>Summary</dt><dd>Warn when a field has not the expected type</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-623 – Invalid real modifier {#XKB-623}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Error</dd>
|
||||
<dt>Summary</dt><dd>Invalid _real_ modifier</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-645 – Unknown char escape sequence {#XKB-645}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Warning</dd>
|
||||
<dt>Summary</dt><dd>Warn on unknown escape sequence in string literal</dd>
|
||||
</dl>
|
||||
|
||||
xkbcommon support the following escape sequences in string literals:
|
||||
|
||||
| Escape sequence | Corresponding character |
|
||||
| --------------- | ----------------------------------- |
|
||||
| `\b` | `U+0008` Backspace |
|
||||
| `\t` | `U+0009` Character tabulation |
|
||||
| `\n` | `U+000A` Line feed |
|
||||
| `\v` | `U+000B` Vertical tabulation |
|
||||
| `\f` | `U+000C` Form feed |
|
||||
| `\r` | `U+000D` Carriage return |
|
||||
| `\e` | `U+001B` Escape |
|
||||
| `\\` | `U+005C` Backslash |
|
||||
| `\NNN` | _Octal_ escape, from `\0` to `\777` |
|
||||
|
||||
|
||||
### XKB-661 – Invalid included file {#XKB-661}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Error</dd>
|
||||
<dt>Summary</dt><dd>The target file of an include statement could not be processed</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-700 – Multiple groups at once {#XKB-700}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Warning</dd>
|
||||
<dt>Summary</dt><dd>Warn if a key defines multiple groups at once</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-711 – Unsupported symbols field {#XKB-711}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Warning</dd>
|
||||
<dt>Summary</dt><dd>A legacy X11 symbol field is not supported</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-769 – Invalid syntax {#XKB-769}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Error</dd>
|
||||
<dt>Summary</dt><dd>The syntax is invalid and the file cannot be parsed</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-770 – Undefined keycode {#XKB-770}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Warning</dd>
|
||||
<dt>Summary</dt><dd>Reference to an undefined keycode</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-784 – Invalid expression type {#XKB-784}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Error</dd>
|
||||
<dt>Summary</dt><dd>An expression has not the expected type</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-796 – Invalid value {#XKB-796}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Error</dd>
|
||||
<dt>Summary</dt><dd>A value is invalid and will be ignored</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-800 – Conflicting modmap {#XKB-800}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Warning</dd>
|
||||
<dt>Summary</dt><dd>Warn if there are conflicting modmap definitions</dd>
|
||||
</dl>
|
||||
|
||||
@todo detailed explanation and examples
|
||||
|
||||
|
||||
### XKB-812 – Unknown field {#XKB-812}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Error</dd>
|
||||
<dt>Summary</dt><dd>A field is unknown and will be ignored</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-883 – Conflicting key action {#XKB-883}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Warning</dd>
|
||||
<dt>Summary</dt><dd>Warn if there are conflicting actions while merging keys</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-893 – Conflicting key type merging groups {#XKB-893}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Warning</dd>
|
||||
<dt>Summary</dt><dd>Warn if there are conflicting key types while merging groups</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-901 – Conflicting key symbols entry {#XKB-901}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Error</dd>
|
||||
<dt>Summary</dt><dd>Conflicting symbols entry for a key</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-903 – Missing symbols group name index {#XKB-903}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Warning</dd>
|
||||
<dt>Summary</dt><dd>Missing group index in a group name entry</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-935 – Conflicting key fields {#XKB-935}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Warning</dd>
|
||||
<dt>Summary</dt><dd>Warn if there are conflicting fields while merging keys</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-949 – Invalid identifier {#XKB-949}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Error</dd>
|
||||
<dt>Summary</dt><dd>An identifier is used but is not built-in</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-965 – Unresolved keymap symbol {#XKB-965}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Warning</dd>
|
||||
<dt>Summary</dt><dd>Warn if using a symbol not defined in the keymap</dd>
|
||||
</dl>
|
||||
|
||||
### XKB-971 – Undeclared modifiers in key type {#XKB-971}
|
||||
|
||||
<dl>
|
||||
<dt>Since</dt><dd>1.0.0</dd>
|
||||
<dt>Type</dt><dd>Warning</dd>
|
||||
<dt>Summary</dt><dd>Some modifiers used in a key type “map” or “preserve” entry are not declared</dd>
|
||||
</dl>
|
||||
|
||||
The modifiers used in `map` or `preserve` entries should be declared using the entry
|
||||
`modifiers` in the key type.
|
||||
|
||||
|
||||
[XKB-034]: @ref XKB-034
|
||||
[XKB-043]: @ref XKB-043
|
||||
[XKB-060]: @ref XKB-060
|
||||
[XKB-077]: @ref XKB-077
|
||||
[XKB-101]: @ref XKB-101
|
||||
[XKB-107]: @ref XKB-107
|
||||
[XKB-123]: @ref XKB-123
|
||||
[XKB-134]: @ref XKB-134
|
||||
[XKB-150]: @ref XKB-150
|
||||
[XKB-172]: @ref XKB-172
|
||||
[XKB-183]: @ref XKB-183
|
||||
[XKB-193]: @ref XKB-193
|
||||
[XKB-195]: @ref XKB-195
|
||||
[XKB-203]: @ref XKB-203
|
||||
[XKB-206]: @ref XKB-206
|
||||
[XKB-237]: @ref XKB-237
|
||||
[XKB-239]: @ref XKB-239
|
||||
[XKB-254]: @ref XKB-254
|
||||
[XKB-266]: @ref XKB-266
|
||||
[XKB-286]: @ref XKB-286
|
||||
[XKB-305]: @ref XKB-305
|
||||
[XKB-312]: @ref XKB-312
|
||||
[XKB-338]: @ref XKB-338
|
||||
[XKB-345]: @ref XKB-345
|
||||
[XKB-378]: @ref XKB-378
|
||||
[XKB-386]: @ref XKB-386
|
||||
[XKB-407]: @ref XKB-407
|
||||
[XKB-428]: @ref XKB-428
|
||||
[XKB-433]: @ref XKB-433
|
||||
[XKB-461]: @ref XKB-461
|
||||
[XKB-478]: @ref XKB-478
|
||||
[XKB-489]: @ref XKB-489
|
||||
[XKB-516]: @ref XKB-516
|
||||
[XKB-523]: @ref XKB-523
|
||||
[XKB-550]: @ref XKB-550
|
||||
[XKB-578]: @ref XKB-578
|
||||
[XKB-623]: @ref XKB-623
|
||||
[XKB-645]: @ref XKB-645
|
||||
[XKB-661]: @ref XKB-661
|
||||
[XKB-700]: @ref XKB-700
|
||||
[XKB-711]: @ref XKB-711
|
||||
[XKB-769]: @ref XKB-769
|
||||
[XKB-770]: @ref XKB-770
|
||||
[XKB-784]: @ref XKB-784
|
||||
[XKB-796]: @ref XKB-796
|
||||
[XKB-800]: @ref XKB-800
|
||||
[XKB-812]: @ref XKB-812
|
||||
[XKB-883]: @ref XKB-883
|
||||
[XKB-893]: @ref XKB-893
|
||||
[XKB-901]: @ref XKB-901
|
||||
[XKB-903]: @ref XKB-903
|
||||
[XKB-935]: @ref XKB-935
|
||||
[XKB-949]: @ref XKB-949
|
||||
[XKB-965]: @ref XKB-965
|
||||
[XKB-971]: @ref XKB-971
|
||||
@@ -1,74 +0,0 @@
|
||||
# Error index { {#--#} #error-index}
|
||||
|
||||
{# NOTE: Prevent Doxygen issue by writing the comment after the first header. #}
|
||||
<!--
|
||||
NOTE: This file has been generated automatically by “{{script}}”.
|
||||
Do not edit manually!
|
||||
-->
|
||||
|
||||
This page lists the warnings and errors generated by xkbcommon.
|
||||
There are currently {{ entries|length }} entries.
|
||||
|
||||
@todo The documentation of the log messages is a work in progress.
|
||||
|
||||
## Index
|
||||
|
||||
| Code | Identifier | Description | Type |
|
||||
| --------- | ---------------------------- | ----------- | ---- |
|
||||
{% for entry in entries %}
|
||||
| [{{entry.message_code}}] | `{{entry.id}}` | {{entry.description|prepend_todo}} | {{entry.type|capitalize}} |
|
||||
{% endfor %}
|
||||
|
||||
## Details
|
||||
|
||||
{% for entry in entries %}
|
||||
### {{entry.message_code}} – {{entry.message_name}} { {#--#}#{{entry.message_code}}}
|
||||
|
||||
<dl>
|
||||
{% if entry.removed %}
|
||||
<dt>Added in</dt><dd>{{entry.added}}</dd>
|
||||
<dt>Removed in</dt><dd>{{entry.removed}}</dd>
|
||||
{% else %}
|
||||
<dt>Since</dt><dd>{{entry.added}}</dd>
|
||||
{% endif %}
|
||||
<dt>Type</dt><dd>{{entry.type|capitalize}}</dd>
|
||||
<dt>Summary</dt><dd>{{entry.description|prepend_todo}}</dd>
|
||||
</dl>
|
||||
|
||||
{% if entry.details %}
|
||||
{{entry.details}}
|
||||
|
||||
{% endif %}
|
||||
{% if entry.examples %}
|
||||
#### Examples
|
||||
|
||||
{% for example in entry.examples %}
|
||||
<details>
|
||||
<summary>{{example.name}}</summary>
|
||||
|
||||
{{example.description}}
|
||||
{% if example.before %}
|
||||
**Fix:**
|
||||
<div class="example-container">
|
||||
<div class="example">
|
||||
<div class="example-inner">
|
||||
<div class="example-title">Before</div>
|
||||
{{example.before-}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="example">
|
||||
<div class="example-inner">
|
||||
<div class="example-title">After</div>
|
||||
{{example.after-}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</details>
|
||||
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% for entry in entries %}
|
||||
[{{entry.message_code}}]: @ref {{entry.message_code}}
|
||||
{% endfor %}
|
||||
@@ -1,414 +0,0 @@
|
||||
# Guidelines:
|
||||
# • A message code must always have the same meaning forever.
|
||||
# • Codes may be retired or introduced in new releases. In order to avoid
|
||||
# clashes, retired codes must not be deleted.
|
||||
# • Codes should not themselves reflect classification, e.g. a range for parse
|
||||
# errors and a range for each keymap component.
|
||||
# • Codes should not be assigned sequentially because it is misleading.
|
||||
# • Codes must be in the range 1..999. This range may be extended once every
|
||||
# code has be assigned.
|
||||
#
|
||||
# See the following guidelines for further details on good practices:
|
||||
# https://github.com/haskellfoundation/error-message-index/blob/main/tool-developers.md#code-assignment-recommendations
|
||||
|
||||
# NOTE: Field “added: ALWAYS” means that the precise version is unknown and
|
||||
# anterior to the introduction of the message registry. It will be replaced by
|
||||
# the default version 1.0.0 in the generated documentation. While this is deemed
|
||||
# good enough to avoid spelunking commit history, a more precise version would
|
||||
# be welcome.
|
||||
|
||||
# TODO: fix missing detailed description, examples, resolution
|
||||
|
||||
- id: "malformed-number-literal"
|
||||
code: 34
|
||||
added: ALWAYS
|
||||
type: error
|
||||
description: "Warn on malformed number literals"
|
||||
details: |
|
||||
xkbcommon can parse the following number literal formats:
|
||||
|
||||
- *decimal integer:* 1, 123, etc.
|
||||
- *decimal floating-point number:* 1.23, etc.
|
||||
- *hexadecimal integer:* prefixed with “0x”: 0x123, 0xff, 0xAB, etc.
|
||||
- id: "conflicting-key-type-preserve-entries"
|
||||
code: 43
|
||||
added: ALWAYS
|
||||
type: warning
|
||||
description: "Conflicting “preserve” entries in a key type"
|
||||
- id: "unsupported-modifier-mask"
|
||||
code: 60
|
||||
added: ALWAYS
|
||||
type: error
|
||||
description: "Warn on unsupported modifier mask"
|
||||
- id: "expected-array-entry"
|
||||
code: 77
|
||||
added: ALWAYS
|
||||
type: error
|
||||
description: "Expected an array entry, but the index is missing"
|
||||
- id: "illegal-keycode-alias"
|
||||
code: 101
|
||||
added: ALWAYS
|
||||
type: warning
|
||||
description: "Illegal keycode alias with the name of a real key"
|
||||
- id: "unrecognized-keysym"
|
||||
code: 107
|
||||
added: ALWAYS
|
||||
type: warning
|
||||
description: "Warn on unrecognized keysyms"
|
||||
details: |
|
||||
xkbcommon replaces keysyms it does not recognize by the keysym `NoSymbol`.
|
||||
|
||||
You may find the list of supported keysyms in
|
||||
`include/xkbcommon/xkbcommon-keysyms.h`.
|
||||
examples:
|
||||
- name: Unrecognized keysym “`coma`”
|
||||
description: |
|
||||
**Error message:**
|
||||
|
||||
```
|
||||
xkbcommon: WARNING: [XKB-107] de:31:20: unrecognized keysym "coma"
|
||||
```
|
||||
|
||||
xkbcommon does not recognize the keysym “`coma`”. It is most probably
|
||||
a typo for “<code>com<em>m</em>a</code>”.
|
||||
See: `XKB_KEY_comma` in `include/xkbcommon/xkbcommon-keysyms.h`.
|
||||
before: |
|
||||
```c
|
||||
key <AB08> {[ coma, semicolon, periodcentered, multiply ]};
|
||||
```
|
||||
after: |
|
||||
```c
|
||||
key <AB08> {[ comma, semicolon, periodcentered, multiply ]};
|
||||
```
|
||||
- id: "undeclared-virtual-modifier"
|
||||
code: 123
|
||||
added: ALWAYS
|
||||
type: error
|
||||
description: "A virtual modifier is used before being declared"
|
||||
- id: "insufficient-buffer-size"
|
||||
code: 134
|
||||
added: ALWAYS
|
||||
type: error
|
||||
description: "A buffer has an insufficient size"
|
||||
- id: "wrong-statement-type"
|
||||
code: 150
|
||||
added: ALWAYS
|
||||
type: error
|
||||
description: "The type of the statement is not allowed in the context"
|
||||
- id: "unsupported-geometry-section"
|
||||
code: 172
|
||||
added: ALWAYS
|
||||
type: warning
|
||||
description: "Geometry sections are not supported"
|
||||
- id: "cannot-infer-key-type"
|
||||
code: 183
|
||||
added: ALWAYS
|
||||
type: warning
|
||||
description: "Warn if no key type can be inferred"
|
||||
- id: "invalid-escape-sequence"
|
||||
code: 193
|
||||
added: ALWAYS
|
||||
type: warning
|
||||
description: "Invalid escape sequence in a string"
|
||||
- id: "illegal-key-type-preserve-result"
|
||||
code: 195
|
||||
added: ALWAYS
|
||||
type: warning
|
||||
description: "The result of a key type “preserve” entry must be a subset of its input modifiers."
|
||||
- id: "invalid-include-statement"
|
||||
code: 203
|
||||
added: ALWAYS
|
||||
type: error
|
||||
description: "Syntax error in the include statement"
|
||||
- id: "invalid-modmap-entry"
|
||||
code: 206
|
||||
added: ALWAYS
|
||||
type: error
|
||||
description: "A modmap entry is invalid"
|
||||
- id: "unsupported-group-index"
|
||||
code: 237
|
||||
added: ALWAYS
|
||||
type: error
|
||||
description: "Warn when a group index is not supported"
|
||||
details: |
|
||||
xkbcommon supports group index in the range (1..{{XKB_MAX_GROUPS}}).
|
||||
- id: "conflicting-key-type-level-names"
|
||||
code: 239
|
||||
added: ALWAYS
|
||||
type: warning
|
||||
description: "The name of a key type level is defined multiple times."
|
||||
- id: "invalid-set-default-statement"
|
||||
code: 254
|
||||
added: ALWAYS
|
||||
type: error
|
||||
description: "Invalid statement setting default values"
|
||||
- id: "conflicting-key-type-map-entry"
|
||||
code: 266
|
||||
added: ALWAYS
|
||||
type: warning
|
||||
description: "Conflicting “map” entries in type definition"
|
||||
- id: "undefined-key-type"
|
||||
code: 286
|
||||
added: ALWAYS
|
||||
type: warning
|
||||
description: "Warn if using an undefined key type"
|
||||
- id: "non-base-group-name"
|
||||
code: 305
|
||||
added: ALWAYS
|
||||
type: warning
|
||||
description: "Warn if a group name was defined for group other than the first one"
|
||||
- id: "unsupported-shift-level"
|
||||
code: 312
|
||||
added: ALWAYS
|
||||
type: error
|
||||
description: "Warn when a shift level is not supported"
|
||||
details: |
|
||||
Shift levels are _one_-indexed. xkbcommon supports two formats of shift levels:
|
||||
as numbers and as identifiers `LevelN`, where `N` is in the range (1..8).
|
||||
- id: "included-file-not-found"
|
||||
code: 338
|
||||
added: ALWAYS
|
||||
type: error
|
||||
description: "Could not find a file used in an include statement"
|
||||
- id: "unknown-operator"
|
||||
code: 345
|
||||
added: ALWAYS
|
||||
type: error
|
||||
description: "Use of an operator that is unknown and thus unsupported"
|
||||
- id: "duplicate-entry"
|
||||
code: 378
|
||||
added: ALWAYS
|
||||
type: warning
|
||||
description: "An entry is duplicated and will be ignored"
|
||||
- id: "recursive-include"
|
||||
code: 386
|
||||
added: 1.7.0
|
||||
type: error
|
||||
description: "Included files form cycle"
|
||||
- id: "conflicting-key-type-definitions"
|
||||
code: 407
|
||||
added: ALWAYS
|
||||
type: warning
|
||||
description: "Conflicting definitions of a key type"
|
||||
details: |
|
||||
The given key type is defined multiple times, but only one definition is kept.
|
||||
- id: "global-defaults-wrong-scope"
|
||||
code: 428
|
||||
added: ALWAYS
|
||||
type: error
|
||||
description: "A global defaults statement is in a wrong scope and should be moved"
|
||||
examples:
|
||||
- name: Default key type in key statement
|
||||
description: |
|
||||
**Error message:**
|
||||
|
||||
```
|
||||
xkbcommon: ERROR: [XKB-428] Cannot set global defaults for "type" element
|
||||
within a key statement: move statements to the global file scope.
|
||||
Assignment to "key.type" ignored.
|
||||
```
|
||||
before: |
|
||||
```c
|
||||
key <AE01> {
|
||||
key.type = "FOUR_LEVEL_SEMIALPHABETIC",
|
||||
symbols = [q, Q, at]
|
||||
};
|
||||
```
|
||||
after: |
|
||||
```c
|
||||
// Either put default key type in global file scope
|
||||
key.type = "FOUR_LEVEL_SEMIALPHABETIC";
|
||||
key <AE01> { [q, Q, at] };
|
||||
// or use a local setting (unqualified, i.e. without `key.`)
|
||||
key <AE01> {
|
||||
type = "FOUR_LEVEL_SEMIALPHABETIC",
|
||||
symbols = [ q, Q, at ]
|
||||
};
|
||||
```
|
||||
- id: "missing-default-section"
|
||||
code: 433
|
||||
added: ALWAYS
|
||||
type: warning
|
||||
description: "Missing default section in included file"
|
||||
details: |
|
||||
When using an include statement, the included file may contains multiple sections.
|
||||
The include statement may specify the name of the section to include, or leave it
|
||||
unspecified. In the latter case, the included file must then define a *default* section.
|
||||
The present warning is shown when no default section is defined.
|
||||
|
||||
To solve this, either fix the include statement by specifying the exact section to
|
||||
include, or declare a default section in the included file.
|
||||
- id: "conflicting-key-symbol"
|
||||
code: 461
|
||||
added: ALWAYS
|
||||
type: warning
|
||||
description: "Warn if there are conflicting keysyms while merging keys"
|
||||
- id: "invalid-operation"
|
||||
code: 478
|
||||
added: ALWAYS
|
||||
type: error
|
||||
description: "The operation is invalid in the context"
|
||||
- id: "numeric-keysym"
|
||||
code: 489
|
||||
added: 1.6.0
|
||||
type: warning
|
||||
description: "Warn on numeric keysym (other than 0-9)"
|
||||
details: |
|
||||
Numeric keysyms are not human-friendly. Use the corresponding named keysym
|
||||
or Unicode keysym, if available.
|
||||
examples:
|
||||
- name: Hexadecimal keysym `0x1001ed0`
|
||||
description: |
|
||||
**Error message:**
|
||||
|
||||
```
|
||||
xkbcommon: WARNING: [XKB-489] numeric keysym "0x1001ed0"
|
||||
```
|
||||
before: |
|
||||
```c
|
||||
key <AE01> { [ 0x1001ed0] };
|
||||
```
|
||||
after: |
|
||||
```c
|
||||
// Preferred form: human-friendly
|
||||
key <AE01> { [ Ocircumflexacute ] };
|
||||
// or
|
||||
key <AE01> { [ U1ED0 ] };
|
||||
```
|
||||
- id: "extra-symbols-ignored"
|
||||
code: 516
|
||||
added: ALWAYS
|
||||
type: warning
|
||||
description: "TODO: add description"
|
||||
- id: "conflicting-key-name"
|
||||
code: 523
|
||||
added: ALWAYS
|
||||
type: warning
|
||||
description: "Conflicting definitions of a key name or alias"
|
||||
- id: "allocation-error"
|
||||
code: 550
|
||||
added: ALWAYS
|
||||
type: error
|
||||
description: "Cannot allocate memory"
|
||||
- id: "wrong-field-type"
|
||||
code: 578
|
||||
added: ALWAYS
|
||||
type: error
|
||||
description: "Warn when a field has not the expected type"
|
||||
- id: "invalid-real-modifier"
|
||||
code: 623
|
||||
added: ALWAYS
|
||||
type: error
|
||||
description: "Invalid _real_ modifier"
|
||||
- id: "unknown-char-escape-sequence"
|
||||
code: 645
|
||||
added: ALWAYS
|
||||
type: warning
|
||||
description: "Warn on unknown escape sequence in string literal"
|
||||
details: |
|
||||
xkbcommon support the following escape sequences in string literals:
|
||||
|
||||
| Escape sequence | Corresponding character |
|
||||
| --------------- | ----------------------------------- |
|
||||
| `\b` | `U+0008` Backspace |
|
||||
| `\t` | `U+0009` Character tabulation |
|
||||
| `\n` | `U+000A` Line feed |
|
||||
| `\v` | `U+000B` Vertical tabulation |
|
||||
| `\f` | `U+000C` Form feed |
|
||||
| `\r` | `U+000D` Carriage return |
|
||||
| `\e` | `U+001B` Escape |
|
||||
| `\\` | `U+005C` Backslash |
|
||||
| `\NNN` | _Octal_ escape, from `\0` to `\777` |
|
||||
- id: "invalid-included-file"
|
||||
code: 661
|
||||
added: ALWAYS
|
||||
type: error
|
||||
description: "The target file of an include statement could not be processed"
|
||||
- id: "multiple-groups-at-once"
|
||||
code: 700
|
||||
added: ALWAYS
|
||||
type: warning
|
||||
description: "Warn if a key defines multiple groups at once"
|
||||
- id: "unsupported-symbols-field"
|
||||
code: 711
|
||||
added: ALWAYS
|
||||
type: warning
|
||||
description: "A legacy X11 symbol field is not supported"
|
||||
- id: "invalid-syntax"
|
||||
code: 769
|
||||
added: ALWAYS
|
||||
type: error
|
||||
description: "The syntax is invalid and the file cannot be parsed"
|
||||
- id: "undefined-keycode"
|
||||
code: 770
|
||||
added: ALWAYS
|
||||
type: warning
|
||||
description: "Reference to an undefined keycode"
|
||||
- id: "invalid-expression-type"
|
||||
code: 784
|
||||
added: ALWAYS
|
||||
type: error
|
||||
description: "An expression has not the expected type"
|
||||
- id: "invalid-value"
|
||||
code: 796
|
||||
added: ALWAYS
|
||||
type: error
|
||||
description: "A value is invalid and will be ignored"
|
||||
- id: "conflicting-modmap"
|
||||
code: 800
|
||||
added: ALWAYS
|
||||
type: warning
|
||||
description: "Warn if there are conflicting modmap definitions"
|
||||
details: |
|
||||
@todo detailed explanation and examples
|
||||
- id: "unknown-field"
|
||||
code: 812
|
||||
added: ALWAYS
|
||||
type: error
|
||||
description: "A field is unknown and will be ignored"
|
||||
- id: "conflicting-key-action"
|
||||
code: 883
|
||||
added: ALWAYS
|
||||
type: warning
|
||||
description: "Warn if there are conflicting actions while merging keys"
|
||||
- id: "conflicting-key-type-merging-groups"
|
||||
code: 893
|
||||
added: ALWAYS
|
||||
type: warning
|
||||
description: "Warn if there are conflicting key types while merging groups"
|
||||
- id: "conflicting-key-symbols-entry"
|
||||
code: 901
|
||||
added: ALWAYS
|
||||
type: error
|
||||
description: "Conflicting symbols entry for a key"
|
||||
- id: "missing-symbols-group-name-index"
|
||||
code: 903
|
||||
added: ALWAYS
|
||||
type: warning
|
||||
description: "Missing group index in a group name entry"
|
||||
- id: "conflicting-key-fields"
|
||||
code: 935
|
||||
added: ALWAYS
|
||||
type: warning
|
||||
description: "Warn if there are conflicting fields while merging keys"
|
||||
- id: "invalid-identifier"
|
||||
code: 949
|
||||
added: ALWAYS
|
||||
type: error
|
||||
description: "An identifier is used but is not built-in"
|
||||
- id: "unresolved-keymap-symbol"
|
||||
code: 965
|
||||
added: ALWAYS
|
||||
type: warning
|
||||
description: "Warn if using a symbol not defined in the keymap"
|
||||
- id: "undeclared-modifiers-in-key-type"
|
||||
code: 971
|
||||
added: ALWAYS
|
||||
type: warning
|
||||
description: "Some modifiers used in a key type “map” or “preserve” entry are not declared"
|
||||
details: |
|
||||
The modifiers used in `map` or `preserve` entries should be declared using the entry
|
||||
`modifiers` in the key type.
|
||||
|
||||
# TODO: deprecated keysym
|
||||
# TODO: unicode keysym when named and recommended keysym exists
|
||||
@@ -1,229 +0,0 @@
|
||||
# Quick Guide
|
||||
|
||||
## Introduction
|
||||
|
||||
This document contains a quick walk-through of the often-used parts of
|
||||
the library. We will employ a few use-cases to lead the examples:
|
||||
|
||||
1. An evdev client. "evdev" is the Linux kernel's input subsystem; it
|
||||
only reports to the client which keys are pressed and released.
|
||||
|
||||
2. An X11 client, using the XCB library to communicate with the X
|
||||
server and the xcb-xkb library for using the XKB protocol.
|
||||
|
||||
3. A Wayland client, using the standard protocol.
|
||||
|
||||
The snippets are not complete, and some support code is omitted. You
|
||||
can find complete and more complex examples in the source directory:
|
||||
|
||||
1. tools/interactive-evdev.c contains an interactive evdev client.
|
||||
|
||||
2. tools/interactive-x11.c contains an interactive X11 client.
|
||||
|
||||
3. tools/interactive-wayland.c contains an interactive Wayland client.
|
||||
|
||||
Also, the library contains many more functions for examining and using
|
||||
the library context, the keymap and the keyboard state. See the
|
||||
hyper-linked reference documentation or go through the header files in
|
||||
xkbcommon/ for more details.
|
||||
|
||||
## Code
|
||||
|
||||
Before we can do anything interesting, we need a library context:
|
||||
|
||||
~~~{.c}
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
struct xkb_context *ctx;
|
||||
|
||||
ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||
if (!ctx) <error>
|
||||
~~~
|
||||
|
||||
The `xkb_context` contains the keymap include paths, the log level and
|
||||
functions, and other general customizable administrativia.
|
||||
|
||||
Next we need to create a keymap, `xkb_keymap`. This is an immutable object
|
||||
which contains all of the information about the keys, layouts, etc. There
|
||||
are different ways to do this.
|
||||
|
||||
If we are an evdev client, we have nothing to go by, so we need to ask
|
||||
the user for his/her keymap preferences (for example, an Icelandic
|
||||
keyboard with a Dvorak layout). The configuration format is commonly
|
||||
called RMLVO (Rules+Model+Layout+Variant+Options), the same format used
|
||||
by the X server. With it, we can fill a struct called `xkb_rule_names`;
|
||||
passing `NULL` chooses the system's default.
|
||||
|
||||
~~~{.c}
|
||||
struct xkb_keymap *keymap;
|
||||
/* Example RMLVO for Icelandic Dvorak. */
|
||||
struct xkb_rule_names names = {
|
||||
.rules = NULL,
|
||||
.model = "pc105",
|
||||
.layout = "is",
|
||||
.variant = "dvorak",
|
||||
.options = "terminate:ctrl_alt_bksp"
|
||||
};
|
||||
|
||||
keymap = xkb_keymap_new_from_names(ctx, &names,
|
||||
XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
if (!keymap) <error>
|
||||
~~~
|
||||
|
||||
If we are a Wayland client, the compositor gives us a string complete
|
||||
with a keymap. In this case, we can create the keymap object like this:
|
||||
|
||||
~~~{.c}
|
||||
/* From the wl_keyboard::keymap event. */
|
||||
const char *keymap_string = <...>;
|
||||
struct xkb_keymap *keymap;
|
||||
|
||||
keymap = xkb_keymap_new_from_string(ctx, keymap_string,
|
||||
XKB_KEYMAP_FORMAT_TEXT_V1,
|
||||
XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
if (!keymap) <error>
|
||||
~~~
|
||||
|
||||
If we are an X11 client, we are better off getting the keymap from the
|
||||
X server directly. For this we need to choose the XInput device; here
|
||||
we will use the core keyboard device:
|
||||
|
||||
~~~{.c}
|
||||
#include <xkbcommon/xkbcommon-x11.h>
|
||||
|
||||
xcb_connection_t *conn = <...>;
|
||||
int32_t device_id;
|
||||
|
||||
device_id = xkb_x11_get_core_keyboard_device_id(conn);
|
||||
if (device_id == -1) <error>
|
||||
|
||||
keymap = xkb_x11_keymap_new_from_device(ctx, conn, device_id,
|
||||
XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
if (!keymap) <error>
|
||||
~~~
|
||||
|
||||
Now that we have the keymap, we are ready to handle the keyboard devices.
|
||||
For each device, we create an `xkb_state`, which remembers things like which
|
||||
keyboard modifiers and LEDs are active:
|
||||
|
||||
~~~{.c}
|
||||
struct xkb_state *state;
|
||||
|
||||
state = xkb_state_new(keymap);
|
||||
if (!state) <error>
|
||||
~~~
|
||||
|
||||
For X11/XCB clients, this is better:
|
||||
|
||||
~~~{.c}
|
||||
state = xkb_x11_state_new_from_device(keymap, conn, device_id);
|
||||
if (!state) <error>
|
||||
~~~
|
||||
|
||||
When we have an `xkb_state` for a device, we can start handling key events
|
||||
from it. Given a keycode for a key, we can get its keysym:
|
||||
|
||||
~~~{.c}
|
||||
<key event structure> event;
|
||||
xkb_keycode_t keycode;
|
||||
xkb_keysym_t keysym;
|
||||
|
||||
keycode = event->keycode;
|
||||
keysym = xkb_state_key_get_one_sym(state, keycode);
|
||||
~~~
|
||||
|
||||
We can see which keysym we got, and get its name:
|
||||
|
||||
~~~{.c}
|
||||
char keysym_name[64];
|
||||
|
||||
if (keysym == XKB_KEY_Space)
|
||||
<got a space>
|
||||
|
||||
xkb_keysym_get_name(keysym, keysym_name, sizeof(keysym_name));
|
||||
~~~
|
||||
|
||||
libxkbcommon also supports an extension to the classic XKB, whereby a
|
||||
single event can result in multiple keysyms. Here's how to use it:
|
||||
|
||||
~~~{.c}
|
||||
const xkb_keysym_t *keysyms;
|
||||
int num_keysyms;
|
||||
|
||||
num_keysyms = xkb_state_key_get_syms(state, keycode, &keysyms);
|
||||
~~~
|
||||
|
||||
We can also get a UTF-8 string representation for this key:
|
||||
|
||||
~~~{.c}
|
||||
char *buffer;
|
||||
int size;
|
||||
|
||||
// First find the needed size; return value is the same as snprintf(3).
|
||||
size = xkb_state_key_get_utf8(state, keycode, NULL, 0) + 1;
|
||||
if (size <= 1) <nothing to do>
|
||||
buffer = <allocate size bytes>
|
||||
|
||||
xkb_state_key_get_utf8(state, keycode, buffer, size);
|
||||
~~~
|
||||
|
||||
Of course, we also need to keep the `xkb_state` up-to-date with the
|
||||
keyboard device, if we want to get the correct keysyms in the future.
|
||||
|
||||
If we are an evdev client, we must let the library know whether a key
|
||||
is pressed or released at any given time:
|
||||
|
||||
~~~{.c}
|
||||
enum xkb_state_component changed;
|
||||
|
||||
if (<key press>)
|
||||
changed = xkb_state_update_key(state, keycode, XKB_KEY_DOWN);
|
||||
else if (<key release>)
|
||||
changed = xkb_state_update_key(state, keycode, XKB_KEY_UP);
|
||||
~~~
|
||||
|
||||
The `changed` return value tells us exactly which parts of the state
|
||||
have changed.
|
||||
|
||||
If it is a key-repeat event, we can ask the keymap what to do with it:
|
||||
|
||||
~~~{.c}
|
||||
if (<key repeat> && !xkb_keymap_key_repeats(keymap, keycode))
|
||||
<discard event>
|
||||
~~~
|
||||
|
||||
On the other hand, if we are an X or Wayland client, the server already
|
||||
does the hard work for us. It notifies us when the device's state
|
||||
changes, and we can simply use what it tells us (the necessary
|
||||
information usually comes in a form of some "state changed" event):
|
||||
|
||||
~~~{.c}
|
||||
changed = xkb_state_update_mask(state,
|
||||
event->depressed_mods,
|
||||
event->latched_mods,
|
||||
event->locked_mods,
|
||||
event->depressed_layout,
|
||||
event->latched_layout,
|
||||
event->locked_layout);
|
||||
~~~
|
||||
|
||||
Now that we have an always-up-to-date `xkb_state`, we can examine it.
|
||||
For example, we can check whether the Control modifier is active, or
|
||||
whether the Num Lock LED is active:
|
||||
|
||||
~~~{.c}
|
||||
if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CTRL,
|
||||
XKB_STATE_MODS_EFFECTIVE) > 0)
|
||||
<The Control modifier is active>
|
||||
|
||||
if (xkb_state_led_name_is_active(state, XKB_LED_NAME_NUM) > 0)
|
||||
<The Num Lock LED is active>
|
||||
~~~
|
||||
|
||||
And that's it! Eventually, we should free the objects we've created:
|
||||
|
||||
~~~{.c}
|
||||
xkb_state_unref(state);
|
||||
xkb_keymap_unref(keymap);
|
||||
xkb_context_unref(ctx);
|
||||
~~~
|
||||
@@ -1,113 +0,0 @@
|
||||
The rules file {#rule-file-format}
|
||||
==============
|
||||
|
||||
The purpose of the rules file is to map between configuration values
|
||||
that are easy for a user to specify and understand, and the
|
||||
configuration values xkbcomp uses and understands.
|
||||
|
||||
xkbcomp uses the `xkb_component_names` struct, which maps directly to
|
||||
include statements of the appropriate sections, called for short
|
||||
[KcCGST] \(see the [XKB introduction]; 'G' stands for "geometry",
|
||||
which is not supported). These are not really intuitive nor
|
||||
straightforward for the uninitiated.
|
||||
|
||||
[KcCGST]: @ref KcCGST-intro
|
||||
[XKB introduction]: @ref xkb-intro
|
||||
|
||||
Instead, the user passes in a `xkb_rule_names` struct, which consists
|
||||
of the name of a rules file (in Linux this is usually "evdev"), a
|
||||
keyboard model (e.g. "pc105"), a set of layouts (which will end up
|
||||
in different groups, e.g. "us,fr"), variants (used to alter/augment
|
||||
the respective layout, e.g. "intl,dvorak"), and a set of options
|
||||
(used to tweak some general behavior of the keyboard, e.g.
|
||||
"ctrl:nocaps,compose:menu" to make the Caps Lock key act like Ctrl
|
||||
and the Menu key like Compose). We call these
|
||||
[RMLVO](@ref RMLVO-intro).
|
||||
|
||||
Format of the file
|
||||
------------------
|
||||
The file consists of rule sets, each consisting of rules (one per
|
||||
line), which match the MLVO values on the left hand side, and, if
|
||||
the values match to the values the user passed in, results in the
|
||||
values on the right hand side being added to the resulting KcCGST.
|
||||
Since some values are related and repeated often, it is possible
|
||||
to group them together and refer to them by a group name in the
|
||||
rules.
|
||||
|
||||
Along with matching values by simple string equality, and for
|
||||
membership in a group defined previously, rules may also contain
|
||||
"wildcard" values - "*" - which always match. These usually appear
|
||||
near the end.
|
||||
|
||||
Grammar
|
||||
-------
|
||||
(It might be helpful to look at a file like rules/evdev along with
|
||||
this grammar. Comments, whitespace, etc. are not shown.)
|
||||
|
||||
```
|
||||
File ::= { "!" (Include | Group | RuleSet) }
|
||||
|
||||
Include ::= "include" <ident>
|
||||
|
||||
Group ::= GroupName "=" { GroupElement } "\n"
|
||||
GroupName ::= "$"<ident>
|
||||
GroupElement ::= <ident>
|
||||
|
||||
RuleSet ::= Mapping { Rule }
|
||||
|
||||
Mapping ::= { Mlvo } "=" { Kccgst } "\n"
|
||||
Mlvo ::= "model" | "option" | ("layout" | "variant") [ Index ]
|
||||
Index ::= "[" 1..XKB_NUM_GROUPS "]"
|
||||
Kccgst ::= "keycodes" | "symbols" | "types" | "compat" | "geometry"
|
||||
|
||||
Rule ::= { MlvoValue } "=" { KccgstValue } "\n"
|
||||
MlvoValue ::= "*" | GroupName | <ident>
|
||||
KccgstValue ::= <ident>
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- Include processes the rules in the file path specified in the ident,
|
||||
in order. %-expansion is performed, as follows:
|
||||
|
||||
```
|
||||
%%:
|
||||
A literal %.
|
||||
|
||||
%H:
|
||||
The value of the HOME environment variable.
|
||||
|
||||
%E:
|
||||
The extra lookup path for system-wide XKB data (usually /etc/xkb/rules).
|
||||
|
||||
%S:
|
||||
The system-installed rules directory (usually /usr/share/X11/xkb/rules).
|
||||
```
|
||||
|
||||
- The order of values in a Rule must be the same as the Mapping it
|
||||
follows. The mapping line determines the meaning of the values in
|
||||
the rules which follow in the RuleSet.
|
||||
|
||||
- If a Rule is matched, %-expansion is performed on the KccgstValue,
|
||||
as follows:
|
||||
|
||||
```
|
||||
%m, %l, %v:
|
||||
The model, layout or variant, if only one was given (e.g.
|
||||
%l for "us,il" is invalid).
|
||||
|
||||
%l[1], %v[1]:
|
||||
Layout or variant for the specified group Index, if more than
|
||||
one was given (e.g. %l[1] for "us" is invalid).
|
||||
|
||||
%+m, %+l, %+v, %+l[1], %+v[1]
|
||||
As above, but prefixed with '+'. Similarly, '|', '-', '_' may be
|
||||
used instead of '+'.
|
||||
|
||||
%(m), %(l), %(l[1]), %(v), %(v[1]):
|
||||
As above, but prefixed by '(' and suffixed by ')'.
|
||||
```
|
||||
|
||||
In case the expansion is invalid, as described above, it is
|
||||
skipped (the rest of the string is still processed); this includes
|
||||
the prefix and suffix (that's why you shouldn't use e.g. "(%v[1])").
|
||||
@@ -1,240 +0,0 @@
|
||||
# User-configuration {#user-configuration}
|
||||
|
||||
This page describes how to add a *custom* layout or option so that it will be
|
||||
parsed by libxkbcommon.
|
||||
|
||||
@note For an introduction to XKB and keymap components, please see
|
||||
“@ref xkb-intro ""”.
|
||||
|
||||
@warning The below requires libxkbcommon as keymap compiler and
|
||||
**does not work in X**.
|
||||
|
||||
@tableofcontents{html:2}
|
||||
|
||||
## Data locations
|
||||
|
||||
libxkbcommon searches the following paths for XKB configuration files:
|
||||
1. `$XDG_CONFIG_HOME/xkb/`, or `$HOME/.config/xkb/` if the `$XDG_CONFIG_HOME`
|
||||
environment variable is not defined
|
||||
2. `$HOME/.xkb/`
|
||||
3. `$XKB_CONFIG_EXTRA_PATH` if set, otherwise `<sysconfdir>/xkb` (on most
|
||||
distributions this is `/etc/xkb`)
|
||||
4. `$XKB_CONFIG_ROOT` if set, otherwise `<datadir>/X11/xkb/` (path defined by
|
||||
the `xkeyboard-config` package, on most distributions this is
|
||||
`/usr/share/X11/xkb`)
|
||||
|
||||
A keymap created with `xkb_keymap::xkb_keymap_new_from_names()` will look up
|
||||
those paths in order until the required data is found.
|
||||
|
||||
@note Where libxkbcommon runs in a privileged context, only the system
|
||||
(`<datadir>`) path is available.
|
||||
|
||||
Each directory should have one or more of the following subdirectories:
|
||||
- `compat`
|
||||
- `geometry` (libxkbcommon ignores this directory)
|
||||
- `keycodes`
|
||||
- `rules`
|
||||
- `symbols`
|
||||
- `types`
|
||||
|
||||
The majority of user-specific configurations involve modifying key symbols and
|
||||
this is what this document focuses on. For use-cases where a user may need to
|
||||
add new key types or compat entries the general approach remains the same. A
|
||||
detailed description for how to add those types or compat entries is out of
|
||||
scope for this document.
|
||||
|
||||
You should never need to add user-specific keycodes. Where a keycode is missing,
|
||||
the addition should be filed in the upstream [xkeyboard-config] project.
|
||||
|
||||
[xkeyboard-config]: https://gitlab.freedesktop.org/xkeyboard-config/xkeyboard-config
|
||||
|
||||
## RMLVO vs KcCGST
|
||||
|
||||
Due to how XKB is configured, there is no such thing as a "layout" in XKB
|
||||
itself, or, indeed, any of the rules, models, variant, options (RMLVO) described
|
||||
in `struct xkb_rule_names`. RMLVO names are merely lookup keys in the
|
||||
rules file provided by xkeyboard-config to map to the correct keycode, compat,
|
||||
geometry (ignored by libxkbcommon), symbols and types (KcCGST). The KcCGST data
|
||||
is the one used by XKB and libxkbcommon to map keys to actual symbols.
|
||||
|
||||
For example, a common RMLVO configuration is layout "us", variant "dvorak" and
|
||||
option "terminate:ctrl_alt_bksp". Using the default rules file and model
|
||||
this maps into the following KcCGST components:
|
||||
|
||||
```
|
||||
xkb_keymap {
|
||||
xkb_keycodes { include "evdev+aliases(qwerty)" };
|
||||
xkb_types { include "complete" };
|
||||
xkb_compat { include "complete" };
|
||||
xkb_symbols { include "pc+us(dvorak)+inet(evdev)+terminate(ctrl_alt_bksp)" };
|
||||
xkb_geometry { include "pc(pc105)" };
|
||||
};
|
||||
```
|
||||
|
||||
A detailed explanation of how rules files convert RMLVO to KcCGST is out of
|
||||
scope for this document. See [the rules file](md_doc_rules-format.html) page
|
||||
instead.
|
||||
|
||||
|
||||
## Adding a layout
|
||||
|
||||
Adding a layout requires that the user adds **symbols** in the correct location.
|
||||
|
||||
The default rules files (usually `evdev`) have a catch-all to map a layout, say
|
||||
"foo", and a variant, say "bar", into the "bar" section in the file
|
||||
`$xkb_base_dir/symbols/foo`.
|
||||
This is sufficient to define a new keyboard layout. The example below defines
|
||||
the keyboard layout "banana" with an optional variant "orange":
|
||||
|
||||
```
|
||||
$ cat $XDG_CONFIG_HOME/xkb/symbols/banana
|
||||
// Like a US layout but swap the top row so numbers are on Shift
|
||||
default partial alphanumeric_keys
|
||||
xkb_symbols "basic" {
|
||||
include "us(basic)"
|
||||
name[Group1]= "Banana (US)";
|
||||
|
||||
key <AE01> { [ exclam, 1] };
|
||||
key <AE02> { [ at, 2] };
|
||||
key <AE03> { [ numbersign, 3] };
|
||||
key <AE04> { [ dollar, 4] };
|
||||
key <AE05> { [ percent, 5] };
|
||||
key <AE06> { [ asciicircum, 6] };
|
||||
key <AE07> { [ ampersand, 7] };
|
||||
key <AE08> { [ asterisk, 8] };
|
||||
key <AE09> { [ parenleft, 9] };
|
||||
key <AE10> { [ parenright, 0] };
|
||||
key <AE11> { [ underscore, minus] };
|
||||
key <AE12> { [ plus, equal] };
|
||||
};
|
||||
|
||||
// Same as banana but map the euro sign to the 5 key
|
||||
partial alphanumeric_keys
|
||||
xkb_symbols "orange" {
|
||||
include "banana(basic)"
|
||||
name[Group1] = "Banana (Eurosign on 5)";
|
||||
include "eurosign(5)"
|
||||
};
|
||||
```
|
||||
|
||||
The `default` section is loaded when no variant is given. The first example
|
||||
sections uses ``include`` to populate with a symbols list defined elsewhere
|
||||
(here: section `basic` from the file `symbols/us`, aka. the default US keyboard
|
||||
layout) and overrides parts of these symbols. The effect of this section is to
|
||||
swap the numbers and symbols in the top-most row (compared to the US layout) but
|
||||
otherwise use the US layout.
|
||||
|
||||
The "orange" variant uses the "banana" symbols and includes a different section
|
||||
to define the eurosign. It does not specificially override any symbols.
|
||||
|
||||
The exact details of how `xkb_symbols` work is out of scope for this document.
|
||||
|
||||
## Adding an option
|
||||
|
||||
For technical reasons, options do **not** have a catch-all to map option names
|
||||
to files and sections and must be specifically mapped by the user. This requires
|
||||
a custom rules file. As the `evdev` ruleset is hardcoded in many clients, the
|
||||
custom rules file must usually be named `evdev`.
|
||||
|
||||
```
|
||||
$ cat $XDG_CONFIG_HOME/xkb/rules/evdev
|
||||
! option = symbols
|
||||
custom:foo = +custom(bar)
|
||||
custom:baz = +other(baz)
|
||||
|
||||
! include %S/evdev
|
||||
```
|
||||
|
||||
This rules file maps the RMLVO option "custom:foo" to the "bar" section in the
|
||||
`symbols/custom` file and the "custom:baz" option to the "baz" section in the
|
||||
`symbols/other` file. Note how the RMLVO option name may be different to the
|
||||
file or section name.
|
||||
|
||||
The `include` statement includes the system-provided `evdev` ruleset. This
|
||||
allows users to only override those options they need.
|
||||
|
||||
The files themselves are similar to the layout examples in the previous section:
|
||||
|
||||
```
|
||||
$ cat $XDG_CONFIG_HOME/xkb/symbols/custom
|
||||
// map the Tilde key to nothing on the first shift level
|
||||
partial alphanumeric_keys
|
||||
xkb_symbols "bar" {
|
||||
key <TLDE> { [ VoidSymbol ] };
|
||||
};
|
||||
|
||||
$ cat $XDG_CONFIG_HOME/xkb/symbols/other
|
||||
// map first key in bottom row (Z in the US layout) to k/K
|
||||
partial alphanumeric_keys
|
||||
xkb_symbols "baz" {
|
||||
key <AB01> { [ k, K ] };
|
||||
};
|
||||
```
|
||||
|
||||
With these in place, a user may select any layout/variant together with
|
||||
the "custom:foo" and/or "custom:baz" options.
|
||||
|
||||
## Discoverable layouts
|
||||
|
||||
@warning The below requires `libxkbregistry` as XKB lookup tool and
|
||||
**does not work where clients parse the XML file directly**.
|
||||
|
||||
The above sections apply only to the data files and require that the user knows
|
||||
about the existence of the new entries. To make custom entries discoverable by
|
||||
the configuration tools (e.g. the GNOME Control Center), the new entries must
|
||||
also be added to the XML file that is parsed by `libxkbregistry`. In most cases,
|
||||
this is the `evdev.xml` file in the rules directory. The example below shows the
|
||||
XML file that would add the custom layout and custom options as outlined above
|
||||
to the XKB registry:
|
||||
|
||||
```
|
||||
$ cat $XDG_CONFIG_HOME/xkb/rules/evdev.xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE xkbConfigRegistry SYSTEM "xkb.dtd">
|
||||
<xkbConfigRegistry version="1.1">
|
||||
<layoutList>
|
||||
<layout>
|
||||
<configItem>
|
||||
<name>banana</name>
|
||||
<shortDescription>ban</shortDescription>
|
||||
<description>Banana</description>
|
||||
</configItem>
|
||||
<variantList>
|
||||
<variant>
|
||||
<configItem>
|
||||
<name>orange</name>
|
||||
<shortDescription>or</shortDescription>
|
||||
<description>Orange (Banana)</description>
|
||||
</configItem>
|
||||
</variant>
|
||||
</variantList>
|
||||
</layout>
|
||||
</layoutList>
|
||||
<optionList>
|
||||
<group allowMultipleSelection="true">
|
||||
<configItem>
|
||||
<name>custom</name>
|
||||
<description>Custom options</description>
|
||||
</configItem>
|
||||
<option>
|
||||
<configItem>
|
||||
<name>custom:foo</name>
|
||||
<description>Map Tilde to nothing</description>
|
||||
</configItem>
|
||||
</option>
|
||||
<option>
|
||||
<configItem>
|
||||
<name>custom:baz</name>
|
||||
<description>Map Z to K</description>
|
||||
</configItem>
|
||||
</option>
|
||||
</group>
|
||||
</optionList>
|
||||
</xkbConfigRegistry>
|
||||
```
|
||||
|
||||
The default behavior of `libxkbregistry` ensures that the new layout and options
|
||||
are added to the system-provided layouts and options.
|
||||
|
||||
For details on the XML format, see the DTD in `<datadir>/X11/xkb/rules/xkb.dtd`
|
||||
and the system-provided XML files `<datadir>/X11/xkb/rules/*.xml`.
|
||||
@@ -1,8 +0,0 @@
|
||||
"Ctrl"
|
||||
"Lock"
|
||||
"Caps"
|
||||
"Shift"
|
||||
"Alt"
|
||||
"Meta"
|
||||
"None"
|
||||
"acute"
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* A target program for fuzzing the Compose text format.
|
||||
*
|
||||
* Currently, just parses an input file, and hopefully doesn't crash or hang.
|
||||
*/
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "xkbcommon/xkbcommon.h"
|
||||
#include "xkbcommon/xkbcommon-compose.h"
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct xkb_context *ctx;
|
||||
FILE *file;
|
||||
struct xkb_compose_table *table;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "usage: %s <file>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ctx = xkb_context_new(XKB_CONTEXT_NO_DEFAULT_INCLUDES | XKB_CONTEXT_NO_ENVIRONMENT_NAMES);
|
||||
assert(ctx);
|
||||
|
||||
#ifdef __AFL_HAVE_MANUAL_CONTROL
|
||||
__AFL_INIT();
|
||||
|
||||
while (__AFL_LOOP(1000))
|
||||
#endif
|
||||
{
|
||||
file = fopen(argv[1], "rb");
|
||||
assert(file);
|
||||
table = xkb_compose_table_new_from_file(ctx, file,
|
||||
"en_US.UTF-8",
|
||||
XKB_COMPOSE_FORMAT_TEXT_V1,
|
||||
XKB_COMPOSE_COMPILE_NO_FLAGS);
|
||||
xkb_compose_table_unref(table);
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
puts(table ? "OK" : "FAIL");
|
||||
xkb_context_unref(ctx);
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
<dead_tilde> <space> : "~" asciitilde # X
|
||||
Meta <Multi_key> !Alt ~Shift <apostrophe> <apostrophe> : "\"\'\x43\123abc" acute # Y
|
||||
@@ -1,17 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
case "$1" in
|
||||
keymap|compose)
|
||||
;;
|
||||
*)
|
||||
echo "usage: $0 keymap|compose" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
export CC=afl-clang-fast
|
||||
export AFL_HARDEN=1
|
||||
test -d fuzz/build || meson setup -Db_lto=true fuzz/build
|
||||
meson compile -C fuzz/build
|
||||
afl-fuzz -i fuzz/$1/testcases -x fuzz/$1/dict -o fuzz/$1/findings -t 200 -m 10 -- ./fuzz/build/fuzz-$1 @@
|
||||
@@ -1,120 +0,0 @@
|
||||
"Control"
|
||||
"Group1"
|
||||
"Group5"
|
||||
"Lock"
|
||||
"Mod1"
|
||||
"Mod9"
|
||||
"Shift"
|
||||
"U1"
|
||||
"0x1"
|
||||
"Up"
|
||||
"accel"
|
||||
"action"
|
||||
"actions"
|
||||
"affect"
|
||||
"alias"
|
||||
"all"
|
||||
"allowexplicit"
|
||||
"allownone"
|
||||
"alphanumeric_keys"
|
||||
"alternate"
|
||||
"alternate_group"
|
||||
"any"
|
||||
"augment"
|
||||
"both"
|
||||
"button"
|
||||
"clearLocks"
|
||||
"clearmods"
|
||||
"controls"
|
||||
"count"
|
||||
"ctrls"
|
||||
"data"
|
||||
"default"
|
||||
"dev"
|
||||
"device"
|
||||
"dfltbtn"
|
||||
"driveskbd"
|
||||
"false"
|
||||
"foo"
|
||||
"function_keys"
|
||||
"genKeyEvent"
|
||||
"group"
|
||||
"groupname"
|
||||
"groups"
|
||||
"groupsclamp"
|
||||
"groupsredirect"
|
||||
"groupswrap"
|
||||
"hidden"
|
||||
"include"
|
||||
"increment"
|
||||
"index"
|
||||
"indicator"
|
||||
"indicatordriveskbd"
|
||||
"interpret"
|
||||
"kc"
|
||||
"key"
|
||||
"keycode"
|
||||
"keypad_keys"
|
||||
"keys"
|
||||
"latchToLock"
|
||||
"leddriveskbd"
|
||||
"levelname"
|
||||
"lock"
|
||||
"locking"
|
||||
"logo"
|
||||
"map"
|
||||
"mod_map"
|
||||
"modifier_keys"
|
||||
"modifier_map"
|
||||
"modifiers"
|
||||
"modmap"
|
||||
"modmapmods"
|
||||
"mods"
|
||||
"name"
|
||||
"neither"
|
||||
"no"
|
||||
"none"
|
||||
"nosymbol"
|
||||
"off"
|
||||
"on"
|
||||
"outline"
|
||||
"overlay"
|
||||
"override"
|
||||
"partial"
|
||||
"preserve"
|
||||
"radiogroup"
|
||||
"repeat"
|
||||
"replace"
|
||||
"report"
|
||||
"row"
|
||||
"same"
|
||||
"sameServer"
|
||||
"screen"
|
||||
"section"
|
||||
"shape"
|
||||
"solid"
|
||||
"symbols"
|
||||
"text"
|
||||
"true"
|
||||
"type"
|
||||
"unlock"
|
||||
"usemodmap"
|
||||
"value"
|
||||
"virtual"
|
||||
"virtual_modifiers"
|
||||
"virtualmod"
|
||||
"vmods"
|
||||
"voidsymbol"
|
||||
"whichgroupstate"
|
||||
"whichmodstate"
|
||||
"x"
|
||||
"xkb_compat"
|
||||
"xkb_geometry"
|
||||
"xkb_keycodes"
|
||||
"xkb_keymap"
|
||||
"xkb_layout"
|
||||
"xkb_semantics"
|
||||
"xkb_symbols"
|
||||
"xkb_types"
|
||||
"y"
|
||||
"yes"
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* A target program for fuzzing the XKB keymap text format.
|
||||
*
|
||||
* Currently, just parses an input file, and hopefully doesn't crash or hang.
|
||||
*/
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "xkbcommon/xkbcommon.h"
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct xkb_context *ctx;
|
||||
FILE *file;
|
||||
struct xkb_keymap *keymap;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "usage: %s <file>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ctx = xkb_context_new(XKB_CONTEXT_NO_DEFAULT_INCLUDES | XKB_CONTEXT_NO_ENVIRONMENT_NAMES);
|
||||
assert(ctx);
|
||||
|
||||
#ifdef __AFL_HAVE_MANUAL_CONTROL
|
||||
__AFL_INIT();
|
||||
|
||||
while (__AFL_LOOP(1000))
|
||||
#endif
|
||||
{
|
||||
file = fopen(argv[1], "rb");
|
||||
assert(file);
|
||||
keymap = xkb_keymap_new_from_file(ctx, file,
|
||||
XKB_KEYMAP_FORMAT_TEXT_V1,
|
||||
XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
xkb_keymap_unref(keymap);
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
puts(keymap ? "OK" : "FAIL");
|
||||
xkb_context_unref(ctx);
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
xkb_keymap{
|
||||
xkb_keycodes"0"{
|
||||
minimum=0;
|
||||
maximum=500;
|
||||
<a>=0;
|
||||
indicator 1="X";
|
||||
alias<X>=<Y>;
|
||||
};
|
||||
xkb_types"X"{
|
||||
virtual_modifiers NumLock;
|
||||
type"X"{
|
||||
modifiers=Shift;
|
||||
map[Shift]=Level2;
|
||||
level_name[Level1]="X";
|
||||
preserve[Shift]=Shift;
|
||||
};
|
||||
};
|
||||
partial xkb_compat{
|
||||
virtual_modifiers Alt;
|
||||
interpret.useModMapMods=AnyLevel;
|
||||
interpret.repeat=False;
|
||||
interpret.locking=False;
|
||||
interpret ISO_Level2_Latch+Exactly(Shift){
|
||||
repeat=True;
|
||||
virtualModifier=NumLock;
|
||||
useModMapMods=level1;
|
||||
action=LatchMods(modifiers=Shift,clearLocks,latchToLock);
|
||||
action=MovePtr(x=+0,y=-0);
|
||||
action=SwitchScreen(screen=00,!same);
|
||||
action=Private(type=0x80,data[0]=0x00);
|
||||
};
|
||||
indicator"X"{whichModState=locked;modifiers=Lock;};
|
||||
};
|
||||
xkb_symbols{
|
||||
name[group1]="X";
|
||||
key<Y>{type[group2]="X",symbols[Group1]=[0,exclam],symbols[Group2]=[0xff,U00],symbols[Group3]=[z]};
|
||||
modifier_map Control{<a>};
|
||||
};
|
||||
default xkb_geometry"X"{
|
||||
description="X";
|
||||
width=470;
|
||||
shape.cornerRadius=1;
|
||||
shape"NORM"{cornerRadius=0,{[0.0,0]},{[0,0],[0,0.0]}};
|
||||
solid"X"{shape="X";top=00;left=00;color="X";};
|
||||
indicator.onColor="X";
|
||||
indicator.top=00.0;
|
||||
indicator.shape="X";
|
||||
indicator"X"{left=0;};
|
||||
text.top=00;
|
||||
text.color="X";
|
||||
text"X"{left=0;text="X";};
|
||||
section.left=00;
|
||||
row.left=0;
|
||||
key.shape="X";
|
||||
key.gap=1;
|
||||
section"X"{top=22;row{top=1;keys{{<X>,color="X"},{<X>,00.0},<X>,<X>,<X>};};};
|
||||
alias<AC00>=<CAPS>;
|
||||
};
|
||||
};
|
||||
@@ -1,98 +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>
|
||||
*/
|
||||
|
||||
#ifndef _XKBCOMMON_COMPAT_H
|
||||
#define _XKBCOMMON_COMPAT_H
|
||||
|
||||
/**
|
||||
* Renamed keymap API.
|
||||
*/
|
||||
#define xkb_group_index_t xkb_layout_index_t
|
||||
#define xkb_group_mask_t xkb_layout_mask_t
|
||||
#define xkb_map_compile_flags xkb_keymap_compile_flags
|
||||
#define XKB_GROUP_INVALID XKB_LAYOUT_INVALID
|
||||
|
||||
#define XKB_STATE_DEPRESSED \
|
||||
(XKB_STATE_MODS_DEPRESSED | XKB_STATE_LAYOUT_DEPRESSED)
|
||||
#define XKB_STATE_LATCHED \
|
||||
(XKB_STATE_MODS_LATCHED | XKB_STATE_LAYOUT_LATCHED)
|
||||
#define XKB_STATE_LOCKED \
|
||||
(XKB_STATE_MODS_LOCKED | XKB_STATE_LAYOUT_LOCKED)
|
||||
#define XKB_STATE_EFFECTIVE \
|
||||
(XKB_STATE_DEPRESSED | XKB_STATE_LATCHED | XKB_STATE_LOCKED | \
|
||||
XKB_STATE_MODS_EFFECTIVE | XKB_STATE_LAYOUT_EFFECTIVE)
|
||||
|
||||
#define xkb_map_new_from_names(context, names, flags) \
|
||||
xkb_keymap_new_from_names(context, names, flags)
|
||||
#define xkb_map_new_from_file(context, file, format, flags) \
|
||||
xkb_keymap_new_from_file(context, file, format, flags)
|
||||
#define xkb_map_new_from_string(context, string, format, flags) \
|
||||
xkb_keymap_new_from_string(context, string, format, flags)
|
||||
#define xkb_map_get_as_string(keymap) \
|
||||
xkb_keymap_get_as_string(keymap, XKB_KEYMAP_FORMAT_TEXT_V1)
|
||||
#define xkb_map_ref(keymap) xkb_keymap_ref(keymap)
|
||||
#define xkb_map_unref(keymap) xkb_keymap_unref(keymap)
|
||||
|
||||
#define xkb_map_num_mods(keymap) xkb_keymap_num_mods(keymap)
|
||||
#define xkb_map_mod_get_name(keymap, idx) xkb_keymap_mod_get_name(keymap, idx)
|
||||
#define xkb_map_mod_get_index(keymap, str) xkb_keymap_mod_get_index(keymap, str)
|
||||
#define xkb_key_mod_index_is_consumed(state, key, mod) \
|
||||
xkb_state_mod_index_is_consumed(state, key, mod)
|
||||
#define xkb_key_mod_mask_remove_consumed(state, key, modmask) \
|
||||
xkb_state_mod_mask_remove_consumed(state, key, modmask)
|
||||
|
||||
#define xkb_map_num_groups(keymap) xkb_keymap_num_layouts(keymap)
|
||||
#define xkb_key_num_groups(keymap, key) \
|
||||
xkb_keymap_num_layouts_for_key(keymap, key)
|
||||
#define xkb_map_group_get_name(keymap, idx) \
|
||||
xkb_keymap_layout_get_name(keymap, idx)
|
||||
#define xkb_map_group_get_index(keymap, str) \
|
||||
xkb_keymap_layout_get_index(keymap, str)
|
||||
|
||||
#define xkb_map_num_leds(keymap) xkb_keymap_num_leds(keymap)
|
||||
#define xkb_map_led_get_name(keymap, idx) xkb_keymap_led_get_name(keymap, idx)
|
||||
#define xkb_map_led_get_index(keymap, str) \
|
||||
xkb_keymap_led_get_index(keymap, str)
|
||||
|
||||
#define xkb_key_repeats(keymap, key) xkb_keymap_key_repeats(keymap, key)
|
||||
|
||||
#define xkb_key_get_syms(state, key, syms_out) \
|
||||
xkb_state_key_get_syms(state, key, syms_out)
|
||||
|
||||
#define xkb_state_group_name_is_active(state, name, type) \
|
||||
xkb_state_layout_name_is_active(state, name, type)
|
||||
#define xkb_state_group_index_is_active(state, idx, type) \
|
||||
xkb_state_layout_index_is_active(state, idx, type)
|
||||
|
||||
#define xkb_state_serialize_group(state, component) \
|
||||
xkb_state_serialize_layout(state, component)
|
||||
|
||||
#define xkb_state_get_map(state) xkb_state_get_keymap(state)
|
||||
|
||||
/* Not needed anymore, since there's NO_FLAGS. */
|
||||
#define XKB_MAP_COMPILE_PLACEHOLDER XKB_KEYMAP_COMPILE_NO_FLAGS
|
||||
#define XKB_MAP_COMPILE_NO_FLAGS XKB_KEYMAP_COMPILE_NO_FLAGS
|
||||
|
||||
#endif
|
||||
@@ -1,637 +0,0 @@
|
||||
/*
|
||||
* 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. `XDG_CONFIG_HOME` - before `$HOME/.XCompose` is checked,
|
||||
* `$XDG_CONFIG_HOME/XCompose` is checked (with a fall back to
|
||||
* `$HOME/.config/XCompose` if `XDG_CONFIG_HOME` is not defined).
|
||||
* This is a libxkbcommon extension to the search procedure in
|
||||
* Compose(5) (since libxkbcommon 1.0.0). Note that other
|
||||
* implementations, such as libX11, might not find a Compose file in
|
||||
* this path.
|
||||
* 3. `HOME` - see Compose(5).
|
||||
* 4. `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);
|
||||
|
||||
/**
|
||||
* @struct xkb_compose_table_entry
|
||||
* Opaque Compose table entry object.
|
||||
*
|
||||
* Represents a single entry in a Compose file in the iteration API.
|
||||
* It is immutable.
|
||||
*
|
||||
* @sa xkb_compose_table_iterator_new
|
||||
* @since 1.6.0
|
||||
*/
|
||||
struct xkb_compose_table_entry;
|
||||
|
||||
/**
|
||||
* Get the left-hand keysym sequence of a Compose table entry.
|
||||
*
|
||||
* For example, given the following entry:
|
||||
*
|
||||
* ```
|
||||
* <dead_tilde> <space> : "~" asciitilde # TILDE
|
||||
* ```
|
||||
*
|
||||
* it will return `{XKB_KEY_dead_tilde, XKB_KEY_space}`.
|
||||
*
|
||||
* @param[in] entry The compose table entry object to process.
|
||||
*
|
||||
* @param[out] sequence_length Number of keysyms in the sequence.
|
||||
*
|
||||
* @returns The array of left-hand side keysyms. The number of keysyms
|
||||
* is returned in the @p sequence_length out-parameter.
|
||||
*
|
||||
* @memberof xkb_compose_table_entry
|
||||
* @since 1.6.0
|
||||
*/
|
||||
const xkb_keysym_t *
|
||||
xkb_compose_table_entry_sequence(struct xkb_compose_table_entry *entry,
|
||||
size_t *sequence_length);
|
||||
|
||||
/**
|
||||
* Get the right-hand result keysym of a Compose table entry.
|
||||
*
|
||||
* For example, given the following entry:
|
||||
*
|
||||
* ```
|
||||
* <dead_tilde> <space> : "~" asciitilde # TILDE
|
||||
* ```
|
||||
*
|
||||
* it will return `XKB_KEY_asciitilde`.
|
||||
*
|
||||
* The keysym is optional; if the entry does not specify a keysym,
|
||||
* returns `XKB_KEY_NoSymbol`.
|
||||
*
|
||||
* @memberof xkb_compose_table_entry
|
||||
* @since 1.6.0
|
||||
*/
|
||||
xkb_keysym_t
|
||||
xkb_compose_table_entry_keysym(struct xkb_compose_table_entry *entry);
|
||||
|
||||
/**
|
||||
* Get the right-hand result string of a Compose table entry.
|
||||
*
|
||||
* The string is UTF-8 encoded and NULL-terminated.
|
||||
*
|
||||
* For example, given the following entry:
|
||||
*
|
||||
* ```
|
||||
* <dead_tilde> <space> : "~" asciitilde # TILDE
|
||||
* ```
|
||||
*
|
||||
* it will return `"~"`.
|
||||
*
|
||||
* The string is optional; if the entry does not specify a string,
|
||||
* returns the empty string.
|
||||
*
|
||||
* @memberof xkb_compose_table_entry
|
||||
* @since 1.6.0
|
||||
*/
|
||||
const char *
|
||||
xkb_compose_table_entry_utf8(struct xkb_compose_table_entry *entry);
|
||||
|
||||
/**
|
||||
* @struct xkb_compose_table_iterator
|
||||
* Iterator over a compose table’s entries.
|
||||
*
|
||||
* @sa xkb_compose_table_iterator_new()
|
||||
* @since 1.6.0
|
||||
*/
|
||||
struct xkb_compose_table_iterator;
|
||||
|
||||
/**
|
||||
* Create a new iterator for a compose table.
|
||||
*
|
||||
* Intended use:
|
||||
*
|
||||
* ```c
|
||||
* struct xkb_compose_table_iterator *iter = xkb_compose_table_iterator_new(compose_table);
|
||||
* struct xkb_compose_table_entry *entry;
|
||||
* while ((entry = xkb_compose_table_iterator_next(iter))) {
|
||||
* // ...
|
||||
* }
|
||||
* xkb_compose_table_iterator_free(iter);
|
||||
* ```
|
||||
*
|
||||
* @returns A new compose table iterator, or `NULL` on failure.
|
||||
*
|
||||
* @memberof xkb_compose_table_iterator
|
||||
* @sa xkb_compose_table_iterator_free()
|
||||
* @since 1.6.0
|
||||
*/
|
||||
struct xkb_compose_table_iterator *
|
||||
xkb_compose_table_iterator_new(struct xkb_compose_table *table);
|
||||
|
||||
/**
|
||||
* Free a compose iterator.
|
||||
*
|
||||
* @memberof xkb_compose_table_iterator
|
||||
* @since 1.6.0
|
||||
*/
|
||||
void
|
||||
xkb_compose_table_iterator_free(struct xkb_compose_table_iterator *iter);
|
||||
|
||||
/**
|
||||
* Get the next compose entry from a compose table iterator.
|
||||
*
|
||||
* The entries are returned in lexicographic order of the left-hand
|
||||
* side of entries. This does not correspond to the order in which
|
||||
* the entries appear in the Compose file.
|
||||
*
|
||||
* @attention The return value is valid until the next call to this function.
|
||||
*
|
||||
* Returns `NULL` in case there is no more entries.
|
||||
*
|
||||
* @memberof xkb_compose_table_iterator
|
||||
* @since 1.6.0
|
||||
*/
|
||||
struct xkb_compose_table_entry *
|
||||
xkb_compose_table_iterator_next(struct xkb_compose_table_iterator *iter);
|
||||
|
||||
/** 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 */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2012 Intel Corporation
|
||||
*
|
||||
* 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>
|
||||
*/
|
||||
|
||||
#ifndef _XKBCOMMON_NAMES_H
|
||||
#define _XKBCOMMON_NAMES_H
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Predefined names for common modifiers and LEDs.
|
||||
*/
|
||||
|
||||
#define XKB_MOD_NAME_SHIFT "Shift"
|
||||
#define XKB_MOD_NAME_CAPS "Lock"
|
||||
#define XKB_MOD_NAME_CTRL "Control"
|
||||
#define XKB_MOD_NAME_ALT "Mod1"
|
||||
#define XKB_MOD_NAME_NUM "Mod2"
|
||||
#define XKB_MOD_NAME_LOGO "Mod4"
|
||||
|
||||
#define XKB_LED_NAME_CAPS "Caps Lock"
|
||||
#define XKB_LED_NAME_NUM "Num Lock"
|
||||
#define XKB_LED_NAME_SCROLL "Scroll Lock"
|
||||
|
||||
#endif
|
||||
@@ -1,244 +0,0 @@
|
||||
/*
|
||||
* 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_X11_H
|
||||
#define _XKBCOMMON_X11_H
|
||||
|
||||
#include <xcb/xcb.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* libxkbcommon-x11 API - Additional X11 support for xkbcommon.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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 tools/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.
|
||||
*/
|
||||
#define XKB_X11_MIN_MAJOR_XKB_VERSION 1
|
||||
/**
|
||||
* The minimal compatible minor version of the XKB X11 extension which
|
||||
* this library can use (for the minimal major version).
|
||||
*/
|
||||
#define XKB_X11_MIN_MINOR_XKB_VERSION 0
|
||||
|
||||
/** Flags for the xkb_x11_setup_xkb_extension() function. */
|
||||
enum xkb_x11_setup_xkb_extension_flags {
|
||||
/** Do not apply any flags. */
|
||||
XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS = 0
|
||||
};
|
||||
|
||||
/**
|
||||
* Setup the XKB X11 extension for this X client.
|
||||
*
|
||||
* The xkbcommon-x11 library uses various XKB requests. Before doing so,
|
||||
* an X client must notify the server that it will be using the extension.
|
||||
* This function (or an XCB equivalent) must be called before any other
|
||||
* function in this library is used.
|
||||
*
|
||||
* Some X servers may not support or disable the XKB extension. If you
|
||||
* want to support such servers, you need to use a different fallback.
|
||||
*
|
||||
* You may call this function several times; it is idempotent.
|
||||
*
|
||||
* @param connection
|
||||
* An XCB connection to the X server.
|
||||
* @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
|
||||
* 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
|
||||
* Backfilled with the XKB base (also known as first) event code, needed
|
||||
* to distinguish XKB events. Can be NULL.
|
||||
* @param[out] base_error_out
|
||||
* Backfilled with the XKB base (also known as first) error code, needed
|
||||
* to distinguish XKB errors. Can be NULL.
|
||||
*
|
||||
* @returns 1 on success, or 0 on failure.
|
||||
*/
|
||||
int
|
||||
xkb_x11_setup_xkb_extension(xcb_connection_t *connection,
|
||||
uint16_t major_xkb_version,
|
||||
uint16_t minor_xkb_version,
|
||||
enum xkb_x11_setup_xkb_extension_flags flags,
|
||||
uint16_t *major_xkb_version_out,
|
||||
uint16_t *minor_xkb_version_out,
|
||||
uint8_t *base_event_out,
|
||||
uint8_t *base_error_out);
|
||||
|
||||
/**
|
||||
* Get the keyboard device ID of the core X11 keyboard.
|
||||
*
|
||||
* @param connection An XCB connection to the X server.
|
||||
*
|
||||
* @returns A device ID which may be used with other xkb_x11_* functions,
|
||||
* or -1 on failure.
|
||||
*/
|
||||
int32_t
|
||||
xkb_x11_get_core_keyboard_device_id(xcb_connection_t *connection);
|
||||
|
||||
/**
|
||||
* Create a keymap from an X11 keyboard device.
|
||||
*
|
||||
* This function queries the X server with various requests, fetches the
|
||||
* details of the active keymap on a keyboard device, and creates an
|
||||
* xkb_keymap from these details.
|
||||
*
|
||||
* @param context
|
||||
* The context in which to create the keymap.
|
||||
* @param connection
|
||||
* An XCB connection to the X server.
|
||||
* @param device_id
|
||||
* 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.
|
||||
*
|
||||
* @returns A keymap retrieved from the X server, or NULL on failure.
|
||||
*
|
||||
* @memberof xkb_keymap
|
||||
*/
|
||||
struct xkb_keymap *
|
||||
xkb_x11_keymap_new_from_device(struct xkb_context *context,
|
||||
xcb_connection_t *connection,
|
||||
int32_t device_id,
|
||||
enum xkb_keymap_compile_flags flags);
|
||||
|
||||
/**
|
||||
* Create a new keyboard state object from an X11 keyboard device.
|
||||
*
|
||||
* This function is the same as xkb_state_new(), only pre-initialized
|
||||
* with the state of the device at the time this function is called.
|
||||
*
|
||||
* @param keymap
|
||||
* The keymap for which to create the state.
|
||||
* @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.
|
||||
*
|
||||
* @returns A new keyboard state object, or NULL on failure.
|
||||
*
|
||||
* @memberof xkb_state
|
||||
*/
|
||||
struct xkb_state *
|
||||
xkb_x11_state_new_from_device(struct xkb_keymap *keymap,
|
||||
xcb_connection_t *connection,
|
||||
int32_t device_id);
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* _XKBCOMMON_X11_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,789 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2020 Red Hat, Inc.
|
||||
*
|
||||
* 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 _XKBREGISTRY_H_
|
||||
#define _XKBREGISTRY_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Query for available RMLVO
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @defgroup registry Query for available RMLVO
|
||||
*
|
||||
* The libxkbregistry API to query for available rules, models, layouts,
|
||||
* variants and options (RMLVO). libxkbregistry is a separate library to
|
||||
* libxkbcommon.
|
||||
*
|
||||
* This library is the replacement for clients currently parsing evdev.xml
|
||||
* directly. The library is intended to provide easy access to the set of
|
||||
* **possible** MLVO configurations for a given ruleset. It is not a library to
|
||||
* apply these configurations, merely to enumerate them. The intended users of
|
||||
* this library are the configuration UIs that allow a user to select their
|
||||
* keyboard layout of choice.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @struct rxkb_context
|
||||
*
|
||||
* Opaque top level library context object.
|
||||
*
|
||||
* The context contains general library state, like include paths and parsed
|
||||
* data. Objects are created in a specific context, and multiple contexts
|
||||
* may coexist simultaneously. Objects from different contexts are
|
||||
* completely separated and do not share any memory or state.
|
||||
*/
|
||||
struct rxkb_context;
|
||||
|
||||
/**
|
||||
* @struct rxkb_model
|
||||
*
|
||||
* Opaque struct representing an XKB model.
|
||||
*/
|
||||
struct rxkb_model;
|
||||
|
||||
/**
|
||||
* @struct rxkb_layout
|
||||
*
|
||||
* Opaque struct representing an XKB layout, including an optional variant.
|
||||
* Where the variant is NULL, the layout is the base layout.
|
||||
*
|
||||
* For example, "us" is the base layout, "us(intl)" is the "intl" variant of the
|
||||
* layout "us".
|
||||
*/
|
||||
struct rxkb_layout;
|
||||
|
||||
/**
|
||||
* @struct rxkb_option_group
|
||||
*
|
||||
* Opaque struct representing an option group. Option groups divide the
|
||||
* individual options into logical groups. Their main purpose is to indicate
|
||||
* whether some options are mutually exclusive or not.
|
||||
*/
|
||||
struct rxkb_option_group;
|
||||
|
||||
/**
|
||||
* @struct rxkb_option
|
||||
*
|
||||
* Opaque struct representing an XKB option. Options are grouped inside an @ref
|
||||
* rxkb_option_group.
|
||||
*/
|
||||
struct rxkb_option;
|
||||
|
||||
/**
|
||||
*
|
||||
* @struct rxkb_iso639_code
|
||||
*
|
||||
* Opaque struct representing an ISO 639-3 code (e.g. "eng", "fra"). There
|
||||
* is no guarantee that two identical ISO codes share the same struct. You
|
||||
* must not rely on the pointer value of this struct.
|
||||
*
|
||||
* See https://iso639-3.sil.org/code_tables/639/data for a list of codes.
|
||||
*/
|
||||
struct rxkb_iso639_code;
|
||||
|
||||
/**
|
||||
*
|
||||
* @struct rxkb_iso3166_code
|
||||
*
|
||||
* Opaque struct representing an ISO 3166 Alpha 2 code (e.g. "US", "FR").
|
||||
* There is no guarantee that two identical ISO codes share the same struct.
|
||||
* You must not rely on the pointer value of this struct.
|
||||
*
|
||||
* See https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes for a list
|
||||
* of codes.
|
||||
*/
|
||||
struct rxkb_iso3166_code;
|
||||
|
||||
/**
|
||||
* Describes the popularity of an item. Historically, some highly specialized or
|
||||
* experimental definitions are excluded from the default list and shipped in
|
||||
* separate files. If these extra definitions are loaded (see @ref
|
||||
* RXKB_CONTEXT_LOAD_EXOTIC_RULES), the popularity of the item is set
|
||||
* accordingly.
|
||||
*
|
||||
* If the exotic items are not loaded, all items will have the standard
|
||||
* popularity.
|
||||
*/
|
||||
enum rxkb_popularity {
|
||||
RXKB_POPULARITY_STANDARD = 1,
|
||||
RXKB_POPULARITY_EXOTIC,
|
||||
};
|
||||
|
||||
/**
|
||||
* Flags for context creation.
|
||||
*/
|
||||
enum rxkb_context_flags {
|
||||
RXKB_CONTEXT_NO_FLAGS = 0,
|
||||
/**
|
||||
* Skip the default include paths. This requires the caller to call
|
||||
* rxkb_context_include_path_append() or
|
||||
* rxkb_context_include_path_append_default().
|
||||
*/
|
||||
RXKB_CONTEXT_NO_DEFAULT_INCLUDES = (1 << 0),
|
||||
/**
|
||||
* Load the extra items that are considered too exotic for the default list.
|
||||
*
|
||||
* For historical reasons, xkeyboard-config ships those exotic rules in a
|
||||
* separate file (e.g. `evdev.extras.xml`). Where the exotic rules are
|
||||
* requested, libxkbregistry will look for and load `$ruleset.extras.xml`
|
||||
* in the include paths, see rxkb_context_include_path_append() for details
|
||||
* on the lookup behavior.
|
||||
*/
|
||||
RXKB_CONTEXT_LOAD_EXOTIC_RULES = (1 << 1),
|
||||
/**
|
||||
* Disable the use of secure_getenv for this context, so that privileged
|
||||
* processes can use environment variables. Client uses at their own risk.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
RXKB_CONTEXT_NO_SECURE_GETENV = (1 << 2)
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new xkb registry context.
|
||||
*
|
||||
* The context has an initial refcount of 1. Use rxkb_context_unref() to release
|
||||
* memory associated with this context.
|
||||
*
|
||||
* Creating a context does not parse the files yet, use
|
||||
* rxkb_context_parse().
|
||||
*
|
||||
* @param flags Flags affecting context behavior
|
||||
* @return A new xkb registry context or NULL on failure
|
||||
*/
|
||||
struct rxkb_context *
|
||||
rxkb_context_new(enum rxkb_context_flags flags);
|
||||
|
||||
/** Specifies a logging level. */
|
||||
enum rxkb_log_level {
|
||||
RXKB_LOG_LEVEL_CRITICAL = 10, /**< Log critical internal errors only. */
|
||||
RXKB_LOG_LEVEL_ERROR = 20, /**< Log all errors. */
|
||||
RXKB_LOG_LEVEL_WARNING = 30, /**< Log warnings and errors. */
|
||||
RXKB_LOG_LEVEL_INFO = 40, /**< Log information, warnings, and errors. */
|
||||
RXKB_LOG_LEVEL_DEBUG = 50 /**< Log everything. */
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the current logging level.
|
||||
*
|
||||
* @param ctx The context in which to set the logging level.
|
||||
* @param level The logging level to use. Only messages from this level
|
||||
* and below will be logged.
|
||||
*
|
||||
* The default level is RXKB_LOG_LEVEL_ERROR. The environment variable
|
||||
* RXKB_LOG_LEVEL, if set at the time the context was created, overrides the
|
||||
* default value. It may be specified as a level number or name.
|
||||
*/
|
||||
void
|
||||
rxkb_context_set_log_level(struct rxkb_context *ctx,
|
||||
enum rxkb_log_level level);
|
||||
|
||||
/**
|
||||
* Get the current logging level.
|
||||
*/
|
||||
enum rxkb_log_level
|
||||
rxkb_context_get_log_level(struct rxkb_context *ctx);
|
||||
|
||||
/**
|
||||
* Set a custom function to handle logging messages.
|
||||
*
|
||||
* @param ctx The context in which to use the set logging function.
|
||||
* @param log_fn The function that will be called for logging messages.
|
||||
* Passing NULL restores the default function, which logs to stderr.
|
||||
*
|
||||
* By default, log messages from this library are printed to stderr. This
|
||||
* function allows you to replace the default behavior with a custom
|
||||
* handler. The handler is only called with messages which match the
|
||||
* current logging level and verbosity settings for the context.
|
||||
* level is the logging level of the message. @a format and @a args are
|
||||
* the same as in the vprintf(3) function.
|
||||
*
|
||||
* You may use rxkb_context_set_user_data() on the context, and then call
|
||||
* rxkb_context_get_user_data() from within the logging function to provide
|
||||
* it with additional private context.
|
||||
*/
|
||||
void
|
||||
rxkb_context_set_log_fn(struct rxkb_context *ctx,
|
||||
void (*log_fn)(struct rxkb_context *ctx,
|
||||
enum rxkb_log_level level,
|
||||
const char *format, va_list args));
|
||||
|
||||
|
||||
/**
|
||||
* Parse the given ruleset. This can only be called once per context and once
|
||||
* parsed the data in the context is considered constant and will never
|
||||
* change.
|
||||
*
|
||||
* This function parses all files with the given ruleset name. See
|
||||
* rxkb_context_include_path_append() for details.
|
||||
*
|
||||
* If this function returns false, libxkbregistry failed to parse the xml files.
|
||||
* This is usually caused by invalid files on the host and should be debugged by
|
||||
* the host's administrator using external tools. Callers should reduce the
|
||||
* include paths to known good paths and/or fall back to a default RMLVO set.
|
||||
*
|
||||
* If this function returns false, the context should be be considered dead and
|
||||
* must be released with rxkb_context_unref().
|
||||
*
|
||||
* @param ctx The xkb registry context
|
||||
* @param ruleset The ruleset to parse, e.g. "evdev"
|
||||
* @return true on success or false on failure
|
||||
*/
|
||||
bool
|
||||
rxkb_context_parse(struct rxkb_context *ctx, const char *ruleset);
|
||||
|
||||
/**
|
||||
* Parse the default ruleset as configured at build time. See
|
||||
* rxkb_context_parse() for details.
|
||||
*/
|
||||
bool
|
||||
rxkb_context_parse_default_ruleset(struct rxkb_context *ctx);
|
||||
|
||||
/**
|
||||
* Increases the refcount of this object by one and returns the object.
|
||||
*
|
||||
* @param ctx The xkb registry context
|
||||
* @return The passed in object
|
||||
*/
|
||||
struct rxkb_context*
|
||||
rxkb_context_ref(struct rxkb_context *ctx);
|
||||
|
||||
/**
|
||||
* Decreases the refcount of this object by one. Where the refcount of an
|
||||
* object hits zero, associated resources will be freed.
|
||||
*
|
||||
* @param ctx The xkb registry context
|
||||
* @return always NULL
|
||||
*/
|
||||
struct rxkb_context*
|
||||
rxkb_context_unref(struct rxkb_context *ctx);
|
||||
|
||||
/**
|
||||
* Assign user-specific data. libxkbregistry will not look at or modify the
|
||||
* data, it will merely return the same pointer in
|
||||
* rxkb_context_get_user_data().
|
||||
*
|
||||
* @param ctx The xkb registry context
|
||||
* @param user_data User-specific data pointer
|
||||
*/
|
||||
void
|
||||
rxkb_context_set_user_data(struct rxkb_context *ctx, void *user_data);
|
||||
|
||||
/**
|
||||
* Return the pointer passed into rxkb_context_get_user_data().
|
||||
*
|
||||
* @param ctx The xkb registry context
|
||||
* @return User-specific data pointer
|
||||
*/
|
||||
void *
|
||||
rxkb_context_get_user_data(struct rxkb_context *ctx);
|
||||
|
||||
/**
|
||||
* Append a new entry to the context's include path.
|
||||
*
|
||||
* The include path handling is optimized for the most common use-case: a set of
|
||||
* system files that provide a complete set of MLVO and some
|
||||
* custom MLVO provided by a user **in addition** to the system set.
|
||||
*
|
||||
* The include paths should be given so that the least complete path is
|
||||
* specified first and the most complete path is appended last. For example:
|
||||
*
|
||||
* @code
|
||||
* ctx = rxkb_context_new(RXKB_CONTEXT_NO_DEFAULT_INCLUDES);
|
||||
* rxkb_context_include_path_append(ctx, "/home/user/.config/xkb");
|
||||
* rxkb_context_include_path_append(ctx, "/usr/share/X11/xkb");
|
||||
* rxkb_context_parse(ctx, "evdev");
|
||||
* @endcode
|
||||
*
|
||||
* The above example reflects the default behavior unless @ref
|
||||
* RXKB_CONTEXT_NO_DEFAULT_INCLUDES is provided.
|
||||
*
|
||||
* Loading of the files is in **reverse order**, i.e. the last path appended is
|
||||
* loaded first - in this case the ``/usr/share/X11/xkb`` path.
|
||||
* Any models, layouts, variants and options defined in the "evdev" ruleset
|
||||
* are loaded into the context. Then, any RMLVO found in the "evdev" ruleset of
|
||||
* the user's path (``/home/user/.config/xkb`` in this example) are **appended**
|
||||
* to the existing set.
|
||||
*
|
||||
* Note that data from previously loaded include paths is never overwritten,
|
||||
* only appended to. It is not not possible to change the system-provided data,
|
||||
* only to append new models, layouts, variants and options to it.
|
||||
*
|
||||
* In other words, to define a new variant of the "us" layout called "banana",
|
||||
* the following XML is sufficient.
|
||||
*
|
||||
* @verbatim
|
||||
* <xkbConfigRegistry version="1.1">
|
||||
* <layoutList>
|
||||
* <layout>
|
||||
* <configItem>
|
||||
* <name>us</name>
|
||||
* </configItem>
|
||||
* <variantList>
|
||||
* <variant>
|
||||
* <configItem>
|
||||
* <name>banana</name>
|
||||
* <description>English (Banana)</description>
|
||||
* </configItem>
|
||||
* </variant>
|
||||
* </layout>
|
||||
* </layoutList>
|
||||
* </xkbConfigRegistry>
|
||||
* @endverbatim
|
||||
*
|
||||
* The list of models, options and all other layouts (including "us" and its
|
||||
* variants) is taken from the system files. The resulting list of layouts will
|
||||
* thus have a "us" keyboard layout with the variant "banana" and all other
|
||||
* system-provided variants (dvorak, colemak, intl, etc.)
|
||||
*
|
||||
* This function must be called before rxkb_context_parse() or
|
||||
* rxkb_context_parse_default_ruleset().
|
||||
*
|
||||
* @returns true on success, or false if the include path could not be added
|
||||
* or is inaccessible.
|
||||
*/
|
||||
bool
|
||||
rxkb_context_include_path_append(struct rxkb_context *ctx, const char *path);
|
||||
|
||||
/**
|
||||
* Append the default include paths to the context's include path.
|
||||
* See rxkb_context_include_path_append() for details about the merge order.
|
||||
*
|
||||
* This function must be called before rxkb_context_parse() or
|
||||
* rxkb_context_parse_default_ruleset().
|
||||
*
|
||||
* @returns true on success, or false if the include path could not be added
|
||||
* or is inaccessible.
|
||||
*/
|
||||
bool
|
||||
rxkb_context_include_path_append_default(struct rxkb_context *ctx);
|
||||
|
||||
/**
|
||||
* Return the first model for this context. Use this to start iterating over
|
||||
* the models, followed by calls to rxkb_model_next(). Models are not sorted.
|
||||
*
|
||||
* The refcount of the returned model is not increased. Use rxkb_model_ref() if
|
||||
* you need to keep this struct outside the immediate scope.
|
||||
*
|
||||
* @return The first model in the model list.
|
||||
*/
|
||||
struct rxkb_model *
|
||||
rxkb_model_first(struct rxkb_context *ctx);
|
||||
|
||||
/**
|
||||
* Return the next model for this context. Returns NULL when no more models
|
||||
* are available.
|
||||
*
|
||||
* The refcount of the returned model is not increased. Use rxkb_model_ref() if
|
||||
* you need to keep this struct outside the immediate scope.
|
||||
*
|
||||
* @return the next model or NULL at the end of the list
|
||||
*/
|
||||
struct rxkb_model *
|
||||
rxkb_model_next(struct rxkb_model *m);
|
||||
|
||||
/**
|
||||
* Increase the refcount of the argument by one.
|
||||
*
|
||||
* @returns The argument passed in to this function.
|
||||
*/
|
||||
struct rxkb_model *
|
||||
rxkb_model_ref(struct rxkb_model *m);
|
||||
|
||||
/**
|
||||
* Decrease the refcount of the argument by one. When the refcount hits zero,
|
||||
* all memory associated with this struct is freed.
|
||||
*
|
||||
* @returns always NULL
|
||||
*/
|
||||
struct rxkb_model *
|
||||
rxkb_model_unref(struct rxkb_model *m);
|
||||
|
||||
/**
|
||||
* Return the name of this model. This is the value for M in RMLVO, to be used
|
||||
* with libxkbcommon.
|
||||
*/
|
||||
const char *
|
||||
rxkb_model_get_name(struct rxkb_model *m);
|
||||
|
||||
/**
|
||||
* Return a human-readable description of this model. This function may return
|
||||
* NULL.
|
||||
*/
|
||||
const char *
|
||||
rxkb_model_get_description(struct rxkb_model *m);
|
||||
|
||||
/**
|
||||
* Return the vendor name for this model. This function may return NULL.
|
||||
*/
|
||||
const char *
|
||||
rxkb_model_get_vendor(struct rxkb_model *m);
|
||||
|
||||
/**
|
||||
* Return the popularity for this model.
|
||||
*/
|
||||
enum rxkb_popularity
|
||||
rxkb_model_get_popularity(struct rxkb_model *m);
|
||||
|
||||
/**
|
||||
* Return the first layout for this context. Use this to start iterating over
|
||||
* the layouts, followed by calls to rxkb_layout_next(). Layouts are not sorted.
|
||||
*
|
||||
* The refcount of the returned layout is not increased. Use rxkb_layout_ref() if
|
||||
* you need to keep this struct outside the immediate scope.
|
||||
*
|
||||
* @return The first layout in the layout list.
|
||||
*/
|
||||
struct rxkb_layout *
|
||||
rxkb_layout_first(struct rxkb_context *ctx);
|
||||
|
||||
/**
|
||||
* Return the next layout for this context. Returns NULL when no more layouts
|
||||
* are available.
|
||||
*
|
||||
* The refcount of the returned layout is not increased. Use rxkb_layout_ref()
|
||||
* if you need to keep this struct outside the immediate scope.
|
||||
*
|
||||
* @return the next layout or NULL at the end of the list
|
||||
*/
|
||||
struct rxkb_layout *
|
||||
rxkb_layout_next(struct rxkb_layout *l);
|
||||
|
||||
/**
|
||||
* Increase the refcount of the argument by one.
|
||||
*
|
||||
* @returns The argument passed in to this function.
|
||||
*/
|
||||
struct rxkb_layout *
|
||||
rxkb_layout_ref(struct rxkb_layout *l);
|
||||
|
||||
/**
|
||||
* Decrease the refcount of the argument by one. When the refcount hits zero,
|
||||
* all memory associated with this struct is freed.
|
||||
*
|
||||
* @returns always NULL
|
||||
*/
|
||||
struct rxkb_layout *
|
||||
rxkb_layout_unref(struct rxkb_layout *l);
|
||||
|
||||
/**
|
||||
* Return the name of this layout. This is the value for L in RMLVO, to be used
|
||||
* with libxkbcommon.
|
||||
*/
|
||||
const char *
|
||||
rxkb_layout_get_name(struct rxkb_layout *l);
|
||||
|
||||
/**
|
||||
* Return the variant of this layout. This is the value for V in RMLVO, to be
|
||||
* used with libxkbcommon.
|
||||
*
|
||||
* A variant does not stand on its own, it always depends on the base layout.
|
||||
* e.g. there may be multiple variants called "intl" but there is only one
|
||||
* "us(intl)".
|
||||
*
|
||||
* Where the variant is NULL, the layout is the base layout (e.g. "us").
|
||||
*/
|
||||
const char *
|
||||
rxkb_layout_get_variant(struct rxkb_layout *l);
|
||||
|
||||
/**
|
||||
* Return a short (one-word) description of this layout. This function may
|
||||
* return NULL.
|
||||
*/
|
||||
const char *
|
||||
rxkb_layout_get_brief(struct rxkb_layout *l);
|
||||
|
||||
/**
|
||||
* Return a human-readable description of this layout. This function may return
|
||||
* NULL.
|
||||
*/
|
||||
const char *
|
||||
rxkb_layout_get_description(struct rxkb_layout *l);
|
||||
|
||||
/**
|
||||
* Return the popularity for this layout.
|
||||
*/
|
||||
enum rxkb_popularity
|
||||
rxkb_layout_get_popularity(struct rxkb_layout *l);
|
||||
|
||||
/**
|
||||
* Return the first option group for this context. Use this to start iterating
|
||||
* over the option groups, followed by calls to rxkb_option_group_next().
|
||||
* Option groups are not sorted.
|
||||
*
|
||||
* The refcount of the returned option group is not increased. Use
|
||||
* rxkb_option_group_ref() if you need to keep this struct outside the immediate
|
||||
* scope.
|
||||
*
|
||||
* @return The first option group in the option group list.
|
||||
*/
|
||||
struct rxkb_option_group *
|
||||
rxkb_option_group_first(struct rxkb_context *ctx);
|
||||
|
||||
/**
|
||||
* Return the next option group for this context. Returns NULL when no more
|
||||
* option groups are available.
|
||||
*
|
||||
* The refcount of the returned option group is not increased. Use
|
||||
* rxkb_option_group_ref() if you need to keep this struct outside the immediate
|
||||
* scope.
|
||||
*
|
||||
* @return the next option group or NULL at the end of the list
|
||||
*/
|
||||
struct rxkb_option_group *
|
||||
rxkb_option_group_next(struct rxkb_option_group *g);
|
||||
|
||||
/**
|
||||
* Increase the refcount of the argument by one.
|
||||
*
|
||||
* @returns The argument passed in to this function.
|
||||
*/
|
||||
struct rxkb_option_group *
|
||||
rxkb_option_group_ref(struct rxkb_option_group *g);
|
||||
|
||||
/**
|
||||
* Decrease the refcount of the argument by one. When the refcount hits zero,
|
||||
* all memory associated with this struct is freed.
|
||||
*
|
||||
* @returns always NULL
|
||||
*/
|
||||
struct rxkb_option_group *
|
||||
rxkb_option_group_unref(struct rxkb_option_group *g);
|
||||
|
||||
/**
|
||||
* Return the name of this option group. This is **not** the value for O in
|
||||
* RMLVO, the name can be used for internal sorting in the caller. This function
|
||||
* may return NULL.
|
||||
*/
|
||||
const char *
|
||||
rxkb_option_group_get_name(struct rxkb_option_group *m);
|
||||
|
||||
/**
|
||||
* Return a human-readable description of this option group. This function may
|
||||
* return NULL.
|
||||
*/
|
||||
const char *
|
||||
rxkb_option_group_get_description(struct rxkb_option_group *m);
|
||||
|
||||
/**
|
||||
* @return true if multiple options within this option group can be selected
|
||||
* simultaneously, false if all options within this option group
|
||||
* are mutually exclusive.
|
||||
*/
|
||||
bool
|
||||
rxkb_option_group_allows_multiple(struct rxkb_option_group *g);
|
||||
|
||||
/**
|
||||
* Return the popularity for this option group.
|
||||
*/
|
||||
enum rxkb_popularity
|
||||
rxkb_option_group_get_popularity(struct rxkb_option_group *g);
|
||||
|
||||
/**
|
||||
* Return the first option for this option group. Use this to start iterating
|
||||
* over the options, followed by calls to rxkb_option_next(). Options are not
|
||||
* sorted.
|
||||
*
|
||||
* The refcount of the returned option is not increased. Use rxkb_option_ref()
|
||||
* if you need to keep this struct outside the immediate scope.
|
||||
*
|
||||
* @return The first option in the option list.
|
||||
*/
|
||||
struct rxkb_option *
|
||||
rxkb_option_first(struct rxkb_option_group *group);
|
||||
|
||||
/**
|
||||
* Return the next option for this option group. Returns NULL when no more
|
||||
* options are available.
|
||||
*
|
||||
* The refcount of the returned options is not increased. Use rxkb_option_ref()
|
||||
* if you need to keep this struct outside the immediate scope.
|
||||
*
|
||||
* @returns The next option or NULL at the end of the list
|
||||
*/
|
||||
struct rxkb_option *
|
||||
rxkb_option_next(struct rxkb_option *o);
|
||||
|
||||
/**
|
||||
* Increase the refcount of the argument by one.
|
||||
*
|
||||
* @returns The argument passed in to this function.
|
||||
*/
|
||||
struct rxkb_option *
|
||||
rxkb_option_ref(struct rxkb_option *o);
|
||||
|
||||
/**
|
||||
* Decrease the refcount of the argument by one. When the refcount hits zero,
|
||||
* all memory associated with this struct is freed.
|
||||
*
|
||||
* @returns always NULL
|
||||
*/
|
||||
struct rxkb_option *
|
||||
rxkb_option_unref(struct rxkb_option *o);
|
||||
|
||||
/**
|
||||
* Return the name of this option. This is the value for O in RMLVO, to be used
|
||||
* with libxkbcommon.
|
||||
*/
|
||||
const char *
|
||||
rxkb_option_get_name(struct rxkb_option *o);
|
||||
|
||||
/**
|
||||
* Return a short (one-word) description of this option. This function may
|
||||
* return NULL.
|
||||
*/
|
||||
const char *
|
||||
rxkb_option_get_brief(struct rxkb_option *o);
|
||||
|
||||
/**
|
||||
* Return a human-readable description of this option. This function may return
|
||||
* NULL.
|
||||
*/
|
||||
const char *
|
||||
rxkb_option_get_description(struct rxkb_option *o);
|
||||
|
||||
/**
|
||||
* Return the popularity for this option.
|
||||
*/
|
||||
enum rxkb_popularity
|
||||
rxkb_option_get_popularity(struct rxkb_option *o);
|
||||
|
||||
/**
|
||||
* Increase the refcount of the argument by one.
|
||||
*
|
||||
* @returns The argument passed in to this function.
|
||||
*/
|
||||
struct rxkb_iso639_code *
|
||||
rxkb_iso639_code_ref(struct rxkb_iso639_code *iso639);
|
||||
|
||||
/**
|
||||
* Decrease the refcount of the argument by one. When the refcount hits zero,
|
||||
* all memory associated with this struct is freed.
|
||||
*
|
||||
* @returns always NULL
|
||||
*/
|
||||
struct rxkb_iso639_code *
|
||||
rxkb_iso639_code_unref(struct rxkb_iso639_code *iso639);
|
||||
|
||||
/**
|
||||
* Return the ISO 639-3 code for this code (e.g. "eng", "fra").
|
||||
*/
|
||||
const char *
|
||||
rxkb_iso639_code_get_code(struct rxkb_iso639_code *iso639);
|
||||
|
||||
/**
|
||||
* Return the first ISO 639 for this layout. Use this to start iterating over
|
||||
* the codes, followed by calls to rxkb_iso639_code_next(). Codes are not
|
||||
* sorted.
|
||||
*
|
||||
* The refcount of the returned code is not increased. Use rxkb_iso639_code_ref()
|
||||
* if you need to keep this struct outside the immediate scope.
|
||||
*
|
||||
* @return The first code in the code list.
|
||||
*/
|
||||
struct rxkb_iso639_code *
|
||||
rxkb_layout_get_iso639_first(struct rxkb_layout *layout);
|
||||
|
||||
/**
|
||||
* Return the next code in the list. Returns NULL when no more codes
|
||||
* are available.
|
||||
*
|
||||
* The refcount of the returned codes is not increased. Use
|
||||
* rxkb_iso639_code_ref() if you need to keep this struct outside the immediate
|
||||
* scope.
|
||||
*
|
||||
* @returns The next code or NULL at the end of the list
|
||||
*/
|
||||
struct rxkb_iso639_code *
|
||||
rxkb_iso639_code_next(struct rxkb_iso639_code *iso639);
|
||||
|
||||
/**
|
||||
* Increase the refcount of the argument by one.
|
||||
*
|
||||
* @returns The argument passed in to this function.
|
||||
*/
|
||||
struct rxkb_iso3166_code *
|
||||
rxkb_iso3166_code_ref(struct rxkb_iso3166_code *iso3166);
|
||||
|
||||
/**
|
||||
* Decrease the refcount of the argument by one. When the refcount hits zero,
|
||||
* all memory associated with this struct is freed.
|
||||
*
|
||||
* @returns always NULL
|
||||
*/
|
||||
struct rxkb_iso3166_code *
|
||||
rxkb_iso3166_code_unref(struct rxkb_iso3166_code *iso3166);
|
||||
|
||||
/**
|
||||
* Return the ISO 3166 Alpha 2 code for this code (e.g. "US", "FR").
|
||||
*/
|
||||
const char *
|
||||
rxkb_iso3166_code_get_code(struct rxkb_iso3166_code *iso3166);
|
||||
|
||||
/**
|
||||
* Return the first ISO 3166 for this layout. Use this to start iterating over
|
||||
* the codes, followed by calls to rxkb_iso3166_code_next(). Codes are not
|
||||
* sorted.
|
||||
*
|
||||
* The refcount of the returned code is not increased. Use
|
||||
* rxkb_iso3166_code_ref() if you need to keep this struct outside the immediate
|
||||
* scope.
|
||||
*
|
||||
* @return The first code in the code list.
|
||||
*/
|
||||
struct rxkb_iso3166_code *
|
||||
rxkb_layout_get_iso3166_first(struct rxkb_layout *layout);
|
||||
|
||||
/**
|
||||
* Return the next code in the list. Returns NULL when no more codes
|
||||
* are available.
|
||||
*
|
||||
* The refcount of the returned codes is not increased. Use
|
||||
* rxkb_iso3166_code_ref() if you need to keep this struct outside the immediate
|
||||
* scope.
|
||||
*
|
||||
* @returns The next code or NULL at the end of the list
|
||||
*/
|
||||
struct rxkb_iso3166_code *
|
||||
rxkb_iso3166_code_next(struct rxkb_iso3166_code *iso3166);
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* _XKBREGISTRY_H_ */
|
||||
@@ -1,994 +0,0 @@
|
||||
project(
|
||||
'libxkbcommon',
|
||||
'c',
|
||||
version: '1.7.0',
|
||||
default_options: [
|
||||
'c_std=c11',
|
||||
'warning_level=2',
|
||||
'b_lundef=true',
|
||||
],
|
||||
meson_version : '>= 0.52.0',
|
||||
)
|
||||
pkgconfig = import('pkgconfig')
|
||||
cc = meson.get_compiler('c')
|
||||
|
||||
dir_libexec = get_option('prefix')/get_option('libexecdir')/'xkbcommon'
|
||||
|
||||
# Compiler flags.
|
||||
cflags = [
|
||||
'-fno-strict-aliasing',
|
||||
'-Wno-unused-parameter',
|
||||
'-Wno-missing-field-initializers',
|
||||
'-Wpointer-arith',
|
||||
'-Wmissing-declarations',
|
||||
'-Wformat=2',
|
||||
'-Wstrict-prototypes',
|
||||
'-Wmissing-prototypes',
|
||||
'-Wnested-externs',
|
||||
'-Wbad-function-cast',
|
||||
'-Wshadow',
|
||||
'-Wlogical-op',
|
||||
'-Wdate-time',
|
||||
'-Wwrite-strings',
|
||||
'-Wno-documentation-deprecated-sync',
|
||||
]
|
||||
add_project_arguments(cc.get_supported_arguments(cflags), language: 'c')
|
||||
|
||||
|
||||
# The XKB config root.
|
||||
XKBCONFIGROOT = get_option('xkb-config-root')
|
||||
if XKBCONFIGROOT == ''
|
||||
xkeyboard_config_dep = dependency('xkeyboard-config', required: false)
|
||||
if xkeyboard_config_dep.found()
|
||||
XKBCONFIGROOT = xkeyboard_config_dep.get_variable(pkgconfig: 'xkb_base')
|
||||
else
|
||||
XKBCONFIGROOT = get_option('prefix')/get_option('datadir')/'X11'/'xkb'
|
||||
endif
|
||||
endif
|
||||
|
||||
XKBCONFIGEXTRAPATH = get_option('xkb-config-extra-path')
|
||||
if XKBCONFIGEXTRAPATH == ''
|
||||
XKBCONFIGEXTRAPATH = get_option('prefix')/get_option('sysconfdir')/'xkb'
|
||||
endif
|
||||
|
||||
# The X locale directory for compose.
|
||||
XLOCALEDIR = get_option('x-locale-root')
|
||||
if XLOCALEDIR == ''
|
||||
XLOCALEDIR = get_option('prefix')/get_option('datadir')/'X11'/'locale'
|
||||
endif
|
||||
|
||||
|
||||
# config.h.
|
||||
configh_data = configuration_data()
|
||||
configh_data.set('EXIT_INVALID_USAGE', '2')
|
||||
configh_data.set_quoted('LIBXKBCOMMON_VERSION', meson.project_version())
|
||||
configh_data.set_quoted('LIBXKBCOMMON_TOOL_PATH', dir_libexec)
|
||||
# Like AC_USE_SYSTEM_EXTENSIONS, what #define to use to get extensions
|
||||
# beyond the base POSIX function set.
|
||||
if host_machine.system() == 'sunos'
|
||||
system_extensions = '__EXTENSIONS__'
|
||||
else
|
||||
system_extensions = '_GNU_SOURCE'
|
||||
endif
|
||||
configh_data.set(system_extensions, 1)
|
||||
system_ext_define = '#define ' + system_extensions
|
||||
configh_data.set_quoted('DFLT_XKB_CONFIG_ROOT', XKBCONFIGROOT)
|
||||
configh_data.set_quoted('DFLT_XKB_CONFIG_EXTRA_PATH', XKBCONFIGEXTRAPATH)
|
||||
configh_data.set_quoted('XLOCALEDIR', XLOCALEDIR)
|
||||
configh_data.set_quoted('DEFAULT_XKB_RULES', get_option('default-rules'))
|
||||
configh_data.set_quoted('DEFAULT_XKB_MODEL', get_option('default-model'))
|
||||
configh_data.set_quoted('DEFAULT_XKB_LAYOUT', get_option('default-layout'))
|
||||
if get_option('default-variant') != ''
|
||||
configh_data.set_quoted('DEFAULT_XKB_VARIANT', get_option('default-variant'))
|
||||
else
|
||||
configh_data.set('DEFAULT_XKB_VARIANT', 'NULL')
|
||||
endif
|
||||
if get_option('default-options') != ''
|
||||
configh_data.set_quoted('DEFAULT_XKB_OPTIONS', get_option('default-options'))
|
||||
else
|
||||
configh_data.set('DEFAULT_XKB_OPTIONS', 'NULL')
|
||||
endif
|
||||
if cc.has_header('unistd.h')
|
||||
configh_data.set('HAVE_UNISTD_H', 1)
|
||||
endif
|
||||
if cc.links('int main(){if(__builtin_expect(1<0,0)){}}', name: '__builtin_expect')
|
||||
configh_data.set('HAVE___BUILTIN_EXPECT', 1)
|
||||
endif
|
||||
if cc.has_header_symbol('unistd.h', 'eaccess', prefix: system_ext_define)
|
||||
configh_data.set('HAVE_EACCESS', 1)
|
||||
endif
|
||||
if cc.has_header_symbol('unistd.h', 'euidaccess', prefix: system_ext_define)
|
||||
configh_data.set('HAVE_EUIDACCESS', 1)
|
||||
endif
|
||||
if cc.has_header_symbol('sys/mman.h', 'mmap')
|
||||
configh_data.set('HAVE_MMAP', 1)
|
||||
endif
|
||||
if cc.has_header_symbol('stdlib.h', 'mkostemp', prefix: system_ext_define)
|
||||
configh_data.set('HAVE_MKOSTEMP', 1)
|
||||
endif
|
||||
if cc.has_header_symbol('fcntl.h', 'posix_fallocate', prefix: system_ext_define)
|
||||
configh_data.set('HAVE_POSIX_FALLOCATE', 1)
|
||||
endif
|
||||
if cc.has_header_symbol('string.h', 'strndup', prefix: system_ext_define)
|
||||
configh_data.set('HAVE_STRNDUP', 1)
|
||||
endif
|
||||
if cc.has_header_symbol('stdio.h', 'asprintf', prefix: system_ext_define)
|
||||
configh_data.set('HAVE_ASPRINTF', 1)
|
||||
elif cc.has_header_symbol('stdio.h', 'vasprintf', prefix: system_ext_define)
|
||||
configh_data.set('HAVE_VASPRINTF', 1)
|
||||
endif
|
||||
if cc.has_header_symbol('stdlib.h', 'secure_getenv', prefix: system_ext_define)
|
||||
configh_data.set('HAVE_SECURE_GETENV', 1)
|
||||
elif cc.has_header_symbol('stdlib.h', '__secure_getenv', prefix: system_ext_define)
|
||||
configh_data.set('HAVE___SECURE_GETENV', 1)
|
||||
else
|
||||
message('C library does not support secure_getenv, using getenv instead')
|
||||
endif
|
||||
if not cc.has_header_symbol('limits.h', 'PATH_MAX', prefix: system_ext_define)
|
||||
if host_machine.system() == 'windows'
|
||||
# see https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#maximum-path-length-limitation
|
||||
configh_data.set('PATH_MAX', 260)
|
||||
else
|
||||
configh_data.set('PATH_MAX', 4096)
|
||||
endif
|
||||
endif
|
||||
|
||||
# Silence some security & deprecation warnings on MSVC
|
||||
# for some unix/C functions we use.
|
||||
# https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-3-c4996?view=vs-2019
|
||||
configh_data.set('_CRT_SECURE_NO_WARNINGS', 1)
|
||||
configh_data.set('_CRT_NONSTDC_NO_WARNINGS', 1)
|
||||
configh_data.set('_CRT_NONSTDC_NO_DEPRECATE', 1)
|
||||
# Reduce unnecessary includes on MSVC.
|
||||
configh_data.set('WIN32_LEAN_AND_MEAN', 1)
|
||||
|
||||
# Supports -Wl,--version-script?
|
||||
have_version_script = cc.links(
|
||||
'int main(){}',
|
||||
args: '-Wl,--undefined-version,--version-script=' + meson.current_source_dir()/'xkbcommon.map',
|
||||
name: '-Wl,--version-script',
|
||||
)
|
||||
|
||||
map_to_def = find_program('scripts/map-to-def')
|
||||
|
||||
# libxkbcommon.
|
||||
# Note: we use some yacc extensions, which work with either GNU bison
|
||||
# (preferred) or byacc (with backtracking enabled).
|
||||
bison = find_program('bison', 'win_bison', required: false, version: '>= 2.3a')
|
||||
if bison.found()
|
||||
yacc = bison
|
||||
yacc_gen = generator(
|
||||
bison,
|
||||
output: ['@BASENAME@.c', '@BASENAME@.h'],
|
||||
arguments: ['--defines=@OUTPUT1@', '-o', '@OUTPUT0@', '-p', '_xkbcommon_', '@INPUT@'],
|
||||
)
|
||||
else
|
||||
byacc = find_program('byacc', required: false)
|
||||
if byacc.found()
|
||||
yacc = byacc
|
||||
yacc_gen = generator(
|
||||
byacc,
|
||||
output: ['@BASENAME@.c', '@BASENAME@.h'],
|
||||
arguments: ['-H', '@OUTPUT1@', '-o', '@OUTPUT0@', '-p', '_xkbcommon_', '@INPUT@'],
|
||||
)
|
||||
else
|
||||
error('Could not find a compatible YACC program (bison or byacc)')
|
||||
endif
|
||||
endif
|
||||
libxkbcommon_sources = [
|
||||
'src/compose/parser.c',
|
||||
'src/compose/parser.h',
|
||||
'src/compose/paths.c',
|
||||
'src/compose/paths.h',
|
||||
'src/compose/state.c',
|
||||
'src/compose/table.c',
|
||||
'src/compose/table.h',
|
||||
'src/xkbcomp/action.c',
|
||||
'src/xkbcomp/action.h',
|
||||
'src/xkbcomp/ast.h',
|
||||
'src/xkbcomp/ast-build.c',
|
||||
'src/xkbcomp/ast-build.h',
|
||||
'src/xkbcomp/compat.c',
|
||||
'src/xkbcomp/expr.c',
|
||||
'src/xkbcomp/expr.h',
|
||||
'src/xkbcomp/include.c',
|
||||
'src/xkbcomp/include.h',
|
||||
'src/xkbcomp/keycodes.c',
|
||||
'src/xkbcomp/keymap.c',
|
||||
'src/xkbcomp/keymap-dump.c',
|
||||
'src/xkbcomp/keywords.c',
|
||||
yacc_gen.process('src/xkbcomp/parser.y'),
|
||||
'src/xkbcomp/parser-priv.h',
|
||||
'src/xkbcomp/rules.c',
|
||||
'src/xkbcomp/rules.h',
|
||||
'src/xkbcomp/scanner.c',
|
||||
'src/xkbcomp/symbols.c',
|
||||
'src/xkbcomp/types.c',
|
||||
'src/xkbcomp/vmod.c',
|
||||
'src/xkbcomp/vmod.h',
|
||||
'src/xkbcomp/xkbcomp.c',
|
||||
'src/xkbcomp/xkbcomp-priv.h',
|
||||
'src/atom.c',
|
||||
'src/atom.h',
|
||||
'src/context.c',
|
||||
'src/context.h',
|
||||
'src/context-priv.c',
|
||||
'src/darray.h',
|
||||
'src/keysym.c',
|
||||
'src/keysym.h',
|
||||
'src/keysym-utf.c',
|
||||
'src/ks_tables.h',
|
||||
'src/keymap.c',
|
||||
'src/keymap.h',
|
||||
'src/keymap-priv.c',
|
||||
'src/messages-codes.h',
|
||||
'src/scanner-utils.h',
|
||||
'src/state.c',
|
||||
'src/text.c',
|
||||
'src/text.h',
|
||||
'src/utf8.c',
|
||||
'src/utf8.h',
|
||||
'src/util-mem.h',
|
||||
'src/utils.c',
|
||||
'src/utils.h',
|
||||
]
|
||||
libxkbcommon_link_args = []
|
||||
libxkbcommon_link_deps = []
|
||||
if have_version_script
|
||||
libxkbcommon_link_args += '-Wl,--version-script=' + meson.current_source_dir()/'xkbcommon.map'
|
||||
libxkbcommon_link_deps += 'xkbcommon.map'
|
||||
elif cc.get_argument_syntax() == 'msvc'
|
||||
libxkbcommon_def = custom_target('xkbcommon.def',
|
||||
command: [map_to_def, '@INPUT@', '@OUTPUT@'],
|
||||
input: 'xkbcommon.map',
|
||||
output: 'kxbcommon.def',
|
||||
)
|
||||
libxkbcommon_link_deps += libxkbcommon_def
|
||||
libxkbcommon_link_args += '/DEF:' + libxkbcommon_def.full_path()
|
||||
endif
|
||||
libxkbcommon = library(
|
||||
'xkbcommon',
|
||||
'include/xkbcommon/xkbcommon.h',
|
||||
libxkbcommon_sources,
|
||||
link_args: libxkbcommon_link_args,
|
||||
link_depends: libxkbcommon_link_deps,
|
||||
gnu_symbol_visibility: 'hidden',
|
||||
version: '0.0.0',
|
||||
install: true,
|
||||
include_directories: include_directories('src', 'include'),
|
||||
)
|
||||
install_headers(
|
||||
'include/xkbcommon/xkbcommon.h',
|
||||
'include/xkbcommon/xkbcommon-compat.h',
|
||||
'include/xkbcommon/xkbcommon-compose.h',
|
||||
'include/xkbcommon/xkbcommon-keysyms.h',
|
||||
'include/xkbcommon/xkbcommon-names.h',
|
||||
subdir: 'xkbcommon',
|
||||
)
|
||||
|
||||
dep_libxkbcommon = declare_dependency(
|
||||
link_with: libxkbcommon,
|
||||
include_directories: include_directories('include'),
|
||||
)
|
||||
if meson.version().version_compare('>= 0.54.0')
|
||||
meson.override_dependency('xkbcommon', dep_libxkbcommon)
|
||||
endif
|
||||
pkgconfig.generate(
|
||||
libxkbcommon,
|
||||
name: 'xkbcommon',
|
||||
filebase: 'xkbcommon',
|
||||
version: meson.project_version(),
|
||||
description: 'XKB API common to servers and clients',
|
||||
)
|
||||
|
||||
|
||||
# libxkbcommon-x11.
|
||||
if get_option('enable-x11')
|
||||
xcb_dep = dependency('xcb', version: '>=1.10', required: false)
|
||||
xcb_xkb_dep = dependency('xcb-xkb', version: '>=1.10', required: false)
|
||||
if not xcb_dep.found() or not xcb_xkb_dep.found()
|
||||
error('''X11 support requires xcb-xkb >= 1.10 which was not found.
|
||||
You can disable X11 support with -Denable-x11=false.''')
|
||||
endif
|
||||
|
||||
libxkbcommon_x11_sources = [
|
||||
'src/x11/keymap.c',
|
||||
'src/x11/state.c',
|
||||
'src/x11/util.c',
|
||||
'src/x11/x11-priv.h',
|
||||
'src/context.h',
|
||||
'src/context-priv.c',
|
||||
'src/keymap.h',
|
||||
'src/keymap-priv.c',
|
||||
'src/atom.h',
|
||||
'src/atom.c',
|
||||
]
|
||||
libxkbcommon_x11_link_args = []
|
||||
libxkbcommon_x11_link_deps = []
|
||||
if have_version_script
|
||||
libxkbcommon_x11_link_args += '-Wl,--version-script=' + meson.current_source_dir()/'xkbcommon-x11.map'
|
||||
libxkbcommon_x11_link_deps += 'xkbcommon-x11.map'
|
||||
elif cc.get_argument_syntax() == 'msvc'
|
||||
libxkbcommon_x11_def = custom_target('xkbcommon-x11.def',
|
||||
command: [map_to_def, '@INPUT@', '@OUTPUT@'],
|
||||
input: 'xkbcommon-x11.map',
|
||||
output: 'xkbcommon-x11.def',
|
||||
)
|
||||
libxkbcommon_x11_link_deps += libxkbcommon_x11_def
|
||||
libxkbcommon_x11_link_args += '/DEF:' + libxkbcommon_x11_def.full_path()
|
||||
endif
|
||||
libxkbcommon_x11 = library(
|
||||
'xkbcommon-x11',
|
||||
'include/xkbcommon/xkbcommon-x11.h',
|
||||
libxkbcommon_x11_sources,
|
||||
link_args: libxkbcommon_x11_link_args,
|
||||
link_depends: libxkbcommon_x11_link_deps,
|
||||
gnu_symbol_visibility: 'hidden',
|
||||
version: '0.0.0',
|
||||
install: true,
|
||||
include_directories: include_directories('src', 'include'),
|
||||
link_with: libxkbcommon,
|
||||
dependencies: [
|
||||
xcb_dep,
|
||||
xcb_xkb_dep,
|
||||
],
|
||||
)
|
||||
install_headers(
|
||||
'include/xkbcommon/xkbcommon-x11.h',
|
||||
subdir: 'xkbcommon',
|
||||
)
|
||||
dep_libxkbcommon_x11 = declare_dependency(
|
||||
link_with: libxkbcommon_x11,
|
||||
include_directories: include_directories('include'),
|
||||
)
|
||||
if meson.version().version_compare('>= 0.54.0')
|
||||
meson.override_dependency('xkbcommon-x11', dep_libxkbcommon_x11)
|
||||
endif
|
||||
pkgconfig.generate(
|
||||
libxkbcommon_x11,
|
||||
name: 'xkbcommon-x11',
|
||||
filebase: 'xkbcommon-x11',
|
||||
version: meson.project_version(),
|
||||
description: 'XKB API common to servers and clients - X11 support',
|
||||
requires: ['xkbcommon'],
|
||||
requires_private: ['xcb>=1.10', 'xcb-xkb>=1.10'],
|
||||
)
|
||||
endif
|
||||
|
||||
# libxkbregistry
|
||||
if get_option('enable-xkbregistry')
|
||||
dep_libxml = dependency('libxml-2.0')
|
||||
deps_libxkbregistry = [dep_libxml]
|
||||
libxkbregistry_sources = [
|
||||
'src/registry.c',
|
||||
'src/utils.h',
|
||||
'src/utils.c',
|
||||
'src/util-list.h',
|
||||
'src/util-list.c',
|
||||
'src/util-mem.h',
|
||||
]
|
||||
libxkbregistry_link_args = []
|
||||
libxkbregistry_link_deps = []
|
||||
if have_version_script
|
||||
libxkbregistry_link_args += '-Wl,--version-script=' + meson.current_source_dir()/'xkbregistry.map'
|
||||
libxkbregistry_link_deps += 'xkbregistry.map'
|
||||
elif cc.get_argument_syntax() == 'msvc'
|
||||
libxkbregistry_def = custom_target('xkbregistry.def',
|
||||
command: [map_to_def, '@INPUT@', '@OUTPUT@'],
|
||||
input: 'xkbregistry.map',
|
||||
output: 'xkbregistry.def',
|
||||
)
|
||||
libxkbregistry_link_deps += libxkbregistry_def
|
||||
libxkbregistry_link_args += '/DEF:' + libxkbregistry_def.full_path()
|
||||
endif
|
||||
libxkbregistry = library(
|
||||
'xkbregistry',
|
||||
'include/xkbcommon/xkbregistry.h',
|
||||
libxkbregistry_sources,
|
||||
link_args: libxkbregistry_link_args,
|
||||
link_depends: libxkbregistry_link_deps,
|
||||
gnu_symbol_visibility: 'hidden',
|
||||
dependencies: deps_libxkbregistry,
|
||||
version: '0.0.0',
|
||||
install: true,
|
||||
include_directories: include_directories('src', 'include'),
|
||||
)
|
||||
install_headers(
|
||||
'include/xkbcommon/xkbregistry.h',
|
||||
subdir: 'xkbcommon',
|
||||
)
|
||||
pkgconfig.generate(
|
||||
libxkbregistry,
|
||||
name: 'xkbregistry',
|
||||
filebase: 'xkbregistry',
|
||||
version: meson.project_version(),
|
||||
description: 'XKB API to query available rules, models, layouts, variants and options',
|
||||
)
|
||||
|
||||
dep_libxkbregistry = declare_dependency(
|
||||
link_with: libxkbregistry,
|
||||
include_directories: include_directories('include'),
|
||||
)
|
||||
if meson.version().version_compare('>= 0.54.0')
|
||||
meson.override_dependency('xkbregistry', dep_libxkbregistry)
|
||||
endif
|
||||
endif
|
||||
|
||||
man_pages = []
|
||||
|
||||
# Tools
|
||||
build_tools = get_option('enable-tools') and cc.has_header_symbol('getopt.h', 'getopt_long', prefix: '#define _GNU_SOURCE')
|
||||
if build_tools
|
||||
# Common resources
|
||||
libxkbcommon_tools_internal_sources = [
|
||||
'tools/tools-common.h',
|
||||
'tools/tools-common.c',
|
||||
]
|
||||
libxkbcommon_tools_internal = static_library(
|
||||
'tools-internal',
|
||||
libxkbcommon_tools_internal_sources,
|
||||
dependencies: dep_libxkbcommon,
|
||||
)
|
||||
tools_dep = declare_dependency(
|
||||
include_directories: [include_directories('tools', 'include')],
|
||||
link_with: libxkbcommon_tools_internal,
|
||||
dependencies: dep_libxkbcommon,
|
||||
)
|
||||
configh_data.set10('HAVE_TOOLS', true)
|
||||
|
||||
# Tool: xkbcli
|
||||
executable('xkbcli', 'tools/xkbcli.c',
|
||||
dependencies: tools_dep, install: true)
|
||||
install_man('tools/xkbcli.1')
|
||||
|
||||
if get_option('enable-bash-completion')
|
||||
bash_completion_path = get_option('bash-completion-path')
|
||||
if bash_completion_path == ''
|
||||
bash_completion = dependency('bash-completion', required: false)
|
||||
if bash_completion.found()
|
||||
bash_completion_path = bash_completion.get_variable(pkgconfig: 'completionsdir')
|
||||
else
|
||||
bash_completion_path = get_option('datadir') / 'bash-completion/completions'
|
||||
endif
|
||||
endif
|
||||
install_data('tools/xkbcli-bash-completion.sh',
|
||||
rename: 'xkbcli',
|
||||
install_dir: bash_completion_path)
|
||||
endif
|
||||
|
||||
# Tool: compile-keymap
|
||||
xkbcli_compile_keymap = executable('xkbcli-compile-keymap',
|
||||
'tools/compile-keymap.c',
|
||||
dependencies: tools_dep,
|
||||
install: true,
|
||||
install_dir: dir_libexec)
|
||||
install_man('tools/xkbcli-compile-keymap.1')
|
||||
configh_data.set10('HAVE_XKBCLI_COMPILE_KEYMAP', true)
|
||||
# The same tool again, but with access to some private APIs.
|
||||
executable('compile-keymap',
|
||||
'tools/compile-keymap.c',
|
||||
libxkbcommon_sources,
|
||||
dependencies: [tools_dep],
|
||||
c_args: ['-DENABLE_PRIVATE_APIS'],
|
||||
include_directories: [include_directories('src', 'include')],
|
||||
install: false)
|
||||
|
||||
# Tool: compose
|
||||
executable('xkbcli-compile-compose',
|
||||
'tools/compile-compose.c',
|
||||
dependencies: tools_dep,
|
||||
install: true,
|
||||
install_dir: dir_libexec)
|
||||
install_man('tools/xkbcli-compile-compose.1')
|
||||
configh_data.set10('HAVE_XKBCLI_COMPILE_COMPOSE', true)
|
||||
|
||||
# Tool: how-to-type
|
||||
executable('xkbcli-how-to-type',
|
||||
'tools/how-to-type.c',
|
||||
dependencies: tools_dep,
|
||||
install: true,
|
||||
install_dir: dir_libexec)
|
||||
install_man('tools/xkbcli-how-to-type.1')
|
||||
configh_data.set10('HAVE_XKBCLI_HOW_TO_TYPE', true)
|
||||
|
||||
# Tool: interactive-evdev
|
||||
if cc.has_header('linux/input.h')
|
||||
executable('xkbcli-interactive-evdev',
|
||||
'tools/interactive-evdev.c',
|
||||
dependencies: tools_dep,
|
||||
install: true,
|
||||
install_dir: dir_libexec)
|
||||
configh_data.set10('HAVE_XKBCLI_INTERACTIVE_EVDEV', true)
|
||||
install_man('tools/xkbcli-interactive-evdev.1')
|
||||
# The same tool again, but with access to some private APIs.
|
||||
executable('interactive-evdev',
|
||||
'tools/interactive-evdev.c',
|
||||
libxkbcommon_sources,
|
||||
libxkbcommon_tools_internal_sources,
|
||||
dependencies: [tools_dep],
|
||||
c_args: ['-DENABLE_PRIVATE_APIS'],
|
||||
include_directories: [include_directories('src', 'include')],
|
||||
install: false)
|
||||
endif
|
||||
|
||||
# Tool: interactive-x11
|
||||
if get_option('enable-x11')
|
||||
x11_tools_dep = declare_dependency(
|
||||
link_with: libxkbcommon_x11,
|
||||
dependencies: [
|
||||
tools_dep,
|
||||
xcb_dep,
|
||||
xcb_xkb_dep,
|
||||
],
|
||||
)
|
||||
executable('xkbcli-interactive-x11',
|
||||
'tools/interactive-x11.c',
|
||||
dependencies: x11_tools_dep,
|
||||
install: true,
|
||||
install_dir: dir_libexec)
|
||||
install_man('tools/xkbcli-interactive-x11.1')
|
||||
configh_data.set10('HAVE_XKBCLI_INTERACTIVE_X11', true)
|
||||
endif
|
||||
|
||||
# Tool: interactive-wayland
|
||||
if get_option('enable-wayland')
|
||||
wayland_client_dep = dependency('wayland-client', version: '>=1.2.0', required: false)
|
||||
wayland_protocols_dep = dependency('wayland-protocols', version: '>=1.12', required: false)
|
||||
wayland_scanner_dep = dependency('wayland-scanner', required: false, native: true)
|
||||
if not wayland_client_dep.found() or not wayland_protocols_dep.found() or not wayland_scanner_dep.found()
|
||||
error('''The Wayland xkbcli programs require wayland-client and wayland-protocols which were not found.
|
||||
You can disable the Wayland xkbcli programs with -Denable-wayland=false.''')
|
||||
endif
|
||||
|
||||
wayland_scanner = find_program(wayland_scanner_dep.get_variable(pkgconfig: 'wayland_scanner'))
|
||||
wayland_scanner_code_gen = generator(
|
||||
wayland_scanner,
|
||||
output: '@BASENAME@-protocol.c',
|
||||
arguments: ['private-code', '@INPUT@', '@OUTPUT@'],
|
||||
)
|
||||
wayland_scanner_client_header_gen = generator(
|
||||
wayland_scanner,
|
||||
output: '@BASENAME@-client-protocol.h',
|
||||
arguments: ['client-header', '@INPUT@', '@OUTPUT@'],
|
||||
)
|
||||
wayland_protocols_datadir = wayland_protocols_dep.get_variable(pkgconfig: 'pkgdatadir')
|
||||
xdg_shell_xml = wayland_protocols_datadir/'stable/xdg-shell/xdg-shell.xml'
|
||||
xdg_shell_sources = [
|
||||
wayland_scanner_code_gen.process(xdg_shell_xml),
|
||||
wayland_scanner_client_header_gen.process(xdg_shell_xml),
|
||||
]
|
||||
executable('xkbcli-interactive-wayland',
|
||||
'tools/interactive-wayland.c',
|
||||
xdg_shell_sources,
|
||||
dependencies: [tools_dep, wayland_client_dep],
|
||||
install: true,
|
||||
install_dir: dir_libexec)
|
||||
install_man('tools/xkbcli-interactive-wayland.1')
|
||||
configh_data.set10('HAVE_XKBCLI_INTERACTIVE_WAYLAND', true)
|
||||
endif
|
||||
|
||||
# Tool: list
|
||||
if get_option('enable-xkbregistry')
|
||||
configh_data.set10('HAVE_XKBCLI_LIST', true)
|
||||
executable('xkbcli-list',
|
||||
'tools/registry-list.c',
|
||||
dependencies: dep_libxkbregistry,
|
||||
install: true,
|
||||
install_dir: dir_libexec)
|
||||
install_man('tools/xkbcli-list.1')
|
||||
endif
|
||||
|
||||
# Tool: check-messages
|
||||
executable('xkb-check-messages',
|
||||
'tools/check-messages.c',
|
||||
'tools/messages.c',
|
||||
'tools/messages.h',
|
||||
'src/messages-codes.h',
|
||||
dependencies: [tools_dep],
|
||||
include_directories: [include_directories('src', 'include', 'tools')],
|
||||
install: false)
|
||||
else
|
||||
tools_dep = declare_dependency()
|
||||
endif
|
||||
|
||||
|
||||
# xkeyboard-config "verifier"
|
||||
xkct_config = configuration_data()
|
||||
xkct_config.set('MESON_BUILD_ROOT', meson.current_build_dir())
|
||||
xkct_config.set('XKB_CONFIG_ROOT', XKBCONFIGROOT)
|
||||
configure_file(input: 'test/xkeyboard-config-test.py.in',
|
||||
output: 'xkeyboard-config-test',
|
||||
configuration: xkct_config)
|
||||
|
||||
# Tests
|
||||
test_env = environment()
|
||||
test_env.set('XKB_LOG_LEVEL', 'debug')
|
||||
test_env.set('XKB_LOG_VERBOSITY', '10')
|
||||
test_env.set('top_srcdir', meson.current_source_dir())
|
||||
test_env.set('top_builddir', meson.current_build_dir())
|
||||
test_env.set('HAVE_XKBCLI_INTERACTIVE_EVDEV', configh_data.get('HAVE_XKBCLI_INTERACTIVE_EVDEV', 0).to_string())
|
||||
test_env.set('HAVE_XKBCLI_INTERACTIVE_WAYLAND', configh_data.get('HAVE_XKBCLI_INTERACTIVE_WAYLAND', 0).to_string())
|
||||
test_env.set('HAVE_XKBCLI_INTERACTIVE_X11', configh_data.get('HAVE_XKBCLI_INTERACTIVE_X11', 0).to_string())
|
||||
test_env.set('HAVE_XKBCLI_LIST', configh_data.get('HAVE_XKBCLI_LIST', 0).to_string())
|
||||
|
||||
test_configh_data = configuration_data()
|
||||
test_configh_data.set_quoted('TEST_XKB_CONFIG_ROOT', meson.current_source_dir()/'test'/'data')
|
||||
configure_file(output: 'test-config.h', configuration: test_configh_data)
|
||||
|
||||
# Some tests need to use unexported symbols, so we link them against
|
||||
# an internal copy of libxkbcommon with all symbols exposed.
|
||||
libxkbcommon_test_internal = static_library(
|
||||
'xkbcommon-test-internal',
|
||||
'test/common.c',
|
||||
'test/test.h',
|
||||
'test/evdev-scancodes.h',
|
||||
'bench/bench.c',
|
||||
'bench/bench.h',
|
||||
libxkbcommon_sources,
|
||||
include_directories: include_directories('src', 'include'),
|
||||
c_args: ['-DENABLE_PRIVATE_APIS'],
|
||||
)
|
||||
test_dep = declare_dependency(
|
||||
include_directories: include_directories('src', 'include'),
|
||||
link_with: libxkbcommon_test_internal,
|
||||
dependencies: [tools_dep],
|
||||
)
|
||||
if get_option('enable-x11')
|
||||
libxkbcommon_x11_test_internal = static_library(
|
||||
'xkbcommon-x11-internal',
|
||||
libxkbcommon_x11_sources,
|
||||
'test/xvfb-wrapper.c',
|
||||
'test/xvfb-wrapper.h',
|
||||
include_directories: include_directories('src', 'include'),
|
||||
link_with: libxkbcommon_test_internal,
|
||||
dependencies: [
|
||||
xcb_dep,
|
||||
xcb_xkb_dep,
|
||||
],
|
||||
)
|
||||
x11_test_dep = declare_dependency(
|
||||
link_with: libxkbcommon_x11_test_internal,
|
||||
dependencies: [
|
||||
test_dep,
|
||||
xcb_dep,
|
||||
xcb_xkb_dep,
|
||||
],
|
||||
)
|
||||
endif
|
||||
# TODO: version range?
|
||||
keysyms_test_dep = [test_dep]
|
||||
keysyms_test_c_args = ['-DENABLE_PRIVATE_APIS']
|
||||
icu_dep = dependency('icu-uc', required: false)
|
||||
if icu_dep.found()
|
||||
keysyms_test_dep += [icu_dep]
|
||||
configh_data.set10('HAVE_ICU', true)
|
||||
endif
|
||||
test(
|
||||
'keysym',
|
||||
executable('test-keysym', 'test/keysym.c', 'test/keysym.h',
|
||||
dependencies: keysyms_test_dep,
|
||||
c_args: keysyms_test_c_args),
|
||||
env: test_env,
|
||||
)
|
||||
test(
|
||||
'keymap',
|
||||
executable('test-keymap', 'test/keymap.c', 'test/keysym.h',
|
||||
dependencies: test_dep),
|
||||
env: test_env,
|
||||
)
|
||||
test(
|
||||
'filecomp',
|
||||
executable('test-filecomp', 'test/filecomp.c', dependencies: test_dep),
|
||||
env: test_env,
|
||||
)
|
||||
test(
|
||||
'context',
|
||||
executable('test-context', 'test/context.c', dependencies: test_dep),
|
||||
env: test_env,
|
||||
)
|
||||
test(
|
||||
'rules-file',
|
||||
executable('test-rules-file', 'test/rules-file.c', dependencies: test_dep),
|
||||
env: test_env,
|
||||
)
|
||||
test(
|
||||
'rules-file-includes',
|
||||
executable('test-rules-file-includes', 'test/rules-file-includes.c', dependencies: test_dep),
|
||||
env: test_env,
|
||||
)
|
||||
test(
|
||||
'stringcomp',
|
||||
executable('test-stringcomp', 'test/stringcomp.c', dependencies: test_dep),
|
||||
env: test_env,
|
||||
)
|
||||
test(
|
||||
'buffercomp',
|
||||
executable('test-buffercomp', 'test/buffercomp.c', dependencies: test_dep),
|
||||
env: test_env,
|
||||
)
|
||||
test(
|
||||
'log',
|
||||
executable('test-log', 'test/log.c', dependencies: test_dep),
|
||||
env: test_env,
|
||||
)
|
||||
test(
|
||||
'atom',
|
||||
executable('test-atom', 'test/atom.c', dependencies: test_dep),
|
||||
env: test_env,
|
||||
)
|
||||
test(
|
||||
'utf8',
|
||||
executable('test-utf8', 'test/utf8.c', dependencies: test_dep),
|
||||
env: test_env,
|
||||
)
|
||||
test(
|
||||
'state',
|
||||
executable('test-state', 'test/state.c', dependencies: test_dep),
|
||||
env: test_env,
|
||||
)
|
||||
test(
|
||||
'keyseq',
|
||||
executable('test-keyseq', 'test/keyseq.c', dependencies: test_dep),
|
||||
env: test_env,
|
||||
)
|
||||
test(
|
||||
'rulescomp',
|
||||
executable('test-rulescomp', 'test/rulescomp.c', dependencies: test_dep),
|
||||
env: test_env,
|
||||
)
|
||||
test(
|
||||
'compose',
|
||||
executable('test-compose', 'test/compose.c', dependencies: test_dep),
|
||||
env: test_env,
|
||||
)
|
||||
test(
|
||||
'utils',
|
||||
executable('test-utils', 'test/utils.c', dependencies: test_dep),
|
||||
env: test_env,
|
||||
)
|
||||
test(
|
||||
'symbols-leak-test',
|
||||
find_program('test/symbols-leak-test.py'),
|
||||
env: test_env,
|
||||
suite: ['python-tests'],
|
||||
)
|
||||
test(
|
||||
'modifiers',
|
||||
executable('test-modifiers', 'test/modifiers.c', dependencies: test_dep),
|
||||
env: test_env,
|
||||
)
|
||||
test(
|
||||
'messages',
|
||||
executable(
|
||||
'test-messages',
|
||||
'test/messages.c',
|
||||
'tools/messages.c',
|
||||
'tools/messages.h',
|
||||
include_directories: include_directories('src', 'include', 'tools'),
|
||||
dependencies: test_dep),
|
||||
env: test_env,
|
||||
)
|
||||
if get_option('enable-x11')
|
||||
test(
|
||||
'x11',
|
||||
executable('test-x11', 'test/x11.c', dependencies: x11_test_dep),
|
||||
env: test_env,
|
||||
is_parallel : false,
|
||||
)
|
||||
test(
|
||||
'x11comp',
|
||||
executable('test-x11comp', 'test/x11comp.c', dependencies: x11_test_dep),
|
||||
env: test_env,
|
||||
is_parallel : false,
|
||||
)
|
||||
endif
|
||||
if get_option('enable-xkbregistry')
|
||||
test(
|
||||
'registry',
|
||||
executable('test-registry', 'test/registry.c',
|
||||
include_directories: include_directories('src'),
|
||||
dependencies: [dep_libxkbregistry, test_dep]),
|
||||
env: test_env,
|
||||
)
|
||||
endif
|
||||
if build_tools
|
||||
test('tool-option-parsing',
|
||||
find_program('test/tool-option-parsing.py'),
|
||||
env: test_env,
|
||||
suite: ['python-tests'])
|
||||
|
||||
# A set of keysyms to test for. Add one or two symbols to this array
|
||||
# whenever the xorgproto gets updated to make sure we resolve them.
|
||||
keysyms_to_test = [
|
||||
'XF86Macro23',
|
||||
]
|
||||
|
||||
env = environment()
|
||||
env.set('XKB_CONFIG_ROOT', meson.current_source_dir()/'test'/'data')
|
||||
foreach keysym: keysyms_to_test
|
||||
test('keysym-test-@0@'.format(keysym),
|
||||
find_program('test/test-keysym.py'),
|
||||
env: env,
|
||||
args: [keysym, '--tool', xkbcli_compile_keymap],
|
||||
suite: ['python-tests'])
|
||||
endforeach
|
||||
endif
|
||||
|
||||
valgrind = find_program('valgrind', required: false)
|
||||
if valgrind.found()
|
||||
add_test_setup('valgrind',
|
||||
exe_wrapper: [valgrind,
|
||||
'--leak-check=full',
|
||||
'--track-origins=yes',
|
||||
'--gen-suppressions=all',
|
||||
'--error-exitcode=99'],
|
||||
timeout_multiplier : 10)
|
||||
else
|
||||
message('valgrind not found, disabling valgrind test setup')
|
||||
endif
|
||||
|
||||
|
||||
# Fuzzing target programs.
|
||||
executable('fuzz-keymap', 'fuzz/keymap/target.c', dependencies: test_dep)
|
||||
executable('fuzz-compose', 'fuzz/compose/target.c', dependencies: test_dep)
|
||||
|
||||
|
||||
# Benchmarks.
|
||||
bench_env = environment()
|
||||
bench_env.set('top_srcdir', meson.current_source_dir())
|
||||
benchmark(
|
||||
'key-proc',
|
||||
executable('bench-key-proc', 'bench/key-proc.c', dependencies: test_dep),
|
||||
env: bench_env,
|
||||
)
|
||||
benchmark(
|
||||
'rules',
|
||||
executable('bench-rules', 'bench/rules.c', dependencies: test_dep),
|
||||
env: bench_env,
|
||||
)
|
||||
benchmark(
|
||||
'rulescomp',
|
||||
executable('bench-rulescomp', 'bench/rulescomp.c', dependencies: test_dep),
|
||||
env: bench_env,
|
||||
)
|
||||
benchmark(
|
||||
'compose',
|
||||
executable('bench-compose', 'bench/compose.c', dependencies: test_dep),
|
||||
env: bench_env,
|
||||
)
|
||||
benchmark(
|
||||
'compose-traversal',
|
||||
executable('bench-compose-traversal', 'bench/compose-traversal.c', dependencies: test_dep),
|
||||
env: bench_env,
|
||||
)
|
||||
benchmark(
|
||||
'atom',
|
||||
executable('bench-atom', 'bench/atom.c', dependencies: test_dep),
|
||||
env: bench_env,
|
||||
)
|
||||
if get_option('enable-x11')
|
||||
benchmark(
|
||||
'x11',
|
||||
executable('bench-x11', 'bench/x11.c', dependencies: x11_test_dep),
|
||||
env: bench_env,
|
||||
)
|
||||
endif
|
||||
|
||||
|
||||
# Documentation.
|
||||
if get_option('enable-docs')
|
||||
doxygen = find_program('doxygen', required: false)
|
||||
if not doxygen.found()
|
||||
error('''Documentation requires doxygen which was not found.
|
||||
You can disable the documentation with -Denable-docs=false.''')
|
||||
endif
|
||||
doxygen_wrapper = find_program('scripts/doxygen-wrapper')
|
||||
|
||||
doxygen_input = [
|
||||
'README.md',
|
||||
'doc/diagrams/xkb-configuration.dot',
|
||||
'doc/diagrams/xkb-keymap-components.dot',
|
||||
'doc/diagrams/xkb-types-explanation.dot',
|
||||
'doc/doxygen-extra.css',
|
||||
'doc/introduction-to-xkb.md',
|
||||
'doc/quick-guide.md',
|
||||
'doc/compatibility.md',
|
||||
'doc/user-configuration.md',
|
||||
'doc/rules-format.md',
|
||||
'doc/keymap-format-text-v1.md',
|
||||
'doc/message-registry.md',
|
||||
'include/xkbcommon/xkbcommon.h',
|
||||
'include/xkbcommon/xkbcommon-compose.h',
|
||||
'include/xkbcommon/xkbcommon-keysyms.h',
|
||||
'include/xkbcommon/xkbcommon-names.h',
|
||||
'include/xkbcommon/xkbcommon-x11.h',
|
||||
'include/xkbcommon/xkbregistry.h',
|
||||
]
|
||||
doxygen_data = configuration_data()
|
||||
doxygen_data.set('PACKAGE_NAME', meson.project_name())
|
||||
doxygen_data.set('PACKAGE_VERSION', meson.project_version())
|
||||
doxygen_data.set('INPUT', ' '.join(doxygen_input))
|
||||
doxygen_data.set('OUTPUT_DIRECTORY', meson.current_build_dir())
|
||||
doxyfile = configure_file(
|
||||
input: 'doc/Doxyfile.in',
|
||||
output: 'Doxyfile',
|
||||
configuration: doxygen_data,
|
||||
)
|
||||
# TODO: Meson should provide this.
|
||||
docdir = get_option('datadir')/'doc'/meson.project_name()
|
||||
doc_gen = custom_target(
|
||||
'doc',
|
||||
input: [doxyfile] + doxygen_input,
|
||||
output: 'html',
|
||||
command: [
|
||||
doxygen_wrapper,
|
||||
doxygen,
|
||||
meson.current_build_dir()/'Doxyfile',
|
||||
meson.current_source_dir(),
|
||||
],
|
||||
install: true,
|
||||
install_dir: docdir,
|
||||
build_by_default: true,
|
||||
)
|
||||
if get_option('enable-cool-uris')
|
||||
ensure_stable_urls = find_program('scripts'/'ensure-stable-doc-urls.py')
|
||||
custom_target(
|
||||
'doc-cool-uris',
|
||||
input: [doc_gen, 'doc'/'cool-uris.yaml'],
|
||||
output: 'html-xtra',
|
||||
command: [
|
||||
ensure_stable_urls,
|
||||
'generate-redirections',
|
||||
meson.current_source_dir()/'doc'/'cool-uris.yaml',
|
||||
meson.current_build_dir()/'html'
|
||||
],
|
||||
install: false,
|
||||
build_by_default: true,
|
||||
)
|
||||
endif
|
||||
endif
|
||||
|
||||
configure_file(output: 'config.h', configuration: configh_data)
|
||||
|
||||
|
||||
# Stable variables for projects using xkbcommon as a subproject.
|
||||
# These variables should not be renamed.
|
||||
libxkbcommon_dep = dep_libxkbcommon
|
||||
if get_option('enable-x11')
|
||||
libxkbcommon_x11_dep = dep_libxkbcommon_x11
|
||||
endif
|
||||
if get_option('enable-xkbregistry')
|
||||
libxkbregistry_dep = dep_libxkbregistry
|
||||
endif
|
||||
|
||||
if meson.version().version_compare('>=0.62.0')
|
||||
summary({
|
||||
'backend': meson.backend(),
|
||||
'buildtype': get_option('buildtype'),
|
||||
'c_args': get_option('c_args'),
|
||||
'c_link_args': get_option('c_link_args'),
|
||||
'yacc': yacc.full_path() + ' ' + yacc.version(),
|
||||
}, section: 'Compiler')
|
||||
summary({
|
||||
'prefix': get_option('prefix'),
|
||||
'bindir': get_option('bindir'),
|
||||
'libdir': get_option('libdir'),
|
||||
'datadir': get_option('datadir'),
|
||||
'xkb-config-root': XKBCONFIGROOT,
|
||||
'xkb-config-extra-path': XKBCONFIGEXTRAPATH,
|
||||
'xlocaledir': XLOCALEDIR,
|
||||
}, section: 'Directories')
|
||||
summary({
|
||||
'docs': get_option('enable-docs'),
|
||||
'tools': get_option('enable-tools'),
|
||||
'wayland': get_option('enable-wayland'),
|
||||
'x11': get_option('enable-x11'),
|
||||
}, section: 'Features')
|
||||
summary({
|
||||
'layout': get_option('default-layout'),
|
||||
'model': get_option('default-model'),
|
||||
'options': get_option('default-options'),
|
||||
'rules': get_option('default-rules'),
|
||||
'variant': get_option('default-variant'),
|
||||
}, section: 'Defaults')
|
||||
endif
|
||||
@@ -1,92 +0,0 @@
|
||||
option(
|
||||
'xkb-config-root',
|
||||
type: 'string',
|
||||
description: 'The XKB config root [default=xkeyboard-config install path]',
|
||||
)
|
||||
option(
|
||||
'xkb-config-extra-path',
|
||||
type: 'string',
|
||||
description: 'Extra lookup path for system-wide XKB data [default=$sysconfdir/xkb]',
|
||||
)
|
||||
option(
|
||||
'x-locale-root',
|
||||
type: 'string',
|
||||
description: 'The X locale root [default=$datadir/X11/locale]',
|
||||
)
|
||||
option(
|
||||
'bash-completion-path',
|
||||
type: 'string',
|
||||
description: 'Directory for bash completion scripts'
|
||||
)
|
||||
option(
|
||||
'default-rules',
|
||||
type: 'string',
|
||||
value: 'evdev',
|
||||
description: 'Default XKB ruleset',
|
||||
)
|
||||
option(
|
||||
'default-model',
|
||||
type: 'string',
|
||||
value: 'pc105',
|
||||
description: 'Default XKB model',
|
||||
)
|
||||
option(
|
||||
'default-layout',
|
||||
type: 'string',
|
||||
value: 'us',
|
||||
description: 'Default XKB layout',
|
||||
)
|
||||
option(
|
||||
'default-variant',
|
||||
type: 'string',
|
||||
value: '',
|
||||
description: 'Default XKB variant',
|
||||
)
|
||||
option(
|
||||
'default-options',
|
||||
type: 'string',
|
||||
value: '',
|
||||
description: 'Default XKB options',
|
||||
)
|
||||
option(
|
||||
'enable-tools',
|
||||
type: 'boolean',
|
||||
value: true,
|
||||
description: 'Enable building tools',
|
||||
)
|
||||
option(
|
||||
'enable-x11',
|
||||
type: 'boolean',
|
||||
value: true,
|
||||
description: 'Enable building the xkbcommon-x11 library',
|
||||
)
|
||||
option(
|
||||
'enable-docs',
|
||||
type: 'boolean',
|
||||
value: false,
|
||||
description: 'Enable building the documentation',
|
||||
)
|
||||
option(
|
||||
'enable-cool-uris',
|
||||
type: 'boolean',
|
||||
value: false,
|
||||
description: 'Enable creating redirections to maintain stable documentation pages',
|
||||
)
|
||||
option(
|
||||
'enable-wayland',
|
||||
type: 'boolean',
|
||||
value: true,
|
||||
description: 'Enable support for Wayland utility programs (requires enable-tools)',
|
||||
)
|
||||
option(
|
||||
'enable-xkbregistry',
|
||||
type: 'boolean',
|
||||
value: true,
|
||||
description: 'Enable building libxkbregistry',
|
||||
)
|
||||
option(
|
||||
'enable-bash-completion',
|
||||
type: 'boolean',
|
||||
value: true,
|
||||
description: 'Enable installing bash completion scripts',
|
||||
)
|
||||
@@ -1,15 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Run doxygen such that the working directory is the source root.
|
||||
# This is needed for various reasons (e.g. relative references in md files).
|
||||
# Do not use directly.
|
||||
DOXYGEN="$1"
|
||||
DOXYFILE="$2"
|
||||
ABS_TOP_SRCDIR="$3"
|
||||
# Set environment variables that are unset
|
||||
if [ -z "$DOXYGEN_WARN_AS_ERROR" ]
|
||||
then export DOXYGEN_WARN_AS_ERROR="NO"
|
||||
fi
|
||||
if [ -z "$DOXYGEN_QUIET" ]
|
||||
then export DOXYGEN_QUIET="YES"
|
||||
fi
|
||||
cd "$ABS_TOP_SRCDIR" && exec "$DOXYGEN" "$DOXYFILE"
|
||||
@@ -1,232 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Doc URLs may change with time because they depend on Doxygen machinery.
|
||||
# This is unfortunate because it is good practice to keep valid URLs.
|
||||
# See: “Cool URIs don’t change” at https://www.w3.org/Provider/Style/URI.html.
|
||||
#
|
||||
# There is no built-in solution in Doxygen that we are aware of.
|
||||
# The solution proposed here is to maintain a registry of all URLs and manage
|
||||
# legacy URLs as redirections to their canonical page.
|
||||
|
||||
import argparse
|
||||
from enum import IntFlag
|
||||
import glob
|
||||
from itertools import chain
|
||||
from pathlib import Path
|
||||
from string import Template
|
||||
from typing import NamedTuple, Sequence
|
||||
|
||||
import yaml
|
||||
|
||||
|
||||
class Update(NamedTuple):
|
||||
new: str
|
||||
old: str
|
||||
|
||||
|
||||
class ExitCode(IntFlag):
|
||||
NORMAL = 0
|
||||
INVALID_UPDATES = 1 << 4
|
||||
MISSING_UPDATES = 1 << 5
|
||||
|
||||
|
||||
THIS_SCRIPT_PATH = Path(__file__)
|
||||
RELATIVE_SCRIPT_PATH = THIS_SCRIPT_PATH.relative_to(THIS_SCRIPT_PATH.parent.parent)
|
||||
|
||||
REDIRECTION_DELAY = 6 # in seconds. Note: at least 6s for accessibility
|
||||
|
||||
# NOTE: The redirection works with the HTML tag: <meta http-equiv="refresh">.
|
||||
# See: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta#http-equiv
|
||||
#
|
||||
# NOTE: This page is a simplified version of the Doxygen-generated ones.
|
||||
# It does use the current stylesheets, but it may break if the theme is updated.
|
||||
# Ideally, we would just let Doxygen generate them, but I (Wismill) could not
|
||||
# find a way to do this with the redirection feature.
|
||||
REDIRECTION_PAGE_TEMPLATE = Template(
|
||||
"""<!DOCTYPE HTML>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="refresh" content="${delay}; url=${canonical}">
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css">
|
||||
<link href="doxygen-extra.css" rel="stylesheet" type="text/css">
|
||||
<title>xkbcommon: Page Redirection</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="top">
|
||||
<div id="titlearea" style="padding: 1em 0 1em 0.5em;">
|
||||
<div id="projectname">
|
||||
libxkbcommon
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="header">
|
||||
<div class="headertitle">
|
||||
<div class="title">🔀 Redirection</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="contents">
|
||||
<p>This page has been moved.</p>
|
||||
<p>
|
||||
If you are not redirected automatically,
|
||||
follow the <a href="${canonical}">link to the current page</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def parse_page_update(update: str) -> Update:
|
||||
updateʹ = Update(*update.split("="))
|
||||
if updateʹ.new == updateʹ.old:
|
||||
raise ValueError(f"Invalid update: {updateʹ}")
|
||||
return updateʹ
|
||||
|
||||
|
||||
def update_registry(registry_path: Path, doc_dir: Path, updates: Sequence[str]):
|
||||
"""
|
||||
Update the URL registry by:
|
||||
• Adding new pages
|
||||
• Updating page aliases
|
||||
"""
|
||||
# Parse updates
|
||||
updates_ = dict(map(parse_page_update, updates))
|
||||
# Load previous registry
|
||||
with registry_path.open("rt", encoding="utf-8") as fd:
|
||||
registry = yaml.safe_load(fd) or {}
|
||||
# Expected updates
|
||||
missing_updates = set(file for file in registry if not (doc_dir / file).is_file())
|
||||
# Update
|
||||
invalid_updates = set(updates_)
|
||||
redirections = frozenset(chain(*registry.values()))
|
||||
for file in glob.iglob("**/*.html", root_dir=doc_dir, recursive=True):
|
||||
# Skip redirection pages
|
||||
if file in redirections:
|
||||
continue
|
||||
# Get previous entry and potential update
|
||||
old = updates_.get(file)
|
||||
if old:
|
||||
# Update old entry
|
||||
invalid_updates.remove(file)
|
||||
entry = registry.get(old)
|
||||
if entry is None:
|
||||
raise ValueError(f"Invalid update: {file}<-{old}")
|
||||
else:
|
||||
del registry[old]
|
||||
missing_updates.remove(old)
|
||||
registry[file] = [e for e in [old] + entry if e != file]
|
||||
print(f"[INFO] Updated: “{old}” to “{file}”")
|
||||
else:
|
||||
entry = registry.get(file)
|
||||
if entry is None:
|
||||
# New entry
|
||||
registry[file] = []
|
||||
print(f"[INFO] Added: {file}")
|
||||
else:
|
||||
# Keep previous entry
|
||||
pass
|
||||
exit_code = ExitCode.NORMAL
|
||||
# Check
|
||||
if invalid_updates:
|
||||
for update in invalid_updates:
|
||||
print(f"[ERROR] Update not processed: {update}")
|
||||
exit_code |= ExitCode.INVALID_UPDATES
|
||||
if missing_updates:
|
||||
for old in missing_updates:
|
||||
print(f"[ERROR] “{old}” not found and has no update.")
|
||||
exit_code |= ExitCode.MISSING_UPDATES
|
||||
if exit_code:
|
||||
print("[ERROR] Processing interrupted: please fix the errors above.")
|
||||
exit(exit_code.value)
|
||||
# Write changes
|
||||
with registry_path.open("wt", encoding="utf-8") as fd:
|
||||
fd.write(f"# WARNING: This file is autogenerated by: {RELATIVE_SCRIPT_PATH}\n")
|
||||
fd.write("# Do not edit manually.\n")
|
||||
yaml.dump(
|
||||
registry,
|
||||
fd,
|
||||
)
|
||||
|
||||
|
||||
def generate_redirections(registry_path: Path, doc_dir: Path):
|
||||
"""
|
||||
Create redirection pages using the aliases in the given URL registry.
|
||||
"""
|
||||
cool = True
|
||||
# Load registry
|
||||
with registry_path.open("rt", encoding="utf-8") as fd:
|
||||
registry = yaml.safe_load(fd) or {}
|
||||
for canonical, aliases in registry.items():
|
||||
# Check canonical path is up-to-date
|
||||
if not (doc_dir / canonical).is_file():
|
||||
cool = False
|
||||
print(
|
||||
f"ERROR: missing canonical documentation page “{canonical}”. "
|
||||
f"Please update “{registry_path}” using {RELATIVE_SCRIPT_PATH}”."
|
||||
)
|
||||
# Add a redirection page
|
||||
for alias in aliases:
|
||||
path = doc_dir / alias
|
||||
with path.open("wt", encoding="utf-8") as fd:
|
||||
fd.write(
|
||||
REDIRECTION_PAGE_TEMPLATE.substitute(
|
||||
canonical=canonical, delay=REDIRECTION_DELAY
|
||||
)
|
||||
)
|
||||
if not cool:
|
||||
exit(1)
|
||||
|
||||
|
||||
def add_registry_argument(parser):
|
||||
parser.add_argument(
|
||||
"registry",
|
||||
type=Path,
|
||||
help="Path to the doc URI registry.",
|
||||
)
|
||||
|
||||
|
||||
def add_docdir_argument(parser):
|
||||
parser.add_argument(
|
||||
"docdir",
|
||||
type=Path,
|
||||
metavar="DOC_DIR",
|
||||
help="Path to the generated HTML documentation directory.",
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Tool to ensure HTML documentation has stable URLs"
|
||||
)
|
||||
subparsers = parser.add_subparsers()
|
||||
|
||||
parser_registry = subparsers.add_parser(
|
||||
"update-registry", help="Update the registry of URIs"
|
||||
)
|
||||
add_registry_argument(parser_registry)
|
||||
add_docdir_argument(parser_registry)
|
||||
parser_registry.add_argument(
|
||||
"updates",
|
||||
nargs="*",
|
||||
type=str,
|
||||
help="Update: new=previous entries",
|
||||
)
|
||||
parser_registry.set_defaults(
|
||||
run=lambda args: update_registry(args.registry, args.docdir, args.updates)
|
||||
)
|
||||
|
||||
parser_redirections = subparsers.add_parser(
|
||||
"generate-redirections", help="Generate URIs redirections"
|
||||
)
|
||||
add_registry_argument(parser_redirections)
|
||||
add_docdir_argument(parser_redirections)
|
||||
parser_redirections.set_defaults(
|
||||
run=lambda args: generate_redirections(args.registry, args.docdir)
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
args.run(args)
|
||||
@@ -1,133 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import print_function
|
||||
import re
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# Expected format:
|
||||
# #define XF86XK_FooBar 0x1234 /* some optional comment */
|
||||
# or:
|
||||
# #define XF86XK_FooBar _EVDEVK(0x123) /* some optional comment */
|
||||
# We also need to match commented evdev entries:
|
||||
# /* Use: XF86XK_FooBar _EVDEVK(0x123) some optional comment */
|
||||
keysym_entry_pattern = re.compile(
|
||||
r"""^
|
||||
(?P<define>\#define|/\*\s+Use:)\s+
|
||||
(?P<prefix>\w*)XK_(?P<name>\w+)(?P<spacing>\s+)
|
||||
(?P<evdev>_EVDEVK\()?(?P<value>0x[0-9A-Fa-f]+)(?(evdev)\))
|
||||
""",
|
||||
re.VERBOSE,
|
||||
)
|
||||
|
||||
# Match keysym guarded by #ifndef
|
||||
keysym_ifndef_pattern = re.compile(r"^#ifndef\s+(?P<prefix>\w*)XK_(?P<name>\w+)\s*$")
|
||||
|
||||
# Match remaining XK_ references in the comments, e.g we will replace:
|
||||
# XF86XK_CamelCaseKernelName _EVDEVK(kernel value)
|
||||
# #define XKB_KEY_SunCompose 0x0000FF20 /* Same as XK_Multi_key */
|
||||
# with:
|
||||
# XKB_KEY_XF86CamelCaseKernelName _EVDEVK(kernel value)
|
||||
# #define XKB_KEY_SunCompose 0x0000FF20 /* Same as XKB_KEY_Multi_key */
|
||||
xorgproto_keysym_prefix_pattern = re.compile(r"\b(?P<prefix>\w*)XK_(?!KOREAN\b)")
|
||||
|
||||
|
||||
def make_keysym_name(m: re.Match[str]) -> str:
|
||||
return m.group("prefix") + m.group("name")
|
||||
|
||||
|
||||
def make_keysym_entry(m: re.Match[str]) -> str:
|
||||
"""
|
||||
Perform the substitutions
|
||||
"""
|
||||
if m.group("evdev"):
|
||||
if m.group("define").startswith("#"):
|
||||
# Replace the xorgproto _EVDEVK macro with the actual value:
|
||||
# 0x10081000 is the base, the evdev hex code is added to that.
|
||||
# We replace to make parsing of the keys later easier.
|
||||
value = 0x10081000 + int(m.group("value"), 16)
|
||||
value_str = f"{value:#x} "
|
||||
else:
|
||||
value_str = f"""_EVDEVK({m.group('value')})"""
|
||||
else:
|
||||
value_str = m.group("value")
|
||||
define = m.group("define")
|
||||
prefix = m.group("prefix") or ""
|
||||
name = m.group("name")
|
||||
spacing = m.group("spacing")
|
||||
return f"""{define} XKB_KEY_{prefix}{name}{spacing}{value_str}"""
|
||||
|
||||
|
||||
prefix = Path(os.environ.get("X11_HEADERS_PREFIX", "/usr"))
|
||||
HEADERS = (
|
||||
prefix / "include/X11/keysymdef.h",
|
||||
prefix / "include/X11/XF86keysym.h",
|
||||
prefix / "include/X11/Sunkeysym.h",
|
||||
prefix / "include/X11/DECkeysym.h",
|
||||
prefix / "include/X11/HPkeysym.h",
|
||||
)
|
||||
|
||||
print(
|
||||
"""#ifndef _XKBCOMMON_KEYSYMS_H
|
||||
#define _XKBCOMMON_KEYSYMS_H
|
||||
|
||||
/* This file is autogenerated; please do not commit directly. */
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Key symbols (keysyms) definitions.
|
||||
*/
|
||||
|
||||
#define XKB_KEY_NoSymbol 0x000000 /* Special KeySym */
|
||||
"""
|
||||
)
|
||||
|
||||
keysyms: set[str] = set()
|
||||
for path in HEADERS:
|
||||
pending_guarded_keysym: str | None = None
|
||||
with path.open("rt", encoding="utf-8") as header:
|
||||
for line in header:
|
||||
# Duplicate keysym name guard
|
||||
if m := keysym_ifndef_pattern.match(line):
|
||||
if pending_guarded_keysym:
|
||||
raise ValueError(f"Nested #ifndef {pending_guarded_keysym}")
|
||||
pending_guarded_keysym = make_keysym_name(m)
|
||||
continue
|
||||
|
||||
# Ignore C macro #ifdef/#ifndef
|
||||
elif line.startswith("#ifdef") or line.startswith("#ifndef"):
|
||||
if pending_guarded_keysym:
|
||||
raise ValueError(f"Nested C macro {pending_guarded_keysym}")
|
||||
continue
|
||||
|
||||
# Ignore C macro #endif and check end of keysym name guard
|
||||
elif line.startswith("#endif"):
|
||||
if pending_guarded_keysym:
|
||||
pending_guarded_keysym = None
|
||||
continue
|
||||
|
||||
# Remove #define _OSF_Keysyms and such.
|
||||
elif line.startswith("#define _"):
|
||||
continue
|
||||
|
||||
# Keysym entry: proceed various tests
|
||||
if line.startswith("#") and (m := keysym_entry_pattern.match(line)):
|
||||
name = make_keysym_name(m)
|
||||
# Check expected guarded keysym, if relevant
|
||||
if pending_guarded_keysym and name != pending_guarded_keysym:
|
||||
raise ValueError(f"{path}: Malformed keysym name guard: {line}")
|
||||
# Check if name already defined
|
||||
elif name in keysyms:
|
||||
if pending_guarded_keysym:
|
||||
# Ignore guarded keysym
|
||||
continue
|
||||
else:
|
||||
raise ValueError(f"{path}: Unguarded redefinition: {line}")
|
||||
else:
|
||||
keysyms.add(name)
|
||||
|
||||
# Perform _EVDEV and XK_ substitutions
|
||||
line = keysym_entry_pattern.sub(make_keysym_entry, line)
|
||||
line = xorgproto_keysym_prefix_pattern.sub(r"XKB_KEY_\1", line)
|
||||
|
||||
print(line, end="")
|
||||
print("\n\n#endif")
|
||||
@@ -1,118 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import re
|
||||
import sys
|
||||
import itertools
|
||||
|
||||
import perfect_hash
|
||||
|
||||
pattern = re.compile(r"^#define\s+XKB_KEY_(?P<name>\w+)\s+(?P<value>0x[0-9a-fA-F]+)\s")
|
||||
matches = [pattern.match(line) for line in open(sys.argv[1])]
|
||||
entries = [(m.group("name"), int(m.group("value"), 16)) for m in matches if m]
|
||||
|
||||
# Sort based on the keysym name:
|
||||
# 1. Sort by the casefolded name: e.g. kana_ya < kana_YO.
|
||||
# 2. If same casefolded name, then sort by cased name, i.e for
|
||||
# ASCII: upper before lower: e.g kana_YA < kana_ya.
|
||||
# E.g. kana_YA < kana_ya < kana_YO < kana_yo
|
||||
# WARNING: this sort must not be changed, as some functions e.g.
|
||||
# xkb_keysym_from_name rely on upper case variant occuring first.
|
||||
entries_isorted = sorted(entries, key=lambda e: (e[0].casefold(), e[0]))
|
||||
# Sort based on keysym value. Sort is stable so in case of duplicate, the first
|
||||
# keysym occurence stays first.
|
||||
entries_kssorted = sorted(entries, key=lambda e: e[1])
|
||||
|
||||
print(
|
||||
"""
|
||||
/**
|
||||
* This file comes from libxkbcommon and was generated by makekeys.py
|
||||
* You can always fetch the latest version from:
|
||||
* https://raw.github.com/xkbcommon/libxkbcommon/master/src/ks_tables.h
|
||||
*/
|
||||
"""
|
||||
)
|
||||
|
||||
entry_offsets = {}
|
||||
|
||||
print(
|
||||
"""
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Woverlength-strings"
|
||||
#endif
|
||||
static const char *keysym_names =
|
||||
""".strip()
|
||||
)
|
||||
offs = 0
|
||||
for name, _ in entries_isorted:
|
||||
entry_offsets[name] = offs
|
||||
print(' "{name}\\0"'.format(name=name))
|
||||
offs += len(name) + 1
|
||||
print(
|
||||
"""
|
||||
;
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
""".strip()
|
||||
)
|
||||
|
||||
|
||||
template = r"""
|
||||
static const uint16_t keysym_name_G[] = {
|
||||
$G
|
||||
};
|
||||
|
||||
static size_t
|
||||
keysym_name_hash_f(const char *key, const char *T)
|
||||
{
|
||||
size_t sum = 0;
|
||||
for (size_t i = 0; key[i] != '\0'; i++)
|
||||
sum += T[i % $NS] * key[i];
|
||||
return sum % $NG;
|
||||
}
|
||||
|
||||
static size_t
|
||||
keysym_name_perfect_hash(const char *key)
|
||||
{
|
||||
return (
|
||||
keysym_name_G[keysym_name_hash_f(key, "$S1")] +
|
||||
keysym_name_G[keysym_name_hash_f(key, "$S2")]
|
||||
) % $NG;
|
||||
}
|
||||
"""
|
||||
print(
|
||||
perfect_hash.generate_code(
|
||||
keys=[name for name, value in entries_isorted],
|
||||
template=template,
|
||||
)
|
||||
)
|
||||
|
||||
print(
|
||||
"""
|
||||
struct name_keysym {
|
||||
xkb_keysym_t keysym;
|
||||
uint32_t offset;
|
||||
};\n"""
|
||||
)
|
||||
|
||||
|
||||
def print_entries(x):
|
||||
for name, value in x:
|
||||
print(
|
||||
" {{ 0x{value:08x}, {offs} }}, /* {name} */".format(
|
||||
offs=entry_offsets[name], value=value, name=name
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
print("static const struct name_keysym name_to_keysym[] = {")
|
||||
print_entries(entries_isorted)
|
||||
print("};\n")
|
||||
|
||||
# *.sort() is stable so we always get the first keysym for duplicate
|
||||
print("static const struct name_keysym keysym_to_name[] = {")
|
||||
print_entries(
|
||||
next(g[1]) for g in itertools.groupby(entries_kssorted, key=lambda e: e[1])
|
||||
)
|
||||
print("};")
|
||||
@@ -1,30 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""A script to generate MSVC Module-Definition files from version-script
|
||||
files (which are maintained manually)."""
|
||||
|
||||
import re
|
||||
import sys
|
||||
import pathlib
|
||||
|
||||
|
||||
def symbols_from_map(path):
|
||||
return re.findall(r"^\s+(r?xkb_.*);", path.read_text("utf-8"), re.MULTILINE)
|
||||
|
||||
|
||||
if 2 > len(sys.argv) > 3:
|
||||
raise SystemExit("Usage: {} file.map [file.def]".format(sys.argv[0]))
|
||||
|
||||
|
||||
map_file = pathlib.Path(sys.argv[1])
|
||||
map_symbols = set(symbols_from_map(map_file))
|
||||
|
||||
if len(sys.argv) == 3:
|
||||
def_file = open(sys.argv[2], "w", encoding="utf-8")
|
||||
else:
|
||||
def_file = sys.stdout
|
||||
|
||||
def_file.write("LIBRARY {}\n".format(map_file.stem))
|
||||
def_file.write("EXPORTS\n")
|
||||
for symbol in sorted(map_symbols):
|
||||
def_file.write("\t{}\n".format(symbol))
|
||||
@@ -1,706 +0,0 @@
|
||||
# Derived from: https://github.com/ilanschnell/perfect-hash
|
||||
# Commit: 6b7dd80a525dbd4349ea2c69f04a9c96f3c2fd54
|
||||
|
||||
# BSD 3-Clause License
|
||||
#
|
||||
# Copyright (c) 2019 - 2021, Ilan Schnell
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# * Neither the name of the Ilan Schnell nor the
|
||||
# names of its contributors may be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL ILAN SCHNELL BE LIABLE FOR ANY
|
||||
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""
|
||||
Generate a minimal perfect hash function for the keys in a file,
|
||||
desired hash values may be specified within this file as well.
|
||||
A given code template is filled with parameters, such that the
|
||||
output is code which implements the hash function.
|
||||
Templates can easily be constructed for any programming language.
|
||||
|
||||
The code is based on an a program A.M. Kuchling wrote:
|
||||
http://www.amk.ca/python/code/perfect-hash
|
||||
|
||||
The algorithm the program uses is described in the paper
|
||||
'Optimal algorithms for minimal perfect hashing',
|
||||
Z. J. Czech, G. Havas and B.S. Majewski.
|
||||
http://citeseer.ist.psu.edu/122364.html
|
||||
|
||||
The algorithm works like this:
|
||||
|
||||
1. You have K keys, that you want to perfectly hash against some
|
||||
desired hash values.
|
||||
|
||||
2. Choose a number N larger than K. This is the number of
|
||||
vertices in a graph G, and also the size of the resulting table G.
|
||||
|
||||
3. Pick two random hash functions f1, f2, that return values from 0..N-1.
|
||||
|
||||
4. Now, for all keys, you draw an edge between vertices f1(key) and f2(key)
|
||||
of the graph G, and associate the desired hash value with that edge.
|
||||
|
||||
5. If G is cyclic, go back to step 2.
|
||||
|
||||
6. Assign values to each vertex such that, for each edge, you can add
|
||||
the values for the two vertices and get the desired (hash) value
|
||||
for that edge. This task is easy, because the graph is acyclic.
|
||||
This is done by picking a vertex, and assigning it a value of 0.
|
||||
Then do a depth-first search, assigning values to new vertices so that
|
||||
they sum up properly.
|
||||
|
||||
7. f1, f2, and vertex values of G now make up a perfect hash function.
|
||||
|
||||
|
||||
For simplicity, the implementation of the algorithm combines steps 5 and 6.
|
||||
That is, we check for loops in G and assign the vertex values in one procedure.
|
||||
If this procedure succeeds, G is acyclic and the vertex values are assigned.
|
||||
If the procedure fails, G is cyclic, and we go back to step 2, replacing G
|
||||
with a new graph, and thereby discarding the vertex values from the failed
|
||||
attempt.
|
||||
"""
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import sys
|
||||
import random
|
||||
import string
|
||||
import subprocess
|
||||
import shutil
|
||||
import tempfile
|
||||
from collections import defaultdict
|
||||
from os.path import join
|
||||
|
||||
if sys.version_info[0] == 2:
|
||||
from cStringIO import StringIO
|
||||
else:
|
||||
from io import StringIO
|
||||
|
||||
|
||||
__version__ = "0.4.2"
|
||||
|
||||
|
||||
verbose = False
|
||||
trials = 150
|
||||
|
||||
|
||||
class Graph(object):
|
||||
"""
|
||||
Implements a graph with 'N' vertices. First, you connect the graph with
|
||||
edges, which have a desired value associated. Then the vertex values
|
||||
are assigned, which will fail if the graph is cyclic. The vertex values
|
||||
are assigned such that the two values corresponding to an edge add up to
|
||||
the desired edge value (mod N).
|
||||
"""
|
||||
|
||||
def __init__(self, N):
|
||||
self.N = N # number of vertices
|
||||
|
||||
# maps a vertex number to the list of tuples (vertex, edge value)
|
||||
# to which it is connected by edges.
|
||||
self.adjacent = defaultdict(list)
|
||||
|
||||
def connect(self, vertex1, vertex2, edge_value):
|
||||
"""
|
||||
Connect 'vertex1' and 'vertex2' with an edge, with associated
|
||||
value 'value'
|
||||
"""
|
||||
# Add vertices to each other's adjacent list
|
||||
self.adjacent[vertex1].append((vertex2, edge_value))
|
||||
self.adjacent[vertex2].append((vertex1, edge_value))
|
||||
|
||||
def assign_vertex_values(self):
|
||||
"""
|
||||
Try to assign the vertex values, such that, for each edge, you can
|
||||
add the values for the two vertices involved and get the desired
|
||||
value for that edge, i.e. the desired hash key.
|
||||
This will fail when the graph is cyclic.
|
||||
|
||||
This is done by a Depth-First Search of the graph. If the search
|
||||
finds a vertex that was visited before, there's a loop and False is
|
||||
returned immediately, i.e. the assignment is terminated.
|
||||
On success (when the graph is acyclic) True is returned.
|
||||
"""
|
||||
self.vertex_values = self.N * [-1] # -1 means unassigned
|
||||
|
||||
visited = self.N * [False]
|
||||
|
||||
# Loop over all vertices, taking unvisited ones as roots.
|
||||
for root in range(self.N):
|
||||
if visited[root]:
|
||||
continue
|
||||
|
||||
# explore tree starting at 'root'
|
||||
self.vertex_values[root] = 0 # set arbitrarily to zero
|
||||
|
||||
# Stack of vertices to visit, a list of tuples (parent, vertex)
|
||||
tovisit = [(None, root)]
|
||||
while tovisit:
|
||||
parent, vertex = tovisit.pop()
|
||||
visited[vertex] = True
|
||||
|
||||
# Loop over adjacent vertices, but skip the vertex we arrived
|
||||
# here from the first time it is encountered.
|
||||
skip = True
|
||||
for neighbor, edge_value in self.adjacent[vertex]:
|
||||
if skip and neighbor == parent:
|
||||
skip = False
|
||||
continue
|
||||
|
||||
if visited[neighbor]:
|
||||
# We visited here before, so the graph is cyclic.
|
||||
return False
|
||||
|
||||
tovisit.append((vertex, neighbor))
|
||||
|
||||
# Set new vertex's value to the desired edge value,
|
||||
# minus the value of the vertex we came here from.
|
||||
self.vertex_values[neighbor] = (
|
||||
edge_value - self.vertex_values[vertex]
|
||||
) % self.N
|
||||
|
||||
# check if all vertices have a valid value
|
||||
for vertex in range(self.N):
|
||||
assert self.vertex_values[vertex] >= 0
|
||||
|
||||
# We got though, so the graph is acyclic,
|
||||
# and all values are now assigned.
|
||||
return True
|
||||
|
||||
|
||||
class StrSaltHash(object):
|
||||
"""
|
||||
Random hash function generator.
|
||||
Simple byte level hashing: each byte is multiplied to another byte from
|
||||
a random string of characters, summed up, and finally modulo NG is
|
||||
taken.
|
||||
"""
|
||||
|
||||
chars = string.ascii_letters + string.digits
|
||||
|
||||
def __init__(self, N):
|
||||
self.N = N
|
||||
self.salt = ""
|
||||
|
||||
def __call__(self, key):
|
||||
# XXX: xkbcommon modification: make the salt length a power of 2
|
||||
# so that the % operation in the hash is fast.
|
||||
while len(self.salt) < max(len(key), 32): # add more salt as necessary
|
||||
self.salt += random.choice(self.chars)
|
||||
|
||||
return sum(ord(self.salt[i]) * ord(c) for i, c in enumerate(key)) % self.N
|
||||
|
||||
template = """
|
||||
def hash_f(key, T):
|
||||
return sum(ord(T[i % $NS]) * ord(c) for i, c in enumerate(key)) % $NG
|
||||
|
||||
def perfect_hash(key):
|
||||
return (G[hash_f(key, "$S1")] +
|
||||
G[hash_f(key, "$S2")]) % $NG
|
||||
"""
|
||||
|
||||
|
||||
class IntSaltHash(object):
|
||||
"""
|
||||
Random hash function generator.
|
||||
Simple byte level hashing, each byte is multiplied in sequence to a table
|
||||
containing random numbers, summed tp, and finally modulo NG is taken.
|
||||
"""
|
||||
|
||||
def __init__(self, N):
|
||||
self.N = N
|
||||
self.salt = []
|
||||
|
||||
def __call__(self, key):
|
||||
while len(self.salt) < len(key): # add more salt as necessary
|
||||
self.salt.append(random.randint(1, self.N - 1))
|
||||
|
||||
return sum(self.salt[i] * ord(c) for i, c in enumerate(key)) % self.N
|
||||
|
||||
template = """
|
||||
S1 = [$S1]
|
||||
S2 = [$S2]
|
||||
assert len(S1) == len(S2) == $NS
|
||||
|
||||
def hash_f(key, T):
|
||||
return sum(T[i % $NS] * ord(c) for i, c in enumerate(key)) % $NG
|
||||
|
||||
def perfect_hash(key):
|
||||
return (G[hash_f(key, S1)] + G[hash_f(key, S2)]) % $NG
|
||||
"""
|
||||
|
||||
|
||||
def builtin_template(Hash):
|
||||
return (
|
||||
"""\
|
||||
# =======================================================================
|
||||
# ================= Python code for perfect hash function ===============
|
||||
# =======================================================================
|
||||
|
||||
G = [$G]
|
||||
"""
|
||||
+ Hash.template
|
||||
+ """
|
||||
# ============================ Sanity check =============================
|
||||
|
||||
K = [$K]
|
||||
assert len(K) == $NK
|
||||
|
||||
for h, k in enumerate(K):
|
||||
assert perfect_hash(k) == h
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
class TooManyInterationsError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def generate_hash(keys, Hash=StrSaltHash):
|
||||
"""
|
||||
Return hash functions f1 and f2, and G for a perfect minimal hash.
|
||||
Input is an iterable of 'keys', whos indicies are the desired hash values.
|
||||
'Hash' is a random hash function generator, that means Hash(N) returns a
|
||||
returns a random hash function which returns hash values from 0..N-1.
|
||||
"""
|
||||
if not isinstance(keys, (list, tuple)):
|
||||
raise TypeError("list or tuple expected")
|
||||
NK = len(keys)
|
||||
if NK != len(set(keys)):
|
||||
raise ValueError("duplicate keys")
|
||||
for key in keys:
|
||||
if not isinstance(key, str):
|
||||
raise TypeError("key a not string: %r" % key)
|
||||
if NK > 10000 and Hash == StrSaltHash:
|
||||
print(
|
||||
"""\
|
||||
WARNING: You have %d keys.
|
||||
Using --hft=1 is likely to fail for so many keys.
|
||||
Please use --hft=2 instead.
|
||||
"""
|
||||
% NK
|
||||
)
|
||||
|
||||
# the number of vertices in the graph G
|
||||
NG = NK + 1
|
||||
if verbose:
|
||||
print("NG = %d" % NG)
|
||||
|
||||
trial = 0 # Number of trial graphs so far
|
||||
while True:
|
||||
if (trial % trials) == 0: # trials failures, increase NG slightly
|
||||
if trial > 0:
|
||||
NG = max(NG + 1, int(1.05 * NG))
|
||||
if verbose:
|
||||
sys.stdout.write("\nGenerating graphs NG = %d " % NG)
|
||||
trial += 1
|
||||
|
||||
if NG > 100 * (NK + 1):
|
||||
raise TooManyInterationsError("%d keys" % NK)
|
||||
|
||||
if verbose:
|
||||
sys.stdout.write(".")
|
||||
sys.stdout.flush()
|
||||
|
||||
G = Graph(NG) # Create graph with NG vertices
|
||||
f1 = Hash(NG) # Create 2 random hash functions
|
||||
f2 = Hash(NG)
|
||||
|
||||
# Connect vertices given by the values of the two hash functions
|
||||
# for each key. Associate the desired hash value with each edge.
|
||||
for hashval, key in enumerate(keys):
|
||||
G.connect(f1(key), f2(key), hashval)
|
||||
|
||||
# Try to assign the vertex values. This will fail when the graph
|
||||
# is cyclic. But when the graph is acyclic it will succeed and we
|
||||
# break out, because we're done.
|
||||
if G.assign_vertex_values():
|
||||
break
|
||||
|
||||
if verbose:
|
||||
print("\nAcyclic graph found after %d trials." % trial)
|
||||
print("NG = %d" % NG)
|
||||
|
||||
# Sanity check the result by actually verifying that all the keys
|
||||
# hash to the right value.
|
||||
for hashval, key in enumerate(keys):
|
||||
assert hashval == (G.vertex_values[f1(key)] + G.vertex_values[f2(key)]) % NG
|
||||
|
||||
if verbose:
|
||||
print("OK")
|
||||
|
||||
return f1, f2, G.vertex_values
|
||||
|
||||
|
||||
class Format(object):
|
||||
def __init__(self, width=76, indent=4, delimiter=", "):
|
||||
self.width = width
|
||||
self.indent = indent
|
||||
self.delimiter = delimiter
|
||||
|
||||
def print_format(self):
|
||||
print("Format options:")
|
||||
for name in "width", "indent", "delimiter":
|
||||
print(" %s: %r" % (name, getattr(self, name)))
|
||||
|
||||
def __call__(self, data, quote=False):
|
||||
if not isinstance(data, (list, tuple)):
|
||||
return str(data)
|
||||
|
||||
lendel = len(self.delimiter)
|
||||
aux = StringIO()
|
||||
pos = 20
|
||||
for i, elt in enumerate(data):
|
||||
last = bool(i == len(data) - 1)
|
||||
|
||||
s = ('"%s"' if quote else "%s") % elt
|
||||
|
||||
if pos + len(s) + lendel > self.width:
|
||||
aux.write("\n" + (self.indent * " "))
|
||||
pos = self.indent
|
||||
|
||||
aux.write(s)
|
||||
pos += len(s)
|
||||
if not last:
|
||||
aux.write(self.delimiter)
|
||||
pos += lendel
|
||||
|
||||
return "\n".join(l.rstrip() for l in aux.getvalue().split("\n"))
|
||||
|
||||
|
||||
def generate_code(keys, Hash=StrSaltHash, template=None, options=None):
|
||||
"""
|
||||
Takes a list of key value pairs and inserts the generated parameter
|
||||
lists into the 'template' string. 'Hash' is the random hash function
|
||||
generator, and the optional keywords are formating options.
|
||||
The return value is the substituted code template.
|
||||
"""
|
||||
f1, f2, G = generate_hash(keys, Hash)
|
||||
|
||||
assert f1.N == f2.N == len(G)
|
||||
try:
|
||||
salt_len = len(f1.salt)
|
||||
assert salt_len == len(f2.salt)
|
||||
except TypeError:
|
||||
salt_len = None
|
||||
|
||||
if template is None:
|
||||
template = builtin_template(Hash)
|
||||
|
||||
if options is None:
|
||||
fmt = Format()
|
||||
else:
|
||||
fmt = Format(
|
||||
width=options.width, indent=options.indent, delimiter=options.delimiter
|
||||
)
|
||||
|
||||
if verbose:
|
||||
fmt.print_format()
|
||||
|
||||
return string.Template(template).substitute(
|
||||
NS=salt_len,
|
||||
S1=fmt(f1.salt),
|
||||
S2=fmt(f2.salt),
|
||||
NG=len(G),
|
||||
G=fmt(G),
|
||||
NK=len(keys),
|
||||
K=fmt(list(keys), quote=True),
|
||||
)
|
||||
|
||||
|
||||
def read_table(filename, options):
|
||||
"""
|
||||
Reads keys and desired hash value pairs from a file. If no column
|
||||
for the hash value is specified, a sequence of hash values is generated,
|
||||
from 0 to N-1, where N is the number of rows found in the file.
|
||||
"""
|
||||
if verbose:
|
||||
print("Reading table from file `%s' to extract keys." % filename)
|
||||
try:
|
||||
fi = open(filename)
|
||||
except IOError:
|
||||
sys.exit("Error: Could not open `%s' for reading." % filename)
|
||||
|
||||
keys = []
|
||||
|
||||
if verbose:
|
||||
print("Reader options:")
|
||||
for name in "comment", "splitby", "keycol":
|
||||
print(" %s: %r" % (name, getattr(options, name)))
|
||||
|
||||
for n, line in enumerate(fi):
|
||||
line = line.strip()
|
||||
if not line or line.startswith(options.comment):
|
||||
continue
|
||||
|
||||
if line.count(options.comment): # strip content after comment
|
||||
line = line.split(options.comment)[0].strip()
|
||||
|
||||
row = [col.strip() for col in line.split(options.splitby)]
|
||||
|
||||
try:
|
||||
key = row[options.keycol - 1]
|
||||
except IndexError:
|
||||
sys.exit(
|
||||
"%s:%d: Error: Cannot read key, not enough columns." % (filename, n + 1)
|
||||
)
|
||||
|
||||
keys.append(key)
|
||||
|
||||
fi.close()
|
||||
|
||||
if not keys:
|
||||
exit("Error: no keys found in file `%s'." % filename)
|
||||
|
||||
return keys
|
||||
|
||||
|
||||
def read_template(filename):
|
||||
if verbose:
|
||||
print("Reading template from file `%s'" % filename)
|
||||
try:
|
||||
with open(filename, "r") as fi:
|
||||
return fi.read()
|
||||
except IOError:
|
||||
sys.exit("Error: Could not open `%s' for reading." % filename)
|
||||
|
||||
|
||||
def run_code(code):
|
||||
tmpdir = tempfile.mkdtemp()
|
||||
path = join(tmpdir, "t.py")
|
||||
with open(path, "w") as fo:
|
||||
fo.write(code)
|
||||
try:
|
||||
subprocess.check_call([sys.executable, path])
|
||||
except subprocess.CalledProcessError as e:
|
||||
raise AssertionError(e)
|
||||
finally:
|
||||
shutil.rmtree(tmpdir)
|
||||
|
||||
|
||||
def main():
|
||||
from optparse import OptionParser
|
||||
|
||||
usage = "usage: %prog [options] KEYS_FILE [TMPL_FILE]"
|
||||
|
||||
description = """\
|
||||
Generates code for perfect hash functions from
|
||||
a file with keywords and a code template.
|
||||
If no template file is provided, a small built-in Python template
|
||||
is processed and the output code is written to stdout.
|
||||
"""
|
||||
|
||||
parser = OptionParser(
|
||||
usage=usage,
|
||||
description=description,
|
||||
prog=sys.argv[0],
|
||||
version="%prog: " + __version__,
|
||||
)
|
||||
|
||||
parser.add_option(
|
||||
"--delimiter",
|
||||
action="store",
|
||||
default=", ",
|
||||
help="Delimiter for list items used in output, "
|
||||
"the default delimiter is '%default'",
|
||||
metavar="STR",
|
||||
)
|
||||
|
||||
parser.add_option(
|
||||
"--indent",
|
||||
action="store",
|
||||
default=4,
|
||||
type="int",
|
||||
help="Make INT spaces at the beginning of a "
|
||||
"new line when generated list is wrapped. "
|
||||
"Default is %default",
|
||||
metavar="INT",
|
||||
)
|
||||
|
||||
parser.add_option(
|
||||
"--width",
|
||||
action="store",
|
||||
default=76,
|
||||
type="int",
|
||||
help="Maximal width of generated list when "
|
||||
"wrapped. Default width is %default",
|
||||
metavar="INT",
|
||||
)
|
||||
|
||||
parser.add_option(
|
||||
"--comment",
|
||||
action="store",
|
||||
default="#",
|
||||
help="STR is the character, or sequence of "
|
||||
"characters, which marks the beginning "
|
||||
"of a comment (which runs till "
|
||||
"the end of the line), in the input "
|
||||
"KEYS_FILE. "
|
||||
"Default is '%default'",
|
||||
metavar="STR",
|
||||
)
|
||||
|
||||
parser.add_option(
|
||||
"--splitby",
|
||||
action="store",
|
||||
default=",",
|
||||
help="STR is the character by which the columns "
|
||||
"in the input KEYS_FILE are split. "
|
||||
"Default is '%default'",
|
||||
metavar="STR",
|
||||
)
|
||||
|
||||
parser.add_option(
|
||||
"--keycol",
|
||||
action="store",
|
||||
default=1,
|
||||
type="int",
|
||||
help="Specifies the column INT in the input "
|
||||
"KEYS_FILE which contains the keys. "
|
||||
"Default is %default, i.e. the first column.",
|
||||
metavar="INT",
|
||||
)
|
||||
|
||||
parser.add_option(
|
||||
"--trials",
|
||||
action="store",
|
||||
default=5,
|
||||
type="int",
|
||||
help="Specifies the number of trials before "
|
||||
"NG is increased. A small INT will give "
|
||||
"compute faster, but the array G will be "
|
||||
"large. A large INT will take longer to "
|
||||
"compute but G will be smaller. "
|
||||
"Default is %default",
|
||||
metavar="INT",
|
||||
)
|
||||
|
||||
parser.add_option(
|
||||
"--hft",
|
||||
action="store",
|
||||
default=1,
|
||||
type="int",
|
||||
help="Hash function type INT. Possible values "
|
||||
"are 1 (StrSaltHash) and 2 (IntSaltHash). "
|
||||
"The default is %default",
|
||||
metavar="INT",
|
||||
)
|
||||
|
||||
parser.add_option(
|
||||
"-e",
|
||||
"--execute",
|
||||
action="store_true",
|
||||
help="Execute the generated code within " "the Python interpreter.",
|
||||
)
|
||||
|
||||
parser.add_option(
|
||||
"-o",
|
||||
"--output",
|
||||
action="store",
|
||||
help="Specify output FILE explicitly. "
|
||||
"`-o std' means standard output. "
|
||||
"`-o no' means no output. "
|
||||
"By default, the file name is obtained "
|
||||
"from the name of the template file by "
|
||||
"substituting `tmpl' to `code'.",
|
||||
metavar="FILE",
|
||||
)
|
||||
|
||||
parser.add_option("-v", "--verbose", action="store_true", help="verbosity")
|
||||
|
||||
options, args = parser.parse_args()
|
||||
|
||||
if options.trials <= 0:
|
||||
parser.error("trials before increasing N has to be larger than zero")
|
||||
|
||||
global trials
|
||||
trials = options.trials
|
||||
|
||||
global verbose
|
||||
verbose = options.verbose
|
||||
|
||||
if len(args) not in (1, 2):
|
||||
parser.error("incorrect number of arguments")
|
||||
|
||||
if len(args) == 2 and not args[1].count("tmpl"):
|
||||
parser.error("template filename does not contain 'tmpl'")
|
||||
|
||||
if options.hft == 1:
|
||||
Hash = StrSaltHash
|
||||
elif options.hft == 2:
|
||||
Hash = IntSaltHash
|
||||
else:
|
||||
parser.error("Hash function %s not implemented." % options.hft)
|
||||
|
||||
# --------------------- end parsing and checking --------------
|
||||
|
||||
keys_file = args[0]
|
||||
|
||||
if verbose:
|
||||
print("keys_file = %r" % keys_file)
|
||||
|
||||
keys = read_table(keys_file, options)
|
||||
|
||||
if verbose:
|
||||
print("Number os keys: %d" % len(keys))
|
||||
|
||||
tmpl_file = args[1] if len(args) == 2 else None
|
||||
|
||||
if verbose:
|
||||
print("tmpl_file = %r" % tmpl_file)
|
||||
|
||||
template = read_template(tmpl_file) if tmpl_file else None
|
||||
|
||||
if options.output:
|
||||
outname = options.output
|
||||
else:
|
||||
if tmpl_file:
|
||||
if "tmpl" not in tmpl_file:
|
||||
sys.exit("Hmm, template filename does not contain 'tmpl'")
|
||||
outname = tmpl_file.replace("tmpl", "code")
|
||||
else:
|
||||
outname = "std"
|
||||
|
||||
if verbose:
|
||||
print("outname = %r\n" % outname)
|
||||
|
||||
if outname == "std":
|
||||
outstream = sys.stdout
|
||||
elif outname == "no":
|
||||
outstream = None
|
||||
else:
|
||||
try:
|
||||
outstream = open(outname, "w")
|
||||
except IOError:
|
||||
sys.exit("Error: Could not open `%s' for writing." % outname)
|
||||
|
||||
code = generate_code(keys, Hash, template, options)
|
||||
|
||||
if options.execute or template == builtin_template(Hash):
|
||||
if verbose:
|
||||
print("Executing code...\n")
|
||||
run_code(code)
|
||||
|
||||
if outstream:
|
||||
outstream.write(code)
|
||||
if not outname == "std":
|
||||
outstream.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,135 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
from collections import defaultdict
|
||||
from pathlib import Path
|
||||
import re
|
||||
import sys
|
||||
from typing import Any, TypeAlias
|
||||
|
||||
import jinja2
|
||||
|
||||
KEYSYM_PATTERN = re.compile(
|
||||
r"^#define\s+XKB_KEY_(?P<name>\w+)\s+(?P<value>0x[0-9a-fA-F]+)\s"
|
||||
)
|
||||
MAX_AMBIGUOUS_NAMES = 3
|
||||
|
||||
KeysymsBounds: TypeAlias = dict[str, int]
|
||||
KeysymsCaseFoldedNames: TypeAlias = dict[str, list[str]]
|
||||
|
||||
|
||||
def load_keysyms(path: Path) -> tuple[KeysymsBounds, KeysymsCaseFoldedNames]:
|
||||
# Load the keysyms header
|
||||
keysym_min = sys.maxsize
|
||||
keysym_max = 0
|
||||
min_unicode_keysym = 0x01000100
|
||||
max_unicode_keysym = 0x0110FFFF
|
||||
canonical_names: dict[int, str] = {}
|
||||
casefolded_names: dict[str, list[str]] = defaultdict(list)
|
||||
max_unicode_name = "U10FFFF"
|
||||
max_keysym_name = "0x1fffffff" # XKB_KEYSYM_MAX
|
||||
|
||||
with path.open("rt", encoding="utf-8") as fd:
|
||||
for line in fd:
|
||||
if m := KEYSYM_PATTERN.match(line):
|
||||
value = int(m.group("value"), 16)
|
||||
keysym_min = min(keysym_min, value)
|
||||
keysym_max = max(keysym_max, value)
|
||||
name = m.group("name")
|
||||
casefolded_names[name.casefold()].append(name)
|
||||
if value not in canonical_names:
|
||||
canonical_names[value] = name
|
||||
|
||||
# Keep only ambiguous case-insensitive names and sort them
|
||||
for name in tuple(casefolded_names.keys()):
|
||||
count = len(casefolded_names[name])
|
||||
if count < 2:
|
||||
del casefolded_names[name]
|
||||
elif count > MAX_AMBIGUOUS_NAMES:
|
||||
raise ValueError(
|
||||
f"""Expected max {MAX_AMBIGUOUS_NAMES} keysyms for "{name}", got: {count}"""
|
||||
)
|
||||
else:
|
||||
casefolded_names[name].sort()
|
||||
|
||||
return (
|
||||
{
|
||||
"XKB_KEYSYM_MIN_ASSIGNED": min(keysym_min, min_unicode_keysym),
|
||||
"XKB_KEYSYM_MAX_ASSIGNED": max(keysym_max, max_unicode_keysym),
|
||||
"XKB_KEYSYM_MIN_EXPLICIT": keysym_min,
|
||||
"XKB_KEYSYM_MAX_EXPLICIT": keysym_max,
|
||||
"XKB_KEYSYM_COUNT_EXPLICIT": len(canonical_names),
|
||||
"XKB_KEYSYM_NAME_MAX_SIZE": max(
|
||||
max(len(name) for name in canonical_names.values()),
|
||||
len(max_unicode_name),
|
||||
len(max_keysym_name),
|
||||
),
|
||||
},
|
||||
casefolded_names,
|
||||
)
|
||||
|
||||
|
||||
def generate(
|
||||
env: jinja2.Environment,
|
||||
data: dict[str, Any],
|
||||
root: Path,
|
||||
file: Path,
|
||||
):
|
||||
"""Generate a file from its Jinja2 template"""
|
||||
template_path = file.with_suffix(f"{file.suffix}.jinja")
|
||||
template = env.get_template(str(template_path))
|
||||
path = root / file
|
||||
with path.open("wt", encoding="utf-8") as fd:
|
||||
fd.writelines(template.generate(**data))
|
||||
|
||||
|
||||
# Root of the project
|
||||
ROOT = Path(__file__).parent.parent
|
||||
|
||||
# Parse commands
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Generate C header files related to keysyms bounds"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--root",
|
||||
type=Path,
|
||||
default=ROOT,
|
||||
help="Path to the root of the project (default: %(default)s)",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Configure Jinja
|
||||
template_loader = jinja2.FileSystemLoader(args.root, encoding="utf-8")
|
||||
jinja_env = jinja2.Environment(
|
||||
loader=template_loader,
|
||||
keep_trailing_newline=True,
|
||||
trim_blocks=True,
|
||||
lstrip_blocks=True,
|
||||
)
|
||||
|
||||
jinja_env.filters["keysym"] = lambda ks: f"0x{ks:0>8x}"
|
||||
|
||||
# Load keysyms
|
||||
keysyms_bounds, keysyms_ambiguous_case_insensitive_names = load_keysyms(
|
||||
args.root / "include/xkbcommon/xkbcommon-keysyms.h"
|
||||
)
|
||||
|
||||
# Generate the files
|
||||
generate(
|
||||
jinja_env,
|
||||
keysyms_bounds,
|
||||
args.root,
|
||||
Path("src/keysym.h"),
|
||||
)
|
||||
|
||||
generate(
|
||||
jinja_env,
|
||||
dict(
|
||||
keysyms_bounds,
|
||||
ambiguous_case_insensitive_names=keysyms_ambiguous_case_insensitive_names,
|
||||
MAX_AMBIGUOUS_NAMES=MAX_AMBIGUOUS_NAMES,
|
||||
),
|
||||
args.root,
|
||||
Path("test/keysym.h"),
|
||||
)
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Run this to regenerate xkbcommon-keysyms.h from the X11 headers
|
||||
# defining the keysyms and update the name <-> keysym mapping.
|
||||
export LC_CTYPE=C.UTF-8
|
||||
export LC_COLLATE=C.UTF-8
|
||||
scripts/makeheader > include/xkbcommon/xkbcommon-keysyms.h
|
||||
scripts/makekeys include/xkbcommon/xkbcommon-keysyms.h > src/ks_tables.h
|
||||
scripts/update-headers.py
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Run this if you add/remove a new keyword to the xkbcomp scanner,
|
||||
# or just want to regenerate the gperf file.
|
||||
gperf < src/xkbcomp/keywords.gperf > src/xkbcomp/keywords.c
|
||||
@@ -1,278 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from dataclasses import astuple, dataclass
|
||||
from pathlib import Path
|
||||
import re
|
||||
from typing import Callable, Generic, Sequence, TypeVar
|
||||
|
||||
import jinja2
|
||||
import yaml
|
||||
|
||||
|
||||
@dataclass(order=True)
|
||||
class Version:
|
||||
"""A semantic version number: MAJOR.MINOR.PATCH."""
|
||||
|
||||
UNKNOWN_VERSION = "ALWAYS"
|
||||
DEFAULT_VERSION = "1.0.0"
|
||||
|
||||
major: int
|
||||
minor: int
|
||||
patch: int = 0
|
||||
|
||||
def __str__(self):
|
||||
return ".".join(map(str, astuple(self)))
|
||||
|
||||
@classmethod
|
||||
def parse(cls, raw_version: str) -> Version:
|
||||
if raw_version == cls.UNKNOWN_VERSION:
|
||||
raw_version = cls.DEFAULT_VERSION
|
||||
version = raw_version.split(".")
|
||||
assert 2 <= len(version) <= 3 and all(
|
||||
n.isdecimal() for n in version
|
||||
), raw_version
|
||||
return Version(*map(int, version))
|
||||
|
||||
|
||||
@dataclass
|
||||
class Example:
|
||||
"""An example in a message entry."""
|
||||
|
||||
name: str
|
||||
description: str
|
||||
before: str | None
|
||||
after: str | None
|
||||
|
||||
@classmethod
|
||||
def parse(cls, entry) -> Example:
|
||||
name = entry.get("name")
|
||||
assert name, entry
|
||||
|
||||
description = entry.get("description")
|
||||
assert description
|
||||
|
||||
before = entry.get("before")
|
||||
after = entry.get("after")
|
||||
# Either none or both of them
|
||||
assert not (bool(before) ^ bool(after))
|
||||
|
||||
return Example(name=name, description=description, before=before, after=after)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Entry:
|
||||
"""An xkbcommon message entry in the message registry"""
|
||||
|
||||
VALID_TYPES = ("warning", "error")
|
||||
|
||||
code: int
|
||||
"""A unique strictly positive integer identifier"""
|
||||
id: str
|
||||
"""A unique short human-readable string identifier"""
|
||||
type: str
|
||||
"""Log level of the message"""
|
||||
description: str
|
||||
"""A short description of the meaning of the message"""
|
||||
details: str
|
||||
"""A long description of the meaning of the message"""
|
||||
added: Version
|
||||
"""Version of xkbcommon the message has been added"""
|
||||
removed: Version | None
|
||||
"""Version of xkbcommon the message has been removed"""
|
||||
examples: tuple[Example, ...]
|
||||
"""
|
||||
Optional examples of situations in which the message occurs.
|
||||
If the message is an error or a warning, also provide hints on how to fix it.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def parse(cls, entry) -> Entry:
|
||||
code = entry.get("code")
|
||||
assert code is not None and isinstance(code, int) and code > 0, entry
|
||||
|
||||
id = entry.get("id")
|
||||
assert id is not None, entry
|
||||
|
||||
type_ = entry.get("type")
|
||||
assert type_ in cls.VALID_TYPES, entry
|
||||
|
||||
description = entry.get("description")
|
||||
assert description is not None, entry
|
||||
|
||||
details = entry.get("details", "")
|
||||
|
||||
raw_added = entry.get("added", "")
|
||||
assert raw_added, entry
|
||||
|
||||
added = Version.parse(raw_added)
|
||||
assert added, entry
|
||||
|
||||
if removed := entry.get("removed"):
|
||||
removed = Version.parse(removed)
|
||||
assert added < removed, entry
|
||||
|
||||
if examples := entry.get("examples", ()):
|
||||
examples = tuple(map(Example.parse, examples))
|
||||
|
||||
return Entry(
|
||||
code=code,
|
||||
id=id,
|
||||
type=type_,
|
||||
description=description,
|
||||
added=added,
|
||||
removed=removed,
|
||||
details=details,
|
||||
examples=examples,
|
||||
)
|
||||
|
||||
@property
|
||||
def message_code(self) -> str:
|
||||
"""Format the message code for display"""
|
||||
return f"XKB-{self.code:0>3}"
|
||||
|
||||
@property
|
||||
def message_code_constant(self: Entry) -> str:
|
||||
"""Returns the C enumeration member denoting the message code"""
|
||||
id = self.id.replace("-", "_").upper()
|
||||
return f"XKB_{self.type.upper()}_{id}"
|
||||
|
||||
@property
|
||||
def message_name(self: Entry):
|
||||
"""Format the message string identifier for display"""
|
||||
return self.id.replace("-", " ").capitalize()
|
||||
|
||||
|
||||
def prepend_todo(text: str) -> str:
|
||||
if text.startswith("TODO"):
|
||||
return f"""<span class="todo">{text[:5]}</span>{text[5:]}"""
|
||||
else:
|
||||
return text
|
||||
|
||||
|
||||
def load_message_registry(
|
||||
env: jinja2.Environment, constants: dict[str, int], path: Path
|
||||
) -> Sequence[Entry]:
|
||||
# Load the message registry YAML file as a Jinja2 template
|
||||
registry_template = env.get_template(str(path))
|
||||
|
||||
# Load message registry
|
||||
message_registry = sorted(
|
||||
map(Entry.parse, yaml.safe_load(registry_template.render(constants))),
|
||||
key=lambda e: e.code,
|
||||
)
|
||||
|
||||
# Check message codes and identifiers are unique
|
||||
codes: set[int] = set()
|
||||
identifiers: set[str] = set()
|
||||
for n, entry in enumerate(message_registry):
|
||||
if entry.code in codes:
|
||||
raise ValueError("Duplicated code in entry #{n}: {entry.code}")
|
||||
if entry.id in identifiers:
|
||||
raise ValueError("Duplicated identifier in entry #{n}: {entry.id}")
|
||||
codes.add(entry.code)
|
||||
identifiers.add(entry.id)
|
||||
|
||||
return message_registry
|
||||
|
||||
|
||||
def generate(
|
||||
registry: Sequence[Entry],
|
||||
env: jinja2.Environment,
|
||||
root: Path,
|
||||
file: Path,
|
||||
skip_removed: bool = False,
|
||||
):
|
||||
"""Generate a file from its Jinja2 template and the message registry"""
|
||||
template_path = file.with_suffix(f"{file.suffix}.jinja")
|
||||
template = env.get_template(str(template_path))
|
||||
path = root / file
|
||||
script = Path(__file__).name
|
||||
with path.open("wt", encoding="utf-8") as fd:
|
||||
entries = (
|
||||
tuple(filter(lambda e: e.removed is None, registry))
|
||||
if skip_removed
|
||||
else registry
|
||||
)
|
||||
fd.writelines(template.generate(entries=entries, script=script))
|
||||
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
@dataclass
|
||||
class Constant(Generic[T]):
|
||||
name: str
|
||||
pattern: re.Pattern
|
||||
conversion: Callable[[str], T]
|
||||
|
||||
|
||||
def read_constants(path: Path, patterns: Sequence[Constant[T]]) -> dict[str, T]:
|
||||
constants: dict[str, T] = {}
|
||||
patternsʹ = list(patterns)
|
||||
with path.open("rt", encoding="utf-8") as fd:
|
||||
for line in fd:
|
||||
for k, constant in enumerate(patternsʹ):
|
||||
if m := constant.pattern.match(line):
|
||||
constants[constant.name] = constant.conversion(m.group(1))
|
||||
del patternsʹ[k]
|
||||
continue # Expect only one match per line
|
||||
if not patternsʹ:
|
||||
# No more pattern to match
|
||||
break
|
||||
for constant in patternsʹ:
|
||||
print(f"ERROR: could not find constant: {constant.name}.")
|
||||
if patternsʹ:
|
||||
raise ValueError("Some constants were not found.")
|
||||
return constants
|
||||
|
||||
|
||||
# Root of the project
|
||||
ROOT = Path(__file__).parent.parent
|
||||
|
||||
# Parse commands
|
||||
parser = argparse.ArgumentParser(description="Generate files from the message registry")
|
||||
parser.add_argument(
|
||||
"--root",
|
||||
type=Path,
|
||||
default=ROOT,
|
||||
help="Path to the root of the project (default: %(default)s)",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Read some constants from libxkbcommon that we need
|
||||
constants = read_constants(
|
||||
Path(__file__).parent.parent / "src" / "keymap.h",
|
||||
(Constant("XKB_MAX_GROUPS", re.compile("^#define\s+XKB_MAX_GROUPS\s+(\d+)"), int),),
|
||||
)
|
||||
|
||||
# Configure Jinja
|
||||
template_loader = jinja2.FileSystemLoader(args.root, encoding="utf-8")
|
||||
jinja_env = jinja2.Environment(
|
||||
loader=template_loader,
|
||||
keep_trailing_newline=True,
|
||||
trim_blocks=True,
|
||||
lstrip_blocks=True,
|
||||
)
|
||||
jinja_env.filters["prepend_todo"] = prepend_todo
|
||||
|
||||
# Load message registry
|
||||
message_registry = load_message_registry(
|
||||
jinja_env, constants, Path("doc/message-registry.yaml")
|
||||
)
|
||||
|
||||
# Generate the files
|
||||
generate(
|
||||
message_registry,
|
||||
jinja_env,
|
||||
args.root,
|
||||
Path("src/messages-codes.h"),
|
||||
skip_removed=True,
|
||||
)
|
||||
generate(
|
||||
message_registry, jinja_env, args.root, Path("tools/messages.c"), skip_removed=True
|
||||
)
|
||||
generate(message_registry, jinja_env, args.root, Path("doc/message-registry.md"))
|
||||
@@ -1,193 +0,0 @@
|
||||
/***********************************************************
|
||||
* Copyright 1987, 1998 The Open Group
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The above copyright notice and this permission notice 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
|
||||
* OPEN GROUP 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.
|
||||
*
|
||||
* Except as contained in this notice, the name of The Open Group shall not be
|
||||
* used in advertising or otherwise to promote the sale, use or other dealings
|
||||
* in this Software without prior written authorization from The Open Group.
|
||||
*
|
||||
*
|
||||
* Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software and its
|
||||
* documentation for any purpose and without fee is hereby granted,
|
||||
* 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 Digital not be
|
||||
* used in advertising or publicity pertaining to distribution of the
|
||||
* software without specific, written prior permission.
|
||||
*
|
||||
* DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
|
||||
* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
|
||||
* DIGITAL 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.
|
||||
*
|
||||
******************************************************************/
|
||||
|
||||
/************************************************************
|
||||
* Copyright 1994 by Silicon Graphics Computer Systems, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose and without
|
||||
* fee is hereby granted, 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 Silicon Graphics not be
|
||||
* used in advertising or publicity pertaining to distribution
|
||||
* of the software without specific prior written permission.
|
||||
* Silicon Graphics makes no representation about the suitability
|
||||
* of this software for any purpose. It is provided "as is"
|
||||
* without any express or implied warranty.
|
||||
*
|
||||
* SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
|
||||
* GRAPHICS 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.
|
||||
*
|
||||
********************************************************/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "atom.h"
|
||||
#include "darray.h"
|
||||
#include "utils.h"
|
||||
|
||||
/* FNV-1a (http://www.isthe.com/chongo/tech/comp/fnv/). */
|
||||
static inline uint32_t
|
||||
hash_buf(const char *string, size_t len)
|
||||
{
|
||||
uint32_t hash = 2166136261u;
|
||||
for (size_t i = 0; i < (len + 1) / 2; i++) {
|
||||
hash ^= (uint8_t) string[i];
|
||||
hash *= 0x01000193;
|
||||
hash ^= (uint8_t) string[len - 1 - i];
|
||||
hash *= 0x01000193;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/*
|
||||
* The atom table is an insert-only linear probing hash table
|
||||
* mapping strings to atoms. Another array maps the atoms to
|
||||
* strings. The atom value is the position in the strings array.
|
||||
*/
|
||||
struct atom_table {
|
||||
xkb_atom_t *index;
|
||||
size_t index_size;
|
||||
darray(char *) strings;
|
||||
};
|
||||
|
||||
struct atom_table *
|
||||
atom_table_new(void)
|
||||
{
|
||||
struct atom_table *table = calloc(1, sizeof(*table));
|
||||
if (!table)
|
||||
return NULL;
|
||||
|
||||
darray_init(table->strings);
|
||||
darray_append(table->strings, NULL);
|
||||
table->index_size = 4;
|
||||
table->index = calloc(table->index_size, sizeof(*table->index));
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
void
|
||||
atom_table_free(struct atom_table *table)
|
||||
{
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
char **string;
|
||||
darray_foreach(string, table->strings)
|
||||
free(*string);
|
||||
darray_free(table->strings);
|
||||
free(table->index);
|
||||
free(table);
|
||||
}
|
||||
|
||||
const char *
|
||||
atom_text(struct atom_table *table, xkb_atom_t atom)
|
||||
{
|
||||
assert(atom < darray_size(table->strings));
|
||||
return darray_item(table->strings, atom);
|
||||
}
|
||||
|
||||
xkb_atom_t
|
||||
atom_intern(struct atom_table *table, const char *string, size_t len, bool add)
|
||||
{
|
||||
if (darray_size(table->strings) > 0.80 * table->index_size) {
|
||||
table->index_size *= 2;
|
||||
table->index = realloc(table->index, table->index_size * sizeof(*table->index));
|
||||
memset(table->index, 0, table->index_size * sizeof(*table->index));
|
||||
for (size_t j = 1; j < darray_size(table->strings); j++) {
|
||||
const char *s = darray_item(table->strings, j);
|
||||
uint32_t hash = hash_buf(s, strlen(s));
|
||||
for (size_t i = 0; i < table->index_size; i++) {
|
||||
size_t index_pos = (hash + i) & (table->index_size - 1);
|
||||
if (index_pos == 0)
|
||||
continue;
|
||||
|
||||
xkb_atom_t atom = table->index[index_pos];
|
||||
if (atom == XKB_ATOM_NONE) {
|
||||
table->index[index_pos] = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t hash = hash_buf(string, len);
|
||||
for (size_t i = 0; i < table->index_size; i++) {
|
||||
size_t index_pos = (hash + i) & (table->index_size - 1);
|
||||
if (index_pos == 0)
|
||||
continue;
|
||||
|
||||
xkb_atom_t existing_atom = table->index[index_pos];
|
||||
if (existing_atom == XKB_ATOM_NONE) {
|
||||
if (add) {
|
||||
xkb_atom_t new_atom = darray_size(table->strings);
|
||||
darray_append(table->strings, strndup(string, len));
|
||||
table->index[index_pos] = new_atom;
|
||||
return new_atom;
|
||||
} else {
|
||||
return XKB_ATOM_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
const char *existing_value = darray_item(table->strings, existing_atom);
|
||||
if (strncmp(existing_value, string, len) == 0 && existing_value[len] == '\0')
|
||||
return existing_atom;
|
||||
}
|
||||
|
||||
assert(!"couldn't find an empty slot during probing");
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2009 Dan Nicholson
|
||||
*
|
||||
* 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 ATOM_H
|
||||
#define ATOM_H
|
||||
|
||||
typedef uint32_t xkb_atom_t;
|
||||
|
||||
#define XKB_ATOM_NONE 0
|
||||
|
||||
struct atom_table;
|
||||
|
||||
struct atom_table *
|
||||
atom_table_new(void);
|
||||
|
||||
void
|
||||
atom_table_free(struct atom_table *table);
|
||||
|
||||
xkb_atom_t
|
||||
atom_intern(struct atom_table *table, const char *string, size_t len, bool add);
|
||||
|
||||
const char *
|
||||
atom_text(struct atom_table *table, xkb_atom_t atom);
|
||||
|
||||
#endif /* ATOM_H */
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2023 Pierre Le Marre <dev@wismill.eu>
|
||||
*
|
||||
* 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_DUMP_H
|
||||
#define COMPOSE_DUMP_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "src/utils.h"
|
||||
|
||||
/* Ad-hoc escaping for UTF-8 string
|
||||
*
|
||||
* Note that it only escapes the strict minimum to get a valid Compose file.
|
||||
* It also escapes hexadecimal digits after an hexadecimal escape. This is not
|
||||
* strictly needed by the current implementation: "\x0abcg" parses as "␊bcg",
|
||||
* but better be cautious than sorry and produce "\x0a\x62\x63g" instead.
|
||||
* In the latter string there is no ambiguity and no need to know the maximum
|
||||
* number of digits supported by the escape sequence.
|
||||
*/
|
||||
static inline char*
|
||||
escape_utf8_string_literal(const char *from)
|
||||
{
|
||||
const size_t length = strlen(from);
|
||||
/* Longest escape is converting ASCII character to "\xNN" */
|
||||
char* to = calloc(4 * length + 1, sizeof(to));
|
||||
if (!to)
|
||||
return NULL;
|
||||
|
||||
size_t t = 0;
|
||||
bool previous_is_hex_escape = false;
|
||||
uint8_t nbytes = 0;
|
||||
for (size_t f = 0; f < length;) {
|
||||
if ((unsigned char) from[f] < 0x80) {
|
||||
/* ASCII */
|
||||
if (from[f] <= 0x10 || from[f] == 0x7f ||
|
||||
(is_xdigit(from[f]) && previous_is_hex_escape))
|
||||
{
|
||||
/* Control character or
|
||||
hexadecimal digit following an hexadecimal escape */
|
||||
snprintf_safe(&to[t], 5, "\\x%02x", from[f]);
|
||||
t += 4;
|
||||
previous_is_hex_escape = true;
|
||||
} else if (from[f] == '"' || from[f] == '\\') {
|
||||
/* Quote and backslash */
|
||||
snprintf_safe(&to[t], 3, "\\%c", from[f]);
|
||||
t += 2;
|
||||
previous_is_hex_escape = false;
|
||||
} else {
|
||||
/* Other characters */
|
||||
to[t++] = from[f];
|
||||
previous_is_hex_escape = false;
|
||||
}
|
||||
f++;
|
||||
continue;
|
||||
}
|
||||
/* Test next byte for the next Unicode codepoint’s bytes count */
|
||||
else if ((unsigned char) from[f] < 0xe0)
|
||||
nbytes = 2;
|
||||
else if ((unsigned char) from[f] < 0xf0)
|
||||
nbytes = 3;
|
||||
else
|
||||
nbytes = 4;
|
||||
memcpy(&to[t], &from[f], nbytes);
|
||||
t += nbytes;
|
||||
f += nbytes;
|
||||
previous_is_hex_escape = false;
|
||||
}
|
||||
to[t++] = '\0';
|
||||
return realloc(to, t);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,781 +0,0 @@
|
||||
/*
|
||||
* 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 "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "table.h"
|
||||
#include "scanner-utils.h"
|
||||
#include "paths.h"
|
||||
#include "utf8.h"
|
||||
#include "parser.h"
|
||||
|
||||
/*
|
||||
* 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(scanner_peek(s)))
|
||||
if (scanner_next(s) == '\n')
|
||||
return TOK_END_OF_LINE;
|
||||
|
||||
/* Skip comments. */
|
||||
if (scanner_chr(s, '#')) {
|
||||
scanner_skip_to_eol(s);
|
||||
goto skip_more_whitespace_and_comments;
|
||||
}
|
||||
|
||||
/* See if we're done. */
|
||||
if (scanner_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 (scanner_chr(s, '<')) {
|
||||
while (scanner_peek(s) != '>' && !scanner_eol(s) && !scanner_eof(s))
|
||||
scanner_buf_append(s, scanner_next(s));
|
||||
if (!scanner_chr(s, '>')) {
|
||||
scanner_err(s, "unterminated keysym literal");
|
||||
return TOK_ERROR;
|
||||
}
|
||||
if (!scanner_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 (scanner_chr(s, ':'))
|
||||
return TOK_COLON;
|
||||
if (scanner_chr(s, '!'))
|
||||
return TOK_BANG;
|
||||
if (scanner_chr(s, '~'))
|
||||
return TOK_TILDE;
|
||||
|
||||
/* String literal. */
|
||||
if (scanner_chr(s, '\"')) {
|
||||
while (!scanner_eof(s) && !scanner_eol(s) && scanner_peek(s) != '\"') {
|
||||
if (scanner_chr(s, '\\')) {
|
||||
uint8_t o;
|
||||
size_t start_pos = s->pos;
|
||||
if (scanner_chr(s, '\\')) {
|
||||
scanner_buf_append(s, '\\');
|
||||
}
|
||||
else if (scanner_chr(s, '"')) {
|
||||
scanner_buf_append(s, '"');
|
||||
}
|
||||
else if (scanner_chr(s, 'x') || scanner_chr(s, 'X')) {
|
||||
if (scanner_hex(s, &o) && is_valid_char((char) o)) {
|
||||
scanner_buf_append(s, (char) o);
|
||||
} else {
|
||||
scanner_warn_with_code(s,
|
||||
XKB_WARNING_INVALID_ESCAPE_SEQUENCE,
|
||||
"illegal hexadecimal escape sequence (%.*s) in string literal",
|
||||
(int) (s->pos - start_pos + 1), &s->s[start_pos - 1]);
|
||||
}
|
||||
}
|
||||
else if (scanner_oct(s, &o) && is_valid_char((char) o)) {
|
||||
scanner_buf_append(s, (char) o);
|
||||
}
|
||||
else if (s->pos > start_pos) {
|
||||
scanner_warn_with_code(s,
|
||||
XKB_WARNING_INVALID_ESCAPE_SEQUENCE,
|
||||
"illegal octal escape sequence (%.*s) in string literal",
|
||||
(int) (s->pos - start_pos + 1), &s->s[start_pos - 1]);
|
||||
/* Ignore. */
|
||||
}
|
||||
else {
|
||||
scanner_warn_with_code(s,
|
||||
XKB_WARNING_UNKNOWN_CHAR_ESCAPE_SEQUENCE,
|
||||
"unknown escape sequence (\\%c) in string literal",
|
||||
scanner_peek(s));
|
||||
/* Ignore. */
|
||||
}
|
||||
} else {
|
||||
scanner_buf_append(s, scanner_next(s));
|
||||
}
|
||||
}
|
||||
if (!scanner_chr(s, '\"')) {
|
||||
scanner_err(s, "unterminated string literal");
|
||||
return TOK_ERROR;
|
||||
}
|
||||
if (!scanner_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(scanner_peek(s)) || scanner_peek(s) == '_') {
|
||||
s->buf_pos = 0;
|
||||
while (is_alnum(scanner_peek(s)) || scanner_peek(s) == '_')
|
||||
scanner_buf_append(s, scanner_next(s));
|
||||
if (!scanner_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;
|
||||
}
|
||||
|
||||
scanner_err(s, "unrecognized token");
|
||||
/* Discard rest of line. */
|
||||
scanner_skip_to_eol(s);
|
||||
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(scanner_peek(s)))
|
||||
if (scanner_next(s) == '\n')
|
||||
return TOK_END_OF_LINE;
|
||||
|
||||
s->token_line = s->line;
|
||||
s->token_column = s->column;
|
||||
s->buf_pos = 0;
|
||||
|
||||
if (!scanner_chr(s, '\"')) {
|
||||
scanner_err(s, "include statement must be followed by a path");
|
||||
return TOK_ERROR;
|
||||
}
|
||||
|
||||
while (!scanner_eof(s) && !scanner_eol(s) && scanner_peek(s) != '\"') {
|
||||
if (scanner_chr(s, '%')) {
|
||||
if (scanner_chr(s, '%')) {
|
||||
scanner_buf_append(s, '%');
|
||||
}
|
||||
else if (scanner_chr(s, 'H')) {
|
||||
const char *home = xkb_context_getenv(table->ctx, "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 (!scanner_buf_appends(s, home)) {
|
||||
scanner_err(s, "include path after expanding %%H is too long");
|
||||
return TOK_ERROR;
|
||||
}
|
||||
}
|
||||
else if (scanner_chr(s, 'L')) {
|
||||
char *path = get_locale_compose_file_path(table->ctx, table->locale);
|
||||
if (!path) {
|
||||
scanner_err(s, "failed to expand %%L to the locale Compose file");
|
||||
return TOK_ERROR;
|
||||
}
|
||||
if (!scanner_buf_appends(s, path)) {
|
||||
free(path);
|
||||
scanner_err(s, "include path after expanding %%L is too long");
|
||||
return TOK_ERROR;
|
||||
}
|
||||
free(path);
|
||||
}
|
||||
else if (scanner_chr(s, 'S')) {
|
||||
const char *xlocaledir = get_xlocaledir_path(table->ctx);
|
||||
if (!scanner_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", scanner_peek(s));
|
||||
return TOK_ERROR;
|
||||
}
|
||||
} else {
|
||||
scanner_buf_append(s, scanner_next(s));
|
||||
}
|
||||
}
|
||||
if (!scanner_chr(s, '\"')) {
|
||||
scanner_err(s, "unterminated include statement");
|
||||
return TOK_ERROR;
|
||||
}
|
||||
if (!scanner_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[XKB_COMPOSE_MAX_STRING_SIZE];
|
||||
/* 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 void
|
||||
add_production(struct xkb_compose_table *table, struct scanner *s,
|
||||
const struct production *production)
|
||||
{
|
||||
unsigned lhs_pos = 0;
|
||||
uint32_t curr = darray_size(table->nodes) == 1 ? 0 : 1;
|
||||
uint32_t *pptr = NULL;
|
||||
struct compose_node *node = NULL;
|
||||
|
||||
/* Warn before potentially going over the limit, discard silently after. */
|
||||
if (darray_size(table->nodes) + production->len + MAX_LHS_LEN > MAX_COMPOSE_NODES)
|
||||
scanner_warn(s, "too many sequences for one Compose file; will ignore further lines");
|
||||
if (darray_size(table->nodes) + production->len >= MAX_COMPOSE_NODES)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Insert the sequence to the ternary search tree, creating new nodes as
|
||||
* needed.
|
||||
*
|
||||
* TODO: We insert in the order given, this means some inputs can create
|
||||
* long O(n) chains, which results in total O(n^2) parsing time. We should
|
||||
* ensure the tree is reasonably balanced somehow.
|
||||
*/
|
||||
while (true) {
|
||||
const xkb_keysym_t keysym = production->lhs[lhs_pos];
|
||||
const bool last = lhs_pos + 1 == production->len;
|
||||
|
||||
if (curr == 0) {
|
||||
/*
|
||||
* Create a new node and update the parent pointer to it.
|
||||
* Update the pointer first because the append invalidates it.
|
||||
*/
|
||||
struct compose_node new = {
|
||||
.keysym = keysym,
|
||||
.lokid = 0,
|
||||
.hikid = 0,
|
||||
.internal = {
|
||||
.eqkid = 0,
|
||||
.is_leaf = false,
|
||||
},
|
||||
};
|
||||
curr = darray_size(table->nodes);
|
||||
if (pptr != NULL) {
|
||||
*pptr = curr;
|
||||
pptr = NULL;
|
||||
}
|
||||
darray_append(table->nodes, new);
|
||||
}
|
||||
|
||||
node = &darray_item(table->nodes, curr);
|
||||
|
||||
if (keysym < node->keysym) {
|
||||
pptr = &node->lokid;
|
||||
curr = node->lokid;
|
||||
} else if (keysym > node->keysym) {
|
||||
pptr = &node->hikid;
|
||||
curr = node->hikid;
|
||||
} else if (!last) {
|
||||
if (node->is_leaf) {
|
||||
scanner_warn(s, "a sequence already exists which is a prefix of this sequence; overriding");
|
||||
node->internal.eqkid = 0;
|
||||
node->internal.is_leaf = false;
|
||||
}
|
||||
lhs_pos++;
|
||||
pptr = &node->internal.eqkid;
|
||||
curr = node->internal.eqkid;
|
||||
} else {
|
||||
if (node->is_leaf) {
|
||||
bool same_string =
|
||||
(node->leaf.utf8 == 0 && !production->has_string) ||
|
||||
(
|
||||
node->leaf.utf8 != 0 && production->has_string &&
|
||||
streq(&darray_item(table->utf8, node->leaf.utf8),
|
||||
production->string)
|
||||
);
|
||||
bool same_keysym =
|
||||
(node->leaf.keysym == XKB_KEY_NoSymbol && !production->has_keysym) ||
|
||||
(
|
||||
node->leaf.keysym != XKB_KEY_NoSymbol && production->has_keysym &&
|
||||
node->leaf.keysym == production->keysym
|
||||
);
|
||||
if (same_string && same_keysym) {
|
||||
scanner_warn(s, "this compose sequence is a duplicate of another; skipping line");
|
||||
return;
|
||||
} else {
|
||||
scanner_warn(s, "this compose sequence already exists; overriding");
|
||||
}
|
||||
} else if (node->internal.eqkid != 0) {
|
||||
scanner_warn(s, "this compose sequence is a prefix of another; skipping line");
|
||||
return;
|
||||
}
|
||||
node->is_leaf = true;
|
||||
if (production->has_string) {
|
||||
node->leaf.utf8 = darray_size(table->utf8);
|
||||
darray_append_items(table->utf8, production->string,
|
||||
strlen(production->string) + 1);
|
||||
}
|
||||
if (production->has_keysym) {
|
||||
node->leaf.keysym = production->keysym;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Parse a string literal ("...") and return the corresponding unescaped string,
|
||||
* or NULL if it fails.
|
||||
* This is aimed only for testing (un)escaping characters. */
|
||||
char *
|
||||
parse_string_literal(struct xkb_context *ctx, const char *string)
|
||||
{
|
||||
struct scanner s;
|
||||
union lvalue val;
|
||||
scanner_init(&s, ctx, string, strlen(string), "(unamed)", NULL);
|
||||
switch (lex(&s, &val)) {
|
||||
case TOK_STRING:
|
||||
return strdup(val.string.str);
|
||||
default:
|
||||
fprintf(stderr, "ERROR: %s\n", s.s);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
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, "rb");
|
||||
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;
|
||||
|
||||
/* Basic detection of wrong character encoding.
|
||||
The first character relevant to the grammar must be ASCII:
|
||||
whitespace, include, modifier list, keysym, comment */
|
||||
if (!scanner_check_supported_char_encoding(s)) {
|
||||
scanner_err(s,
|
||||
"This could be a file encoding issue. "
|
||||
"Supported file encodings are ASCII and UTF-8.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
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: expected max: %d, got: %d; "
|
||||
"skipping line", (int)sizeof(production.string) - 1, (int)val.string.len);
|
||||
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,
|
||||
XKB_LOG_MESSAGE_NO_ID,
|
||||
"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;
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
#define MAX_LHS_LEN 10
|
||||
#define MAX_INCLUDE_DEPTH 5
|
||||
/** Maximum size of the string returned by xkb_compose_state_get_utf8() */
|
||||
#define XKB_COMPOSE_MAX_STRING_SIZE 256
|
||||
|
||||
char *
|
||||
parse_string_literal(struct xkb_context *ctx, const char *string);
|
||||
|
||||
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
|
||||
@@ -1,216 +0,0 @@
|
||||
/*
|
||||
* 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 "config.h"
|
||||
|
||||
#include "xkbcommon/xkbcommon.h"
|
||||
#include "utils.h"
|
||||
#include "context.h"
|
||||
#include "paths.h"
|
||||
|
||||
enum resolve_name_direction {
|
||||
LEFT_TO_RIGHT,
|
||||
RIGHT_TO_LEFT,
|
||||
};
|
||||
|
||||
const char *
|
||||
get_xlocaledir_path(struct xkb_context *ctx)
|
||||
{
|
||||
const char *dir = xkb_context_getenv(ctx, "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(struct xkb_context *ctx, 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(ctx);
|
||||
|
||||
ret = snprintf(path, sizeof(path), "%s/%s", xlocaledir, filename);
|
||||
if (ret < 0 || (size_t) ret >= sizeof(path))
|
||||
return false;
|
||||
|
||||
file = fopen(path, "rb");
|
||||
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(struct xkb_context *ctx, const char *locale)
|
||||
{
|
||||
char *alias = resolve_name(ctx, "locale.alias", LEFT_TO_RIGHT, locale);
|
||||
return alias ? alias : strdup(locale);
|
||||
}
|
||||
|
||||
char *
|
||||
get_xcomposefile_path(struct xkb_context *ctx)
|
||||
{
|
||||
return strdup_safe(xkb_context_getenv(ctx, "XCOMPOSEFILE"));
|
||||
}
|
||||
|
||||
char *
|
||||
get_xdg_xcompose_file_path(struct xkb_context *ctx)
|
||||
{
|
||||
const char *xdg_config_home;
|
||||
const char *home;
|
||||
|
||||
xdg_config_home = xkb_context_getenv(ctx, "XDG_CONFIG_HOME");
|
||||
if (!xdg_config_home || xdg_config_home[0] != '/') {
|
||||
home = xkb_context_getenv(ctx, "HOME");
|
||||
if (!home)
|
||||
return NULL;
|
||||
return asprintf_safe("%s/.config/XCompose", home);
|
||||
}
|
||||
|
||||
return asprintf_safe("%s/XCompose", xdg_config_home);
|
||||
}
|
||||
|
||||
char *
|
||||
get_home_xcompose_file_path(struct xkb_context *ctx)
|
||||
{
|
||||
const char *home;
|
||||
|
||||
home = xkb_context_getenv(ctx, "HOME");
|
||||
if (!home)
|
||||
return NULL;
|
||||
|
||||
return asprintf_safe("%s/.XCompose", home);
|
||||
}
|
||||
|
||||
char *
|
||||
get_locale_compose_file_path(struct xkb_context *ctx, 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(ctx, "compose.dir", RIGHT_TO_LEFT, locale);
|
||||
if (!resolved)
|
||||
return NULL;
|
||||
|
||||
if (resolved[0] == '/') {
|
||||
path = resolved;
|
||||
}
|
||||
else {
|
||||
const char *xlocaledir = get_xlocaledir_path(ctx);
|
||||
path = asprintf_safe("%s/%s", xlocaledir, resolved);
|
||||
free(resolved);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* 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(struct xkb_context *ctx, const char *locale);
|
||||
|
||||
const char *
|
||||
get_xlocaledir_path(struct xkb_context *ctx);
|
||||
|
||||
char *
|
||||
get_xcomposefile_path(struct xkb_context *ctx);
|
||||
|
||||
char *
|
||||
get_xdg_xcompose_file_path(struct xkb_context *ctx);
|
||||
|
||||
char *
|
||||
get_home_xcompose_file_path(struct xkb_context *ctx);
|
||||
|
||||
char *
|
||||
get_locale_compose_file_path(struct xkb_context *ctx, const char *locale);
|
||||
|
||||
#endif
|
||||
@@ -1,201 +0,0 @@
|
||||
/*
|
||||
* 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 "config.h"
|
||||
|
||||
#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 ? 1 : node->internal.eqkid);
|
||||
if (context == 1 && darray_size(state->table->nodes) == 1)
|
||||
context = 0;
|
||||
|
||||
while (context != 0) {
|
||||
node = &darray_item(state->table->nodes, context);
|
||||
if (keysym < node->keysym)
|
||||
context = node->lokid;
|
||||
else if (keysym > node->keysym)
|
||||
context = node->hikid;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
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->leaf.utf8 == 0 && node->leaf.keysym != XKB_KEY_NoSymbol) {
|
||||
char utf8[7];
|
||||
int ret;
|
||||
|
||||
ret = xkb_keysym_to_utf8(node->leaf.keysym, utf8, sizeof(utf8));
|
||||
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", utf8);
|
||||
}
|
||||
|
||||
return snprintf(buffer, size, "%s",
|
||||
&darray_item(state->table->utf8, node->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->leaf.keysym;
|
||||
}
|
||||
@@ -1,382 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2013,2021 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 "config.h"
|
||||
|
||||
#include "utils.h"
|
||||
#include "table.h"
|
||||
#include "parser.h"
|
||||
#include "paths.h"
|
||||
#include "xkbcommon/xkbcommon.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 dummy;
|
||||
|
||||
resolved_locale = resolve_locale(ctx, 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);
|
||||
|
||||
dummy.keysym = XKB_KEY_NoSymbol;
|
||||
dummy.leaf.is_leaf = true;
|
||||
dummy.leaf.utf8 = 0;
|
||||
dummy.leaf.keysym = XKB_KEY_NoSymbol;
|
||||
darray_append(table->nodes, dummy);
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
path = get_xcomposefile_path(ctx);
|
||||
file = open_file(path);
|
||||
if (file)
|
||||
goto found_path;
|
||||
free(path);
|
||||
|
||||
path = get_xdg_xcompose_file_path(ctx);
|
||||
file = open_file(path);
|
||||
if (file)
|
||||
goto found_path;
|
||||
free(path);
|
||||
|
||||
path = get_home_xcompose_file_path(ctx);
|
||||
file = open_file(path);
|
||||
if (file)
|
||||
goto found_path;
|
||||
free(path);
|
||||
|
||||
path = get_locale_compose_file_path(ctx, table->locale);
|
||||
file = open_file(path);
|
||||
if (file)
|
||||
goto found_path;
|
||||
free(path);
|
||||
|
||||
log_err(ctx, XKB_LOG_MESSAGE_NO_ID,
|
||||
"couldn't find a Compose file for locale \"%s\" (mapped to \"%s\")\n",
|
||||
locale, table->locale);
|
||||
xkb_compose_table_unref(table);
|
||||
return NULL;
|
||||
|
||||
found_path:
|
||||
ok = parse_file(table, file, path);
|
||||
fclose(file);
|
||||
if (!ok) {
|
||||
free(path);
|
||||
xkb_compose_table_unref(table);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
log_dbg(ctx, XKB_LOG_MESSAGE_NO_ID,
|
||||
"created compose table from locale %s with path %s\n",
|
||||
table->locale, path);
|
||||
|
||||
free(path);
|
||||
return table;
|
||||
}
|
||||
|
||||
XKB_EXPORT const xkb_keysym_t *
|
||||
xkb_compose_table_entry_sequence(struct xkb_compose_table_entry *entry,
|
||||
size_t *sequence_length)
|
||||
{
|
||||
*sequence_length = entry->sequence_length;
|
||||
return entry->sequence;
|
||||
}
|
||||
|
||||
XKB_EXPORT xkb_keysym_t
|
||||
xkb_compose_table_entry_keysym(struct xkb_compose_table_entry *entry)
|
||||
{
|
||||
return entry->keysym;
|
||||
}
|
||||
|
||||
XKB_EXPORT const char *
|
||||
xkb_compose_table_entry_utf8(struct xkb_compose_table_entry *entry)
|
||||
{
|
||||
return entry->utf8;
|
||||
}
|
||||
|
||||
enum node_direction {
|
||||
NODE_LEFT = 0,
|
||||
NODE_DOWN,
|
||||
NODE_RIGHT,
|
||||
NODE_UP
|
||||
};
|
||||
|
||||
struct xkb_compose_table_iterator_cursor {
|
||||
uint32_t node_offset:30; /* WARNING: ensure it fits MAX_COMPOSE_NODES */
|
||||
uint8_t direction:2; /* enum node_direction: current direction
|
||||
* traversing the tree */
|
||||
};
|
||||
|
||||
struct xkb_compose_table_iterator {
|
||||
struct xkb_compose_table *table;
|
||||
/* Current entry */
|
||||
struct xkb_compose_table_entry entry;
|
||||
/* Stack of pending nodes to process */
|
||||
darray(struct xkb_compose_table_iterator_cursor) cursors;
|
||||
};
|
||||
|
||||
XKB_EXPORT struct xkb_compose_table_iterator *
|
||||
xkb_compose_table_iterator_new(struct xkb_compose_table *table)
|
||||
{
|
||||
struct xkb_compose_table_iterator *iter;
|
||||
xkb_keysym_t *sequence;
|
||||
|
||||
iter = calloc(1, sizeof(*iter));
|
||||
if (!iter) {
|
||||
return NULL;
|
||||
}
|
||||
iter->table = xkb_compose_table_ref(table);
|
||||
sequence = calloc(MAX_LHS_LEN, sizeof(xkb_keysym_t));
|
||||
if (!sequence) {
|
||||
free(iter);
|
||||
return NULL;
|
||||
}
|
||||
iter->entry.sequence = sequence;
|
||||
iter->entry.sequence_length = 0;
|
||||
|
||||
darray_init(iter->cursors);
|
||||
/* Add first cursor only if there is at least one non-dummy node */
|
||||
if (darray_size(iter->table->nodes) > 1) {
|
||||
const struct xkb_compose_table_iterator_cursor cursor = {
|
||||
.direction = NODE_LEFT,
|
||||
/* Offset 0 is a dummy null entry, skip it. */
|
||||
.node_offset = 1
|
||||
};
|
||||
darray_append(iter->cursors, cursor);
|
||||
}
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
XKB_EXPORT void
|
||||
xkb_compose_table_iterator_free(struct xkb_compose_table_iterator *iter)
|
||||
{
|
||||
xkb_compose_table_unref(iter->table);
|
||||
darray_free(iter->cursors);
|
||||
free(iter->entry.sequence);
|
||||
free(iter);
|
||||
}
|
||||
|
||||
XKB_EXPORT struct xkb_compose_table_entry *
|
||||
xkb_compose_table_iterator_next(struct xkb_compose_table_iterator *iter)
|
||||
{
|
||||
/*
|
||||
* This function takes the following recursive traversal function,
|
||||
* and makes it non-recursive and resumable. The iter->cursors stack
|
||||
* is analogous to the call stack, and cursor->direction to the
|
||||
* instruction pointer of a stack frame.
|
||||
*
|
||||
* traverse(xkb_keysym_t *sequence, size_t sequence_length, uint16_t p) {
|
||||
* if (!p) return
|
||||
* // cursor->direction == NODE_LEFT
|
||||
* node = &darray_item(table->nodes, p)
|
||||
* traverse(sequence, sequence_length, node->lokid)
|
||||
* // cursor->direction == NODE_DOWN
|
||||
* sequence[sequence_length++] = node->keysym
|
||||
* if (node->is_leaf)
|
||||
* emit(sequence, sequence_length, node->leaf.keysym, table->utf[node->leaf.utf8])
|
||||
* else
|
||||
* traverse(sequence, sequence_length, node->internal.eqkid)
|
||||
* sequence_length--
|
||||
* // cursor->direction == NODE_RIGHT
|
||||
* traverse(sequence, sequence_length, node->hikid)
|
||||
* // cursor->direction == NODE_UP
|
||||
* }
|
||||
*/
|
||||
|
||||
struct xkb_compose_table_iterator_cursor *cursor;
|
||||
const struct compose_node *node;
|
||||
|
||||
while (!darray_empty(iter->cursors)) {
|
||||
cursor = &darray_item(iter->cursors, darray_size(iter->cursors) - 1);
|
||||
node = &darray_item(iter->table->nodes, cursor->node_offset);
|
||||
|
||||
switch (cursor->direction) {
|
||||
case NODE_LEFT:
|
||||
cursor->direction = NODE_DOWN;
|
||||
if (node->lokid) {
|
||||
struct xkb_compose_table_iterator_cursor new_cursor = {node->lokid, NODE_LEFT};
|
||||
darray_append(iter->cursors, new_cursor);
|
||||
}
|
||||
break;
|
||||
|
||||
case NODE_DOWN:
|
||||
cursor->direction = NODE_RIGHT;
|
||||
assert (iter->entry.sequence_length <= MAX_LHS_LEN);
|
||||
iter->entry.sequence[iter->entry.sequence_length] = node->keysym;
|
||||
iter->entry.sequence_length++;
|
||||
if (node->is_leaf) {
|
||||
iter->entry.keysym = node->leaf.keysym;
|
||||
iter->entry.utf8 = &darray_item(iter->table->utf8, node->leaf.utf8);
|
||||
return &iter->entry;
|
||||
} else {
|
||||
struct xkb_compose_table_iterator_cursor new_cursor = {node->internal.eqkid, NODE_LEFT};
|
||||
darray_append(iter->cursors, new_cursor);
|
||||
}
|
||||
break;
|
||||
|
||||
case NODE_RIGHT:
|
||||
cursor->direction = NODE_UP;
|
||||
iter->entry.sequence_length--;
|
||||
if (node->hikid) {
|
||||
struct xkb_compose_table_iterator_cursor new_cursor = {node->hikid, NODE_LEFT};
|
||||
darray_append(iter->cursors, new_cursor);
|
||||
}
|
||||
break;
|
||||
|
||||
case NODE_UP:
|
||||
darray_remove_last(iter->cursors);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2013,2021 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 ternary search tree.
|
||||
*
|
||||
* Reference: https://www.drdobbs.com/database/ternary-search-trees/184410528
|
||||
* Visualization: https://www.cs.usfca.edu/~galles/visualization/TST.html
|
||||
*
|
||||
* Short example. Given these sequences:
|
||||
*
|
||||
* <B> <C> : "first" dead_a
|
||||
* <B> <D> <E> : "second" dead_b
|
||||
* <A> <F> : "third" dead_c
|
||||
*
|
||||
* the tree would look like:
|
||||
*
|
||||
* -------- [<B>]---------
|
||||
* | | #
|
||||
* v V
|
||||
* -- [<A>] -- [<C>] --------
|
||||
* # | # | |
|
||||
* v # -- [<D>] --
|
||||
* -- [<F>] -- # | #
|
||||
* # | # v
|
||||
* # -- [<E>] --
|
||||
* # | #
|
||||
* #
|
||||
*
|
||||
* where:
|
||||
* - [<X>] is a node for a sequence keysym <X>.
|
||||
* - right arrows are `hikid` pointers.
|
||||
* - left arrows are `lokid` pointers.
|
||||
* - down arrows are `eqkid` 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 an empty dummy node).
|
||||
*
|
||||
* Nodes without an eqkid 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).
|
||||
*/
|
||||
|
||||
/* 7 nodes for every potential Unicode character and then some should be
|
||||
* enough for all purposes. */
|
||||
#define MAX_COMPOSE_NODES (1 << 23)
|
||||
|
||||
struct compose_node {
|
||||
xkb_keysym_t keysym;
|
||||
|
||||
/* Offset into xkb_compose_table::nodes or 0. */
|
||||
uint32_t lokid;
|
||||
/* Offset into xkb_compose_table::nodes or 0. */
|
||||
uint32_t hikid;
|
||||
|
||||
union {
|
||||
struct {
|
||||
uint32_t _pad:31;
|
||||
bool is_leaf:1;
|
||||
};
|
||||
struct {
|
||||
uint32_t _pad:31;
|
||||
bool is_leaf:1;
|
||||
/* Offset into xkb_compose_table::nodes or 0. */
|
||||
uint32_t eqkid;
|
||||
} internal;
|
||||
struct {
|
||||
/* Offset into xkb_compose_table::utf8. */
|
||||
uint32_t utf8:31;
|
||||
bool is_leaf:1;
|
||||
xkb_keysym_t keysym;
|
||||
} leaf;
|
||||
};
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
struct xkb_compose_table_entry {
|
||||
xkb_keysym_t *sequence;
|
||||
size_t sequence_length;
|
||||
xkb_keysym_t keysym;
|
||||
const char *utf8;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,198 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2012 Intel Corporation
|
||||
* Copyright © 2012 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.
|
||||
*
|
||||
* Author: Daniel Stone <daniel@fooishbar.org>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "xkbcommon/xkbcommon.h"
|
||||
#include "utils.h"
|
||||
#include "context.h"
|
||||
|
||||
char *
|
||||
xkb_context_getenv(struct xkb_context *ctx, const char *name)
|
||||
{
|
||||
if (ctx->use_secure_getenv) {
|
||||
return secure_getenv(name);
|
||||
} else {
|
||||
return getenv(name);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int
|
||||
xkb_context_num_failed_include_paths(struct xkb_context *ctx)
|
||||
{
|
||||
return darray_size(ctx->failed_includes);
|
||||
}
|
||||
|
||||
const char *
|
||||
xkb_context_failed_include_path_get(struct xkb_context *ctx,
|
||||
unsigned int idx)
|
||||
{
|
||||
if (idx >= xkb_context_num_failed_include_paths(ctx))
|
||||
return NULL;
|
||||
|
||||
return darray_item(ctx->failed_includes, idx);
|
||||
}
|
||||
|
||||
xkb_atom_t
|
||||
xkb_atom_lookup(struct xkb_context *ctx, const char *string)
|
||||
{
|
||||
return atom_intern(ctx->atom_table, string, strlen(string), false);
|
||||
}
|
||||
|
||||
xkb_atom_t
|
||||
xkb_atom_intern(struct xkb_context *ctx, const char *string, size_t len)
|
||||
{
|
||||
return atom_intern(ctx->atom_table, string, len, true);
|
||||
}
|
||||
|
||||
const char *
|
||||
xkb_atom_text(struct xkb_context *ctx, xkb_atom_t atom)
|
||||
{
|
||||
return atom_text(ctx->atom_table, atom);
|
||||
}
|
||||
|
||||
void
|
||||
xkb_log(struct xkb_context *ctx, enum xkb_log_level level, int verbosity,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (ctx->log_level < level || ctx->log_verbosity < verbosity)
|
||||
return;
|
||||
|
||||
va_start(args, fmt);
|
||||
ctx->log_fn(ctx, level, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
char *
|
||||
xkb_context_get_buffer(struct xkb_context *ctx, size_t size)
|
||||
{
|
||||
char *rtrn;
|
||||
|
||||
if (size >= sizeof(ctx->text_buffer))
|
||||
return NULL;
|
||||
|
||||
if (sizeof(ctx->text_buffer) - ctx->text_next <= size)
|
||||
ctx->text_next = 0;
|
||||
|
||||
rtrn = &ctx->text_buffer[ctx->text_next];
|
||||
ctx->text_next += size;
|
||||
|
||||
return rtrn;
|
||||
}
|
||||
|
||||
static const char *
|
||||
xkb_context_get_default_rules(struct xkb_context *ctx)
|
||||
{
|
||||
const char *env = NULL;
|
||||
|
||||
if (ctx->use_environment_names)
|
||||
env = xkb_context_getenv(ctx, "XKB_DEFAULT_RULES");
|
||||
|
||||
return env ? env : DEFAULT_XKB_RULES;
|
||||
}
|
||||
|
||||
static const char *
|
||||
xkb_context_get_default_model(struct xkb_context *ctx)
|
||||
{
|
||||
const char *env = NULL;
|
||||
|
||||
if (ctx->use_environment_names)
|
||||
env = xkb_context_getenv(ctx, "XKB_DEFAULT_MODEL");
|
||||
|
||||
return env ? env : DEFAULT_XKB_MODEL;
|
||||
}
|
||||
|
||||
static const char *
|
||||
xkb_context_get_default_layout(struct xkb_context *ctx)
|
||||
{
|
||||
const char *env = NULL;
|
||||
|
||||
if (ctx->use_environment_names)
|
||||
env = xkb_context_getenv(ctx, "XKB_DEFAULT_LAYOUT");
|
||||
|
||||
return env ? env : DEFAULT_XKB_LAYOUT;
|
||||
}
|
||||
|
||||
static const char *
|
||||
xkb_context_get_default_variant(struct xkb_context *ctx)
|
||||
{
|
||||
const char *env = NULL;
|
||||
const char *layout = xkb_context_getenv(ctx, "XKB_DEFAULT_LAYOUT");
|
||||
|
||||
/* We don't want to inherit the variant if they haven't also set a
|
||||
* layout, since they're so closely paired. */
|
||||
if (layout && ctx->use_environment_names)
|
||||
env = xkb_context_getenv(ctx, "XKB_DEFAULT_VARIANT");
|
||||
|
||||
return env ? env : DEFAULT_XKB_VARIANT;
|
||||
}
|
||||
|
||||
static const char *
|
||||
xkb_context_get_default_options(struct xkb_context *ctx)
|
||||
{
|
||||
const char *env = NULL;
|
||||
|
||||
if (ctx->use_environment_names)
|
||||
env = xkb_context_getenv(ctx, "XKB_DEFAULT_OPTIONS");
|
||||
|
||||
return env ? env : DEFAULT_XKB_OPTIONS;
|
||||
}
|
||||
|
||||
void
|
||||
xkb_context_sanitize_rule_names(struct xkb_context *ctx,
|
||||
struct xkb_rule_names *rmlvo)
|
||||
{
|
||||
if (isempty(rmlvo->rules))
|
||||
rmlvo->rules = xkb_context_get_default_rules(ctx);
|
||||
if (isempty(rmlvo->model))
|
||||
rmlvo->model = xkb_context_get_default_model(ctx);
|
||||
/* Layout and variant are tied together, so don't try to use one from
|
||||
* the caller and one from the environment. */
|
||||
if (isempty(rmlvo->layout)) {
|
||||
rmlvo->layout = xkb_context_get_default_layout(ctx);
|
||||
if (!isempty(rmlvo->variant)) {
|
||||
const char *variant = xkb_context_get_default_variant(ctx);
|
||||
log_warn(ctx,
|
||||
XKB_LOG_MESSAGE_NO_ID,
|
||||
"Layout not provided, but variant set to \"%s\": "
|
||||
"ignoring variant and using defaults for both: "
|
||||
"layout=\"%s\", variant=\"%s\".\n",
|
||||
rmlvo->variant,
|
||||
rmlvo->layout,
|
||||
variant ? variant : "");
|
||||
}
|
||||
rmlvo->variant = xkb_context_get_default_variant(ctx);
|
||||
}
|
||||
/* Options can be empty, so respect that if passed in. */
|
||||
if (rmlvo->options == NULL)
|
||||
rmlvo->options = xkb_context_get_default_options(ctx);
|
||||
}
|
||||
@@ -1,371 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2012 Intel Corporation
|
||||
* Copyright © 2012 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.
|
||||
*
|
||||
* Author: Daniel Stone <daniel@fooishbar.org>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "xkbcommon/xkbcommon.h"
|
||||
#include "utils.h"
|
||||
#include "context.h"
|
||||
|
||||
|
||||
/**
|
||||
* Append one directory to the context's include path.
|
||||
*/
|
||||
XKB_EXPORT int
|
||||
xkb_context_include_path_append(struct xkb_context *ctx, const char *path)
|
||||
{
|
||||
struct stat stat_buf;
|
||||
int err = ENOMEM;
|
||||
char *tmp;
|
||||
|
||||
tmp = strdup(path);
|
||||
if (!tmp)
|
||||
goto err;
|
||||
|
||||
err = stat(path, &stat_buf);
|
||||
if (err != 0) {
|
||||
err = errno;
|
||||
goto err;
|
||||
}
|
||||
if (!S_ISDIR(stat_buf.st_mode)) {
|
||||
err = ENOTDIR;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!check_eaccess(path, R_OK | X_OK)) {
|
||||
err = EACCES;
|
||||
goto err;
|
||||
}
|
||||
|
||||
darray_append(ctx->includes, tmp);
|
||||
log_dbg(ctx, XKB_LOG_MESSAGE_NO_ID, "Include path added: %s\n", tmp);
|
||||
|
||||
return 1;
|
||||
|
||||
err:
|
||||
darray_append(ctx->failed_includes, tmp);
|
||||
log_dbg(ctx, XKB_LOG_MESSAGE_NO_ID,
|
||||
"Include path failed: %s (%s)\n", tmp, strerror(err));
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *
|
||||
xkb_context_include_path_get_extra_path(struct xkb_context *ctx)
|
||||
{
|
||||
const char *extra = xkb_context_getenv(ctx, "XKB_CONFIG_EXTRA_PATH");
|
||||
return extra ? extra : DFLT_XKB_CONFIG_EXTRA_PATH;
|
||||
}
|
||||
|
||||
const char *
|
||||
xkb_context_include_path_get_system_path(struct xkb_context *ctx)
|
||||
{
|
||||
const char *root = xkb_context_getenv(ctx, "XKB_CONFIG_ROOT");
|
||||
return root ? root : DFLT_XKB_CONFIG_ROOT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append the default include directories to the context.
|
||||
*/
|
||||
XKB_EXPORT int
|
||||
xkb_context_include_path_append_default(struct xkb_context *ctx)
|
||||
{
|
||||
const char *home, *xdg, *root, *extra;
|
||||
char *user_path;
|
||||
int ret = 0;
|
||||
|
||||
home = xkb_context_getenv(ctx, "HOME");
|
||||
|
||||
xdg = xkb_context_getenv(ctx, "XDG_CONFIG_HOME");
|
||||
if (xdg != NULL) {
|
||||
user_path = asprintf_safe("%s/xkb", xdg);
|
||||
if (user_path) {
|
||||
ret |= xkb_context_include_path_append(ctx, user_path);
|
||||
free(user_path);
|
||||
}
|
||||
} else if (home != NULL) {
|
||||
/* XDG_CONFIG_HOME fallback is $HOME/.config/ */
|
||||
user_path = asprintf_safe("%s/.config/xkb", home);
|
||||
if (user_path) {
|
||||
ret |= xkb_context_include_path_append(ctx, user_path);
|
||||
free(user_path);
|
||||
}
|
||||
}
|
||||
|
||||
if (home != NULL) {
|
||||
user_path = asprintf_safe("%s/.xkb", home);
|
||||
if (user_path) {
|
||||
ret |= xkb_context_include_path_append(ctx, user_path);
|
||||
free(user_path);
|
||||
}
|
||||
}
|
||||
|
||||
extra = xkb_context_include_path_get_extra_path(ctx);
|
||||
ret |= xkb_context_include_path_append(ctx, extra);
|
||||
root = xkb_context_include_path_get_system_path(ctx);
|
||||
ret |= xkb_context_include_path_append(ctx, root);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all entries in the context's include path.
|
||||
*/
|
||||
XKB_EXPORT void
|
||||
xkb_context_include_path_clear(struct xkb_context *ctx)
|
||||
{
|
||||
char **path;
|
||||
|
||||
darray_foreach(path, ctx->includes)
|
||||
free(*path);
|
||||
darray_free(ctx->includes);
|
||||
|
||||
darray_foreach(path, ctx->failed_includes)
|
||||
free(*path);
|
||||
darray_free(ctx->failed_includes);
|
||||
}
|
||||
|
||||
/**
|
||||
* xkb_context_include_path_clear() + xkb_context_include_path_append_default()
|
||||
*/
|
||||
XKB_EXPORT int
|
||||
xkb_context_include_path_reset_defaults(struct xkb_context *ctx)
|
||||
{
|
||||
xkb_context_include_path_clear(ctx);
|
||||
return xkb_context_include_path_append_default(ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of entries in the context's include path.
|
||||
*/
|
||||
XKB_EXPORT unsigned int
|
||||
xkb_context_num_include_paths(struct xkb_context *ctx)
|
||||
{
|
||||
return darray_size(ctx->includes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given entry in the context's include path, or NULL if an
|
||||
* invalid index is passed.
|
||||
*/
|
||||
XKB_EXPORT const char *
|
||||
xkb_context_include_path_get(struct xkb_context *ctx, unsigned int idx)
|
||||
{
|
||||
if (idx >= xkb_context_num_include_paths(ctx))
|
||||
return NULL;
|
||||
|
||||
return darray_item(ctx->includes, idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Take a new reference on the context.
|
||||
*/
|
||||
XKB_EXPORT struct xkb_context *
|
||||
xkb_context_ref(struct xkb_context *ctx)
|
||||
{
|
||||
ctx->refcnt++;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop an existing reference on the context, and free it if the refcnt is
|
||||
* now 0.
|
||||
*/
|
||||
XKB_EXPORT void
|
||||
xkb_context_unref(struct xkb_context *ctx)
|
||||
{
|
||||
if (!ctx || --ctx->refcnt > 0)
|
||||
return;
|
||||
|
||||
free(ctx->x11_atom_cache);
|
||||
xkb_context_include_path_clear(ctx);
|
||||
atom_table_free(ctx->atom_table);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
static const char *
|
||||
log_level_to_prefix(enum xkb_log_level level)
|
||||
{
|
||||
switch (level) {
|
||||
case XKB_LOG_LEVEL_DEBUG:
|
||||
return "xkbcommon: DEBUG: ";
|
||||
case XKB_LOG_LEVEL_INFO:
|
||||
return "xkbcommon: INFO: ";
|
||||
case XKB_LOG_LEVEL_WARNING:
|
||||
return "xkbcommon: WARNING: ";
|
||||
case XKB_LOG_LEVEL_ERROR:
|
||||
return "xkbcommon: ERROR: ";
|
||||
case XKB_LOG_LEVEL_CRITICAL:
|
||||
return "xkbcommon: CRITICAL: ";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ATTR_PRINTF(3, 0) static void
|
||||
default_log_fn(struct xkb_context *ctx, enum xkb_log_level level,
|
||||
const char *fmt, va_list args)
|
||||
{
|
||||
const char *prefix = log_level_to_prefix(level);
|
||||
|
||||
if (prefix)
|
||||
fprintf(stderr, "%s", prefix);
|
||||
vfprintf(stderr, fmt, args);
|
||||
}
|
||||
|
||||
static enum xkb_log_level
|
||||
log_level(const char *level) {
|
||||
char *endptr;
|
||||
enum xkb_log_level lvl;
|
||||
|
||||
errno = 0;
|
||||
lvl = strtol(level, &endptr, 10);
|
||||
if (errno == 0 && (endptr[0] == '\0' || is_space(endptr[0])))
|
||||
return lvl;
|
||||
if (istreq_prefix("crit", level))
|
||||
return XKB_LOG_LEVEL_CRITICAL;
|
||||
if (istreq_prefix("err", level))
|
||||
return XKB_LOG_LEVEL_ERROR;
|
||||
if (istreq_prefix("warn", level))
|
||||
return XKB_LOG_LEVEL_WARNING;
|
||||
if (istreq_prefix("info", level))
|
||||
return XKB_LOG_LEVEL_INFO;
|
||||
if (istreq_prefix("debug", level) || istreq_prefix("dbg", level))
|
||||
return XKB_LOG_LEVEL_DEBUG;
|
||||
|
||||
return XKB_LOG_LEVEL_ERROR;
|
||||
}
|
||||
|
||||
static int
|
||||
log_verbosity(const char *verbosity) {
|
||||
char *endptr;
|
||||
int v;
|
||||
|
||||
errno = 0;
|
||||
v = strtol(verbosity, &endptr, 10);
|
||||
if (errno == 0)
|
||||
return v;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new context.
|
||||
*/
|
||||
XKB_EXPORT struct xkb_context *
|
||||
xkb_context_new(enum xkb_context_flags flags)
|
||||
{
|
||||
const char *env;
|
||||
struct xkb_context *ctx = calloc(1, sizeof(*ctx));
|
||||
|
||||
if (!ctx)
|
||||
return NULL;
|
||||
|
||||
ctx->refcnt = 1;
|
||||
ctx->log_fn = default_log_fn;
|
||||
ctx->log_level = XKB_LOG_LEVEL_ERROR;
|
||||
ctx->log_verbosity = 0;
|
||||
ctx->use_environment_names = !(flags & XKB_CONTEXT_NO_ENVIRONMENT_NAMES);
|
||||
ctx->use_secure_getenv = !(flags & XKB_CONTEXT_NO_SECURE_GETENV);
|
||||
|
||||
/* Environment overwrites defaults. */
|
||||
env = xkb_context_getenv(ctx, "XKB_LOG_LEVEL");
|
||||
if (env)
|
||||
xkb_context_set_log_level(ctx, log_level(env));
|
||||
|
||||
env = xkb_context_getenv(ctx, "XKB_LOG_VERBOSITY");
|
||||
if (env)
|
||||
xkb_context_set_log_verbosity(ctx, log_verbosity(env));
|
||||
|
||||
if (!(flags & XKB_CONTEXT_NO_DEFAULT_INCLUDES) &&
|
||||
!xkb_context_include_path_append_default(ctx)) {
|
||||
log_err(ctx, XKB_LOG_MESSAGE_NO_ID,
|
||||
"failed to add default include path %s\n",
|
||||
DFLT_XKB_CONFIG_ROOT);
|
||||
xkb_context_unref(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->atom_table = atom_table_new();
|
||||
if (!ctx->atom_table) {
|
||||
xkb_context_unref(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->x11_atom_cache = NULL;
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
XKB_EXPORT void
|
||||
xkb_context_set_log_fn(struct xkb_context *ctx,
|
||||
void (*log_fn)(struct xkb_context *ctx,
|
||||
enum xkb_log_level level,
|
||||
const char *fmt, va_list args))
|
||||
{
|
||||
ctx->log_fn = (log_fn ? log_fn : default_log_fn);
|
||||
}
|
||||
|
||||
XKB_EXPORT enum xkb_log_level
|
||||
xkb_context_get_log_level(struct xkb_context *ctx)
|
||||
{
|
||||
return ctx->log_level;
|
||||
}
|
||||
|
||||
XKB_EXPORT void
|
||||
xkb_context_set_log_level(struct xkb_context *ctx, enum xkb_log_level level)
|
||||
{
|
||||
ctx->log_level = level;
|
||||
}
|
||||
|
||||
XKB_EXPORT int
|
||||
xkb_context_get_log_verbosity(struct xkb_context *ctx)
|
||||
{
|
||||
return ctx->log_verbosity;
|
||||
}
|
||||
|
||||
XKB_EXPORT void
|
||||
xkb_context_set_log_verbosity(struct xkb_context *ctx, int verbosity)
|
||||
{
|
||||
ctx->log_verbosity = verbosity;
|
||||
}
|
||||
|
||||
XKB_EXPORT void *
|
||||
xkb_context_get_user_data(struct xkb_context *ctx)
|
||||
{
|
||||
if (ctx)
|
||||
return ctx->user_data;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
XKB_EXPORT void
|
||||
xkb_context_set_user_data(struct xkb_context *ctx, void *user_data)
|
||||
{
|
||||
ctx->user_data = user_data;
|
||||
}
|
||||
@@ -1,172 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2012 Intel Corporation
|
||||
*
|
||||
* 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>
|
||||
*/
|
||||
|
||||
#ifndef CONTEXT_H
|
||||
#define CONTEXT_H
|
||||
|
||||
#include "atom.h"
|
||||
#include "messages-codes.h"
|
||||
|
||||
struct xkb_context {
|
||||
int refcnt;
|
||||
|
||||
ATTR_PRINTF(3, 0) void (*log_fn)(struct xkb_context *ctx,
|
||||
enum xkb_log_level level,
|
||||
const char *fmt, va_list args);
|
||||
enum xkb_log_level log_level;
|
||||
int log_verbosity;
|
||||
void *user_data;
|
||||
|
||||
struct xkb_rule_names names_dflt;
|
||||
|
||||
darray(char *) includes;
|
||||
darray(char *) failed_includes;
|
||||
|
||||
struct atom_table *atom_table;
|
||||
|
||||
/* Used and allocated by xkbcommon-x11, free()d with the context. */
|
||||
void *x11_atom_cache;
|
||||
|
||||
/* Buffer for the *Text() functions. */
|
||||
char text_buffer[2048];
|
||||
size_t text_next;
|
||||
|
||||
unsigned int use_environment_names : 1;
|
||||
unsigned int use_secure_getenv : 1;
|
||||
};
|
||||
|
||||
char *
|
||||
xkb_context_getenv(struct xkb_context *ctx, const char *name);
|
||||
|
||||
unsigned int
|
||||
xkb_context_num_failed_include_paths(struct xkb_context *ctx);
|
||||
|
||||
const char *
|
||||
xkb_context_failed_include_path_get(struct xkb_context *ctx,
|
||||
unsigned int idx);
|
||||
|
||||
const char *
|
||||
xkb_context_include_path_get_extra_path(struct xkb_context *ctx);
|
||||
|
||||
const char *
|
||||
xkb_context_include_path_get_system_path(struct xkb_context *ctx);
|
||||
|
||||
/*
|
||||
* Returns XKB_ATOM_NONE if @string was not previously interned,
|
||||
* otherwise returns the atom.
|
||||
*/
|
||||
xkb_atom_t
|
||||
xkb_atom_lookup(struct xkb_context *ctx, const char *string);
|
||||
|
||||
xkb_atom_t
|
||||
xkb_atom_intern(struct xkb_context *ctx, const char *string, size_t len);
|
||||
|
||||
#define xkb_atom_intern_literal(ctx, literal) \
|
||||
xkb_atom_intern((ctx), (literal), sizeof(literal) - 1)
|
||||
|
||||
/**
|
||||
* If @string is dynamically allocated, NUL-terminated, free'd immediately
|
||||
* after being interned, and not used afterwards, use this function
|
||||
* instead of xkb_atom_intern to avoid some unnecessary allocations.
|
||||
* The caller should not use or free the passed in string afterwards.
|
||||
*/
|
||||
xkb_atom_t
|
||||
xkb_atom_steal(struct xkb_context *ctx, char *string);
|
||||
|
||||
const char *
|
||||
xkb_atom_text(struct xkb_context *ctx, xkb_atom_t atom);
|
||||
|
||||
char *
|
||||
xkb_context_get_buffer(struct xkb_context *ctx, size_t size);
|
||||
|
||||
ATTR_PRINTF(4, 5) void
|
||||
xkb_log(struct xkb_context *ctx, enum xkb_log_level level, int verbosity,
|
||||
const char *fmt, ...);
|
||||
|
||||
void
|
||||
xkb_context_sanitize_rule_names(struct xkb_context *ctx,
|
||||
struct xkb_rule_names *rmlvo);
|
||||
|
||||
/*
|
||||
* Macro sorcery: PREPEND_MESSAGE_ID enables the log functions to format messages
|
||||
* with the message ID only if the ID is not 0 (XKB_LOG_MESSAGE_NO_ID).
|
||||
* This avoid checking the ID value at run time.
|
||||
*
|
||||
* The trick resides in CHECK_ID:
|
||||
* • CHECK_ID(0) expands to:
|
||||
* ‣ SECOND(MATCH0, WITH_ID, unused)
|
||||
* ‣ SECOND(unused,WITHOUT_ID, WITH_ID, unused)
|
||||
* ‣ WITHOUT_ID
|
||||
* • CHECK_ID(123) expands to:
|
||||
* ‣ SECOND(MATCH123, WITH_ID, unused)
|
||||
* ‣ WITH_ID
|
||||
*/
|
||||
#define EXPAND(...) __VA_ARGS__ /* needed for MSVC compatibility */
|
||||
|
||||
#define JOIN_EXPAND(a, b) a##b
|
||||
#define JOIN(a, b) JOIN_EXPAND(a, b)
|
||||
|
||||
#define SECOND_EXPAND(a, b, ...) b
|
||||
#define SECOND(...) EXPAND(SECOND_EXPAND(__VA_ARGS__))
|
||||
|
||||
#define MATCH0 unused,WITHOUT_ID
|
||||
#define CHECK_ID(value) SECOND(JOIN(MATCH, value), WITH_ID, unused)
|
||||
|
||||
#define FORMAT_MESSAGE_WITHOUT_ID(id, fmt) fmt
|
||||
#define FORMAT_MESSAGE_WITH_ID(id, fmt) "[XKB-%03d] " fmt, id
|
||||
#define PREPEND_MESSAGE_ID(id, fmt) JOIN(FORMAT_MESSAGE_, CHECK_ID(id))(id, fmt)
|
||||
|
||||
/*
|
||||
* The format is not part of the argument list in order to avoid the
|
||||
* "ISO C99 requires rest arguments to be used" warning when only the
|
||||
* format is supplied without arguments. Not supplying it would still
|
||||
* result in an error, though.
|
||||
*/
|
||||
#define xkb_log_with_code(ctx, level, verbosity, msg_id, fmt, ...) \
|
||||
xkb_log(ctx, level, verbosity, PREPEND_MESSAGE_ID(msg_id, fmt), ##__VA_ARGS__)
|
||||
#define log_dbg(ctx, id, ...) \
|
||||
xkb_log_with_code((ctx), XKB_LOG_LEVEL_DEBUG, 0, id, __VA_ARGS__)
|
||||
#define log_info(ctx, id, ...) \
|
||||
xkb_log_with_code((ctx), XKB_LOG_LEVEL_INFO, 0, id, __VA_ARGS__)
|
||||
#define log_warn(ctx, id, ...) \
|
||||
xkb_log_with_code((ctx), XKB_LOG_LEVEL_WARNING, 0, id, __VA_ARGS__)
|
||||
#define log_err(ctx, id, ...) \
|
||||
xkb_log_with_code((ctx), XKB_LOG_LEVEL_ERROR, 0, id, __VA_ARGS__)
|
||||
#define log_wsgo(ctx, id, ...) \
|
||||
xkb_log_with_code((ctx), XKB_LOG_LEVEL_CRITICAL, 0, id, __VA_ARGS__)
|
||||
#define log_vrb(ctx, vrb, id, ...) \
|
||||
xkb_log_with_code((ctx), XKB_LOG_LEVEL_WARNING, (vrb), id, __VA_ARGS__)
|
||||
|
||||
/*
|
||||
* Variants which are prefixed by the name of the function they're
|
||||
* called from.
|
||||
* Here we must have the silly 1 variant.
|
||||
*/
|
||||
#define log_err_func(ctx, fmt, ...) \
|
||||
log_err(ctx, XKB_LOG_MESSAGE_NO_ID, "%s: " fmt, __func__, __VA_ARGS__)
|
||||
#define log_err_func1(ctx, fmt) \
|
||||
log_err(ctx, XKB_LOG_MESSAGE_NO_ID, "%s: " fmt, __func__)
|
||||
|
||||
#endif
|
||||
@@ -1,217 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Joseph Adams <joeyadams3.14159@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 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 CCAN_DARRAY_H
|
||||
#define CCAN_DARRAY_H
|
||||
|
||||
/* Originally taken from: https://ccodearchive.net/info/darray.html
|
||||
* But modified for libxkbcommon. */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define darray(type) struct { type *item; unsigned size; unsigned alloc; }
|
||||
|
||||
#define darray_new() { 0, 0, 0 }
|
||||
|
||||
#define darray_init(arr) do { \
|
||||
(arr).item = 0; (arr).size = 0; (arr).alloc = 0; \
|
||||
} while (0)
|
||||
|
||||
#define darray_free(arr) do { \
|
||||
free((arr).item); \
|
||||
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.
|
||||
*
|
||||
* The following will produce an incompatible pointer warning:
|
||||
*
|
||||
* void foo(darray(int) *arr);
|
||||
* darray(int) arr = darray_new();
|
||||
* foo(&arr);
|
||||
*
|
||||
* The workaround:
|
||||
*
|
||||
* void foo(darray_int *arr);
|
||||
* darray_int arr = darray_new();
|
||||
* foo(&arr);
|
||||
*/
|
||||
|
||||
typedef darray (char) darray_char;
|
||||
typedef darray (signed char) darray_schar;
|
||||
typedef darray (unsigned char) darray_uchar;
|
||||
|
||||
typedef darray (short) darray_short;
|
||||
typedef darray (int) darray_int;
|
||||
typedef darray (long) darray_long;
|
||||
|
||||
typedef darray (unsigned short) darray_ushort;
|
||||
typedef darray (unsigned int) darray_uint;
|
||||
typedef darray (unsigned long) darray_ulong;
|
||||
|
||||
/*** Access ***/
|
||||
|
||||
#define darray_item(arr, i) ((arr).item[i])
|
||||
#define darray_size(arr) ((arr).size)
|
||||
#define darray_empty(arr) ((arr).size == 0)
|
||||
|
||||
/*** Insertion (single item) ***/
|
||||
|
||||
#define darray_append(arr, ...) do { \
|
||||
darray_resize(arr, (arr).size + 1); \
|
||||
(arr).item[(arr).size - 1] = (__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
/*** Insertion (multiple items) ***/
|
||||
|
||||
#define darray_append_items(arr, items, count) do { \
|
||||
unsigned __count = (count), __oldSize = (arr).size; \
|
||||
darray_resize(arr, __oldSize + __count); \
|
||||
memcpy((arr).item + __oldSize, items, __count * sizeof(*(arr).item)); \
|
||||
} while (0)
|
||||
|
||||
#define darray_from_items(arr, items, count) do { \
|
||||
unsigned __count = (count); \
|
||||
darray_resize(arr, __count); \
|
||||
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)
|
||||
|
||||
/*** Removal ***/
|
||||
|
||||
/* Warning: Do not call darray_remove_last on an empty darray. */
|
||||
#define darray_remove_last(arr) (--(arr).size)
|
||||
|
||||
/*** String buffer ***/
|
||||
|
||||
#define darray_append_string(arr, str) do { \
|
||||
const char *__str = (str); \
|
||||
darray_append_items(arr, __str, strlen(__str) + 1); \
|
||||
(arr).size--; \
|
||||
} while (0)
|
||||
|
||||
#define darray_append_lit(arr, stringLiteral) do { \
|
||||
darray_append_items(arr, stringLiteral, sizeof(stringLiteral)); \
|
||||
(arr).size--; \
|
||||
} while (0)
|
||||
|
||||
#define darray_appends_nullterminate(arr, items, count) do { \
|
||||
unsigned __count = (count), __oldSize = (arr).size; \
|
||||
darray_resize(arr, __oldSize + __count + 1); \
|
||||
memcpy((arr).item + __oldSize, items, __count * sizeof(*(arr).item)); \
|
||||
(arr).item[--(arr).size] = 0; \
|
||||
} while (0)
|
||||
|
||||
#define darray_prepends_nullterminate(arr, items, count) do { \
|
||||
unsigned __count = (count), __oldSize = (arr).size; \
|
||||
darray_resize(arr, __count + __oldSize + 1); \
|
||||
memmove((arr).item + __count, (arr).item, \
|
||||
__oldSize * sizeof(*(arr).item)); \
|
||||
memcpy((arr).item, items, __count * sizeof(*(arr).item)); \
|
||||
(arr).item[--(arr).size] = 0; \
|
||||
} while (0)
|
||||
|
||||
/*** Size management ***/
|
||||
|
||||
#define darray_resize(arr, newSize) \
|
||||
darray_growalloc(arr, (arr).size = (newSize))
|
||||
|
||||
#define darray_resize0(arr, newSize) do { \
|
||||
unsigned __oldSize = (arr).size, __newSize = (newSize); \
|
||||
(arr).size = __newSize; \
|
||||
if (__newSize > __oldSize) { \
|
||||
darray_growalloc(arr, __newSize); \
|
||||
memset(&(arr).item[__oldSize], 0, \
|
||||
(__newSize - __oldSize) * sizeof(*(arr).item)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define darray_realloc(arr, newAlloc) do { \
|
||||
(arr).item = realloc((arr).item, \
|
||||
((arr).alloc = (newAlloc)) * sizeof(*(arr).item)); \
|
||||
} while (0)
|
||||
|
||||
#define darray_growalloc(arr, need) do { \
|
||||
unsigned __need = (need); \
|
||||
if (__need > (arr).alloc) \
|
||||
darray_realloc(arr, darray_next_alloc((arr).alloc, __need, \
|
||||
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)
|
||||
{
|
||||
assert(need < UINT_MAX / itemSize / 2); /* Overflow. */
|
||||
if (alloc == 0)
|
||||
alloc = 4;
|
||||
while (alloc < need)
|
||||
alloc *= 2;
|
||||
return alloc;
|
||||
}
|
||||
|
||||
/*** Traversal ***/
|
||||
|
||||
#define darray_foreach(i, arr) \
|
||||
for ((i) = &(arr).item[0]; (i) < &(arr).item[(arr).size]; (i)++)
|
||||
|
||||
#define darray_foreach_from(i, arr, from) \
|
||||
for ((i) = &(arr).item[from]; (i) < &(arr).item[(arr).size]; (i)++)
|
||||
|
||||
/* Iterate on index and value at the same time, like Python's enumerate. */
|
||||
#define darray_enumerate(idx, val, arr) \
|
||||
for ((idx) = 0, (val) = &(arr).item[0]; \
|
||||
(idx) < (arr).size; \
|
||||
(idx)++, (val)++)
|
||||
|
||||
#define darray_enumerate_from(idx, val, arr, from) \
|
||||
for ((idx) = (from), (val) = &(arr).item[0]; \
|
||||
(idx) < (arr).size; \
|
||||
(idx)++, (val)++)
|
||||
|
||||
#define darray_foreach_reverse(i, arr) \
|
||||
for ((i) = &(arr).item[(arr).size - 1]; (arr).size > 0 && (i) >= &(arr).item[0]; (i)--)
|
||||
|
||||
#endif /* CCAN_DARRAY_H */
|
||||
@@ -1,152 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2012 Intel Corporation
|
||||
* Copyright © 2012 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.
|
||||
*
|
||||
* Author: Daniel Stone <daniel@fooishbar.org>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "keymap.h"
|
||||
|
||||
static void
|
||||
update_builtin_keymap_fields(struct xkb_keymap *keymap)
|
||||
{
|
||||
/* 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"
|
||||
};
|
||||
|
||||
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 *
|
||||
xkb_keymap_new(struct xkb_context *ctx,
|
||||
enum xkb_keymap_format format,
|
||||
enum xkb_keymap_compile_flags flags)
|
||||
{
|
||||
struct xkb_keymap *keymap;
|
||||
|
||||
keymap = calloc(1, sizeof(*keymap));
|
||||
if (!keymap)
|
||||
return NULL;
|
||||
|
||||
keymap->refcnt = 1;
|
||||
keymap->ctx = xkb_context_ref(ctx);
|
||||
|
||||
keymap->format = format;
|
||||
keymap->flags = flags;
|
||||
|
||||
update_builtin_keymap_fields(keymap);
|
||||
|
||||
return keymap;
|
||||
}
|
||||
|
||||
struct xkb_key *
|
||||
XkbKeyByName(struct xkb_keymap *keymap, xkb_atom_t name, bool use_aliases)
|
||||
{
|
||||
struct xkb_key *key;
|
||||
|
||||
xkb_keys_foreach(key, keymap)
|
||||
if (key->name == name)
|
||||
return key;
|
||||
|
||||
if (use_aliases) {
|
||||
xkb_atom_t new_name = XkbResolveKeyAlias(keymap, name);
|
||||
if (new_name != XKB_ATOM_NONE)
|
||||
return XkbKeyByName(keymap, new_name, false);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
xkb_atom_t
|
||||
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)
|
||||
return keymap->key_aliases[i].real;
|
||||
|
||||
return XKB_ATOM_NONE;
|
||||
}
|
||||
|
||||
void
|
||||
XkbEscapeMapName(char *name)
|
||||
{
|
||||
/*
|
||||
* All latin-1 alphanumerics, plus parens, slash, minus, underscore and
|
||||
* wildcards.
|
||||
*/
|
||||
static const unsigned char legal[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, 0xff, 0x83,
|
||||
0xfe, 0xff, 0xff, 0x87, 0xfe, 0xff, 0xff, 0x07,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff
|
||||
};
|
||||
|
||||
if (!name)
|
||||
return;
|
||||
|
||||
while (*name) {
|
||||
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;
|
||||
}
|
||||
@@ -1,585 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2012 Intel Corporation
|
||||
* Copyright © 2012 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.
|
||||
*
|
||||
* Author: Daniel Stone <daniel@fooishbar.org>
|
||||
*/
|
||||
|
||||
/************************************************************
|
||||
* Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose and without
|
||||
* fee is hereby granted, 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 Silicon Graphics not be
|
||||
* used in advertising or publicity pertaining to distribution
|
||||
* of the software without specific prior written permission.
|
||||
* Silicon Graphics makes no representation about the suitability
|
||||
* of this software for any purpose. It is provided "as is"
|
||||
* without any express or implied warranty.
|
||||
*
|
||||
* SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
|
||||
* GRAPHICS 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.
|
||||
*
|
||||
* ********************************************************/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "keymap.h"
|
||||
#include "text.h"
|
||||
|
||||
XKB_EXPORT struct xkb_keymap *
|
||||
xkb_keymap_ref(struct xkb_keymap *keymap)
|
||||
{
|
||||
keymap->refcnt++;
|
||||
return keymap;
|
||||
}
|
||||
|
||||
XKB_EXPORT void
|
||||
xkb_keymap_unref(struct xkb_keymap *keymap)
|
||||
{
|
||||
if (!keymap || --keymap->refcnt > 0)
|
||||
return;
|
||||
|
||||
if (keymap->keys) {
|
||||
struct xkb_key *key;
|
||||
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 < 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);
|
||||
}
|
||||
}
|
||||
free(key->groups);
|
||||
}
|
||||
}
|
||||
free(keymap->keys);
|
||||
}
|
||||
if (keymap->types) {
|
||||
for (unsigned i = 0; i < keymap->num_types; i++) {
|
||||
free(keymap->types[i].entries);
|
||||
free(keymap->types[i].level_names);
|
||||
}
|
||||
free(keymap->types);
|
||||
}
|
||||
free(keymap->sym_interprets);
|
||||
free(keymap->key_aliases);
|
||||
free(keymap->group_names);
|
||||
free(keymap->keycodes_section_name);
|
||||
free(keymap->symbols_section_name);
|
||||
free(keymap->types_section_name);
|
||||
free(keymap->compat_section_name);
|
||||
xkb_context_unref(keymap->ctx);
|
||||
free(keymap);
|
||||
}
|
||||
|
||||
static const struct xkb_keymap_format_ops *
|
||||
get_keymap_format_ops(enum xkb_keymap_format format)
|
||||
{
|
||||
static const struct xkb_keymap_format_ops *keymap_format_ops[] = {
|
||||
[XKB_KEYMAP_FORMAT_TEXT_V1] = &text_v1_keymap_format_ops,
|
||||
};
|
||||
|
||||
if ((int) format < 0 || (int) format >= (int) ARRAY_SIZE(keymap_format_ops))
|
||||
return NULL;
|
||||
|
||||
return keymap_format_ops[(int) format];
|
||||
}
|
||||
|
||||
XKB_EXPORT struct xkb_keymap *
|
||||
xkb_keymap_new_from_names(struct xkb_context *ctx,
|
||||
const struct xkb_rule_names *rmlvo_in,
|
||||
enum xkb_keymap_compile_flags flags)
|
||||
{
|
||||
struct xkb_keymap *keymap;
|
||||
struct xkb_rule_names rmlvo;
|
||||
const enum xkb_keymap_format format = XKB_KEYMAP_FORMAT_TEXT_V1;
|
||||
const struct xkb_keymap_format_ops *ops;
|
||||
|
||||
ops = get_keymap_format_ops(format);
|
||||
if (!ops || !ops->keymap_new_from_names) {
|
||||
log_err_func(ctx, "unsupported keymap format: %d\n", format);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (flags & ~(XKB_KEYMAP_COMPILE_NO_FLAGS)) {
|
||||
log_err_func(ctx, "unrecognized flags: %#x\n", flags);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
keymap = xkb_keymap_new(ctx, format, flags);
|
||||
if (!keymap)
|
||||
return NULL;
|
||||
|
||||
if (rmlvo_in)
|
||||
rmlvo = *rmlvo_in;
|
||||
else
|
||||
memset(&rmlvo, 0, sizeof(rmlvo));
|
||||
xkb_context_sanitize_rule_names(ctx, &rmlvo);
|
||||
|
||||
if (!ops->keymap_new_from_names(keymap, &rmlvo)) {
|
||||
xkb_keymap_unref(keymap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return keymap;
|
||||
}
|
||||
|
||||
XKB_EXPORT struct xkb_keymap *
|
||||
xkb_keymap_new_from_string(struct xkb_context *ctx,
|
||||
const char *string,
|
||||
enum xkb_keymap_format format,
|
||||
enum xkb_keymap_compile_flags flags)
|
||||
{
|
||||
return xkb_keymap_new_from_buffer(ctx, string, strlen(string),
|
||||
format, flags);
|
||||
}
|
||||
|
||||
XKB_EXPORT struct xkb_keymap *
|
||||
xkb_keymap_new_from_buffer(struct xkb_context *ctx,
|
||||
const char *buffer, size_t length,
|
||||
enum xkb_keymap_format format,
|
||||
enum xkb_keymap_compile_flags flags)
|
||||
{
|
||||
struct xkb_keymap *keymap;
|
||||
const struct xkb_keymap_format_ops *ops;
|
||||
|
||||
ops = get_keymap_format_ops(format);
|
||||
if (!ops || !ops->keymap_new_from_string) {
|
||||
log_err_func(ctx, "unsupported keymap format: %d\n", format);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (flags & ~(XKB_KEYMAP_COMPILE_NO_FLAGS)) {
|
||||
log_err_func(ctx, "unrecognized flags: %#x\n", flags);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!buffer) {
|
||||
log_err_func1(ctx, "no buffer specified\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
keymap = xkb_keymap_new(ctx, format, flags);
|
||||
if (!keymap)
|
||||
return NULL;
|
||||
|
||||
/* Allow a zero-terminated string as a buffer */
|
||||
if (length > 0 && buffer[length - 1] == '\0')
|
||||
length--;
|
||||
|
||||
if (!ops->keymap_new_from_string(keymap, buffer, length)) {
|
||||
xkb_keymap_unref(keymap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return keymap;
|
||||
}
|
||||
|
||||
XKB_EXPORT struct xkb_keymap *
|
||||
xkb_keymap_new_from_file(struct xkb_context *ctx,
|
||||
FILE *file,
|
||||
enum xkb_keymap_format format,
|
||||
enum xkb_keymap_compile_flags flags)
|
||||
{
|
||||
struct xkb_keymap *keymap;
|
||||
const struct xkb_keymap_format_ops *ops;
|
||||
|
||||
ops = get_keymap_format_ops(format);
|
||||
if (!ops || !ops->keymap_new_from_file) {
|
||||
log_err_func(ctx, "unsupported keymap format: %d\n", format);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (flags & ~(XKB_KEYMAP_COMPILE_NO_FLAGS)) {
|
||||
log_err_func(ctx, "unrecognized flags: %#x\n", flags);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!file) {
|
||||
log_err_func1(ctx, "no file specified\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
keymap = xkb_keymap_new(ctx, format, flags);
|
||||
if (!keymap)
|
||||
return NULL;
|
||||
|
||||
if (!ops->keymap_new_from_file(keymap, file)) {
|
||||
xkb_keymap_unref(keymap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return keymap;
|
||||
}
|
||||
|
||||
XKB_EXPORT char *
|
||||
xkb_keymap_get_as_string(struct xkb_keymap *keymap,
|
||||
enum xkb_keymap_format format)
|
||||
{
|
||||
const struct xkb_keymap_format_ops *ops;
|
||||
|
||||
if (format == XKB_KEYMAP_USE_ORIGINAL_FORMAT)
|
||||
format = keymap->format;
|
||||
|
||||
ops = get_keymap_format_ops(format);
|
||||
if (!ops || !ops->keymap_get_as_string) {
|
||||
log_err_func(keymap->ctx, "unsupported keymap format: %d\n", format);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ops->keymap_get_as_string(keymap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of modifiers active in the keymap.
|
||||
*/
|
||||
XKB_EXPORT xkb_mod_index_t
|
||||
xkb_keymap_num_mods(struct xkb_keymap *keymap)
|
||||
{
|
||||
return keymap->mods.num_mods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name for a given modifier.
|
||||
*/
|
||||
XKB_EXPORT const char *
|
||||
xkb_keymap_mod_get_name(struct xkb_keymap *keymap, xkb_mod_index_t idx)
|
||||
{
|
||||
if (idx >= keymap->mods.num_mods)
|
||||
return NULL;
|
||||
|
||||
return xkb_atom_text(keymap->ctx, keymap->mods.mods[idx].name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index for a named modifier.
|
||||
*/
|
||||
XKB_EXPORT xkb_mod_index_t
|
||||
xkb_keymap_mod_get_index(struct xkb_keymap *keymap, const char *name)
|
||||
{
|
||||
xkb_atom_t atom;
|
||||
|
||||
atom = xkb_atom_lookup(keymap->ctx, name);
|
||||
if (atom == XKB_ATOM_NONE)
|
||||
return XKB_MOD_INVALID;
|
||||
|
||||
return XkbModNameToIndex(&keymap->mods, atom, MOD_BOTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the total number of active groups in the keymap.
|
||||
*/
|
||||
XKB_EXPORT xkb_layout_index_t
|
||||
xkb_keymap_num_layouts(struct xkb_keymap *keymap)
|
||||
{
|
||||
return keymap->num_groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name for a given group.
|
||||
*/
|
||||
XKB_EXPORT const char *
|
||||
xkb_keymap_layout_get_name(struct xkb_keymap *keymap, xkb_layout_index_t idx)
|
||||
{
|
||||
if (idx >= keymap->num_group_names)
|
||||
return NULL;
|
||||
|
||||
return xkb_atom_text(keymap->ctx, keymap->group_names[idx]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index for a named layout.
|
||||
*/
|
||||
XKB_EXPORT xkb_layout_index_t
|
||||
xkb_keymap_layout_get_index(struct xkb_keymap *keymap, const char *name)
|
||||
{
|
||||
xkb_atom_t atom = xkb_atom_lookup(keymap->ctx, name);
|
||||
xkb_layout_index_t i;
|
||||
|
||||
if (atom == XKB_ATOM_NONE)
|
||||
return XKB_LAYOUT_INVALID;
|
||||
|
||||
for (i = 0; i < keymap->num_group_names; i++)
|
||||
if (keymap->group_names[i] == atom)
|
||||
return i;
|
||||
|
||||
return XKB_LAYOUT_INVALID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of layouts active for a particular key.
|
||||
*/
|
||||
XKB_EXPORT xkb_layout_index_t
|
||||
xkb_keymap_num_layouts_for_key(struct xkb_keymap *keymap, xkb_keycode_t kc)
|
||||
{
|
||||
const struct xkb_key *key = XkbKey(keymap, kc);
|
||||
|
||||
if (!key)
|
||||
return 0;
|
||||
|
||||
return key->num_groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of levels active for a particular key and layout.
|
||||
*/
|
||||
XKB_EXPORT xkb_level_index_t
|
||||
xkb_keymap_num_levels_for_key(struct xkb_keymap *keymap, xkb_keycode_t kc,
|
||||
xkb_layout_index_t layout)
|
||||
{
|
||||
const struct xkb_key *key = XkbKey(keymap, kc);
|
||||
|
||||
if (!key)
|
||||
return 0;
|
||||
|
||||
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 XkbKeyNumLevels(key, layout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the total number of LEDs in the keymap.
|
||||
*/
|
||||
XKB_EXPORT xkb_led_index_t
|
||||
xkb_keymap_num_leds(struct xkb_keymap *keymap)
|
||||
{
|
||||
return keymap->num_leds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name for a given LED.
|
||||
*/
|
||||
XKB_EXPORT const char *
|
||||
xkb_keymap_led_get_name(struct xkb_keymap *keymap, xkb_led_index_t idx)
|
||||
{
|
||||
if (idx >= keymap->num_leds)
|
||||
return NULL;
|
||||
|
||||
return xkb_atom_text(keymap->ctx, keymap->leds[idx].name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index for a named LED.
|
||||
*/
|
||||
XKB_EXPORT xkb_led_index_t
|
||||
xkb_keymap_led_get_index(struct xkb_keymap *keymap, const char *name)
|
||||
{
|
||||
xkb_atom_t atom = xkb_atom_lookup(keymap->ctx, name);
|
||||
xkb_led_index_t i;
|
||||
const struct xkb_led *led;
|
||||
|
||||
if (atom == XKB_ATOM_NONE)
|
||||
return XKB_LED_INVALID;
|
||||
|
||||
xkb_leds_enumerate(i, led, keymap)
|
||||
if (led->name == atom)
|
||||
return i;
|
||||
|
||||
return XKB_LED_INVALID;
|
||||
}
|
||||
|
||||
XKB_EXPORT size_t
|
||||
xkb_keymap_key_get_mods_for_level(struct xkb_keymap *keymap,
|
||||
xkb_keycode_t kc,
|
||||
xkb_layout_index_t layout,
|
||||
xkb_level_index_t level,
|
||||
xkb_mod_mask_t *masks_out,
|
||||
size_t masks_size)
|
||||
{
|
||||
const struct xkb_key *key = XkbKey(keymap, kc);
|
||||
if (!key)
|
||||
return 0;
|
||||
|
||||
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;
|
||||
|
||||
if (level >= XkbKeyNumLevels(key, layout))
|
||||
return 0;
|
||||
|
||||
const struct xkb_key_type *type = key->groups[layout].type;
|
||||
|
||||
size_t count = 0;
|
||||
|
||||
/*
|
||||
* If the active set of modifiers doesn't match any explicit entry of
|
||||
* the key type, the resulting level is 0 (i.e. Level 1).
|
||||
* So, if we are asked to find the modifiers for level==0, we can offer
|
||||
* an ~infinite supply, which is not very workable.
|
||||
* What we do instead, is special case the empty set of modifiers for
|
||||
* this purpose. If the empty set isn't explicit mapped to a level, we
|
||||
* take it to map to Level 1.
|
||||
* This is almost always what we want. If applicable, given it priority
|
||||
* over other ways to generate the level.
|
||||
*/
|
||||
if (level == 0) {
|
||||
bool empty_mapped = false;
|
||||
for (unsigned i = 0; i < type->num_entries && count < masks_size; i++)
|
||||
if (entry_is_active(&type->entries[i]) &&
|
||||
type->entries[i].mods.mask == 0) {
|
||||
empty_mapped = true;
|
||||
break;
|
||||
}
|
||||
if (!empty_mapped && count < masks_size) {
|
||||
masks_out[count++] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now search explicit mappings. */
|
||||
for (unsigned i = 0; i < type->num_entries && count < masks_size; i++) {
|
||||
if (entry_is_active(&type->entries[i]) &&
|
||||
type->entries[i].level == level) {
|
||||
masks_out[count++] = type->entries[i].mods.mask;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* As below, but takes an explicit layout/level rather than state.
|
||||
*/
|
||||
XKB_EXPORT int
|
||||
xkb_keymap_key_get_syms_by_level(struct xkb_keymap *keymap,
|
||||
xkb_keycode_t kc,
|
||||
xkb_layout_index_t layout,
|
||||
xkb_level_index_t level,
|
||||
const xkb_keysym_t **syms_out)
|
||||
{
|
||||
const struct xkb_key *key = XkbKey(keymap, kc);
|
||||
int num_syms;
|
||||
|
||||
if (!key)
|
||||
goto err;
|
||||
|
||||
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 >= XkbKeyNumLevels(key, layout))
|
||||
goto err;
|
||||
|
||||
num_syms = key->groups[layout].levels[level].num_syms;
|
||||
if (num_syms == 0)
|
||||
goto err;
|
||||
|
||||
if (num_syms == 1)
|
||||
*syms_out = &key->groups[layout].levels[level].u.sym;
|
||||
else
|
||||
*syms_out = key->groups[layout].levels[level].u.syms;
|
||||
|
||||
return num_syms;
|
||||
|
||||
err:
|
||||
*syms_out = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
XKB_EXPORT xkb_keycode_t
|
||||
xkb_keymap_min_keycode(struct xkb_keymap *keymap)
|
||||
{
|
||||
return keymap->min_key_code;
|
||||
}
|
||||
|
||||
XKB_EXPORT xkb_keycode_t
|
||||
xkb_keymap_max_keycode(struct xkb_keymap *keymap)
|
||||
{
|
||||
return keymap->max_key_code;
|
||||
}
|
||||
|
||||
XKB_EXPORT void
|
||||
xkb_keymap_key_for_each(struct xkb_keymap *keymap, xkb_keymap_key_iter_t iter,
|
||||
void *data)
|
||||
{
|
||||
struct xkb_key *key;
|
||||
|
||||
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.
|
||||
*/
|
||||
XKB_EXPORT int
|
||||
xkb_keymap_key_repeats(struct xkb_keymap *keymap, xkb_keycode_t kc)
|
||||
{
|
||||
const struct xkb_key *key = XkbKey(keymap, kc);
|
||||
|
||||
if (!key)
|
||||
return 0;
|
||||
|
||||
return key->repeats;
|
||||
}
|
||||
@@ -1,496 +0,0 @@
|
||||
/*
|
||||
* Copyright 1985, 1987, 1990, 1998 The Open Group
|
||||
*
|
||||
* 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 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 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.
|
||||
*
|
||||
* Except as contained in this notice, the names of the authors or their
|
||||
* institutions shall not be used in advertising or otherwise to promote the
|
||||
* sale, use or other dealings in this Software without prior written
|
||||
* authorization from the authors.
|
||||
*/
|
||||
|
||||
/************************************************************
|
||||
* Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose and without
|
||||
* fee is hereby granted, 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 Silicon Graphics not be
|
||||
* used in advertising or publicity pertaining to distribution
|
||||
* of the software without specific prior written permission.
|
||||
* Silicon Graphics makes no representation about the suitability
|
||||
* of this software for any purpose. It is provided "as is"
|
||||
* without any express or implied warranty.
|
||||
*
|
||||
* SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
|
||||
* GRAPHICS 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.
|
||||
*
|
||||
********************************************************/
|
||||
|
||||
/*
|
||||
* Copyright © 2009 Dan Nicholson
|
||||
* Copyright © 2012 Intel Corporation
|
||||
* Copyright © 2012 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.
|
||||
*
|
||||
* Author: Daniel Stone <daniel@fooishbar.org>
|
||||
* Dan Nicholson <dbn.lists@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef KEYMAP_H
|
||||
#define KEYMAP_H
|
||||
|
||||
/* Don't use compat names in internal code. */
|
||||
#define _XKBCOMMON_COMPAT_H
|
||||
#include "xkbcommon/xkbcommon.h"
|
||||
|
||||
#include "utils.h"
|
||||
#include "context.h"
|
||||
|
||||
/* This limit is artificially enforced, we do not depend on it any where.
|
||||
* The reason it's still here is that the rules file format does not
|
||||
* support multiple groups very well, and the rules shipped with
|
||||
* xkeyboard-config (see rules/evdev) depend on this limit extensively.
|
||||
* So just lifting this limit would cause problems for people who will use
|
||||
* more than 4 layouts.
|
||||
* TODO: Fix the group index syntax in the rules format, preferably in a
|
||||
* backwards compatible way.
|
||||
* See e.g. https://bugs.freedesktop.org/show_bug.cgi?id=14372
|
||||
* Note: A limit on the number of groups we *do* depend on is imposed by
|
||||
* the size of the xkb_layout_mask_t type (32). This is more than enough
|
||||
* though.
|
||||
*/
|
||||
#define XKB_MAX_GROUPS 4
|
||||
|
||||
/* Don't allow more modifiers than we can hold in xkb_mod_mask_t. */
|
||||
#define XKB_MAX_MODS ((xkb_mod_index_t) (sizeof(xkb_mod_mask_t) * 8))
|
||||
|
||||
/* Don't allow more leds than we can hold in xkb_led_mask_t. */
|
||||
#define XKB_MAX_LEDS ((xkb_led_index_t) (sizeof(xkb_led_mask_t) * 8))
|
||||
|
||||
/* Special value to handle modMap None {…} */
|
||||
#define XKB_MOD_NONE 0xffffffffU
|
||||
|
||||
/* These should all go away. */
|
||||
enum mod_type {
|
||||
MOD_REAL = (1 << 0),
|
||||
MOD_VIRT = (1 << 1),
|
||||
MOD_BOTH = (MOD_REAL | MOD_VIRT),
|
||||
};
|
||||
#define MOD_REAL_MASK_ALL ((xkb_mod_mask_t) 0x000000ff)
|
||||
|
||||
enum xkb_action_type {
|
||||
ACTION_TYPE_NONE = 0,
|
||||
ACTION_TYPE_MOD_SET,
|
||||
ACTION_TYPE_MOD_LATCH,
|
||||
ACTION_TYPE_MOD_LOCK,
|
||||
ACTION_TYPE_GROUP_SET,
|
||||
ACTION_TYPE_GROUP_LATCH,
|
||||
ACTION_TYPE_GROUP_LOCK,
|
||||
ACTION_TYPE_PTR_MOVE,
|
||||
ACTION_TYPE_PTR_BUTTON,
|
||||
ACTION_TYPE_PTR_LOCK,
|
||||
ACTION_TYPE_PTR_DEFAULT,
|
||||
ACTION_TYPE_TERMINATE,
|
||||
ACTION_TYPE_SWITCH_VT,
|
||||
ACTION_TYPE_CTRL_SET,
|
||||
ACTION_TYPE_CTRL_LOCK,
|
||||
ACTION_TYPE_PRIVATE,
|
||||
_ACTION_TYPE_NUM_ENTRIES
|
||||
};
|
||||
|
||||
enum xkb_action_flags {
|
||||
ACTION_LOCK_CLEAR = (1 << 0),
|
||||
ACTION_LATCH_TO_LOCK = (1 << 1),
|
||||
ACTION_LOCK_NO_LOCK = (1 << 2),
|
||||
ACTION_LOCK_NO_UNLOCK = (1 << 3),
|
||||
ACTION_MODS_LOOKUP_MODMAP = (1 << 4),
|
||||
ACTION_ABSOLUTE_SWITCH = (1 << 5),
|
||||
ACTION_ABSOLUTE_X = (1 << 6),
|
||||
ACTION_ABSOLUTE_Y = (1 << 7),
|
||||
ACTION_ACCEL = (1 << 8),
|
||||
ACTION_SAME_SCREEN = (1 << 9),
|
||||
};
|
||||
|
||||
enum xkb_action_controls {
|
||||
CONTROL_REPEAT = (1 << 0),
|
||||
CONTROL_SLOW = (1 << 1),
|
||||
CONTROL_DEBOUNCE = (1 << 2),
|
||||
CONTROL_STICKY = (1 << 3),
|
||||
CONTROL_MOUSEKEYS = (1 << 4),
|
||||
CONTROL_MOUSEKEYS_ACCEL = (1 << 5),
|
||||
CONTROL_AX = (1 << 6),
|
||||
CONTROL_AX_TIMEOUT = (1 << 7),
|
||||
CONTROL_AX_FEEDBACK = (1 << 8),
|
||||
CONTROL_BELL = (1 << 9),
|
||||
CONTROL_IGNORE_GROUP_LOCK = (1 << 10),
|
||||
CONTROL_ALL = \
|
||||
(CONTROL_REPEAT | CONTROL_SLOW | CONTROL_DEBOUNCE | CONTROL_STICKY | \
|
||||
CONTROL_MOUSEKEYS | CONTROL_MOUSEKEYS_ACCEL | CONTROL_AX | \
|
||||
CONTROL_AX_TIMEOUT | CONTROL_AX_FEEDBACK | CONTROL_BELL | \
|
||||
CONTROL_IGNORE_GROUP_LOCK)
|
||||
};
|
||||
|
||||
enum xkb_match_operation {
|
||||
MATCH_NONE,
|
||||
MATCH_ANY_OR_NONE,
|
||||
MATCH_ANY,
|
||||
MATCH_ALL,
|
||||
MATCH_EXACTLY,
|
||||
};
|
||||
|
||||
struct xkb_mods {
|
||||
xkb_mod_mask_t mods; /* original real+virtual mods in definition */
|
||||
xkb_mod_mask_t mask; /* computed effective mask */
|
||||
};
|
||||
|
||||
struct xkb_mod_action {
|
||||
enum xkb_action_type type;
|
||||
enum xkb_action_flags flags;
|
||||
struct xkb_mods mods;
|
||||
};
|
||||
|
||||
struct xkb_group_action {
|
||||
enum xkb_action_type type;
|
||||
enum xkb_action_flags flags;
|
||||
int32_t group;
|
||||
};
|
||||
|
||||
struct xkb_controls_action {
|
||||
enum xkb_action_type type;
|
||||
enum xkb_action_flags flags;
|
||||
enum xkb_action_controls ctrls;
|
||||
};
|
||||
|
||||
struct xkb_pointer_default_action {
|
||||
enum xkb_action_type type;
|
||||
enum xkb_action_flags flags;
|
||||
int8_t value;
|
||||
};
|
||||
|
||||
struct xkb_switch_screen_action {
|
||||
enum xkb_action_type type;
|
||||
enum xkb_action_flags flags;
|
||||
int8_t screen;
|
||||
};
|
||||
|
||||
struct xkb_pointer_action {
|
||||
enum xkb_action_type type;
|
||||
enum xkb_action_flags flags;
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
};
|
||||
|
||||
struct xkb_pointer_button_action {
|
||||
enum xkb_action_type type;
|
||||
enum xkb_action_flags flags;
|
||||
uint8_t count;
|
||||
uint8_t button;
|
||||
};
|
||||
|
||||
struct xkb_private_action {
|
||||
enum xkb_action_type type;
|
||||
uint8_t data[7];
|
||||
};
|
||||
|
||||
union xkb_action {
|
||||
enum xkb_action_type type;
|
||||
struct xkb_mod_action mods;
|
||||
struct xkb_group_action group;
|
||||
struct xkb_controls_action ctrls;
|
||||
struct xkb_pointer_default_action dflt;
|
||||
struct xkb_switch_screen_action screen;
|
||||
struct xkb_pointer_action ptr;
|
||||
struct xkb_pointer_button_action btn;
|
||||
struct xkb_private_action priv;
|
||||
};
|
||||
|
||||
struct xkb_key_type_entry {
|
||||
xkb_level_index_t level;
|
||||
struct xkb_mods mods;
|
||||
struct xkb_mods preserve;
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
struct xkb_sym_interpret {
|
||||
xkb_keysym_t sym;
|
||||
enum xkb_match_operation match;
|
||||
xkb_mod_mask_t mods;
|
||||
xkb_mod_index_t virtual_mod;
|
||||
union xkb_action action;
|
||||
bool level_one_only;
|
||||
bool repeat;
|
||||
};
|
||||
|
||||
struct xkb_led {
|
||||
xkb_atom_t name;
|
||||
enum xkb_state_component which_groups;
|
||||
xkb_layout_mask_t groups;
|
||||
enum xkb_state_component which_mods;
|
||||
struct xkb_mods mods;
|
||||
enum xkb_action_controls ctrls;
|
||||
};
|
||||
|
||||
struct xkb_key_alias {
|
||||
xkb_atom_t real;
|
||||
xkb_atom_t alias;
|
||||
};
|
||||
|
||||
struct xkb_controls {
|
||||
unsigned char groups_wrap;
|
||||
struct xkb_mods internal;
|
||||
struct xkb_mods ignore_lock;
|
||||
unsigned short repeat_delay;
|
||||
unsigned short repeat_interval;
|
||||
unsigned short slow_keys_delay;
|
||||
unsigned short debounce_delay;
|
||||
unsigned short ax_options;
|
||||
unsigned short ax_timeout;
|
||||
unsigned short axt_opts_mask;
|
||||
unsigned short axt_opts_values;
|
||||
unsigned int axt_ctrls_mask;
|
||||
unsigned int axt_ctrls_values;
|
||||
};
|
||||
|
||||
/* Such an awkward name. Oh well. */
|
||||
enum xkb_range_exceed_type {
|
||||
RANGE_WRAP = 0,
|
||||
RANGE_SATURATE,
|
||||
RANGE_REDIRECT,
|
||||
};
|
||||
|
||||
enum xkb_explicit_components {
|
||||
EXPLICIT_INTERP = (1 << 0),
|
||||
EXPLICIT_VMODMAP = (1 << 1),
|
||||
EXPLICIT_REPEAT = (1 << 2),
|
||||
};
|
||||
|
||||
struct xkb_level {
|
||||
union xkb_action action;
|
||||
unsigned int num_syms;
|
||||
union {
|
||||
xkb_keysym_t sym; /* num_syms == 1 */
|
||||
xkb_keysym_t *syms; /* num_syms > 1 */
|
||||
} u;
|
||||
};
|
||||
|
||||
struct xkb_group {
|
||||
bool explicit_type;
|
||||
/* Points to a type in keymap->types. */
|
||||
const struct xkb_key_type *type;
|
||||
/* Use XkbKeyNumLevels for the number of levels. */
|
||||
struct xkb_level *levels;
|
||||
};
|
||||
|
||||
struct xkb_key {
|
||||
xkb_keycode_t keycode;
|
||||
xkb_atom_t name;
|
||||
|
||||
enum xkb_explicit_components explicit;
|
||||
|
||||
xkb_mod_mask_t modmap;
|
||||
xkb_mod_mask_t vmodmap;
|
||||
|
||||
bool repeats;
|
||||
|
||||
enum xkb_range_exceed_type out_of_range_group_action;
|
||||
xkb_layout_index_t out_of_range_group_number;
|
||||
|
||||
xkb_layout_index_t num_groups;
|
||||
struct xkb_group *groups;
|
||||
};
|
||||
|
||||
struct xkb_mod {
|
||||
xkb_atom_t name;
|
||||
enum mod_type type;
|
||||
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;
|
||||
|
||||
int refcnt;
|
||||
enum xkb_keymap_compile_flags flags;
|
||||
enum xkb_keymap_format format;
|
||||
|
||||
enum xkb_action_controls enabled_ctrls;
|
||||
|
||||
xkb_keycode_t min_key_code;
|
||||
xkb_keycode_t max_key_code;
|
||||
struct xkb_key *keys;
|
||||
|
||||
/* aliases in no particular order */
|
||||
unsigned int num_key_aliases;
|
||||
struct xkb_key_alias *key_aliases;
|
||||
|
||||
struct xkb_key_type *types;
|
||||
unsigned int num_types;
|
||||
|
||||
unsigned int num_sym_interprets;
|
||||
struct xkb_sym_interpret *sym_interprets;
|
||||
|
||||
struct xkb_mod_set mods;
|
||||
|
||||
/* Number of groups in the key with the most groups. */
|
||||
xkb_layout_index_t num_groups;
|
||||
/* Not all groups must have names. */
|
||||
xkb_layout_index_t num_group_names;
|
||||
xkb_atom_t *group_names;
|
||||
|
||||
struct xkb_led leds[XKB_MAX_LEDS];
|
||||
unsigned int num_leds;
|
||||
|
||||
char *keycodes_section_name;
|
||||
char *symbols_section_name;
|
||||
char *types_section_name;
|
||||
char *compat_section_name;
|
||||
};
|
||||
|
||||
#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)
|
||||
{
|
||||
if (kc < keymap->min_key_code || kc > keymap->max_key_code)
|
||||
return NULL;
|
||||
return &keymap->keys[kc];
|
||||
}
|
||||
|
||||
static inline xkb_level_index_t
|
||||
XkbKeyNumLevels(const struct xkb_key *key, xkb_layout_index_t layout)
|
||||
{
|
||||
return key->groups[layout].type->num_levels;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 inline bool
|
||||
entry_is_active(const struct xkb_key_type_entry *entry)
|
||||
{
|
||||
return entry->mods.mods == 0 || entry->mods.mask != 0;
|
||||
}
|
||||
|
||||
struct xkb_keymap *
|
||||
xkb_keymap_new(struct xkb_context *ctx,
|
||||
enum xkb_keymap_format format,
|
||||
enum xkb_keymap_compile_flags flags);
|
||||
|
||||
struct xkb_key *
|
||||
XkbKeyByName(struct xkb_keymap *keymap, xkb_atom_t name, bool use_aliases);
|
||||
|
||||
xkb_atom_t
|
||||
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
|
||||
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);
|
||||
bool (*keymap_new_from_string)(struct xkb_keymap *keymap,
|
||||
const char *string, size_t length);
|
||||
bool (*keymap_new_from_file)(struct xkb_keymap *keymap, FILE *file);
|
||||
char *(*keymap_get_as_string)(struct xkb_keymap *keymap);
|
||||
};
|
||||
|
||||
extern const struct xkb_keymap_format_ops text_v1_keymap_format_ops;
|
||||
|
||||
#endif
|
||||
@@ -1,966 +0,0 @@
|
||||
/* The table and comments below along with the function xkb_keysym_to_ucs4
|
||||
* are under the public domain and are derived as described below.
|
||||
*/
|
||||
/* This module converts keysym values into the corresponding ISO 10646
|
||||
* (UCS, Unicode) values.
|
||||
*
|
||||
* The array keysymtab[] contains pairs of X11 keysym values for graphical
|
||||
* characters and the corresponding Unicode value. The function
|
||||
* keysym2ucs() maps a keysym onto a Unicode value using a binary search,
|
||||
* therefore keysymtab[] must remain SORTED by keysym value.
|
||||
*
|
||||
* The keysym -> UTF-8 conversion will hopefully one day be provided
|
||||
* by Xlib via XmbLookupString() and should ideally not have to be
|
||||
* done in X applications. But we are not there yet.
|
||||
*
|
||||
* We allow to represent any UCS character in the range U-00000000 to
|
||||
* U-00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff.
|
||||
* This admittedly does not cover the entire 31-bit space of UCS, but
|
||||
* it does cover all of the characters up to U-10FFFF, which can be
|
||||
* represented by UTF-16, and more, and it is very unlikely that higher
|
||||
* UCS codes will ever be assigned by ISO. So to get Unicode character
|
||||
* U+ABCD you can directly use keysym 0x0100abcd.
|
||||
*
|
||||
* NOTE: The comments in the table below contain the actual character
|
||||
* encoded in UTF-8, so for viewing and editing best use an editor in
|
||||
* UTF-8 mode.
|
||||
*
|
||||
* Author: Markus G. Kuhn <http://www.cl.cam.ac.uk/~mgk25/>,
|
||||
* University of Cambridge, April 2001
|
||||
*
|
||||
* Special thanks to Richard Verhoeven <river@win.tue.nl> for preparing
|
||||
* an initial draft of the mapping table.
|
||||
*
|
||||
* This software is in the public domain. Share and enjoy!
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "xkbcommon/xkbcommon.h"
|
||||
#include "utils.h"
|
||||
#include "utf8.h"
|
||||
#include "keysym.h"
|
||||
|
||||
#define NO_KEYSYM_UNICODE_CONVERSION 0
|
||||
|
||||
/* We don't use the uint32_t types here, to save some space. */
|
||||
struct codepair {
|
||||
uint16_t keysym;
|
||||
uint16_t ucs;
|
||||
};
|
||||
|
||||
static const struct codepair keysymtab[] = {
|
||||
{ 0x01a1, 0x0104 }, /* Aogonek Ą LATIN CAPITAL LETTER A WITH OGONEK */
|
||||
{ 0x01a2, 0x02d8 }, /* breve ˘ BREVE */
|
||||
{ 0x01a3, 0x0141 }, /* Lstroke Ł LATIN CAPITAL LETTER L WITH STROKE */
|
||||
{ 0x01a5, 0x013d }, /* Lcaron Ľ LATIN CAPITAL LETTER L WITH CARON */
|
||||
{ 0x01a6, 0x015a }, /* Sacute Ś LATIN CAPITAL LETTER S WITH ACUTE */
|
||||
{ 0x01a9, 0x0160 }, /* Scaron Š LATIN CAPITAL LETTER S WITH CARON */
|
||||
{ 0x01aa, 0x015e }, /* Scedilla Ş LATIN CAPITAL LETTER S WITH CEDILLA */
|
||||
{ 0x01ab, 0x0164 }, /* Tcaron Ť LATIN CAPITAL LETTER T WITH CARON */
|
||||
{ 0x01ac, 0x0179 }, /* Zacute Ź LATIN CAPITAL LETTER Z WITH ACUTE */
|
||||
{ 0x01ae, 0x017d }, /* Zcaron Ž LATIN CAPITAL LETTER Z WITH CARON */
|
||||
{ 0x01af, 0x017b }, /* Zabovedot Ż LATIN CAPITAL LETTER Z WITH DOT ABOVE */
|
||||
{ 0x01b1, 0x0105 }, /* aogonek ą LATIN SMALL LETTER A WITH OGONEK */
|
||||
{ 0x01b2, 0x02db }, /* ogonek ˛ OGONEK */
|
||||
{ 0x01b3, 0x0142 }, /* lstroke ł LATIN SMALL LETTER L WITH STROKE */
|
||||
{ 0x01b5, 0x013e }, /* lcaron ľ LATIN SMALL LETTER L WITH CARON */
|
||||
{ 0x01b6, 0x015b }, /* sacute ś LATIN SMALL LETTER S WITH ACUTE */
|
||||
{ 0x01b7, 0x02c7 }, /* caron ˇ CARON */
|
||||
{ 0x01b9, 0x0161 }, /* scaron š LATIN SMALL LETTER S WITH CARON */
|
||||
{ 0x01ba, 0x015f }, /* scedilla ş LATIN SMALL LETTER S WITH CEDILLA */
|
||||
{ 0x01bb, 0x0165 }, /* tcaron ť LATIN SMALL LETTER T WITH CARON */
|
||||
{ 0x01bc, 0x017a }, /* zacute ź LATIN SMALL LETTER Z WITH ACUTE */
|
||||
{ 0x01bd, 0x02dd }, /* doubleacute ˝ DOUBLE ACUTE ACCENT */
|
||||
{ 0x01be, 0x017e }, /* zcaron ž LATIN SMALL LETTER Z WITH CARON */
|
||||
{ 0x01bf, 0x017c }, /* zabovedot ż LATIN SMALL LETTER Z WITH DOT ABOVE */
|
||||
{ 0x01c0, 0x0154 }, /* Racute Ŕ LATIN CAPITAL LETTER R WITH ACUTE */
|
||||
{ 0x01c3, 0x0102 }, /* Abreve Ă LATIN CAPITAL LETTER A WITH BREVE */
|
||||
{ 0x01c5, 0x0139 }, /* Lacute Ĺ LATIN CAPITAL LETTER L WITH ACUTE */
|
||||
{ 0x01c6, 0x0106 }, /* Cacute Ć LATIN CAPITAL LETTER C WITH ACUTE */
|
||||
{ 0x01c8, 0x010c }, /* Ccaron Č LATIN CAPITAL LETTER C WITH CARON */
|
||||
{ 0x01ca, 0x0118 }, /* Eogonek Ę LATIN CAPITAL LETTER E WITH OGONEK */
|
||||
{ 0x01cc, 0x011a }, /* Ecaron Ě LATIN CAPITAL LETTER E WITH CARON */
|
||||
{ 0x01cf, 0x010e }, /* Dcaron Ď LATIN CAPITAL LETTER D WITH CARON */
|
||||
{ 0x01d0, 0x0110 }, /* Dstroke Đ LATIN CAPITAL LETTER D WITH STROKE */
|
||||
{ 0x01d1, 0x0143 }, /* Nacute Ń LATIN CAPITAL LETTER N WITH ACUTE */
|
||||
{ 0x01d2, 0x0147 }, /* Ncaron Ň LATIN CAPITAL LETTER N WITH CARON */
|
||||
{ 0x01d5, 0x0150 }, /* Odoubleacute Ő LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */
|
||||
{ 0x01d8, 0x0158 }, /* Rcaron Ř LATIN CAPITAL LETTER R WITH CARON */
|
||||
{ 0x01d9, 0x016e }, /* Uring Ů LATIN CAPITAL LETTER U WITH RING ABOVE */
|
||||
{ 0x01db, 0x0170 }, /* Udoubleacute Ű LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */
|
||||
{ 0x01de, 0x0162 }, /* Tcedilla Ţ LATIN CAPITAL LETTER T WITH CEDILLA */
|
||||
{ 0x01e0, 0x0155 }, /* racute ŕ LATIN SMALL LETTER R WITH ACUTE */
|
||||
{ 0x01e3, 0x0103 }, /* abreve ă LATIN SMALL LETTER A WITH BREVE */
|
||||
{ 0x01e5, 0x013a }, /* lacute ĺ LATIN SMALL LETTER L WITH ACUTE */
|
||||
{ 0x01e6, 0x0107 }, /* cacute ć LATIN SMALL LETTER C WITH ACUTE */
|
||||
{ 0x01e8, 0x010d }, /* ccaron č LATIN SMALL LETTER C WITH CARON */
|
||||
{ 0x01ea, 0x0119 }, /* eogonek ę LATIN SMALL LETTER E WITH OGONEK */
|
||||
{ 0x01ec, 0x011b }, /* ecaron ě LATIN SMALL LETTER E WITH CARON */
|
||||
{ 0x01ef, 0x010f }, /* dcaron ď LATIN SMALL LETTER D WITH CARON */
|
||||
{ 0x01f0, 0x0111 }, /* dstroke đ LATIN SMALL LETTER D WITH STROKE */
|
||||
{ 0x01f1, 0x0144 }, /* nacute ń LATIN SMALL LETTER N WITH ACUTE */
|
||||
{ 0x01f2, 0x0148 }, /* ncaron ň LATIN SMALL LETTER N WITH CARON */
|
||||
{ 0x01f5, 0x0151 }, /* odoubleacute ő LATIN SMALL LETTER O WITH DOUBLE ACUTE */
|
||||
{ 0x01f8, 0x0159 }, /* rcaron ř LATIN SMALL LETTER R WITH CARON */
|
||||
{ 0x01f9, 0x016f }, /* uring ů LATIN SMALL LETTER U WITH RING ABOVE */
|
||||
{ 0x01fb, 0x0171 }, /* udoubleacute ű LATIN SMALL LETTER U WITH DOUBLE ACUTE */
|
||||
{ 0x01fe, 0x0163 }, /* tcedilla ţ LATIN SMALL LETTER T WITH CEDILLA */
|
||||
{ 0x01ff, 0x02d9 }, /* abovedot ˙ DOT ABOVE */
|
||||
{ 0x02a1, 0x0126 }, /* Hstroke Ħ LATIN CAPITAL LETTER H WITH STROKE */
|
||||
{ 0x02a6, 0x0124 }, /* Hcircumflex Ĥ LATIN CAPITAL LETTER H WITH CIRCUMFLEX */
|
||||
{ 0x02a9, 0x0130 }, /* Iabovedot İ LATIN CAPITAL LETTER I WITH DOT ABOVE */
|
||||
{ 0x02ab, 0x011e }, /* Gbreve Ğ LATIN CAPITAL LETTER G WITH BREVE */
|
||||
{ 0x02ac, 0x0134 }, /* Jcircumflex Ĵ LATIN CAPITAL LETTER J WITH CIRCUMFLEX */
|
||||
{ 0x02b1, 0x0127 }, /* hstroke ħ LATIN SMALL LETTER H WITH STROKE */
|
||||
{ 0x02b6, 0x0125 }, /* hcircumflex ĥ LATIN SMALL LETTER H WITH CIRCUMFLEX */
|
||||
{ 0x02b9, 0x0131 }, /* idotless ı LATIN SMALL LETTER DOTLESS I */
|
||||
{ 0x02bb, 0x011f }, /* gbreve ğ LATIN SMALL LETTER G WITH BREVE */
|
||||
{ 0x02bc, 0x0135 }, /* jcircumflex ĵ LATIN SMALL LETTER J WITH CIRCUMFLEX */
|
||||
{ 0x02c5, 0x010a }, /* Cabovedot Ċ LATIN CAPITAL LETTER C WITH DOT ABOVE */
|
||||
{ 0x02c6, 0x0108 }, /* Ccircumflex Ĉ LATIN CAPITAL LETTER C WITH CIRCUMFLEX */
|
||||
{ 0x02d5, 0x0120 }, /* Gabovedot Ġ LATIN CAPITAL LETTER G WITH DOT ABOVE */
|
||||
{ 0x02d8, 0x011c }, /* Gcircumflex Ĝ LATIN CAPITAL LETTER G WITH CIRCUMFLEX */
|
||||
{ 0x02dd, 0x016c }, /* Ubreve Ŭ LATIN CAPITAL LETTER U WITH BREVE */
|
||||
{ 0x02de, 0x015c }, /* Scircumflex Ŝ LATIN CAPITAL LETTER S WITH CIRCUMFLEX */
|
||||
{ 0x02e5, 0x010b }, /* cabovedot ċ LATIN SMALL LETTER C WITH DOT ABOVE */
|
||||
{ 0x02e6, 0x0109 }, /* ccircumflex ĉ LATIN SMALL LETTER C WITH CIRCUMFLEX */
|
||||
{ 0x02f5, 0x0121 }, /* gabovedot ġ LATIN SMALL LETTER G WITH DOT ABOVE */
|
||||
{ 0x02f8, 0x011d }, /* gcircumflex ĝ LATIN SMALL LETTER G WITH CIRCUMFLEX */
|
||||
{ 0x02fd, 0x016d }, /* ubreve ŭ LATIN SMALL LETTER U WITH BREVE */
|
||||
{ 0x02fe, 0x015d }, /* scircumflex ŝ LATIN SMALL LETTER S WITH CIRCUMFLEX */
|
||||
{ 0x03a2, 0x0138 }, /* kra ĸ LATIN SMALL LETTER KRA */
|
||||
{ 0x03a3, 0x0156 }, /* Rcedilla Ŗ LATIN CAPITAL LETTER R WITH CEDILLA */
|
||||
{ 0x03a5, 0x0128 }, /* Itilde Ĩ LATIN CAPITAL LETTER I WITH TILDE */
|
||||
{ 0x03a6, 0x013b }, /* Lcedilla Ļ LATIN CAPITAL LETTER L WITH CEDILLA */
|
||||
{ 0x03aa, 0x0112 }, /* Emacron Ē LATIN CAPITAL LETTER E WITH MACRON */
|
||||
{ 0x03ab, 0x0122 }, /* Gcedilla Ģ LATIN CAPITAL LETTER G WITH CEDILLA */
|
||||
{ 0x03ac, 0x0166 }, /* Tslash Ŧ LATIN CAPITAL LETTER T WITH STROKE */
|
||||
{ 0x03b3, 0x0157 }, /* rcedilla ŗ LATIN SMALL LETTER R WITH CEDILLA */
|
||||
{ 0x03b5, 0x0129 }, /* itilde ĩ LATIN SMALL LETTER I WITH TILDE */
|
||||
{ 0x03b6, 0x013c }, /* lcedilla ļ LATIN SMALL LETTER L WITH CEDILLA */
|
||||
{ 0x03ba, 0x0113 }, /* emacron ē LATIN SMALL LETTER E WITH MACRON */
|
||||
{ 0x03bb, 0x0123 }, /* gcedilla ģ LATIN SMALL LETTER G WITH CEDILLA */
|
||||
{ 0x03bc, 0x0167 }, /* tslash ŧ LATIN SMALL LETTER T WITH STROKE */
|
||||
{ 0x03bd, 0x014a }, /* ENG Ŋ LATIN CAPITAL LETTER ENG */
|
||||
{ 0x03bf, 0x014b }, /* eng ŋ LATIN SMALL LETTER ENG */
|
||||
{ 0x03c0, 0x0100 }, /* Amacron Ā LATIN CAPITAL LETTER A WITH MACRON */
|
||||
{ 0x03c7, 0x012e }, /* Iogonek Į LATIN CAPITAL LETTER I WITH OGONEK */
|
||||
{ 0x03cc, 0x0116 }, /* Eabovedot Ė LATIN CAPITAL LETTER E WITH DOT ABOVE */
|
||||
{ 0x03cf, 0x012a }, /* Imacron Ī LATIN CAPITAL LETTER I WITH MACRON */
|
||||
{ 0x03d1, 0x0145 }, /* Ncedilla Ņ LATIN CAPITAL LETTER N WITH CEDILLA */
|
||||
{ 0x03d2, 0x014c }, /* Omacron Ō LATIN CAPITAL LETTER O WITH MACRON */
|
||||
{ 0x03d3, 0x0136 }, /* Kcedilla Ķ LATIN CAPITAL LETTER K WITH CEDILLA */
|
||||
{ 0x03d9, 0x0172 }, /* Uogonek Ų LATIN CAPITAL LETTER U WITH OGONEK */
|
||||
{ 0x03dd, 0x0168 }, /* Utilde Ũ LATIN CAPITAL LETTER U WITH TILDE */
|
||||
{ 0x03de, 0x016a }, /* Umacron Ū LATIN CAPITAL LETTER U WITH MACRON */
|
||||
{ 0x03e0, 0x0101 }, /* amacron ā LATIN SMALL LETTER A WITH MACRON */
|
||||
{ 0x03e7, 0x012f }, /* iogonek į LATIN SMALL LETTER I WITH OGONEK */
|
||||
{ 0x03ec, 0x0117 }, /* eabovedot ė LATIN SMALL LETTER E WITH DOT ABOVE */
|
||||
{ 0x03ef, 0x012b }, /* imacron ī LATIN SMALL LETTER I WITH MACRON */
|
||||
{ 0x03f1, 0x0146 }, /* ncedilla ņ LATIN SMALL LETTER N WITH CEDILLA */
|
||||
{ 0x03f2, 0x014d }, /* omacron ō LATIN SMALL LETTER O WITH MACRON */
|
||||
{ 0x03f3, 0x0137 }, /* kcedilla ķ LATIN SMALL LETTER K WITH CEDILLA */
|
||||
{ 0x03f9, 0x0173 }, /* uogonek ų LATIN SMALL LETTER U WITH OGONEK */
|
||||
{ 0x03fd, 0x0169 }, /* utilde ũ LATIN SMALL LETTER U WITH TILDE */
|
||||
{ 0x03fe, 0x016b }, /* umacron ū LATIN SMALL LETTER U WITH MACRON */
|
||||
{ 0x047e, 0x203e }, /* overline ‾ OVERLINE */
|
||||
{ 0x04a1, 0x3002 }, /* kana_fullstop 。 IDEOGRAPHIC FULL STOP */
|
||||
{ 0x04a2, 0x300c }, /* kana_openingbracket 「 LEFT CORNER BRACKET */
|
||||
{ 0x04a3, 0x300d }, /* kana_closingbracket 」 RIGHT CORNER BRACKET */
|
||||
{ 0x04a4, 0x3001 }, /* kana_comma 、 IDEOGRAPHIC COMMA */
|
||||
{ 0x04a5, 0x30fb }, /* kana_conjunctive ・ KATAKANA MIDDLE DOT */
|
||||
{ 0x04a6, 0x30f2 }, /* kana_WO ヲ KATAKANA LETTER WO */
|
||||
{ 0x04a7, 0x30a1 }, /* kana_a ァ KATAKANA LETTER SMALL A */
|
||||
{ 0x04a8, 0x30a3 }, /* kana_i ィ KATAKANA LETTER SMALL I */
|
||||
{ 0x04a9, 0x30a5 }, /* kana_u ゥ KATAKANA LETTER SMALL U */
|
||||
{ 0x04aa, 0x30a7 }, /* kana_e ェ KATAKANA LETTER SMALL E */
|
||||
{ 0x04ab, 0x30a9 }, /* kana_o ォ KATAKANA LETTER SMALL O */
|
||||
{ 0x04ac, 0x30e3 }, /* kana_ya ャ KATAKANA LETTER SMALL YA */
|
||||
{ 0x04ad, 0x30e5 }, /* kana_yu ュ KATAKANA LETTER SMALL YU */
|
||||
{ 0x04ae, 0x30e7 }, /* kana_yo ョ KATAKANA LETTER SMALL YO */
|
||||
{ 0x04af, 0x30c3 }, /* kana_tsu ッ KATAKANA LETTER SMALL TU */
|
||||
{ 0x04b0, 0x30fc }, /* prolongedsound ー KATAKANA-HIRAGANA PROLONGED SOUND MARK */
|
||||
{ 0x04b1, 0x30a2 }, /* kana_A ア KATAKANA LETTER A */
|
||||
{ 0x04b2, 0x30a4 }, /* kana_I イ KATAKANA LETTER I */
|
||||
{ 0x04b3, 0x30a6 }, /* kana_U ウ KATAKANA LETTER U */
|
||||
{ 0x04b4, 0x30a8 }, /* kana_E エ KATAKANA LETTER E */
|
||||
{ 0x04b5, 0x30aa }, /* kana_O オ KATAKANA LETTER O */
|
||||
{ 0x04b6, 0x30ab }, /* kana_KA カ KATAKANA LETTER KA */
|
||||
{ 0x04b7, 0x30ad }, /* kana_KI キ KATAKANA LETTER KI */
|
||||
{ 0x04b8, 0x30af }, /* kana_KU ク KATAKANA LETTER KU */
|
||||
{ 0x04b9, 0x30b1 }, /* kana_KE ケ KATAKANA LETTER KE */
|
||||
{ 0x04ba, 0x30b3 }, /* kana_KO コ KATAKANA LETTER KO */
|
||||
{ 0x04bb, 0x30b5 }, /* kana_SA サ KATAKANA LETTER SA */
|
||||
{ 0x04bc, 0x30b7 }, /* kana_SHI シ KATAKANA LETTER SI */
|
||||
{ 0x04bd, 0x30b9 }, /* kana_SU ス KATAKANA LETTER SU */
|
||||
{ 0x04be, 0x30bb }, /* kana_SE セ KATAKANA LETTER SE */
|
||||
{ 0x04bf, 0x30bd }, /* kana_SO ソ KATAKANA LETTER SO */
|
||||
{ 0x04c0, 0x30bf }, /* kana_TA タ KATAKANA LETTER TA */
|
||||
{ 0x04c1, 0x30c1 }, /* kana_CHI チ KATAKANA LETTER TI */
|
||||
{ 0x04c2, 0x30c4 }, /* kana_TSU ツ KATAKANA LETTER TU */
|
||||
{ 0x04c3, 0x30c6 }, /* kana_TE テ KATAKANA LETTER TE */
|
||||
{ 0x04c4, 0x30c8 }, /* kana_TO ト KATAKANA LETTER TO */
|
||||
{ 0x04c5, 0x30ca }, /* kana_NA ナ KATAKANA LETTER NA */
|
||||
{ 0x04c6, 0x30cb }, /* kana_NI ニ KATAKANA LETTER NI */
|
||||
{ 0x04c7, 0x30cc }, /* kana_NU ヌ KATAKANA LETTER NU */
|
||||
{ 0x04c8, 0x30cd }, /* kana_NE ネ KATAKANA LETTER NE */
|
||||
{ 0x04c9, 0x30ce }, /* kana_NO ノ KATAKANA LETTER NO */
|
||||
{ 0x04ca, 0x30cf }, /* kana_HA ハ KATAKANA LETTER HA */
|
||||
{ 0x04cb, 0x30d2 }, /* kana_HI ヒ KATAKANA LETTER HI */
|
||||
{ 0x04cc, 0x30d5 }, /* kana_FU フ KATAKANA LETTER HU */
|
||||
{ 0x04cd, 0x30d8 }, /* kana_HE ヘ KATAKANA LETTER HE */
|
||||
{ 0x04ce, 0x30db }, /* kana_HO ホ KATAKANA LETTER HO */
|
||||
{ 0x04cf, 0x30de }, /* kana_MA マ KATAKANA LETTER MA */
|
||||
{ 0x04d0, 0x30df }, /* kana_MI ミ KATAKANA LETTER MI */
|
||||
{ 0x04d1, 0x30e0 }, /* kana_MU ム KATAKANA LETTER MU */
|
||||
{ 0x04d2, 0x30e1 }, /* kana_ME メ KATAKANA LETTER ME */
|
||||
{ 0x04d3, 0x30e2 }, /* kana_MO モ KATAKANA LETTER MO */
|
||||
{ 0x04d4, 0x30e4 }, /* kana_YA ヤ KATAKANA LETTER YA */
|
||||
{ 0x04d5, 0x30e6 }, /* kana_YU ユ KATAKANA LETTER YU */
|
||||
{ 0x04d6, 0x30e8 }, /* kana_YO ヨ KATAKANA LETTER YO */
|
||||
{ 0x04d7, 0x30e9 }, /* kana_RA ラ KATAKANA LETTER RA */
|
||||
{ 0x04d8, 0x30ea }, /* kana_RI リ KATAKANA LETTER RI */
|
||||
{ 0x04d9, 0x30eb }, /* kana_RU ル KATAKANA LETTER RU */
|
||||
{ 0x04da, 0x30ec }, /* kana_RE レ KATAKANA LETTER RE */
|
||||
{ 0x04db, 0x30ed }, /* kana_RO ロ KATAKANA LETTER RO */
|
||||
{ 0x04dc, 0x30ef }, /* kana_WA ワ KATAKANA LETTER WA */
|
||||
{ 0x04dd, 0x30f3 }, /* kana_N ン KATAKANA LETTER N */
|
||||
{ 0x04de, 0x309b }, /* voicedsound ゛ KATAKANA-HIRAGANA VOICED SOUND MARK */
|
||||
{ 0x04df, 0x309c }, /* semivoicedsound ゜ KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */
|
||||
{ 0x05ac, 0x060c }, /* Arabic_comma ، ARABIC COMMA */
|
||||
{ 0x05bb, 0x061b }, /* Arabic_semicolon ؛ ARABIC SEMICOLON */
|
||||
{ 0x05bf, 0x061f }, /* Arabic_question_mark ؟ ARABIC QUESTION MARK */
|
||||
{ 0x05c1, 0x0621 }, /* Arabic_hamza ء ARABIC LETTER HAMZA */
|
||||
{ 0x05c2, 0x0622 }, /* Arabic_maddaonalef آ ARABIC LETTER ALEF WITH MADDA ABOVE */
|
||||
{ 0x05c3, 0x0623 }, /* Arabic_hamzaonalef أ ARABIC LETTER ALEF WITH HAMZA ABOVE */
|
||||
{ 0x05c4, 0x0624 }, /* Arabic_hamzaonwaw ؤ ARABIC LETTER WAW WITH HAMZA ABOVE */
|
||||
{ 0x05c5, 0x0625 }, /* Arabic_hamzaunderalef إ ARABIC LETTER ALEF WITH HAMZA BELOW */
|
||||
{ 0x05c6, 0x0626 }, /* Arabic_hamzaonyeh ئ ARABIC LETTER YEH WITH HAMZA ABOVE */
|
||||
{ 0x05c7, 0x0627 }, /* Arabic_alef ا ARABIC LETTER ALEF */
|
||||
{ 0x05c8, 0x0628 }, /* Arabic_beh ب ARABIC LETTER BEH */
|
||||
{ 0x05c9, 0x0629 }, /* Arabic_tehmarbuta ة ARABIC LETTER TEH MARBUTA */
|
||||
{ 0x05ca, 0x062a }, /* Arabic_teh ت ARABIC LETTER TEH */
|
||||
{ 0x05cb, 0x062b }, /* Arabic_theh ث ARABIC LETTER THEH */
|
||||
{ 0x05cc, 0x062c }, /* Arabic_jeem ج ARABIC LETTER JEEM */
|
||||
{ 0x05cd, 0x062d }, /* Arabic_hah ح ARABIC LETTER HAH */
|
||||
{ 0x05ce, 0x062e }, /* Arabic_khah خ ARABIC LETTER KHAH */
|
||||
{ 0x05cf, 0x062f }, /* Arabic_dal د ARABIC LETTER DAL */
|
||||
{ 0x05d0, 0x0630 }, /* Arabic_thal ذ ARABIC LETTER THAL */
|
||||
{ 0x05d1, 0x0631 }, /* Arabic_ra ر ARABIC LETTER REH */
|
||||
{ 0x05d2, 0x0632 }, /* Arabic_zain ز ARABIC LETTER ZAIN */
|
||||
{ 0x05d3, 0x0633 }, /* Arabic_seen س ARABIC LETTER SEEN */
|
||||
{ 0x05d4, 0x0634 }, /* Arabic_sheen ش ARABIC LETTER SHEEN */
|
||||
{ 0x05d5, 0x0635 }, /* Arabic_sad ص ARABIC LETTER SAD */
|
||||
{ 0x05d6, 0x0636 }, /* Arabic_dad ض ARABIC LETTER DAD */
|
||||
{ 0x05d7, 0x0637 }, /* Arabic_tah ط ARABIC LETTER TAH */
|
||||
{ 0x05d8, 0x0638 }, /* Arabic_zah ظ ARABIC LETTER ZAH */
|
||||
{ 0x05d9, 0x0639 }, /* Arabic_ain ع ARABIC LETTER AIN */
|
||||
{ 0x05da, 0x063a }, /* Arabic_ghain غ ARABIC LETTER GHAIN */
|
||||
{ 0x05e0, 0x0640 }, /* Arabic_tatweel ـ ARABIC TATWEEL */
|
||||
{ 0x05e1, 0x0641 }, /* Arabic_feh ف ARABIC LETTER FEH */
|
||||
{ 0x05e2, 0x0642 }, /* Arabic_qaf ق ARABIC LETTER QAF */
|
||||
{ 0x05e3, 0x0643 }, /* Arabic_kaf ك ARABIC LETTER KAF */
|
||||
{ 0x05e4, 0x0644 }, /* Arabic_lam ل ARABIC LETTER LAM */
|
||||
{ 0x05e5, 0x0645 }, /* Arabic_meem م ARABIC LETTER MEEM */
|
||||
{ 0x05e6, 0x0646 }, /* Arabic_noon ن ARABIC LETTER NOON */
|
||||
{ 0x05e7, 0x0647 }, /* Arabic_ha ه ARABIC LETTER HEH */
|
||||
{ 0x05e8, 0x0648 }, /* Arabic_waw و ARABIC LETTER WAW */
|
||||
{ 0x05e9, 0x0649 }, /* Arabic_alefmaksura ى ARABIC LETTER ALEF MAKSURA */
|
||||
{ 0x05ea, 0x064a }, /* Arabic_yeh ي ARABIC LETTER YEH */
|
||||
{ 0x05eb, 0x064b }, /* Arabic_fathatan ً ARABIC FATHATAN */
|
||||
{ 0x05ec, 0x064c }, /* Arabic_dammatan ٌ ARABIC DAMMATAN */
|
||||
{ 0x05ed, 0x064d }, /* Arabic_kasratan ٍ ARABIC KASRATAN */
|
||||
{ 0x05ee, 0x064e }, /* Arabic_fatha َ ARABIC FATHA */
|
||||
{ 0x05ef, 0x064f }, /* Arabic_damma ُ ARABIC DAMMA */
|
||||
{ 0x05f0, 0x0650 }, /* Arabic_kasra ِ ARABIC KASRA */
|
||||
{ 0x05f1, 0x0651 }, /* Arabic_shadda ّ ARABIC SHADDA */
|
||||
{ 0x05f2, 0x0652 }, /* Arabic_sukun ْ ARABIC SUKUN */
|
||||
{ 0x06a1, 0x0452 }, /* Serbian_dje ђ CYRILLIC SMALL LETTER DJE */
|
||||
{ 0x06a2, 0x0453 }, /* Macedonia_gje ѓ CYRILLIC SMALL LETTER GJE */
|
||||
{ 0x06a3, 0x0451 }, /* Cyrillic_io ё CYRILLIC SMALL LETTER IO */
|
||||
{ 0x06a4, 0x0454 }, /* Ukrainian_ie є CYRILLIC SMALL LETTER UKRAINIAN IE */
|
||||
{ 0x06a5, 0x0455 }, /* Macedonia_dse ѕ CYRILLIC SMALL LETTER DZE */
|
||||
{ 0x06a6, 0x0456 }, /* Ukrainian_i і CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */
|
||||
{ 0x06a7, 0x0457 }, /* Ukrainian_yi ї CYRILLIC SMALL LETTER YI */
|
||||
{ 0x06a8, 0x0458 }, /* Cyrillic_je ј CYRILLIC SMALL LETTER JE */
|
||||
{ 0x06a9, 0x0459 }, /* Cyrillic_lje љ CYRILLIC SMALL LETTER LJE */
|
||||
{ 0x06aa, 0x045a }, /* Cyrillic_nje њ CYRILLIC SMALL LETTER NJE */
|
||||
{ 0x06ab, 0x045b }, /* Serbian_tshe ћ CYRILLIC SMALL LETTER TSHE */
|
||||
{ 0x06ac, 0x045c }, /* Macedonia_kje ќ CYRILLIC SMALL LETTER KJE */
|
||||
{ 0x06ad, 0x0491 }, /* Ukrainian_ghe_with_upturn ґ CYRILLIC SMALL LETTER GHE WITH UPTURN */
|
||||
{ 0x06ae, 0x045e }, /* Byelorussian_shortu ў CYRILLIC SMALL LETTER SHORT U */
|
||||
{ 0x06af, 0x045f }, /* Cyrillic_dzhe џ CYRILLIC SMALL LETTER DZHE */
|
||||
{ 0x06b0, 0x2116 }, /* numerosign № NUMERO SIGN */
|
||||
{ 0x06b1, 0x0402 }, /* Serbian_DJE Ђ CYRILLIC CAPITAL LETTER DJE */
|
||||
{ 0x06b2, 0x0403 }, /* Macedonia_GJE Ѓ CYRILLIC CAPITAL LETTER GJE */
|
||||
{ 0x06b3, 0x0401 }, /* Cyrillic_IO Ё CYRILLIC CAPITAL LETTER IO */
|
||||
{ 0x06b4, 0x0404 }, /* Ukrainian_IE Є CYRILLIC CAPITAL LETTER UKRAINIAN IE */
|
||||
{ 0x06b5, 0x0405 }, /* Macedonia_DSE Ѕ CYRILLIC CAPITAL LETTER DZE */
|
||||
{ 0x06b6, 0x0406 }, /* Ukrainian_I І CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */
|
||||
{ 0x06b7, 0x0407 }, /* Ukrainian_YI Ї CYRILLIC CAPITAL LETTER YI */
|
||||
{ 0x06b8, 0x0408 }, /* Cyrillic_JE Ј CYRILLIC CAPITAL LETTER JE */
|
||||
{ 0x06b9, 0x0409 }, /* Cyrillic_LJE Љ CYRILLIC CAPITAL LETTER LJE */
|
||||
{ 0x06ba, 0x040a }, /* Cyrillic_NJE Њ CYRILLIC CAPITAL LETTER NJE */
|
||||
{ 0x06bb, 0x040b }, /* Serbian_TSHE Ћ CYRILLIC CAPITAL LETTER TSHE */
|
||||
{ 0x06bc, 0x040c }, /* Macedonia_KJE Ќ CYRILLIC CAPITAL LETTER KJE */
|
||||
{ 0x06bd, 0x0490 }, /* Ukrainian_GHE_WITH_UPTURN Ґ CYRILLIC CAPITAL LETTER GHE WITH UPTURN */
|
||||
{ 0x06be, 0x040e }, /* Byelorussian_SHORTU Ў CYRILLIC CAPITAL LETTER SHORT U */
|
||||
{ 0x06bf, 0x040f }, /* Cyrillic_DZHE Џ CYRILLIC CAPITAL LETTER DZHE */
|
||||
{ 0x06c0, 0x044e }, /* Cyrillic_yu ю CYRILLIC SMALL LETTER YU */
|
||||
{ 0x06c1, 0x0430 }, /* Cyrillic_a а CYRILLIC SMALL LETTER A */
|
||||
{ 0x06c2, 0x0431 }, /* Cyrillic_be б CYRILLIC SMALL LETTER BE */
|
||||
{ 0x06c3, 0x0446 }, /* Cyrillic_tse ц CYRILLIC SMALL LETTER TSE */
|
||||
{ 0x06c4, 0x0434 }, /* Cyrillic_de д CYRILLIC SMALL LETTER DE */
|
||||
{ 0x06c5, 0x0435 }, /* Cyrillic_ie е CYRILLIC SMALL LETTER IE */
|
||||
{ 0x06c6, 0x0444 }, /* Cyrillic_ef ф CYRILLIC SMALL LETTER EF */
|
||||
{ 0x06c7, 0x0433 }, /* Cyrillic_ghe г CYRILLIC SMALL LETTER GHE */
|
||||
{ 0x06c8, 0x0445 }, /* Cyrillic_ha х CYRILLIC SMALL LETTER HA */
|
||||
{ 0x06c9, 0x0438 }, /* Cyrillic_i и CYRILLIC SMALL LETTER I */
|
||||
{ 0x06ca, 0x0439 }, /* Cyrillic_shorti й CYRILLIC SMALL LETTER SHORT I */
|
||||
{ 0x06cb, 0x043a }, /* Cyrillic_ka к CYRILLIC SMALL LETTER KA */
|
||||
{ 0x06cc, 0x043b }, /* Cyrillic_el л CYRILLIC SMALL LETTER EL */
|
||||
{ 0x06cd, 0x043c }, /* Cyrillic_em м CYRILLIC SMALL LETTER EM */
|
||||
{ 0x06ce, 0x043d }, /* Cyrillic_en н CYRILLIC SMALL LETTER EN */
|
||||
{ 0x06cf, 0x043e }, /* Cyrillic_o о CYRILLIC SMALL LETTER O */
|
||||
{ 0x06d0, 0x043f }, /* Cyrillic_pe п CYRILLIC SMALL LETTER PE */
|
||||
{ 0x06d1, 0x044f }, /* Cyrillic_ya я CYRILLIC SMALL LETTER YA */
|
||||
{ 0x06d2, 0x0440 }, /* Cyrillic_er р CYRILLIC SMALL LETTER ER */
|
||||
{ 0x06d3, 0x0441 }, /* Cyrillic_es с CYRILLIC SMALL LETTER ES */
|
||||
{ 0x06d4, 0x0442 }, /* Cyrillic_te т CYRILLIC SMALL LETTER TE */
|
||||
{ 0x06d5, 0x0443 }, /* Cyrillic_u у CYRILLIC SMALL LETTER U */
|
||||
{ 0x06d6, 0x0436 }, /* Cyrillic_zhe ж CYRILLIC SMALL LETTER ZHE */
|
||||
{ 0x06d7, 0x0432 }, /* Cyrillic_ve в CYRILLIC SMALL LETTER VE */
|
||||
{ 0x06d8, 0x044c }, /* Cyrillic_softsign ь CYRILLIC SMALL LETTER SOFT SIGN */
|
||||
{ 0x06d9, 0x044b }, /* Cyrillic_yeru ы CYRILLIC SMALL LETTER YERU */
|
||||
{ 0x06da, 0x0437 }, /* Cyrillic_ze з CYRILLIC SMALL LETTER ZE */
|
||||
{ 0x06db, 0x0448 }, /* Cyrillic_sha ш CYRILLIC SMALL LETTER SHA */
|
||||
{ 0x06dc, 0x044d }, /* Cyrillic_e э CYRILLIC SMALL LETTER E */
|
||||
{ 0x06dd, 0x0449 }, /* Cyrillic_shcha щ CYRILLIC SMALL LETTER SHCHA */
|
||||
{ 0x06de, 0x0447 }, /* Cyrillic_che ч CYRILLIC SMALL LETTER CHE */
|
||||
{ 0x06df, 0x044a }, /* Cyrillic_hardsign ъ CYRILLIC SMALL LETTER HARD SIGN */
|
||||
{ 0x06e0, 0x042e }, /* Cyrillic_YU Ю CYRILLIC CAPITAL LETTER YU */
|
||||
{ 0x06e1, 0x0410 }, /* Cyrillic_A А CYRILLIC CAPITAL LETTER A */
|
||||
{ 0x06e2, 0x0411 }, /* Cyrillic_BE Б CYRILLIC CAPITAL LETTER BE */
|
||||
{ 0x06e3, 0x0426 }, /* Cyrillic_TSE Ц CYRILLIC CAPITAL LETTER TSE */
|
||||
{ 0x06e4, 0x0414 }, /* Cyrillic_DE Д CYRILLIC CAPITAL LETTER DE */
|
||||
{ 0x06e5, 0x0415 }, /* Cyrillic_IE Е CYRILLIC CAPITAL LETTER IE */
|
||||
{ 0x06e6, 0x0424 }, /* Cyrillic_EF Ф CYRILLIC CAPITAL LETTER EF */
|
||||
{ 0x06e7, 0x0413 }, /* Cyrillic_GHE Г CYRILLIC CAPITAL LETTER GHE */
|
||||
{ 0x06e8, 0x0425 }, /* Cyrillic_HA Х CYRILLIC CAPITAL LETTER HA */
|
||||
{ 0x06e9, 0x0418 }, /* Cyrillic_I И CYRILLIC CAPITAL LETTER I */
|
||||
{ 0x06ea, 0x0419 }, /* Cyrillic_SHORTI Й CYRILLIC CAPITAL LETTER SHORT I */
|
||||
{ 0x06eb, 0x041a }, /* Cyrillic_KA К CYRILLIC CAPITAL LETTER KA */
|
||||
{ 0x06ec, 0x041b }, /* Cyrillic_EL Л CYRILLIC CAPITAL LETTER EL */
|
||||
{ 0x06ed, 0x041c }, /* Cyrillic_EM М CYRILLIC CAPITAL LETTER EM */
|
||||
{ 0x06ee, 0x041d }, /* Cyrillic_EN Н CYRILLIC CAPITAL LETTER EN */
|
||||
{ 0x06ef, 0x041e }, /* Cyrillic_O О CYRILLIC CAPITAL LETTER O */
|
||||
{ 0x06f0, 0x041f }, /* Cyrillic_PE П CYRILLIC CAPITAL LETTER PE */
|
||||
{ 0x06f1, 0x042f }, /* Cyrillic_YA Я CYRILLIC CAPITAL LETTER YA */
|
||||
{ 0x06f2, 0x0420 }, /* Cyrillic_ER Р CYRILLIC CAPITAL LETTER ER */
|
||||
{ 0x06f3, 0x0421 }, /* Cyrillic_ES С CYRILLIC CAPITAL LETTER ES */
|
||||
{ 0x06f4, 0x0422 }, /* Cyrillic_TE Т CYRILLIC CAPITAL LETTER TE */
|
||||
{ 0x06f5, 0x0423 }, /* Cyrillic_U У CYRILLIC CAPITAL LETTER U */
|
||||
{ 0x06f6, 0x0416 }, /* Cyrillic_ZHE Ж CYRILLIC CAPITAL LETTER ZHE */
|
||||
{ 0x06f7, 0x0412 }, /* Cyrillic_VE В CYRILLIC CAPITAL LETTER VE */
|
||||
{ 0x06f8, 0x042c }, /* Cyrillic_SOFTSIGN Ь CYRILLIC CAPITAL LETTER SOFT SIGN */
|
||||
{ 0x06f9, 0x042b }, /* Cyrillic_YERU Ы CYRILLIC CAPITAL LETTER YERU */
|
||||
{ 0x06fa, 0x0417 }, /* Cyrillic_ZE З CYRILLIC CAPITAL LETTER ZE */
|
||||
{ 0x06fb, 0x0428 }, /* Cyrillic_SHA Ш CYRILLIC CAPITAL LETTER SHA */
|
||||
{ 0x06fc, 0x042d }, /* Cyrillic_E Э CYRILLIC CAPITAL LETTER E */
|
||||
{ 0x06fd, 0x0429 }, /* Cyrillic_SHCHA Щ CYRILLIC CAPITAL LETTER SHCHA */
|
||||
{ 0x06fe, 0x0427 }, /* Cyrillic_CHE Ч CYRILLIC CAPITAL LETTER CHE */
|
||||
{ 0x06ff, 0x042a }, /* Cyrillic_HARDSIGN Ъ CYRILLIC CAPITAL LETTER HARD SIGN */
|
||||
{ 0x07a1, 0x0386 }, /* Greek_ALPHAaccent Ά GREEK CAPITAL LETTER ALPHA WITH TONOS */
|
||||
{ 0x07a2, 0x0388 }, /* Greek_EPSILONaccent Έ GREEK CAPITAL LETTER EPSILON WITH TONOS */
|
||||
{ 0x07a3, 0x0389 }, /* Greek_ETAaccent Ή GREEK CAPITAL LETTER ETA WITH TONOS */
|
||||
{ 0x07a4, 0x038a }, /* Greek_IOTAaccent Ί GREEK CAPITAL LETTER IOTA WITH TONOS */
|
||||
{ 0x07a5, 0x03aa }, /* Greek_IOTAdiaeresis Ϊ GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */
|
||||
{ 0x07a7, 0x038c }, /* Greek_OMICRONaccent Ό GREEK CAPITAL LETTER OMICRON WITH TONOS */
|
||||
{ 0x07a8, 0x038e }, /* Greek_UPSILONaccent Ύ GREEK CAPITAL LETTER UPSILON WITH TONOS */
|
||||
{ 0x07a9, 0x03ab }, /* Greek_UPSILONdieresis Ϋ GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */
|
||||
{ 0x07ab, 0x038f }, /* Greek_OMEGAaccent Ώ GREEK CAPITAL LETTER OMEGA WITH TONOS */
|
||||
{ 0x07ae, 0x0385 }, /* Greek_accentdieresis ΅ GREEK DIALYTIKA TONOS */
|
||||
{ 0x07af, 0x2015 }, /* Greek_horizbar ― HORIZONTAL BAR */
|
||||
{ 0x07b1, 0x03ac }, /* Greek_alphaaccent ά GREEK SMALL LETTER ALPHA WITH TONOS */
|
||||
{ 0x07b2, 0x03ad }, /* Greek_epsilonaccent έ GREEK SMALL LETTER EPSILON WITH TONOS */
|
||||
{ 0x07b3, 0x03ae }, /* Greek_etaaccent ή GREEK SMALL LETTER ETA WITH TONOS */
|
||||
{ 0x07b4, 0x03af }, /* Greek_iotaaccent ί GREEK SMALL LETTER IOTA WITH TONOS */
|
||||
{ 0x07b5, 0x03ca }, /* Greek_iotadieresis ϊ GREEK SMALL LETTER IOTA WITH DIALYTIKA */
|
||||
{ 0x07b6, 0x0390 }, /* Greek_iotaaccentdieresis ΐ GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */
|
||||
{ 0x07b7, 0x03cc }, /* Greek_omicronaccent ό GREEK SMALL LETTER OMICRON WITH TONOS */
|
||||
{ 0x07b8, 0x03cd }, /* Greek_upsilonaccent ύ GREEK SMALL LETTER UPSILON WITH TONOS */
|
||||
{ 0x07b9, 0x03cb }, /* Greek_upsilondieresis ϋ GREEK SMALL LETTER UPSILON WITH DIALYTIKA */
|
||||
{ 0x07ba, 0x03b0 }, /* Greek_upsilonaccentdieresis ΰ GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */
|
||||
{ 0x07bb, 0x03ce }, /* Greek_omegaaccent ώ GREEK SMALL LETTER OMEGA WITH TONOS */
|
||||
{ 0x07c1, 0x0391 }, /* Greek_ALPHA Α GREEK CAPITAL LETTER ALPHA */
|
||||
{ 0x07c2, 0x0392 }, /* Greek_BETA Β GREEK CAPITAL LETTER BETA */
|
||||
{ 0x07c3, 0x0393 }, /* Greek_GAMMA Γ GREEK CAPITAL LETTER GAMMA */
|
||||
{ 0x07c4, 0x0394 }, /* Greek_DELTA Δ GREEK CAPITAL LETTER DELTA */
|
||||
{ 0x07c5, 0x0395 }, /* Greek_EPSILON Ε GREEK CAPITAL LETTER EPSILON */
|
||||
{ 0x07c6, 0x0396 }, /* Greek_ZETA Ζ GREEK CAPITAL LETTER ZETA */
|
||||
{ 0x07c7, 0x0397 }, /* Greek_ETA Η GREEK CAPITAL LETTER ETA */
|
||||
{ 0x07c8, 0x0398 }, /* Greek_THETA Θ GREEK CAPITAL LETTER THETA */
|
||||
{ 0x07c9, 0x0399 }, /* Greek_IOTA Ι GREEK CAPITAL LETTER IOTA */
|
||||
{ 0x07ca, 0x039a }, /* Greek_KAPPA Κ GREEK CAPITAL LETTER KAPPA */
|
||||
{ 0x07cb, 0x039b }, /* Greek_LAMBDA Λ GREEK CAPITAL LETTER LAMDA */
|
||||
{ 0x07cc, 0x039c }, /* Greek_MU Μ GREEK CAPITAL LETTER MU */
|
||||
{ 0x07cd, 0x039d }, /* Greek_NU Ν GREEK CAPITAL LETTER NU */
|
||||
{ 0x07ce, 0x039e }, /* Greek_XI Ξ GREEK CAPITAL LETTER XI */
|
||||
{ 0x07cf, 0x039f }, /* Greek_OMICRON Ο GREEK CAPITAL LETTER OMICRON */
|
||||
{ 0x07d0, 0x03a0 }, /* Greek_PI Π GREEK CAPITAL LETTER PI */
|
||||
{ 0x07d1, 0x03a1 }, /* Greek_RHO Ρ GREEK CAPITAL LETTER RHO */
|
||||
{ 0x07d2, 0x03a3 }, /* Greek_SIGMA Σ GREEK CAPITAL LETTER SIGMA */
|
||||
{ 0x07d4, 0x03a4 }, /* Greek_TAU Τ GREEK CAPITAL LETTER TAU */
|
||||
{ 0x07d5, 0x03a5 }, /* Greek_UPSILON Υ GREEK CAPITAL LETTER UPSILON */
|
||||
{ 0x07d6, 0x03a6 }, /* Greek_PHI Φ GREEK CAPITAL LETTER PHI */
|
||||
{ 0x07d7, 0x03a7 }, /* Greek_CHI Χ GREEK CAPITAL LETTER CHI */
|
||||
{ 0x07d8, 0x03a8 }, /* Greek_PSI Ψ GREEK CAPITAL LETTER PSI */
|
||||
{ 0x07d9, 0x03a9 }, /* Greek_OMEGA Ω GREEK CAPITAL LETTER OMEGA */
|
||||
{ 0x07e1, 0x03b1 }, /* Greek_alpha α GREEK SMALL LETTER ALPHA */
|
||||
{ 0x07e2, 0x03b2 }, /* Greek_beta β GREEK SMALL LETTER BETA */
|
||||
{ 0x07e3, 0x03b3 }, /* Greek_gamma γ GREEK SMALL LETTER GAMMA */
|
||||
{ 0x07e4, 0x03b4 }, /* Greek_delta δ GREEK SMALL LETTER DELTA */
|
||||
{ 0x07e5, 0x03b5 }, /* Greek_epsilon ε GREEK SMALL LETTER EPSILON */
|
||||
{ 0x07e6, 0x03b6 }, /* Greek_zeta ζ GREEK SMALL LETTER ZETA */
|
||||
{ 0x07e7, 0x03b7 }, /* Greek_eta η GREEK SMALL LETTER ETA */
|
||||
{ 0x07e8, 0x03b8 }, /* Greek_theta θ GREEK SMALL LETTER THETA */
|
||||
{ 0x07e9, 0x03b9 }, /* Greek_iota ι GREEK SMALL LETTER IOTA */
|
||||
{ 0x07ea, 0x03ba }, /* Greek_kappa κ GREEK SMALL LETTER KAPPA */
|
||||
{ 0x07eb, 0x03bb }, /* Greek_lambda λ GREEK SMALL LETTER LAMDA */
|
||||
{ 0x07ec, 0x03bc }, /* Greek_mu μ GREEK SMALL LETTER MU */
|
||||
{ 0x07ed, 0x03bd }, /* Greek_nu ν GREEK SMALL LETTER NU */
|
||||
{ 0x07ee, 0x03be }, /* Greek_xi ξ GREEK SMALL LETTER XI */
|
||||
{ 0x07ef, 0x03bf }, /* Greek_omicron ο GREEK SMALL LETTER OMICRON */
|
||||
{ 0x07f0, 0x03c0 }, /* Greek_pi π GREEK SMALL LETTER PI */
|
||||
{ 0x07f1, 0x03c1 }, /* Greek_rho ρ GREEK SMALL LETTER RHO */
|
||||
{ 0x07f2, 0x03c3 }, /* Greek_sigma σ GREEK SMALL LETTER SIGMA */
|
||||
{ 0x07f3, 0x03c2 }, /* Greek_finalsmallsigma ς GREEK SMALL LETTER FINAL SIGMA */
|
||||
{ 0x07f4, 0x03c4 }, /* Greek_tau τ GREEK SMALL LETTER TAU */
|
||||
{ 0x07f5, 0x03c5 }, /* Greek_upsilon υ GREEK SMALL LETTER UPSILON */
|
||||
{ 0x07f6, 0x03c6 }, /* Greek_phi φ GREEK SMALL LETTER PHI */
|
||||
{ 0x07f7, 0x03c7 }, /* Greek_chi χ GREEK SMALL LETTER CHI */
|
||||
{ 0x07f8, 0x03c8 }, /* Greek_psi ψ GREEK SMALL LETTER PSI */
|
||||
{ 0x07f9, 0x03c9 }, /* Greek_omega ω GREEK SMALL LETTER OMEGA */
|
||||
{ 0x08a1, 0x23b7 }, /* leftradical ⎷ ??? */
|
||||
{ 0x08a2, 0x250c }, /* topleftradical ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */
|
||||
{ 0x08a3, 0x2500 }, /* horizconnector ─ BOX DRAWINGS LIGHT HORIZONTAL */
|
||||
{ 0x08a4, 0x2320 }, /* topintegral ⌠ TOP HALF INTEGRAL */
|
||||
{ 0x08a5, 0x2321 }, /* botintegral ⌡ BOTTOM HALF INTEGRAL */
|
||||
{ 0x08a6, 0x2502 }, /* vertconnector │ BOX DRAWINGS LIGHT VERTICAL */
|
||||
{ 0x08a7, 0x23a1 }, /* topleftsqbracket ⎡ ??? */
|
||||
{ 0x08a8, 0x23a3 }, /* botleftsqbracket ⎣ ??? */
|
||||
{ 0x08a9, 0x23a4 }, /* toprightsqbracket ⎤ ??? */
|
||||
{ 0x08aa, 0x23a6 }, /* botrightsqbracket ⎦ ??? */
|
||||
{ 0x08ab, 0x239b }, /* topleftparens ⎛ ??? */
|
||||
{ 0x08ac, 0x239d }, /* botleftparens ⎝ ??? */
|
||||
{ 0x08ad, 0x239e }, /* toprightparens ⎞ ??? */
|
||||
{ 0x08ae, 0x23a0 }, /* botrightparens ⎠ ??? */
|
||||
{ 0x08af, 0x23a8 }, /* leftmiddlecurlybrace ⎨ ??? */
|
||||
{ 0x08b0, 0x23ac }, /* rightmiddlecurlybrace ⎬ ??? */
|
||||
/* 0x08b1 topleftsummation ? ??? */
|
||||
/* 0x08b2 botleftsummation ? ??? */
|
||||
/* 0x08b3 topvertsummationconnector ? ??? */
|
||||
/* 0x08b4 botvertsummationconnector ? ??? */
|
||||
/* 0x08b5 toprightsummation ? ??? */
|
||||
/* 0x08b6 botrightsummation ? ??? */
|
||||
/* 0x08b7 rightmiddlesummation ? ??? */
|
||||
{ 0x08bc, 0x2264 }, /* lessthanequal ≤ LESS-THAN OR EQUAL TO */
|
||||
{ 0x08bd, 0x2260 }, /* notequal ≠ NOT EQUAL TO */
|
||||
{ 0x08be, 0x2265 }, /* greaterthanequal ≥ GREATER-THAN OR EQUAL TO */
|
||||
{ 0x08bf, 0x222b }, /* integral ∫ INTEGRAL */
|
||||
{ 0x08c0, 0x2234 }, /* therefore ∴ THEREFORE */
|
||||
{ 0x08c1, 0x221d }, /* variation ∝ PROPORTIONAL TO */
|
||||
{ 0x08c2, 0x221e }, /* infinity ∞ INFINITY */
|
||||
{ 0x08c5, 0x2207 }, /* nabla ∇ NABLA */
|
||||
{ 0x08c8, 0x223c }, /* approximate ∼ TILDE OPERATOR */
|
||||
{ 0x08c9, 0x2243 }, /* similarequal ≃ ASYMPTOTICALLY EQUAL TO */
|
||||
{ 0x08cd, 0x21d4 }, /* ifonlyif ⇔ LEFT RIGHT DOUBLE ARROW */
|
||||
{ 0x08ce, 0x21d2 }, /* implies ⇒ RIGHTWARDS DOUBLE ARROW */
|
||||
{ 0x08cf, 0x2261 }, /* identical ≡ IDENTICAL TO */
|
||||
{ 0x08d6, 0x221a }, /* radical √ SQUARE ROOT */
|
||||
{ 0x08da, 0x2282 }, /* includedin ⊂ SUBSET OF */
|
||||
{ 0x08db, 0x2283 }, /* includes ⊃ SUPERSET OF */
|
||||
{ 0x08dc, 0x2229 }, /* intersection ∩ INTERSECTION */
|
||||
{ 0x08dd, 0x222a }, /* union ∪ UNION */
|
||||
{ 0x08de, 0x2227 }, /* logicaland ∧ LOGICAL AND */
|
||||
{ 0x08df, 0x2228 }, /* logicalor ∨ LOGICAL OR */
|
||||
{ 0x08ef, 0x2202 }, /* partialderivative ∂ PARTIAL DIFFERENTIAL */
|
||||
{ 0x08f6, 0x0192 }, /* function ƒ LATIN SMALL LETTER F WITH HOOK */
|
||||
{ 0x08fb, 0x2190 }, /* leftarrow ← LEFTWARDS ARROW */
|
||||
{ 0x08fc, 0x2191 }, /* uparrow ↑ UPWARDS ARROW */
|
||||
{ 0x08fd, 0x2192 }, /* rightarrow → RIGHTWARDS ARROW */
|
||||
{ 0x08fe, 0x2193 }, /* downarrow ↓ DOWNWARDS ARROW */
|
||||
/* 0x09df blank ? ??? */
|
||||
{ 0x09e0, 0x25c6 }, /* soliddiamond ◆ BLACK DIAMOND */
|
||||
{ 0x09e1, 0x2592 }, /* checkerboard ▒ MEDIUM SHADE */
|
||||
{ 0x09e2, 0x2409 }, /* ht ␉ SYMBOL FOR HORIZONTAL TABULATION */
|
||||
{ 0x09e3, 0x240c }, /* ff ␌ SYMBOL FOR FORM FEED */
|
||||
{ 0x09e4, 0x240d }, /* cr ␍ SYMBOL FOR CARRIAGE RETURN */
|
||||
{ 0x09e5, 0x240a }, /* lf ␊ SYMBOL FOR LINE FEED */
|
||||
{ 0x09e8, 0x2424 }, /* nl  SYMBOL FOR NEWLINE */
|
||||
{ 0x09e9, 0x240b }, /* vt ␋ SYMBOL FOR VERTICAL TABULATION */
|
||||
{ 0x09ea, 0x2518 }, /* lowrightcorner ┘ BOX DRAWINGS LIGHT UP AND LEFT */
|
||||
{ 0x09eb, 0x2510 }, /* uprightcorner ┐ BOX DRAWINGS LIGHT DOWN AND LEFT */
|
||||
{ 0x09ec, 0x250c }, /* upleftcorner ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */
|
||||
{ 0x09ed, 0x2514 }, /* lowleftcorner └ BOX DRAWINGS LIGHT UP AND RIGHT */
|
||||
{ 0x09ee, 0x253c }, /* crossinglines ┼ BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */
|
||||
{ 0x09ef, 0x23ba }, /* horizlinescan1 ⎺ HORIZONTAL SCAN LINE-1 (Unicode 3.2 draft) */
|
||||
{ 0x09f0, 0x23bb }, /* horizlinescan3 ⎻ HORIZONTAL SCAN LINE-3 (Unicode 3.2 draft) */
|
||||
{ 0x09f1, 0x2500 }, /* horizlinescan5 ─ BOX DRAWINGS LIGHT HORIZONTAL */
|
||||
{ 0x09f2, 0x23bc }, /* horizlinescan7 ⎼ HORIZONTAL SCAN LINE-7 (Unicode 3.2 draft) */
|
||||
{ 0x09f3, 0x23bd }, /* horizlinescan9 ⎽ HORIZONTAL SCAN LINE-9 (Unicode 3.2 draft) */
|
||||
{ 0x09f4, 0x251c }, /* leftt ├ BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
|
||||
{ 0x09f5, 0x2524 }, /* rightt ┤ BOX DRAWINGS LIGHT VERTICAL AND LEFT */
|
||||
{ 0x09f6, 0x2534 }, /* bott ┴ BOX DRAWINGS LIGHT UP AND HORIZONTAL */
|
||||
{ 0x09f7, 0x252c }, /* topt ┬ BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */
|
||||
{ 0x09f8, 0x2502 }, /* vertbar │ BOX DRAWINGS LIGHT VERTICAL */
|
||||
{ 0x0aa1, 0x2003 }, /* emspace EM SPACE */
|
||||
{ 0x0aa2, 0x2002 }, /* enspace EN SPACE */
|
||||
{ 0x0aa3, 0x2004 }, /* em3space THREE-PER-EM SPACE */
|
||||
{ 0x0aa4, 0x2005 }, /* em4space FOUR-PER-EM SPACE */
|
||||
{ 0x0aa5, 0x2007 }, /* digitspace FIGURE SPACE */
|
||||
{ 0x0aa6, 0x2008 }, /* punctspace PUNCTUATION SPACE */
|
||||
{ 0x0aa7, 0x2009 }, /* thinspace THIN SPACE */
|
||||
{ 0x0aa8, 0x200a }, /* hairspace HAIR SPACE */
|
||||
{ 0x0aa9, 0x2014 }, /* emdash — EM DASH */
|
||||
{ 0x0aaa, 0x2013 }, /* endash – EN DASH */
|
||||
{ 0x0aac, 0x2423 }, /* signifblank ␣ OPEN BOX */
|
||||
{ 0x0aae, 0x2026 }, /* ellipsis … HORIZONTAL ELLIPSIS */
|
||||
{ 0x0aaf, 0x2025 }, /* doubbaselinedot ‥ TWO DOT LEADER */
|
||||
{ 0x0ab0, 0x2153 }, /* onethird ⅓ VULGAR FRACTION ONE THIRD */
|
||||
{ 0x0ab1, 0x2154 }, /* twothirds ⅔ VULGAR FRACTION TWO THIRDS */
|
||||
{ 0x0ab2, 0x2155 }, /* onefifth ⅕ VULGAR FRACTION ONE FIFTH */
|
||||
{ 0x0ab3, 0x2156 }, /* twofifths ⅖ VULGAR FRACTION TWO FIFTHS */
|
||||
{ 0x0ab4, 0x2157 }, /* threefifths ⅗ VULGAR FRACTION THREE FIFTHS */
|
||||
{ 0x0ab5, 0x2158 }, /* fourfifths ⅘ VULGAR FRACTION FOUR FIFTHS */
|
||||
{ 0x0ab6, 0x2159 }, /* onesixth ⅙ VULGAR FRACTION ONE SIXTH */
|
||||
{ 0x0ab7, 0x215a }, /* fivesixths ⅚ VULGAR FRACTION FIVE SIXTHS */
|
||||
{ 0x0ab8, 0x2105 }, /* careof ℅ CARE OF */
|
||||
{ 0x0abb, 0x2012 }, /* figdash ‒ FIGURE DASH */
|
||||
{ 0x0abc, 0x27e8 }, /* leftanglebracket ⟨ MATHEMATICAL LEFT ANGLE BRACKET */
|
||||
{ 0x0abd, 0x002e }, /* decimalpoint . FULL STOP */
|
||||
{ 0x0abe, 0x27e9 }, /* rightanglebracket ⟩ MATHEMATICAL RIGHT ANGLE BRACKET */
|
||||
/* 0x0abf marker ? ??? */
|
||||
{ 0x0ac3, 0x215b }, /* oneeighth ⅛ VULGAR FRACTION ONE EIGHTH */
|
||||
{ 0x0ac4, 0x215c }, /* threeeighths ⅜ VULGAR FRACTION THREE EIGHTHS */
|
||||
{ 0x0ac5, 0x215d }, /* fiveeighths ⅝ VULGAR FRACTION FIVE EIGHTHS */
|
||||
{ 0x0ac6, 0x215e }, /* seveneighths ⅞ VULGAR FRACTION SEVEN EIGHTHS */
|
||||
{ 0x0ac9, 0x2122 }, /* trademark ™ TRADE MARK SIGN */
|
||||
{ 0x0aca, 0x2613 }, /* signaturemark ☓ SALTIRE */
|
||||
/* 0x0acb trademarkincircle ? ??? */
|
||||
{ 0x0acc, 0x25c1 }, /* leftopentriangle ◁ WHITE LEFT-POINTING TRIANGLE */
|
||||
{ 0x0acd, 0x25b7 }, /* rightopentriangle ▷ WHITE RIGHT-POINTING TRIANGLE */
|
||||
{ 0x0ace, 0x25cb }, /* emopencircle ○ WHITE CIRCLE */
|
||||
{ 0x0acf, 0x25af }, /* emopenrectangle ▯ WHITE VERTICAL RECTANGLE */
|
||||
{ 0x0ad0, 0x2018 }, /* leftsinglequotemark ‘ LEFT SINGLE QUOTATION MARK */
|
||||
{ 0x0ad1, 0x2019 }, /* rightsinglequotemark ’ RIGHT SINGLE QUOTATION MARK */
|
||||
{ 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 */
|
||||
/* 0x0ada hexagram ? ??? */
|
||||
{ 0x0adb, 0x25ac }, /* filledrectbullet ▬ BLACK RECTANGLE */
|
||||
{ 0x0adc, 0x25c0 }, /* filledlefttribullet ◀ BLACK LEFT-POINTING TRIANGLE */
|
||||
{ 0x0add, 0x25b6 }, /* filledrighttribullet ▶ BLACK RIGHT-POINTING TRIANGLE */
|
||||
{ 0x0ade, 0x25cf }, /* emfilledcircle ● BLACK CIRCLE */
|
||||
{ 0x0adf, 0x25ae }, /* emfilledrect ▮ BLACK VERTICAL RECTANGLE */
|
||||
{ 0x0ae0, 0x25e6 }, /* enopencircbullet ◦ WHITE BULLET */
|
||||
{ 0x0ae1, 0x25ab }, /* enopensquarebullet ▫ WHITE SMALL SQUARE */
|
||||
{ 0x0ae2, 0x25ad }, /* openrectbullet ▭ WHITE RECTANGLE */
|
||||
{ 0x0ae3, 0x25b3 }, /* opentribulletup △ WHITE UP-POINTING TRIANGLE */
|
||||
{ 0x0ae4, 0x25bd }, /* opentribulletdown ▽ WHITE DOWN-POINTING TRIANGLE */
|
||||
{ 0x0ae5, 0x2606 }, /* openstar ☆ WHITE STAR */
|
||||
{ 0x0ae6, 0x2022 }, /* enfilledcircbullet • BULLET */
|
||||
{ 0x0ae7, 0x25aa }, /* enfilledsqbullet ▪ BLACK SMALL SQUARE */
|
||||
{ 0x0ae8, 0x25b2 }, /* filledtribulletup ▲ BLACK UP-POINTING TRIANGLE */
|
||||
{ 0x0ae9, 0x25bc }, /* filledtribulletdown ▼ BLACK DOWN-POINTING TRIANGLE */
|
||||
{ 0x0aea, 0x261c }, /* leftpointer ☜ WHITE LEFT POINTING INDEX */
|
||||
{ 0x0aeb, 0x261e }, /* rightpointer ☞ WHITE RIGHT POINTING INDEX */
|
||||
{ 0x0aec, 0x2663 }, /* club ♣ BLACK CLUB SUIT */
|
||||
{ 0x0aed, 0x2666 }, /* diamond ♦ BLACK DIAMOND SUIT */
|
||||
{ 0x0aee, 0x2665 }, /* heart ♥ BLACK HEART SUIT */
|
||||
{ 0x0af0, 0x2720 }, /* maltesecross ✠ MALTESE CROSS */
|
||||
{ 0x0af1, 0x2020 }, /* dagger † DAGGER */
|
||||
{ 0x0af2, 0x2021 }, /* doubledagger ‡ DOUBLE DAGGER */
|
||||
{ 0x0af3, 0x2713 }, /* checkmark ✓ CHECK MARK */
|
||||
{ 0x0af4, 0x2717 }, /* ballotcross ✗ BALLOT X */
|
||||
{ 0x0af5, 0x266f }, /* musicalsharp ♯ MUSIC SHARP SIGN */
|
||||
{ 0x0af6, 0x266d }, /* musicalflat ♭ MUSIC FLAT SIGN */
|
||||
{ 0x0af7, 0x2642 }, /* malesymbol ♂ MALE SIGN */
|
||||
{ 0x0af8, 0x2640 }, /* femalesymbol ♀ FEMALE SIGN */
|
||||
{ 0x0af9, 0x260e }, /* telephone ☎ BLACK TELEPHONE */
|
||||
{ 0x0afa, 0x2315 }, /* telephonerecorder ⌕ TELEPHONE RECORDER */
|
||||
{ 0x0afb, 0x2117 }, /* phonographcopyright ℗ SOUND RECORDING COPYRIGHT */
|
||||
{ 0x0afc, 0x2038 }, /* caret ‸ CARET */
|
||||
{ 0x0afd, 0x201a }, /* singlelowquotemark ‚ SINGLE LOW-9 QUOTATION MARK */
|
||||
{ 0x0afe, 0x201e }, /* doublelowquotemark „ DOUBLE LOW-9 QUOTATION MARK */
|
||||
/* 0x0aff cursor ? ??? */
|
||||
{ 0x0ba3, 0x003c }, /* leftcaret < LESS-THAN SIGN */
|
||||
{ 0x0ba6, 0x003e }, /* rightcaret > GREATER-THAN SIGN */
|
||||
{ 0x0ba8, 0x2228 }, /* downcaret ∨ LOGICAL OR */
|
||||
{ 0x0ba9, 0x2227 }, /* upcaret ∧ LOGICAL AND */
|
||||
{ 0x0bc0, 0x00af }, /* overbar ¯ MACRON */
|
||||
{ 0x0bc2, 0x22a4 }, /* downtack ⊤ DOWN TACK */
|
||||
{ 0x0bc3, 0x2229 }, /* upshoe ∩ INTERSECTION */
|
||||
{ 0x0bc4, 0x230a }, /* downstile ⌊ LEFT FLOOR */
|
||||
{ 0x0bc6, 0x005f }, /* underbar _ LOW LINE */
|
||||
{ 0x0bca, 0x2218 }, /* jot ∘ RING OPERATOR */
|
||||
{ 0x0bcc, 0x2395 }, /* quad ⎕ APL FUNCTIONAL SYMBOL QUAD (Unicode 3.0) */
|
||||
{ 0x0bce, 0x22a5 }, /* uptack ⊥ UP TACK */
|
||||
{ 0x0bcf, 0x25cb }, /* circle ○ WHITE CIRCLE */
|
||||
{ 0x0bd3, 0x2308 }, /* upstile ⌈ LEFT CEILING */
|
||||
{ 0x0bd6, 0x222a }, /* downshoe ∪ UNION */
|
||||
{ 0x0bd8, 0x2283 }, /* rightshoe ⊃ SUPERSET OF */
|
||||
{ 0x0bda, 0x2282 }, /* leftshoe ⊂ SUBSET OF */
|
||||
{ 0x0bdc, 0x22a3 }, /* lefttack ⊣ LEFT TACK */
|
||||
{ 0x0bfc, 0x22a2 }, /* righttack ⊢ RIGHT TACK */
|
||||
{ 0x0cdf, 0x2017 }, /* hebrew_doublelowline ‗ DOUBLE LOW LINE */
|
||||
{ 0x0ce0, 0x05d0 }, /* hebrew_aleph א HEBREW LETTER ALEF */
|
||||
{ 0x0ce1, 0x05d1 }, /* hebrew_bet ב HEBREW LETTER BET */
|
||||
{ 0x0ce2, 0x05d2 }, /* hebrew_gimel ג HEBREW LETTER GIMEL */
|
||||
{ 0x0ce3, 0x05d3 }, /* hebrew_dalet ד HEBREW LETTER DALET */
|
||||
{ 0x0ce4, 0x05d4 }, /* hebrew_he ה HEBREW LETTER HE */
|
||||
{ 0x0ce5, 0x05d5 }, /* hebrew_waw ו HEBREW LETTER VAV */
|
||||
{ 0x0ce6, 0x05d6 }, /* hebrew_zain ז HEBREW LETTER ZAYIN */
|
||||
{ 0x0ce7, 0x05d7 }, /* hebrew_chet ח HEBREW LETTER HET */
|
||||
{ 0x0ce8, 0x05d8 }, /* hebrew_tet ט HEBREW LETTER TET */
|
||||
{ 0x0ce9, 0x05d9 }, /* hebrew_yod י HEBREW LETTER YOD */
|
||||
{ 0x0cea, 0x05da }, /* hebrew_finalkaph ך HEBREW LETTER FINAL KAF */
|
||||
{ 0x0ceb, 0x05db }, /* hebrew_kaph כ HEBREW LETTER KAF */
|
||||
{ 0x0cec, 0x05dc }, /* hebrew_lamed ל HEBREW LETTER LAMED */
|
||||
{ 0x0ced, 0x05dd }, /* hebrew_finalmem ם HEBREW LETTER FINAL MEM */
|
||||
{ 0x0cee, 0x05de }, /* hebrew_mem מ HEBREW LETTER MEM */
|
||||
{ 0x0cef, 0x05df }, /* hebrew_finalnun ן HEBREW LETTER FINAL NUN */
|
||||
{ 0x0cf0, 0x05e0 }, /* hebrew_nun נ HEBREW LETTER NUN */
|
||||
{ 0x0cf1, 0x05e1 }, /* hebrew_samech ס HEBREW LETTER SAMEKH */
|
||||
{ 0x0cf2, 0x05e2 }, /* hebrew_ayin ע HEBREW LETTER AYIN */
|
||||
{ 0x0cf3, 0x05e3 }, /* hebrew_finalpe ף HEBREW LETTER FINAL PE */
|
||||
{ 0x0cf4, 0x05e4 }, /* hebrew_pe פ HEBREW LETTER PE */
|
||||
{ 0x0cf5, 0x05e5 }, /* hebrew_finalzade ץ HEBREW LETTER FINAL TSADI */
|
||||
{ 0x0cf6, 0x05e6 }, /* hebrew_zade צ HEBREW LETTER TSADI */
|
||||
{ 0x0cf7, 0x05e7 }, /* hebrew_qoph ק HEBREW LETTER QOF */
|
||||
{ 0x0cf8, 0x05e8 }, /* hebrew_resh ר HEBREW LETTER RESH */
|
||||
{ 0x0cf9, 0x05e9 }, /* hebrew_shin ש HEBREW LETTER SHIN */
|
||||
{ 0x0cfa, 0x05ea }, /* hebrew_taw ת HEBREW LETTER TAV */
|
||||
{ 0x0da1, 0x0e01 }, /* Thai_kokai ก THAI CHARACTER KO KAI */
|
||||
{ 0x0da2, 0x0e02 }, /* Thai_khokhai ข THAI CHARACTER KHO KHAI */
|
||||
{ 0x0da3, 0x0e03 }, /* Thai_khokhuat ฃ THAI CHARACTER KHO KHUAT */
|
||||
{ 0x0da4, 0x0e04 }, /* Thai_khokhwai ค THAI CHARACTER KHO KHWAI */
|
||||
{ 0x0da5, 0x0e05 }, /* Thai_khokhon ฅ THAI CHARACTER KHO KHON */
|
||||
{ 0x0da6, 0x0e06 }, /* Thai_khorakhang ฆ THAI CHARACTER KHO RAKHANG */
|
||||
{ 0x0da7, 0x0e07 }, /* Thai_ngongu ง THAI CHARACTER NGO NGU */
|
||||
{ 0x0da8, 0x0e08 }, /* Thai_chochan จ THAI CHARACTER CHO CHAN */
|
||||
{ 0x0da9, 0x0e09 }, /* Thai_choching ฉ THAI CHARACTER CHO CHING */
|
||||
{ 0x0daa, 0x0e0a }, /* Thai_chochang ช THAI CHARACTER CHO CHANG */
|
||||
{ 0x0dab, 0x0e0b }, /* Thai_soso ซ THAI CHARACTER SO SO */
|
||||
{ 0x0dac, 0x0e0c }, /* Thai_chochoe ฌ THAI CHARACTER CHO CHOE */
|
||||
{ 0x0dad, 0x0e0d }, /* Thai_yoying ญ THAI CHARACTER YO YING */
|
||||
{ 0x0dae, 0x0e0e }, /* Thai_dochada ฎ THAI CHARACTER DO CHADA */
|
||||
{ 0x0daf, 0x0e0f }, /* Thai_topatak ฏ THAI CHARACTER TO PATAK */
|
||||
{ 0x0db0, 0x0e10 }, /* Thai_thothan ฐ THAI CHARACTER THO THAN */
|
||||
{ 0x0db1, 0x0e11 }, /* Thai_thonangmontho ฑ THAI CHARACTER THO NANGMONTHO */
|
||||
{ 0x0db2, 0x0e12 }, /* Thai_thophuthao ฒ THAI CHARACTER THO PHUTHAO */
|
||||
{ 0x0db3, 0x0e13 }, /* Thai_nonen ณ THAI CHARACTER NO NEN */
|
||||
{ 0x0db4, 0x0e14 }, /* Thai_dodek ด THAI CHARACTER DO DEK */
|
||||
{ 0x0db5, 0x0e15 }, /* Thai_totao ต THAI CHARACTER TO TAO */
|
||||
{ 0x0db6, 0x0e16 }, /* Thai_thothung ถ THAI CHARACTER THO THUNG */
|
||||
{ 0x0db7, 0x0e17 }, /* Thai_thothahan ท THAI CHARACTER THO THAHAN */
|
||||
{ 0x0db8, 0x0e18 }, /* Thai_thothong ธ THAI CHARACTER THO THONG */
|
||||
{ 0x0db9, 0x0e19 }, /* Thai_nonu น THAI CHARACTER NO NU */
|
||||
{ 0x0dba, 0x0e1a }, /* Thai_bobaimai บ THAI CHARACTER BO BAIMAI */
|
||||
{ 0x0dbb, 0x0e1b }, /* Thai_popla ป THAI CHARACTER PO PLA */
|
||||
{ 0x0dbc, 0x0e1c }, /* Thai_phophung ผ THAI CHARACTER PHO PHUNG */
|
||||
{ 0x0dbd, 0x0e1d }, /* Thai_fofa ฝ THAI CHARACTER FO FA */
|
||||
{ 0x0dbe, 0x0e1e }, /* Thai_phophan พ THAI CHARACTER PHO PHAN */
|
||||
{ 0x0dbf, 0x0e1f }, /* Thai_fofan ฟ THAI CHARACTER FO FAN */
|
||||
{ 0x0dc0, 0x0e20 }, /* Thai_phosamphao ภ THAI CHARACTER PHO SAMPHAO */
|
||||
{ 0x0dc1, 0x0e21 }, /* Thai_moma ม THAI CHARACTER MO MA */
|
||||
{ 0x0dc2, 0x0e22 }, /* Thai_yoyak ย THAI CHARACTER YO YAK */
|
||||
{ 0x0dc3, 0x0e23 }, /* Thai_rorua ร THAI CHARACTER RO RUA */
|
||||
{ 0x0dc4, 0x0e24 }, /* Thai_ru ฤ THAI CHARACTER RU */
|
||||
{ 0x0dc5, 0x0e25 }, /* Thai_loling ล THAI CHARACTER LO LING */
|
||||
{ 0x0dc6, 0x0e26 }, /* Thai_lu ฦ THAI CHARACTER LU */
|
||||
{ 0x0dc7, 0x0e27 }, /* Thai_wowaen ว THAI CHARACTER WO WAEN */
|
||||
{ 0x0dc8, 0x0e28 }, /* Thai_sosala ศ THAI CHARACTER SO SALA */
|
||||
{ 0x0dc9, 0x0e29 }, /* Thai_sorusi ษ THAI CHARACTER SO RUSI */
|
||||
{ 0x0dca, 0x0e2a }, /* Thai_sosua ส THAI CHARACTER SO SUA */
|
||||
{ 0x0dcb, 0x0e2b }, /* Thai_hohip ห THAI CHARACTER HO HIP */
|
||||
{ 0x0dcc, 0x0e2c }, /* Thai_lochula ฬ THAI CHARACTER LO CHULA */
|
||||
{ 0x0dcd, 0x0e2d }, /* Thai_oang อ THAI CHARACTER O ANG */
|
||||
{ 0x0dce, 0x0e2e }, /* Thai_honokhuk ฮ THAI CHARACTER HO NOKHUK */
|
||||
{ 0x0dcf, 0x0e2f }, /* Thai_paiyannoi ฯ THAI CHARACTER PAIYANNOI */
|
||||
{ 0x0dd0, 0x0e30 }, /* Thai_saraa ะ THAI CHARACTER SARA A */
|
||||
{ 0x0dd1, 0x0e31 }, /* Thai_maihanakat ั THAI CHARACTER MAI HAN-AKAT */
|
||||
{ 0x0dd2, 0x0e32 }, /* Thai_saraaa า THAI CHARACTER SARA AA */
|
||||
{ 0x0dd3, 0x0e33 }, /* Thai_saraam ำ THAI CHARACTER SARA AM */
|
||||
{ 0x0dd4, 0x0e34 }, /* Thai_sarai ิ THAI CHARACTER SARA I */
|
||||
{ 0x0dd5, 0x0e35 }, /* Thai_saraii ี THAI CHARACTER SARA II */
|
||||
{ 0x0dd6, 0x0e36 }, /* Thai_saraue ึ THAI CHARACTER SARA UE */
|
||||
{ 0x0dd7, 0x0e37 }, /* Thai_sarauee ื THAI CHARACTER SARA UEE */
|
||||
{ 0x0dd8, 0x0e38 }, /* Thai_sarau ุ THAI CHARACTER SARA U */
|
||||
{ 0x0dd9, 0x0e39 }, /* Thai_sarauu ู THAI CHARACTER SARA UU */
|
||||
{ 0x0dda, 0x0e3a }, /* Thai_phinthu ฺ THAI CHARACTER PHINTHU */
|
||||
{ 0x0dde, 0x0e3e }, /* Thai_maihanakat_maitho ??? */
|
||||
{ 0x0ddf, 0x0e3f }, /* Thai_baht ฿ THAI CURRENCY SYMBOL BAHT */
|
||||
{ 0x0de0, 0x0e40 }, /* Thai_sarae เ THAI CHARACTER SARA E */
|
||||
{ 0x0de1, 0x0e41 }, /* Thai_saraae แ THAI CHARACTER SARA AE */
|
||||
{ 0x0de2, 0x0e42 }, /* Thai_sarao โ THAI CHARACTER SARA O */
|
||||
{ 0x0de3, 0x0e43 }, /* Thai_saraaimaimuan ใ THAI CHARACTER SARA AI MAIMUAN */
|
||||
{ 0x0de4, 0x0e44 }, /* Thai_saraaimaimalai ไ THAI CHARACTER SARA AI MAIMALAI */
|
||||
{ 0x0de5, 0x0e45 }, /* Thai_lakkhangyao ๅ THAI CHARACTER LAKKHANGYAO */
|
||||
{ 0x0de6, 0x0e46 }, /* Thai_maiyamok ๆ THAI CHARACTER MAIYAMOK */
|
||||
{ 0x0de7, 0x0e47 }, /* Thai_maitaikhu ็ THAI CHARACTER MAITAIKHU */
|
||||
{ 0x0de8, 0x0e48 }, /* Thai_maiek ่ THAI CHARACTER MAI EK */
|
||||
{ 0x0de9, 0x0e49 }, /* Thai_maitho ้ THAI CHARACTER MAI THO */
|
||||
{ 0x0dea, 0x0e4a }, /* Thai_maitri ๊ THAI CHARACTER MAI TRI */
|
||||
{ 0x0deb, 0x0e4b }, /* Thai_maichattawa ๋ THAI CHARACTER MAI CHATTAWA */
|
||||
{ 0x0dec, 0x0e4c }, /* Thai_thanthakhat ์ THAI CHARACTER THANTHAKHAT */
|
||||
{ 0x0ded, 0x0e4d }, /* Thai_nikhahit ํ THAI CHARACTER NIKHAHIT */
|
||||
{ 0x0df0, 0x0e50 }, /* Thai_leksun ๐ THAI DIGIT ZERO */
|
||||
{ 0x0df1, 0x0e51 }, /* Thai_leknung ๑ THAI DIGIT ONE */
|
||||
{ 0x0df2, 0x0e52 }, /* Thai_leksong ๒ THAI DIGIT TWO */
|
||||
{ 0x0df3, 0x0e53 }, /* Thai_leksam ๓ THAI DIGIT THREE */
|
||||
{ 0x0df4, 0x0e54 }, /* Thai_leksi ๔ THAI DIGIT FOUR */
|
||||
{ 0x0df5, 0x0e55 }, /* Thai_lekha ๕ THAI DIGIT FIVE */
|
||||
{ 0x0df6, 0x0e56 }, /* Thai_lekhok ๖ THAI DIGIT SIX */
|
||||
{ 0x0df7, 0x0e57 }, /* Thai_lekchet ๗ THAI DIGIT SEVEN */
|
||||
{ 0x0df8, 0x0e58 }, /* Thai_lekpaet ๘ THAI DIGIT EIGHT */
|
||||
{ 0x0df9, 0x0e59 }, /* Thai_lekkao ๙ THAI DIGIT NINE */
|
||||
{ 0x0ea1, 0x3131 }, /* Hangul_Kiyeog ㄱ HANGUL LETTER KIYEOK */
|
||||
{ 0x0ea2, 0x3132 }, /* Hangul_SsangKiyeog ㄲ HANGUL LETTER SSANGKIYEOK */
|
||||
{ 0x0ea3, 0x3133 }, /* Hangul_KiyeogSios ㄳ HANGUL LETTER KIYEOK-SIOS */
|
||||
{ 0x0ea4, 0x3134 }, /* Hangul_Nieun ㄴ HANGUL LETTER NIEUN */
|
||||
{ 0x0ea5, 0x3135 }, /* Hangul_NieunJieuj ㄵ HANGUL LETTER NIEUN-CIEUC */
|
||||
{ 0x0ea6, 0x3136 }, /* Hangul_NieunHieuh ㄶ HANGUL LETTER NIEUN-HIEUH */
|
||||
{ 0x0ea7, 0x3137 }, /* Hangul_Dikeud ㄷ HANGUL LETTER TIKEUT */
|
||||
{ 0x0ea8, 0x3138 }, /* Hangul_SsangDikeud ㄸ HANGUL LETTER SSANGTIKEUT */
|
||||
{ 0x0ea9, 0x3139 }, /* Hangul_Rieul ㄹ HANGUL LETTER RIEUL */
|
||||
{ 0x0eaa, 0x313a }, /* Hangul_RieulKiyeog ㄺ HANGUL LETTER RIEUL-KIYEOK */
|
||||
{ 0x0eab, 0x313b }, /* Hangul_RieulMieum ㄻ HANGUL LETTER RIEUL-MIEUM */
|
||||
{ 0x0eac, 0x313c }, /* Hangul_RieulPieub ㄼ HANGUL LETTER RIEUL-PIEUP */
|
||||
{ 0x0ead, 0x313d }, /* Hangul_RieulSios ㄽ HANGUL LETTER RIEUL-SIOS */
|
||||
{ 0x0eae, 0x313e }, /* Hangul_RieulTieut ㄾ HANGUL LETTER RIEUL-THIEUTH */
|
||||
{ 0x0eaf, 0x313f }, /* Hangul_RieulPhieuf ㄿ HANGUL LETTER RIEUL-PHIEUPH */
|
||||
{ 0x0eb0, 0x3140 }, /* Hangul_RieulHieuh ㅀ HANGUL LETTER RIEUL-HIEUH */
|
||||
{ 0x0eb1, 0x3141 }, /* Hangul_Mieum ㅁ HANGUL LETTER MIEUM */
|
||||
{ 0x0eb2, 0x3142 }, /* Hangul_Pieub ㅂ HANGUL LETTER PIEUP */
|
||||
{ 0x0eb3, 0x3143 }, /* Hangul_SsangPieub ㅃ HANGUL LETTER SSANGPIEUP */
|
||||
{ 0x0eb4, 0x3144 }, /* Hangul_PieubSios ㅄ HANGUL LETTER PIEUP-SIOS */
|
||||
{ 0x0eb5, 0x3145 }, /* Hangul_Sios ㅅ HANGUL LETTER SIOS */
|
||||
{ 0x0eb6, 0x3146 }, /* Hangul_SsangSios ㅆ HANGUL LETTER SSANGSIOS */
|
||||
{ 0x0eb7, 0x3147 }, /* Hangul_Ieung ㅇ HANGUL LETTER IEUNG */
|
||||
{ 0x0eb8, 0x3148 }, /* Hangul_Jieuj ㅈ HANGUL LETTER CIEUC */
|
||||
{ 0x0eb9, 0x3149 }, /* Hangul_SsangJieuj ㅉ HANGUL LETTER SSANGCIEUC */
|
||||
{ 0x0eba, 0x314a }, /* Hangul_Cieuc ㅊ HANGUL LETTER CHIEUCH */
|
||||
{ 0x0ebb, 0x314b }, /* Hangul_Khieuq ㅋ HANGUL LETTER KHIEUKH */
|
||||
{ 0x0ebc, 0x314c }, /* Hangul_Tieut ㅌ HANGUL LETTER THIEUTH */
|
||||
{ 0x0ebd, 0x314d }, /* Hangul_Phieuf ㅍ HANGUL LETTER PHIEUPH */
|
||||
{ 0x0ebe, 0x314e }, /* Hangul_Hieuh ㅎ HANGUL LETTER HIEUH */
|
||||
{ 0x0ebf, 0x314f }, /* Hangul_A ㅏ HANGUL LETTER A */
|
||||
{ 0x0ec0, 0x3150 }, /* Hangul_AE ㅐ HANGUL LETTER AE */
|
||||
{ 0x0ec1, 0x3151 }, /* Hangul_YA ㅑ HANGUL LETTER YA */
|
||||
{ 0x0ec2, 0x3152 }, /* Hangul_YAE ㅒ HANGUL LETTER YAE */
|
||||
{ 0x0ec3, 0x3153 }, /* Hangul_EO ㅓ HANGUL LETTER EO */
|
||||
{ 0x0ec4, 0x3154 }, /* Hangul_E ㅔ HANGUL LETTER E */
|
||||
{ 0x0ec5, 0x3155 }, /* Hangul_YEO ㅕ HANGUL LETTER YEO */
|
||||
{ 0x0ec6, 0x3156 }, /* Hangul_YE ㅖ HANGUL LETTER YE */
|
||||
{ 0x0ec7, 0x3157 }, /* Hangul_O ㅗ HANGUL LETTER O */
|
||||
{ 0x0ec8, 0x3158 }, /* Hangul_WA ㅘ HANGUL LETTER WA */
|
||||
{ 0x0ec9, 0x3159 }, /* Hangul_WAE ㅙ HANGUL LETTER WAE */
|
||||
{ 0x0eca, 0x315a }, /* Hangul_OE ㅚ HANGUL LETTER OE */
|
||||
{ 0x0ecb, 0x315b }, /* Hangul_YO ㅛ HANGUL LETTER YO */
|
||||
{ 0x0ecc, 0x315c }, /* Hangul_U ㅜ HANGUL LETTER U */
|
||||
{ 0x0ecd, 0x315d }, /* Hangul_WEO ㅝ HANGUL LETTER WEO */
|
||||
{ 0x0ece, 0x315e }, /* Hangul_WE ㅞ HANGUL LETTER WE */
|
||||
{ 0x0ecf, 0x315f }, /* Hangul_WI ㅟ HANGUL LETTER WI */
|
||||
{ 0x0ed0, 0x3160 }, /* Hangul_YU ㅠ HANGUL LETTER YU */
|
||||
{ 0x0ed1, 0x3161 }, /* Hangul_EU ㅡ HANGUL LETTER EU */
|
||||
{ 0x0ed2, 0x3162 }, /* Hangul_YI ㅢ HANGUL LETTER YI */
|
||||
{ 0x0ed3, 0x3163 }, /* Hangul_I ㅣ HANGUL LETTER I */
|
||||
{ 0x0ed4, 0x11a8 }, /* Hangul_J_Kiyeog ᆨ HANGUL JONGSEONG KIYEOK */
|
||||
{ 0x0ed5, 0x11a9 }, /* Hangul_J_SsangKiyeog ᆩ HANGUL JONGSEONG SSANGKIYEOK */
|
||||
{ 0x0ed6, 0x11aa }, /* Hangul_J_KiyeogSios ᆪ HANGUL JONGSEONG KIYEOK-SIOS */
|
||||
{ 0x0ed7, 0x11ab }, /* Hangul_J_Nieun ᆫ HANGUL JONGSEONG NIEUN */
|
||||
{ 0x0ed8, 0x11ac }, /* Hangul_J_NieunJieuj ᆬ HANGUL JONGSEONG NIEUN-CIEUC */
|
||||
{ 0x0ed9, 0x11ad }, /* Hangul_J_NieunHieuh ᆭ HANGUL JONGSEONG NIEUN-HIEUH */
|
||||
{ 0x0eda, 0x11ae }, /* Hangul_J_Dikeud ᆮ HANGUL JONGSEONG TIKEUT */
|
||||
{ 0x0edb, 0x11af }, /* Hangul_J_Rieul ᆯ HANGUL JONGSEONG RIEUL */
|
||||
{ 0x0edc, 0x11b0 }, /* Hangul_J_RieulKiyeog ᆰ HANGUL JONGSEONG RIEUL-KIYEOK */
|
||||
{ 0x0edd, 0x11b1 }, /* Hangul_J_RieulMieum ᆱ HANGUL JONGSEONG RIEUL-MIEUM */
|
||||
{ 0x0ede, 0x11b2 }, /* Hangul_J_RieulPieub ᆲ HANGUL JONGSEONG RIEUL-PIEUP */
|
||||
{ 0x0edf, 0x11b3 }, /* Hangul_J_RieulSios ᆳ HANGUL JONGSEONG RIEUL-SIOS */
|
||||
{ 0x0ee0, 0x11b4 }, /* Hangul_J_RieulTieut ᆴ HANGUL JONGSEONG RIEUL-THIEUTH */
|
||||
{ 0x0ee1, 0x11b5 }, /* Hangul_J_RieulPhieuf ᆵ HANGUL JONGSEONG RIEUL-PHIEUPH */
|
||||
{ 0x0ee2, 0x11b6 }, /* Hangul_J_RieulHieuh ᆶ HANGUL JONGSEONG RIEUL-HIEUH */
|
||||
{ 0x0ee3, 0x11b7 }, /* Hangul_J_Mieum ᆷ HANGUL JONGSEONG MIEUM */
|
||||
{ 0x0ee4, 0x11b8 }, /* Hangul_J_Pieub ᆸ HANGUL JONGSEONG PIEUP */
|
||||
{ 0x0ee5, 0x11b9 }, /* Hangul_J_PieubSios ᆹ HANGUL JONGSEONG PIEUP-SIOS */
|
||||
{ 0x0ee6, 0x11ba }, /* Hangul_J_Sios ᆺ HANGUL JONGSEONG SIOS */
|
||||
{ 0x0ee7, 0x11bb }, /* Hangul_J_SsangSios ᆻ HANGUL JONGSEONG SSANGSIOS */
|
||||
{ 0x0ee8, 0x11bc }, /* Hangul_J_Ieung ᆼ HANGUL JONGSEONG IEUNG */
|
||||
{ 0x0ee9, 0x11bd }, /* Hangul_J_Jieuj ᆽ HANGUL JONGSEONG CIEUC */
|
||||
{ 0x0eea, 0x11be }, /* Hangul_J_Cieuc ᆾ HANGUL JONGSEONG CHIEUCH */
|
||||
{ 0x0eeb, 0x11bf }, /* Hangul_J_Khieuq ᆿ HANGUL JONGSEONG KHIEUKH */
|
||||
{ 0x0eec, 0x11c0 }, /* Hangul_J_Tieut ᇀ HANGUL JONGSEONG THIEUTH */
|
||||
{ 0x0eed, 0x11c1 }, /* Hangul_J_Phieuf ᇁ HANGUL JONGSEONG PHIEUPH */
|
||||
{ 0x0eee, 0x11c2 }, /* Hangul_J_Hieuh ᇂ HANGUL JONGSEONG HIEUH */
|
||||
{ 0x0eef, 0x316d }, /* Hangul_RieulYeorinHieuh ㅭ HANGUL LETTER RIEUL-YEORINHIEUH */
|
||||
{ 0x0ef0, 0x3171 }, /* Hangul_SunkyeongeumMieum ㅱ HANGUL LETTER KAPYEOUNMIEUM */
|
||||
{ 0x0ef1, 0x3178 }, /* Hangul_SunkyeongeumPieub ㅸ HANGUL LETTER KAPYEOUNPIEUP */
|
||||
{ 0x0ef2, 0x317f }, /* Hangul_PanSios ㅿ HANGUL LETTER PANSIOS */
|
||||
{ 0x0ef3, 0x3181 }, /* Hangul_KkogjiDalrinIeung ㆁ HANGUL LETTER YESIEUNG */
|
||||
{ 0x0ef4, 0x3184 }, /* Hangul_SunkyeongeumPhieuf ㆄ HANGUL LETTER KAPYEOUNPHIEUPH */
|
||||
{ 0x0ef5, 0x3186 }, /* Hangul_YeorinHieuh ㆆ HANGUL LETTER YEORINHIEUH */
|
||||
{ 0x0ef6, 0x318d }, /* Hangul_AraeA ㆍ HANGUL LETTER ARAEA */
|
||||
{ 0x0ef7, 0x318e }, /* Hangul_AraeAE ㆎ HANGUL LETTER ARAEAE */
|
||||
{ 0x0ef8, 0x11eb }, /* Hangul_J_PanSios ᇫ HANGUL JONGSEONG PANSIOS */
|
||||
{ 0x0ef9, 0x11f0 }, /* Hangul_J_KkogjiDalrinIeung ᇰ HANGUL JONGSEONG YESIEUNG */
|
||||
{ 0x0efa, 0x11f9 }, /* Hangul_J_YeorinHieuh ᇹ HANGUL JONGSEONG YEORINHIEUH */
|
||||
{ 0x0eff, 0x20a9 }, /* Korean_Won ₩ WON SIGN */
|
||||
{ 0x13bc, 0x0152 }, /* OE Œ LATIN CAPITAL LIGATURE OE */
|
||||
{ 0x13bd, 0x0153 }, /* oe œ LATIN SMALL LIGATURE OE */
|
||||
{ 0x13be, 0x0178 }, /* Ydiaeresis Ÿ LATIN CAPITAL LETTER Y WITH DIAERESIS */
|
||||
{ 0x20ac, 0x20ac }, /* EuroSign € EURO SIGN */
|
||||
};
|
||||
|
||||
/* binary search with range check */
|
||||
static uint32_t
|
||||
bin_search(const struct codepair *table, size_t length, xkb_keysym_t keysym)
|
||||
{
|
||||
size_t first = 0;
|
||||
size_t last = length;
|
||||
|
||||
if (keysym < table[0].keysym || keysym > table[length].keysym)
|
||||
return 0;
|
||||
|
||||
/* binary search in table */
|
||||
while (last >= first) {
|
||||
size_t mid = (first + last) / 2;
|
||||
if (table[mid].keysym < keysym)
|
||||
first = mid + 1;
|
||||
else if (table[mid].keysym > keysym)
|
||||
last = mid - 1;
|
||||
else /* found it */
|
||||
return table[mid].ucs;
|
||||
}
|
||||
|
||||
/* no matching Unicode value found in table */
|
||||
return NO_KEYSYM_UNICODE_CONVERSION;
|
||||
}
|
||||
|
||||
XKB_EXPORT uint32_t
|
||||
xkb_keysym_to_utf32(xkb_keysym_t keysym)
|
||||
{
|
||||
/* first check for Latin-1 characters (1:1 mapping) */
|
||||
if ((keysym >= 0x0020 && keysym <= 0x007e) ||
|
||||
(keysym >= 0x00a0 && keysym <= 0x00ff))
|
||||
return keysym;
|
||||
|
||||
/* patch encoding botch */
|
||||
if (keysym == XKB_KEY_KP_Space)
|
||||
return XKB_KEY_space & 0x7f;
|
||||
|
||||
/* special keysyms */
|
||||
if ((keysym >= XKB_KEY_BackSpace && keysym <= XKB_KEY_Clear) ||
|
||||
(keysym >= XKB_KEY_KP_Multiply && keysym <= XKB_KEY_KP_9) ||
|
||||
keysym == XKB_KEY_Return || keysym == XKB_KEY_Escape ||
|
||||
keysym == XKB_KEY_Delete || keysym == XKB_KEY_KP_Tab ||
|
||||
keysym == XKB_KEY_KP_Enter || keysym == XKB_KEY_KP_Equal)
|
||||
return keysym & 0x7f;
|
||||
|
||||
/* also check for directly encoded Unicode codepoints */
|
||||
|
||||
/* Exclude surrogates: they are invalid in UTF-32.
|
||||
* See https://www.unicode.org/versions/Unicode15.0.0/ch03.pdf#G28875
|
||||
* for further details.
|
||||
*/
|
||||
if (0x0100d800 <= keysym && keysym <= 0x0100dfff)
|
||||
return NO_KEYSYM_UNICODE_CONVERSION;
|
||||
/*
|
||||
* 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 (XKB_KEYSYM_UNICODE_OFFSET <= keysym && keysym <= XKB_KEYSYM_UNICODE_MAX)
|
||||
return keysym - XKB_KEYSYM_UNICODE_OFFSET;
|
||||
|
||||
/* search main table */
|
||||
return bin_search(keysymtab, ARRAY_SIZE(keysymtab) - 1, keysym);
|
||||
}
|
||||
|
||||
XKB_EXPORT xkb_keysym_t
|
||||
xkb_utf32_to_keysym(uint32_t ucs)
|
||||
{
|
||||
/* first check for Latin-1 characters (1:1 mapping) */
|
||||
if ((ucs >= 0x0020 && ucs <= 0x007e) ||
|
||||
(ucs >= 0x00a0 && ucs <= 0x00ff))
|
||||
return ucs;
|
||||
|
||||
/* special keysyms */
|
||||
if ((ucs >= (XKB_KEY_BackSpace & 0x7f) && ucs <= (XKB_KEY_Clear & 0x7f)) ||
|
||||
ucs == (XKB_KEY_Return & 0x7f) || ucs == (XKB_KEY_Escape & 0x7f))
|
||||
return ucs | 0xff00;
|
||||
if (ucs == (XKB_KEY_Delete & 0x7f))
|
||||
return XKB_KEY_Delete;
|
||||
|
||||
/* Unicode non-symbols and code points outside Unicode planes */
|
||||
if ((ucs >= 0xd800 && ucs <= 0xdfff) ||
|
||||
(ucs >= 0xfdd0 && ucs <= 0xfdef) ||
|
||||
ucs > 0x10ffff || (ucs & 0xfffe) == 0xfffe)
|
||||
return XKB_KEY_NoSymbol;
|
||||
|
||||
/* search main table */
|
||||
for (size_t i = 0; i < ARRAY_SIZE(keysymtab); i++)
|
||||
if (keysymtab[i].ucs == ucs)
|
||||
return keysymtab[i].keysym;
|
||||
|
||||
/* Use direct encoding if everything else fails */
|
||||
return ucs | XKB_KEYSYM_UNICODE_OFFSET;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copyright © 2012 Intel Corporation
|
||||
*
|
||||
* 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: Rob Bradford <rob@linux.intel.com>
|
||||
*/
|
||||
|
||||
XKB_EXPORT int
|
||||
xkb_keysym_to_utf8(xkb_keysym_t keysym, char *buffer, size_t size)
|
||||
{
|
||||
uint32_t codepoint;
|
||||
|
||||
if (size < 7)
|
||||
return -1;
|
||||
|
||||
codepoint = xkb_keysym_to_utf32(keysym);
|
||||
|
||||
if (codepoint == NO_KEYSYM_UNICODE_CONVERSION)
|
||||
return 0;
|
||||
|
||||
return utf32_to_utf8(codepoint, buffer);
|
||||
}
|
||||
@@ -1,904 +0,0 @@
|
||||
/*
|
||||
* Copyright 1985, 1987, 1990, 1998 The Open Group
|
||||
*
|
||||
* 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 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 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.
|
||||
*
|
||||
* Except as contained in this notice, the names of the authors or their
|
||||
* institutions shall not be used in advertising or otherwise to promote the
|
||||
* sale, use or other dealings in this Software without prior written
|
||||
* authorization from the authors.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright © 2009 Dan Nicholson
|
||||
*
|
||||
* 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 "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "xkbcommon/xkbcommon.h"
|
||||
#include "utils.h"
|
||||
#include "keysym.h"
|
||||
#include "ks_tables.h"
|
||||
|
||||
static ssize_t
|
||||
find_keysym_index(xkb_keysym_t ks)
|
||||
{
|
||||
/* Lower bound:
|
||||
* keysym_to_name[0].keysym
|
||||
* == XKB_KEYSYM_MIN_EXPLICIT == XKB_KEYSYM_MIN == 0
|
||||
* No need to check: xkb_keysym_t is unsigned.
|
||||
*
|
||||
* Upper bound:
|
||||
* keysym_to_name[ARRAY_SIZE(keysym_to_name) - 1].keysym
|
||||
* == XKB_KEYSYM_MAX_EXPLICIT <= XKB_KEYSYM_MAX
|
||||
*/
|
||||
if (ks > XKB_KEYSYM_MAX_EXPLICIT)
|
||||
return -1;
|
||||
|
||||
ssize_t lo = 0, hi = ARRAY_SIZE(keysym_to_name) - 1;
|
||||
while (hi >= lo) {
|
||||
ssize_t mid = (lo + hi) / 2;
|
||||
if (ks > keysym_to_name[mid].keysym) {
|
||||
lo = mid + 1;
|
||||
} else if (ks < keysym_to_name[mid].keysym) {
|
||||
hi = mid - 1;
|
||||
} else {
|
||||
return mid;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline const char *
|
||||
get_name(const struct name_keysym *entry)
|
||||
{
|
||||
return keysym_names + entry->offset;
|
||||
}
|
||||
|
||||
/* Unnamed Unicode codepoint. */
|
||||
static inline int
|
||||
get_unicode_name(xkb_keysym_t ks, char *buffer, size_t size)
|
||||
{
|
||||
const int width = (ks & 0xff0000UL) ? 8 : 4;
|
||||
return snprintf(buffer, size, "U%0*lX", width, ks & 0xffffffUL);
|
||||
}
|
||||
|
||||
XKB_EXPORT int
|
||||
xkb_keysym_get_name(xkb_keysym_t ks, char *buffer, size_t size)
|
||||
{
|
||||
if (ks > XKB_KEYSYM_MAX) {
|
||||
snprintf(buffer, size, "Invalid");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t index = find_keysym_index(ks);
|
||||
if (index != -1)
|
||||
return snprintf(buffer, size, "%s", get_name(&keysym_to_name[index]));
|
||||
|
||||
/* Unnamed Unicode codepoint. */
|
||||
if (ks >= XKB_KEYSYM_UNICODE_MIN && ks <= XKB_KEYSYM_UNICODE_MAX)
|
||||
return get_unicode_name(ks, buffer, size);
|
||||
|
||||
/* Unnamed, non-Unicode, symbol (shouldn't generally happen). */
|
||||
return snprintf(buffer, size, "0x%08x", ks);
|
||||
}
|
||||
|
||||
bool
|
||||
xkb_keysym_is_assigned(xkb_keysym_t ks)
|
||||
{
|
||||
return (XKB_KEYSYM_UNICODE_MIN <= ks && ks <= XKB_KEYSYM_UNICODE_MAX) ||
|
||||
find_keysym_index(ks) != -1;
|
||||
}
|
||||
|
||||
struct xkb_keysym_iterator {
|
||||
bool explicit; /* If true, traverse only explicitly named keysyms */
|
||||
int32_t index; /* Current index in `keysym_to_name` */
|
||||
xkb_keysym_t keysym; /* Current keysym */
|
||||
};
|
||||
|
||||
struct xkb_keysym_iterator*
|
||||
xkb_keysym_iterator_new(bool iterate_only_explicit_keysyms)
|
||||
{
|
||||
struct xkb_keysym_iterator* iter = calloc(1, sizeof(*iter));
|
||||
iter->explicit = iterate_only_explicit_keysyms;
|
||||
iter->index = -1;
|
||||
iter->keysym = XKB_KEYSYM_UNICODE_MAX;
|
||||
return iter;
|
||||
}
|
||||
|
||||
struct xkb_keysym_iterator*
|
||||
xkb_keysym_iterator_unref(struct xkb_keysym_iterator *iter)
|
||||
{
|
||||
free(iter);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
xkb_keysym_t
|
||||
xkb_keysym_iterator_get_keysym(struct xkb_keysym_iterator *iter)
|
||||
{
|
||||
return iter->keysym;
|
||||
}
|
||||
|
||||
bool
|
||||
xkb_keysym_iterator_is_explicitly_named(struct xkb_keysym_iterator *iter)
|
||||
{
|
||||
return iter->index >= 0 &&
|
||||
iter->index < (int32_t)ARRAY_SIZE(keysym_to_name) &&
|
||||
(iter->explicit ||
|
||||
iter->keysym == keysym_to_name[iter->index].keysym);
|
||||
}
|
||||
|
||||
int
|
||||
xkb_keysym_iterator_get_name(struct xkb_keysym_iterator *iter,
|
||||
char *buffer, size_t size)
|
||||
{
|
||||
if (iter->index < 0 || iter->index >= (int32_t)ARRAY_SIZE(keysym_to_name))
|
||||
return -1;
|
||||
if (iter->explicit || iter->keysym == keysym_to_name[iter->index].keysym)
|
||||
return snprintf(buffer, size, "%s",
|
||||
get_name(&keysym_to_name[iter->index]));
|
||||
return get_unicode_name(iter->keysym, buffer, size);
|
||||
}
|
||||
|
||||
/* Iterate over the *assigned* keysyms.
|
||||
*
|
||||
* Use:
|
||||
*
|
||||
* ```c
|
||||
* struct xkb_keysym_iterator *iter = xkb_keysym_iterator_new(true);
|
||||
* while (xkb_keysym_iterator_next(iter)) {
|
||||
* ...
|
||||
* }
|
||||
* iter = xkb_keysym_iterator_unref(iter);
|
||||
* ```
|
||||
*/
|
||||
bool
|
||||
xkb_keysym_iterator_next(struct xkb_keysym_iterator *iter)
|
||||
{
|
||||
if (iter->index >= (int32_t)ARRAY_SIZE(keysym_to_name) - 1)
|
||||
return false;
|
||||
|
||||
/* Next keysym */
|
||||
if (iter->explicit || iter->keysym >= XKB_KEYSYM_UNICODE_MAX ||
|
||||
keysym_to_name[iter->index + 1].keysym < XKB_KEYSYM_UNICODE_MIN) {
|
||||
/* Explicitly named keysyms only */
|
||||
iter->keysym = keysym_to_name[++iter->index].keysym;
|
||||
assert(iter->explicit ||
|
||||
iter->keysym <= XKB_KEYSYM_UNICODE_MIN ||
|
||||
iter->keysym >= XKB_KEYSYM_UNICODE_MAX);
|
||||
} else {
|
||||
/* Unicode keysyms
|
||||
* NOTE: Unicode keysyms are within keysym_to_name keysyms range. */
|
||||
if (iter->keysym >= keysym_to_name[iter->index].keysym)
|
||||
iter->index++;
|
||||
if (iter->keysym >= XKB_KEYSYM_UNICODE_MIN) {
|
||||
/* Continue Unicode keysyms */
|
||||
iter->keysym++;
|
||||
} else {
|
||||
/* Start Unicode keysyms */
|
||||
iter->keysym = XKB_KEYSYM_UNICODE_MIN;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the numeric part of a 0xXXXX and UXXXX keysym.
|
||||
* Not using strtoul -- it's slower and accepts a bunch of stuff
|
||||
* we don't want to allow, like signs, spaces, even locale stuff.
|
||||
*/
|
||||
static bool
|
||||
parse_keysym_hex(const char *s, uint32_t *out)
|
||||
{
|
||||
uint32_t result = 0;
|
||||
int i;
|
||||
for (i = 0; i < 8 && s[i] != '\0'; i++) {
|
||||
result <<= 4;
|
||||
if ('0' <= s[i] && s[i] <= '9')
|
||||
result += s[i] - '0';
|
||||
else if ('a' <= s[i] && s[i] <= 'f')
|
||||
result += 10 + s[i] - 'a';
|
||||
else if ('A' <= s[i] && s[i] <= 'F')
|
||||
result += 10 + s[i] - 'A';
|
||||
else
|
||||
return false;
|
||||
}
|
||||
*out = result;
|
||||
return s[i] == '\0' && i > 0;
|
||||
}
|
||||
|
||||
XKB_EXPORT xkb_keysym_t
|
||||
xkb_keysym_from_name(const char *name, enum xkb_keysym_flags flags)
|
||||
{
|
||||
const struct name_keysym *entry = NULL;
|
||||
char *tmp;
|
||||
uint32_t val;
|
||||
bool icase = (flags & XKB_KEYSYM_CASE_INSENSITIVE);
|
||||
|
||||
if (flags & ~XKB_KEYSYM_CASE_INSENSITIVE)
|
||||
return XKB_KEY_NoSymbol;
|
||||
|
||||
/*
|
||||
* We need to !icase case to be fast, for e.g. Compose file parsing.
|
||||
* So do it in a fast path.
|
||||
*/
|
||||
if (!icase) {
|
||||
size_t pos = keysym_name_perfect_hash(name);
|
||||
if (pos < ARRAY_SIZE(name_to_keysym)) {
|
||||
const char *s = get_name(&name_to_keysym[pos]);
|
||||
if (strcmp(name, s) == 0)
|
||||
return name_to_keysym[pos].keysym;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Find the correct keysym for case-insensitive match.
|
||||
*
|
||||
* The name_to_keysym table is sorted by istrcmp(). So the binary
|
||||
* search may return _any_ of all possible case-insensitive duplicates. The
|
||||
* duplicates are sorted so that the "best" case-insensitive match comes
|
||||
* last. So the code searches the entry and all next entries that match by
|
||||
* case-insensitive comparison and returns the "best" case-insensitive match.
|
||||
*
|
||||
* The "best" case-insensitive match is the lower-case keysym name. Most
|
||||
* keysyms names that only differ by letter-case are keysyms that are
|
||||
* available as “small” and “big” variants. For example:
|
||||
*
|
||||
* - Bicameral scripts: Lower-case and upper-case variants,
|
||||
* e.g. KEY_a and KEY_A.
|
||||
* - Non-bicameral scripts: e.g. KEY_kana_a and KEY_kana_A.
|
||||
*
|
||||
* There are some exceptions, e.g. `XF86Screensaver` and `XF86ScreenSaver`.
|
||||
*/
|
||||
else {
|
||||
int32_t lo = 0, hi = ARRAY_SIZE(name_to_keysym) - 1;
|
||||
while (hi >= lo) {
|
||||
int32_t mid = (lo + hi) / 2;
|
||||
int cmp = istrcmp(name, get_name(&name_to_keysym[mid]));
|
||||
if (cmp > 0) {
|
||||
lo = mid + 1;
|
||||
} else if (cmp < 0) {
|
||||
hi = mid - 1;
|
||||
} else {
|
||||
entry = &name_to_keysym[mid];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (entry) {
|
||||
const struct name_keysym *last;
|
||||
last = name_to_keysym + ARRAY_SIZE(name_to_keysym) - 1;
|
||||
/* Keep going until we reach end of array
|
||||
* or non case-insensitve match */
|
||||
while (entry < last &&
|
||||
istrcmp(get_name(entry + 1), get_name(entry)) == 0) {
|
||||
entry++;
|
||||
}
|
||||
return entry->keysym;
|
||||
}
|
||||
}
|
||||
|
||||
if (*name == 'U' || (icase && *name == 'u')) {
|
||||
if (!parse_keysym_hex(&name[1], &val))
|
||||
return XKB_KEY_NoSymbol;
|
||||
|
||||
if (val < 0x20 || (val > 0x7e && val < 0xa0))
|
||||
return XKB_KEY_NoSymbol;
|
||||
if (val < 0x100)
|
||||
return (xkb_keysym_t) val;
|
||||
if (val > 0x10ffff)
|
||||
return XKB_KEY_NoSymbol;
|
||||
return (xkb_keysym_t) val | XKB_KEYSYM_UNICODE_OFFSET;
|
||||
}
|
||||
else if (name[0] == '0' && (name[1] == 'x' || (icase && name[1] == 'X'))) {
|
||||
if (!parse_keysym_hex(&name[2], &val))
|
||||
return XKB_KEY_NoSymbol;
|
||||
if (val > XKB_KEYSYM_MAX)
|
||||
return XKB_KEY_NoSymbol;
|
||||
return (xkb_keysym_t) val;
|
||||
}
|
||||
|
||||
/* Stupid inconsistency between the headers and XKeysymDB: the former has
|
||||
* no separating underscore, while some XF86* syms in the latter did.
|
||||
* As a last ditch effort, try without. */
|
||||
if (strncmp(name, "XF86_", 5) == 0 ||
|
||||
(icase && istrncmp(name, "XF86_", 5) == 0)) {
|
||||
xkb_keysym_t ret;
|
||||
tmp = strdup(name);
|
||||
if (!tmp)
|
||||
return XKB_KEY_NoSymbol;
|
||||
memmove(&tmp[4], &tmp[5], strlen(name) - 5 + 1);
|
||||
ret = xkb_keysym_from_name(tmp, flags);
|
||||
free(tmp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return XKB_KEY_NoSymbol;
|
||||
}
|
||||
|
||||
bool
|
||||
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) ||
|
||||
(keysym >= XKB_KEY_ISO_Lock && keysym <= XKB_KEY_ISO_Level5_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);
|
||||
|
||||
bool
|
||||
xkb_keysym_is_lower(xkb_keysym_t ks)
|
||||
{
|
||||
xkb_keysym_t lower, upper;
|
||||
|
||||
XConvertCase(ks, &lower, &upper);
|
||||
|
||||
if (lower == upper)
|
||||
return false;
|
||||
|
||||
return (ks == lower ? true : false);
|
||||
}
|
||||
|
||||
bool
|
||||
xkb_keysym_is_upper(xkb_keysym_t ks)
|
||||
{
|
||||
xkb_keysym_t lower, upper;
|
||||
|
||||
XConvertCase(ks, &lower, &upper);
|
||||
|
||||
if (lower == upper)
|
||||
return false;
|
||||
|
||||
return (ks == upper ? true : false);
|
||||
}
|
||||
|
||||
XKB_EXPORT xkb_keysym_t
|
||||
xkb_keysym_to_lower(xkb_keysym_t ks)
|
||||
{
|
||||
xkb_keysym_t lower, upper;
|
||||
|
||||
XConvertCase(ks, &lower, &upper);
|
||||
|
||||
return lower;
|
||||
}
|
||||
|
||||
XKB_EXPORT xkb_keysym_t
|
||||
xkb_keysym_to_upper(xkb_keysym_t ks)
|
||||
{
|
||||
xkb_keysym_t lower, upper;
|
||||
|
||||
XConvertCase(ks, &lower, &upper);
|
||||
|
||||
return upper;
|
||||
}
|
||||
|
||||
/*
|
||||
* The following is copied verbatim from libX11:src/KeyBind.c, commit
|
||||
* d45b3fc19fbe95c41afc4e51d768df6d42332010, with the following changes:
|
||||
* - unsigned -> uint32_t
|
||||
* - unsigend short -> uint16_t
|
||||
* - s/XK_/XKB_KEY_
|
||||
*
|
||||
* XXX: If newlocale() and iswlower_l()/iswupper_l() interface ever
|
||||
* become portable, we should use that in conjunction with
|
||||
* xkb_keysym_to_utf32(), instead of all this stuff. We should
|
||||
* be sure to give the same results as libX11, though, and be
|
||||
* locale independent; this information is used by xkbcomp to
|
||||
* find the automatic type to assign to key groups.
|
||||
*/
|
||||
|
||||
static void
|
||||
UCSConvertCase(uint32_t code, xkb_keysym_t *lower, xkb_keysym_t *upper)
|
||||
{
|
||||
/* Case conversion for UCS, as in Unicode Data version 4.0.0 */
|
||||
/* NB: Only converts simple one-to-one mappings. */
|
||||
|
||||
/* Tables are used where they take less space than */
|
||||
/* the code to work out the mappings. Zero values mean */
|
||||
/* undefined code points. */
|
||||
|
||||
static uint16_t const IPAExt_upper_mapping[] = { /* part only */
|
||||
0x0181, 0x0186, 0x0255, 0x0189, 0x018A,
|
||||
0x0258, 0x018F, 0x025A, 0x0190, 0x025C, 0x025D, 0x025E, 0x025F,
|
||||
0x0193, 0x0261, 0x0262, 0x0194, 0x0264, 0x0265, 0x0266, 0x0267,
|
||||
0x0197, 0x0196, 0x026A, 0x026B, 0x026C, 0x026D, 0x026E, 0x019C,
|
||||
0x0270, 0x0271, 0x019D, 0x0273, 0x0274, 0x019F, 0x0276, 0x0277,
|
||||
0x0278, 0x0279, 0x027A, 0x027B, 0x027C, 0x027D, 0x027E, 0x027F,
|
||||
0x01A6, 0x0281, 0x0282, 0x01A9, 0x0284, 0x0285, 0x0286, 0x0287,
|
||||
0x01AE, 0x0289, 0x01B1, 0x01B2, 0x028C, 0x028D, 0x028E, 0x028F,
|
||||
0x0290, 0x0291, 0x01B7
|
||||
};
|
||||
|
||||
static uint16_t const LatinExtB_upper_mapping[] = { /* first part only */
|
||||
0x0180, 0x0181, 0x0182, 0x0182, 0x0184, 0x0184, 0x0186, 0x0187,
|
||||
0x0187, 0x0189, 0x018A, 0x018B, 0x018B, 0x018D, 0x018E, 0x018F,
|
||||
0x0190, 0x0191, 0x0191, 0x0193, 0x0194, 0x01F6, 0x0196, 0x0197,
|
||||
0x0198, 0x0198, 0x019A, 0x019B, 0x019C, 0x019D, 0x0220, 0x019F,
|
||||
0x01A0, 0x01A0, 0x01A2, 0x01A2, 0x01A4, 0x01A4, 0x01A6, 0x01A7,
|
||||
0x01A7, 0x01A9, 0x01AA, 0x01AB, 0x01AC, 0x01AC, 0x01AE, 0x01AF,
|
||||
0x01AF, 0x01B1, 0x01B2, 0x01B3, 0x01B3, 0x01B5, 0x01B5, 0x01B7,
|
||||
0x01B8, 0x01B8, 0x01BA, 0x01BB, 0x01BC, 0x01BC, 0x01BE, 0x01F7,
|
||||
0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C4, 0x01C4, 0x01C4, 0x01C7,
|
||||
0x01C7, 0x01C7, 0x01CA, 0x01CA, 0x01CA
|
||||
};
|
||||
|
||||
static uint16_t const LatinExtB_lower_mapping[] = { /* first part only */
|
||||
0x0180, 0x0253, 0x0183, 0x0183, 0x0185, 0x0185, 0x0254, 0x0188,
|
||||
0x0188, 0x0256, 0x0257, 0x018C, 0x018C, 0x018D, 0x01DD, 0x0259,
|
||||
0x025B, 0x0192, 0x0192, 0x0260, 0x0263, 0x0195, 0x0269, 0x0268,
|
||||
0x0199, 0x0199, 0x019A, 0x019B, 0x026F, 0x0272, 0x019E, 0x0275,
|
||||
0x01A1, 0x01A1, 0x01A3, 0x01A3, 0x01A5, 0x01A5, 0x0280, 0x01A8,
|
||||
0x01A8, 0x0283, 0x01AA, 0x01AB, 0x01AD, 0x01AD, 0x0288, 0x01B0,
|
||||
0x01B0, 0x028A, 0x028B, 0x01B4, 0x01B4, 0x01B6, 0x01B6, 0x0292,
|
||||
0x01B9, 0x01B9, 0x01BA, 0x01BB, 0x01BD, 0x01BD, 0x01BE, 0x01BF,
|
||||
0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C6, 0x01C6, 0x01C6, 0x01C9,
|
||||
0x01C9, 0x01C9, 0x01CC, 0x01CC, 0x01CC
|
||||
};
|
||||
|
||||
static uint16_t const Greek_upper_mapping[] = {
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0374, 0x0375, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x037A, 0x0000, 0x0000, 0x0000, 0x037E, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0384, 0x0385, 0x0386, 0x0387,
|
||||
0x0388, 0x0389, 0x038A, 0x0000, 0x038C, 0x0000, 0x038E, 0x038F,
|
||||
0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
|
||||
0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
|
||||
0x03A0, 0x03A1, 0x0000, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7,
|
||||
0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x0386, 0x0388, 0x0389, 0x038A,
|
||||
0x03B0, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
|
||||
0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
|
||||
0x03A0, 0x03A1, 0x03A3, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7,
|
||||
0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x038C, 0x038E, 0x038F, 0x0000,
|
||||
0x0392, 0x0398, 0x03D2, 0x03D3, 0x03D4, 0x03A6, 0x03A0, 0x03D7,
|
||||
0x03D8, 0x03D8, 0x03DA, 0x03DA, 0x03DC, 0x03DC, 0x03DE, 0x03DE,
|
||||
0x03E0, 0x03E0, 0x03E2, 0x03E2, 0x03E4, 0x03E4, 0x03E6, 0x03E6,
|
||||
0x03E8, 0x03E8, 0x03EA, 0x03EA, 0x03EC, 0x03EC, 0x03EE, 0x03EE,
|
||||
0x039A, 0x03A1, 0x03F9, 0x03F3, 0x03F4, 0x0395, 0x03F6, 0x03F7,
|
||||
0x03F7, 0x03F9, 0x03FA, 0x03FA, 0x0000, 0x0000, 0x0000, 0x0000
|
||||
};
|
||||
|
||||
static uint16_t const Greek_lower_mapping[] = {
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0374, 0x0375, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x037A, 0x0000, 0x0000, 0x0000, 0x037E, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0384, 0x0385, 0x03AC, 0x0387,
|
||||
0x03AD, 0x03AE, 0x03AF, 0x0000, 0x03CC, 0x0000, 0x03CD, 0x03CE,
|
||||
0x0390, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
|
||||
0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
|
||||
0x03C0, 0x03C1, 0x0000, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
|
||||
0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
|
||||
0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
|
||||
0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
|
||||
0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
|
||||
0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x0000,
|
||||
0x03D0, 0x03D1, 0x03D2, 0x03D3, 0x03D4, 0x03D5, 0x03D6, 0x03D7,
|
||||
0x03D9, 0x03D9, 0x03DB, 0x03DB, 0x03DD, 0x03DD, 0x03DF, 0x03DF,
|
||||
0x03E1, 0x03E1, 0x03E3, 0x03E3, 0x03E5, 0x03E5, 0x03E7, 0x03E7,
|
||||
0x03E9, 0x03E9, 0x03EB, 0x03EB, 0x03ED, 0x03ED, 0x03EF, 0x03EF,
|
||||
0x03F0, 0x03F1, 0x03F2, 0x03F3, 0x03B8, 0x03F5, 0x03F6, 0x03F8,
|
||||
0x03F8, 0x03F2, 0x03FB, 0x03FB, 0x0000, 0x0000, 0x0000, 0x0000
|
||||
};
|
||||
|
||||
static uint16_t const GreekExt_lower_mapping[] = {
|
||||
0x1F00, 0x1F01, 0x1F02, 0x1F03, 0x1F04, 0x1F05, 0x1F06, 0x1F07,
|
||||
0x1F00, 0x1F01, 0x1F02, 0x1F03, 0x1F04, 0x1F05, 0x1F06, 0x1F07,
|
||||
0x1F10, 0x1F11, 0x1F12, 0x1F13, 0x1F14, 0x1F15, 0x0000, 0x0000,
|
||||
0x1F10, 0x1F11, 0x1F12, 0x1F13, 0x1F14, 0x1F15, 0x0000, 0x0000,
|
||||
0x1F20, 0x1F21, 0x1F22, 0x1F23, 0x1F24, 0x1F25, 0x1F26, 0x1F27,
|
||||
0x1F20, 0x1F21, 0x1F22, 0x1F23, 0x1F24, 0x1F25, 0x1F26, 0x1F27,
|
||||
0x1F30, 0x1F31, 0x1F32, 0x1F33, 0x1F34, 0x1F35, 0x1F36, 0x1F37,
|
||||
0x1F30, 0x1F31, 0x1F32, 0x1F33, 0x1F34, 0x1F35, 0x1F36, 0x1F37,
|
||||
0x1F40, 0x1F41, 0x1F42, 0x1F43, 0x1F44, 0x1F45, 0x0000, 0x0000,
|
||||
0x1F40, 0x1F41, 0x1F42, 0x1F43, 0x1F44, 0x1F45, 0x0000, 0x0000,
|
||||
0x1F50, 0x1F51, 0x1F52, 0x1F53, 0x1F54, 0x1F55, 0x1F56, 0x1F57,
|
||||
0x0000, 0x1F51, 0x0000, 0x1F53, 0x0000, 0x1F55, 0x0000, 0x1F57,
|
||||
0x1F60, 0x1F61, 0x1F62, 0x1F63, 0x1F64, 0x1F65, 0x1F66, 0x1F67,
|
||||
0x1F60, 0x1F61, 0x1F62, 0x1F63, 0x1F64, 0x1F65, 0x1F66, 0x1F67,
|
||||
0x1F70, 0x1F71, 0x1F72, 0x1F73, 0x1F74, 0x1F75, 0x1F76, 0x1F77,
|
||||
0x1F78, 0x1F79, 0x1F7A, 0x1F7B, 0x1F7C, 0x1F7D, 0x0000, 0x0000,
|
||||
0x1F80, 0x1F81, 0x1F82, 0x1F83, 0x1F84, 0x1F85, 0x1F86, 0x1F87,
|
||||
0x1F80, 0x1F81, 0x1F82, 0x1F83, 0x1F84, 0x1F85, 0x1F86, 0x1F87,
|
||||
0x1F90, 0x1F91, 0x1F92, 0x1F93, 0x1F94, 0x1F95, 0x1F96, 0x1F97,
|
||||
0x1F90, 0x1F91, 0x1F92, 0x1F93, 0x1F94, 0x1F95, 0x1F96, 0x1F97,
|
||||
0x1FA0, 0x1FA1, 0x1FA2, 0x1FA3, 0x1FA4, 0x1FA5, 0x1FA6, 0x1FA7,
|
||||
0x1FA0, 0x1FA1, 0x1FA2, 0x1FA3, 0x1FA4, 0x1FA5, 0x1FA6, 0x1FA7,
|
||||
0x1FB0, 0x1FB1, 0x1FB2, 0x1FB3, 0x1FB4, 0x0000, 0x1FB6, 0x1FB7,
|
||||
0x1FB0, 0x1FB1, 0x1F70, 0x1F71, 0x1FB3, 0x1FBD, 0x1FBE, 0x1FBF,
|
||||
0x1FC0, 0x1FC1, 0x1FC2, 0x1FC3, 0x1FC4, 0x0000, 0x1FC6, 0x1FC7,
|
||||
0x1F72, 0x1F73, 0x1F74, 0x1F75, 0x1FC3, 0x1FCD, 0x1FCE, 0x1FCF,
|
||||
0x1FD0, 0x1FD1, 0x1FD2, 0x1FD3, 0x0000, 0x0000, 0x1FD6, 0x1FD7,
|
||||
0x1FD0, 0x1FD1, 0x1F76, 0x1F77, 0x0000, 0x1FDD, 0x1FDE, 0x1FDF,
|
||||
0x1FE0, 0x1FE1, 0x1FE2, 0x1FE3, 0x1FE4, 0x1FE5, 0x1FE6, 0x1FE7,
|
||||
0x1FE0, 0x1FE1, 0x1F7A, 0x1F7B, 0x1FE5, 0x1FED, 0x1FEE, 0x1FEF,
|
||||
0x0000, 0x0000, 0x1FF2, 0x1FF3, 0x1FF4, 0x0000, 0x1FF6, 0x1FF7,
|
||||
0x1F78, 0x1F79, 0x1F7C, 0x1F7D, 0x1FF3, 0x1FFD, 0x1FFE, 0x0000
|
||||
};
|
||||
|
||||
static uint16_t const GreekExt_upper_mapping[] = {
|
||||
0x1F08, 0x1F09, 0x1F0A, 0x1F0B, 0x1F0C, 0x1F0D, 0x1F0E, 0x1F0F,
|
||||
0x1F08, 0x1F09, 0x1F0A, 0x1F0B, 0x1F0C, 0x1F0D, 0x1F0E, 0x1F0F,
|
||||
0x1F18, 0x1F19, 0x1F1A, 0x1F1B, 0x1F1C, 0x1F1D, 0x0000, 0x0000,
|
||||
0x1F18, 0x1F19, 0x1F1A, 0x1F1B, 0x1F1C, 0x1F1D, 0x0000, 0x0000,
|
||||
0x1F28, 0x1F29, 0x1F2A, 0x1F2B, 0x1F2C, 0x1F2D, 0x1F2E, 0x1F2F,
|
||||
0x1F28, 0x1F29, 0x1F2A, 0x1F2B, 0x1F2C, 0x1F2D, 0x1F2E, 0x1F2F,
|
||||
0x1F38, 0x1F39, 0x1F3A, 0x1F3B, 0x1F3C, 0x1F3D, 0x1F3E, 0x1F3F,
|
||||
0x1F38, 0x1F39, 0x1F3A, 0x1F3B, 0x1F3C, 0x1F3D, 0x1F3E, 0x1F3F,
|
||||
0x1F48, 0x1F49, 0x1F4A, 0x1F4B, 0x1F4C, 0x1F4D, 0x0000, 0x0000,
|
||||
0x1F48, 0x1F49, 0x1F4A, 0x1F4B, 0x1F4C, 0x1F4D, 0x0000, 0x0000,
|
||||
0x1F50, 0x1F59, 0x1F52, 0x1F5B, 0x1F54, 0x1F5D, 0x1F56, 0x1F5F,
|
||||
0x0000, 0x1F59, 0x0000, 0x1F5B, 0x0000, 0x1F5D, 0x0000, 0x1F5F,
|
||||
0x1F68, 0x1F69, 0x1F6A, 0x1F6B, 0x1F6C, 0x1F6D, 0x1F6E, 0x1F6F,
|
||||
0x1F68, 0x1F69, 0x1F6A, 0x1F6B, 0x1F6C, 0x1F6D, 0x1F6E, 0x1F6F,
|
||||
0x1FBA, 0x1FBB, 0x1FC8, 0x1FC9, 0x1FCA, 0x1FCB, 0x1FDA, 0x1FDB,
|
||||
0x1FF8, 0x1FF9, 0x1FEA, 0x1FEB, 0x1FFA, 0x1FFB, 0x0000, 0x0000,
|
||||
0x1F88, 0x1F89, 0x1F8A, 0x1F8B, 0x1F8C, 0x1F8D, 0x1F8E, 0x1F8F,
|
||||
0x1F88, 0x1F89, 0x1F8A, 0x1F8B, 0x1F8C, 0x1F8D, 0x1F8E, 0x1F8F,
|
||||
0x1F98, 0x1F99, 0x1F9A, 0x1F9B, 0x1F9C, 0x1F9D, 0x1F9E, 0x1F9F,
|
||||
0x1F98, 0x1F99, 0x1F9A, 0x1F9B, 0x1F9C, 0x1F9D, 0x1F9E, 0x1F9F,
|
||||
0x1FA8, 0x1FA9, 0x1FAA, 0x1FAB, 0x1FAC, 0x1FAD, 0x1FAE, 0x1FAF,
|
||||
0x1FA8, 0x1FA9, 0x1FAA, 0x1FAB, 0x1FAC, 0x1FAD, 0x1FAE, 0x1FAF,
|
||||
0x1FB8, 0x1FB9, 0x1FB2, 0x1FBC, 0x1FB4, 0x0000, 0x1FB6, 0x1FB7,
|
||||
0x1FB8, 0x1FB9, 0x1FBA, 0x1FBB, 0x1FBC, 0x1FBD, 0x0399, 0x1FBF,
|
||||
0x1FC0, 0x1FC1, 0x1FC2, 0x1FCC, 0x1FC4, 0x0000, 0x1FC6, 0x1FC7,
|
||||
0x1FC8, 0x1FC9, 0x1FCA, 0x1FCB, 0x1FCC, 0x1FCD, 0x1FCE, 0x1FCF,
|
||||
0x1FD8, 0x1FD9, 0x1FD2, 0x1FD3, 0x0000, 0x0000, 0x1FD6, 0x1FD7,
|
||||
0x1FD8, 0x1FD9, 0x1FDA, 0x1FDB, 0x0000, 0x1FDD, 0x1FDE, 0x1FDF,
|
||||
0x1FE8, 0x1FE9, 0x1FE2, 0x1FE3, 0x1FE4, 0x1FEC, 0x1FE6, 0x1FE7,
|
||||
0x1FE8, 0x1FE9, 0x1FEA, 0x1FEB, 0x1FEC, 0x1FED, 0x1FEE, 0x1FEF,
|
||||
0x0000, 0x0000, 0x1FF2, 0x1FFC, 0x1FF4, 0x0000, 0x1FF6, 0x1FF7,
|
||||
0x1FF8, 0x1FF9, 0x1FFA, 0x1FFB, 0x1FFC, 0x1FFD, 0x1FFE, 0x0000
|
||||
};
|
||||
|
||||
*lower = code;
|
||||
*upper = code;
|
||||
|
||||
/* Basic Latin and Latin-1 Supplement, U+0000 to U+00FF */
|
||||
if (code <= 0x00ff) {
|
||||
if (code >= 0x0041 && code <= 0x005a) /* A-Z */
|
||||
*lower += 0x20;
|
||||
else if (code >= 0x0061 && code <= 0x007a) /* a-z */
|
||||
*upper -= 0x20;
|
||||
else if ( (code >= 0x00c0 && code <= 0x00d6) ||
|
||||
(code >= 0x00d8 && code <= 0x00de) )
|
||||
*lower += 0x20;
|
||||
else if ( (code >= 0x00e0 && code <= 0x00f6) ||
|
||||
(code >= 0x00f8 && code <= 0x00fe) )
|
||||
*upper -= 0x20;
|
||||
else if (code == 0x00ff) /* y with diaeresis */
|
||||
*upper = 0x0178;
|
||||
else if (code == 0x00b5) /* micro sign */
|
||||
*upper = 0x039c;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Latin Extended-A, U+0100 to U+017F */
|
||||
if (code >= 0x0100 && code <= 0x017f) {
|
||||
if ( (code >= 0x0100 && code <= 0x012f) ||
|
||||
(code >= 0x0132 && code <= 0x0137) ||
|
||||
(code >= 0x014a && code <= 0x0177) ) {
|
||||
*upper = code & ~1;
|
||||
*lower = code | 1;
|
||||
}
|
||||
else if ( (code >= 0x0139 && code <= 0x0148) ||
|
||||
(code >= 0x0179 && code <= 0x017e) ) {
|
||||
if (code & 1)
|
||||
*lower += 1;
|
||||
else
|
||||
*upper -= 1;
|
||||
}
|
||||
else if (code == 0x0130)
|
||||
*lower = 0x0069;
|
||||
else if (code == 0x0131)
|
||||
*upper = 0x0049;
|
||||
else if (code == 0x0178)
|
||||
*lower = 0x00ff;
|
||||
else if (code == 0x017f)
|
||||
*upper = 0x0053;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Latin Extended-B, U+0180 to U+024F */
|
||||
if (code >= 0x0180 && code <= 0x024f) {
|
||||
if (code >= 0x01cd && code <= 0x01dc) {
|
||||
if (code & 1)
|
||||
*lower += 1;
|
||||
else
|
||||
*upper -= 1;
|
||||
}
|
||||
else if ( (code >= 0x01de && code <= 0x01ef) ||
|
||||
(code >= 0x01f4 && code <= 0x01f5) ||
|
||||
(code >= 0x01f8 && code <= 0x021f) ||
|
||||
(code >= 0x0222 && code <= 0x0233) ) {
|
||||
*lower |= 1;
|
||||
*upper &= ~1;
|
||||
}
|
||||
else if (code >= 0x0180 && code <= 0x01cc) {
|
||||
*lower = LatinExtB_lower_mapping[code - 0x0180];
|
||||
*upper = LatinExtB_upper_mapping[code - 0x0180];
|
||||
}
|
||||
else if (code == 0x01dd)
|
||||
*upper = 0x018e;
|
||||
else if (code == 0x01f1 || code == 0x01f2) {
|
||||
*lower = 0x01f3;
|
||||
*upper = 0x01f1;
|
||||
}
|
||||
else if (code == 0x01f3)
|
||||
*upper = 0x01f1;
|
||||
else if (code == 0x01f6)
|
||||
*lower = 0x0195;
|
||||
else if (code == 0x01f7)
|
||||
*lower = 0x01bf;
|
||||
else if (code == 0x0220)
|
||||
*lower = 0x019e;
|
||||
return;
|
||||
}
|
||||
|
||||
/* IPA Extensions, U+0250 to U+02AF */
|
||||
if (code >= 0x0253 && code <= 0x0292) {
|
||||
*upper = IPAExt_upper_mapping[code - 0x0253];
|
||||
}
|
||||
|
||||
/* Combining Diacritical Marks, U+0300 to U+036F */
|
||||
if (code == 0x0345) {
|
||||
*upper = 0x0399;
|
||||
}
|
||||
|
||||
/* Greek and Coptic, U+0370 to U+03FF */
|
||||
if (code >= 0x0370 && code <= 0x03ff) {
|
||||
*lower = Greek_lower_mapping[code - 0x0370];
|
||||
*upper = Greek_upper_mapping[code - 0x0370];
|
||||
if (*upper == 0)
|
||||
*upper = code;
|
||||
if (*lower == 0)
|
||||
*lower = code;
|
||||
}
|
||||
|
||||
/* Cyrillic and Cyrillic Supplementary, U+0400 to U+052F */
|
||||
if ( (code >= 0x0400 && code <= 0x04ff) ||
|
||||
(code >= 0x0500 && code <= 0x052f) ) {
|
||||
if (code >= 0x0400 && code <= 0x040f)
|
||||
*lower += 0x50;
|
||||
else if (code >= 0x0410 && code <= 0x042f)
|
||||
*lower += 0x20;
|
||||
else if (code >= 0x0430 && code <= 0x044f)
|
||||
*upper -= 0x20;
|
||||
else if (code >= 0x0450 && code <= 0x045f)
|
||||
*upper -= 0x50;
|
||||
else if ( (code >= 0x0460 && code <= 0x0481) ||
|
||||
(code >= 0x048a && code <= 0x04bf) ||
|
||||
(code >= 0x04d0 && code <= 0x04f5) ||
|
||||
(code >= 0x04f8 && code <= 0x04f9) ||
|
||||
(code >= 0x0500 && code <= 0x050f) ) {
|
||||
*upper &= ~1;
|
||||
*lower |= 1;
|
||||
}
|
||||
else if (code >= 0x04c1 && code <= 0x04ce) {
|
||||
if (code & 1)
|
||||
*lower += 1;
|
||||
else
|
||||
*upper -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Armenian, U+0530 to U+058F */
|
||||
if (code >= 0x0530 && code <= 0x058f) {
|
||||
if (code >= 0x0531 && code <= 0x0556)
|
||||
*lower += 0x30;
|
||||
else if (code >=0x0561 && code <= 0x0586)
|
||||
*upper -= 0x30;
|
||||
}
|
||||
|
||||
/* Latin Extended Additional, U+1E00 to U+1EFF */
|
||||
if (code >= 0x1e00 && code <= 0x1eff) {
|
||||
if ( (code >= 0x1e00 && code <= 0x1e95) ||
|
||||
(code >= 0x1ea0 && code <= 0x1ef9) ) {
|
||||
*upper &= ~1;
|
||||
*lower |= 1;
|
||||
}
|
||||
else if (code == 0x1e9b)
|
||||
*upper = 0x1e60;
|
||||
else if (code == 0x1e9e)
|
||||
*lower = 0x00df; /* ssharp */
|
||||
}
|
||||
|
||||
/* Greek Extended, U+1F00 to U+1FFF */
|
||||
if (code >= 0x1f00 && code <= 0x1fff) {
|
||||
*lower = GreekExt_lower_mapping[code - 0x1f00];
|
||||
*upper = GreekExt_upper_mapping[code - 0x1f00];
|
||||
if (*upper == 0)
|
||||
*upper = code;
|
||||
if (*lower == 0)
|
||||
*lower = code;
|
||||
}
|
||||
|
||||
/* Letterlike Symbols, U+2100 to U+214F */
|
||||
if (code >= 0x2100 && code <= 0x214f) {
|
||||
switch (code) {
|
||||
case 0x2126: *lower = 0x03c9; break;
|
||||
case 0x212a: *lower = 0x006b; break;
|
||||
case 0x212b: *lower = 0x00e5; break;
|
||||
}
|
||||
}
|
||||
/* Number Forms, U+2150 to U+218F */
|
||||
else if (code >= 0x2160 && code <= 0x216f)
|
||||
*lower += 0x10;
|
||||
else if (code >= 0x2170 && code <= 0x217f)
|
||||
*upper -= 0x10;
|
||||
/* Enclosed Alphanumerics, U+2460 to U+24FF */
|
||||
else if (code >= 0x24b6 && code <= 0x24cf)
|
||||
*lower += 0x1a;
|
||||
else if (code >= 0x24d0 && code <= 0x24e9)
|
||||
*upper -= 0x1a;
|
||||
/* Halfwidth and Fullwidth Forms, U+FF00 to U+FFEF */
|
||||
else if (code >= 0xff21 && code <= 0xff3a)
|
||||
*lower += 0x20;
|
||||
else if (code >= 0xff41 && code <= 0xff5a)
|
||||
*upper -= 0x20;
|
||||
/* Deseret, U+10400 to U+104FF */
|
||||
else if (code >= 0x10400 && code <= 0x10427)
|
||||
*lower += 0x28;
|
||||
else if (code >= 0x10428 && code <= 0x1044f)
|
||||
*upper -= 0x28;
|
||||
}
|
||||
|
||||
static void
|
||||
XConvertCase(xkb_keysym_t sym, xkb_keysym_t *lower, xkb_keysym_t *upper)
|
||||
{
|
||||
/* Latin 1 keysym (first part: fast path) */
|
||||
if (sym < 0xb5) {
|
||||
UCSConvertCase(sym, lower, upper);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Unicode keysym */
|
||||
if ((sym & 0xff000000) == XKB_KEYSYM_UNICODE_OFFSET) {
|
||||
UCSConvertCase((sym & 0x00ffffff), lower, upper);
|
||||
*upper |= XKB_KEYSYM_UNICODE_OFFSET;
|
||||
*lower |= XKB_KEYSYM_UNICODE_OFFSET;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Legacy keysym */
|
||||
|
||||
*lower = sym;
|
||||
*upper = sym;
|
||||
|
||||
switch(sym >> 8) {
|
||||
case 0: /* Latin 1 (second part) */
|
||||
if (sym == XKB_KEY_mu)
|
||||
*upper = XKB_KEY_Greek_MU;
|
||||
else if (sym == XKB_KEY_ydiaeresis)
|
||||
*upper = XKB_KEY_Ydiaeresis;
|
||||
else
|
||||
UCSConvertCase(sym, lower, upper);
|
||||
break;
|
||||
case 1: /* Latin 2 */
|
||||
/* Assume the KeySym is a legal value (ignore discontinuities) */
|
||||
if (sym == XKB_KEY_Aogonek)
|
||||
*lower = XKB_KEY_aogonek;
|
||||
else if (sym >= XKB_KEY_Lstroke && sym <= XKB_KEY_Sacute)
|
||||
*lower += (XKB_KEY_lstroke - XKB_KEY_Lstroke);
|
||||
else if (sym >= XKB_KEY_Scaron && sym <= XKB_KEY_Zacute)
|
||||
*lower += (XKB_KEY_scaron - XKB_KEY_Scaron);
|
||||
else if (sym >= XKB_KEY_Zcaron && sym <= XKB_KEY_Zabovedot)
|
||||
*lower += (XKB_KEY_zcaron - XKB_KEY_Zcaron);
|
||||
else if (sym == XKB_KEY_aogonek)
|
||||
*upper = XKB_KEY_Aogonek;
|
||||
else if (sym >= XKB_KEY_lstroke && sym <= XKB_KEY_sacute)
|
||||
*upper -= (XKB_KEY_lstroke - XKB_KEY_Lstroke);
|
||||
else if (sym >= XKB_KEY_scaron && sym <= XKB_KEY_zacute)
|
||||
*upper -= (XKB_KEY_scaron - XKB_KEY_Scaron);
|
||||
else if (sym >= XKB_KEY_zcaron && sym <= XKB_KEY_zabovedot)
|
||||
*upper -= (XKB_KEY_zcaron - XKB_KEY_Zcaron);
|
||||
else if (sym >= XKB_KEY_Racute && sym <= XKB_KEY_Tcedilla)
|
||||
*lower += (XKB_KEY_racute - XKB_KEY_Racute);
|
||||
else if (sym >= XKB_KEY_racute && sym <= XKB_KEY_tcedilla)
|
||||
*upper -= (XKB_KEY_racute - XKB_KEY_Racute);
|
||||
break;
|
||||
case 2: /* Latin 3 */
|
||||
/* Assume the KeySym is a legal value (ignore discontinuities) */
|
||||
if (sym >= XKB_KEY_Hstroke && sym <= XKB_KEY_Hcircumflex)
|
||||
*lower += (XKB_KEY_hstroke - XKB_KEY_Hstroke);
|
||||
else if (sym >= XKB_KEY_Gbreve && sym <= XKB_KEY_Jcircumflex)
|
||||
*lower += (XKB_KEY_gbreve - XKB_KEY_Gbreve);
|
||||
else if (sym >= XKB_KEY_hstroke && sym <= XKB_KEY_hcircumflex)
|
||||
*upper -= (XKB_KEY_hstroke - XKB_KEY_Hstroke);
|
||||
else if (sym >= XKB_KEY_gbreve && sym <= XKB_KEY_jcircumflex)
|
||||
*upper -= (XKB_KEY_gbreve - XKB_KEY_Gbreve);
|
||||
else if (sym >= XKB_KEY_Cabovedot && sym <= XKB_KEY_Scircumflex)
|
||||
*lower += (XKB_KEY_cabovedot - XKB_KEY_Cabovedot);
|
||||
else if (sym >= XKB_KEY_cabovedot && sym <= XKB_KEY_scircumflex)
|
||||
*upper -= (XKB_KEY_cabovedot - XKB_KEY_Cabovedot);
|
||||
break;
|
||||
case 3: /* Latin 4 */
|
||||
/* Assume the KeySym is a legal value (ignore discontinuities) */
|
||||
if (sym >= XKB_KEY_Rcedilla && sym <= XKB_KEY_Tslash)
|
||||
*lower += (XKB_KEY_rcedilla - XKB_KEY_Rcedilla);
|
||||
else if (sym >= XKB_KEY_rcedilla && sym <= XKB_KEY_tslash)
|
||||
*upper -= (XKB_KEY_rcedilla - XKB_KEY_Rcedilla);
|
||||
else if (sym == XKB_KEY_ENG)
|
||||
*lower = XKB_KEY_eng;
|
||||
else if (sym == XKB_KEY_eng)
|
||||
*upper = XKB_KEY_ENG;
|
||||
else if (sym >= XKB_KEY_Amacron && sym <= XKB_KEY_Umacron)
|
||||
*lower += (XKB_KEY_amacron - XKB_KEY_Amacron);
|
||||
else if (sym >= XKB_KEY_amacron && sym <= XKB_KEY_umacron)
|
||||
*upper -= (XKB_KEY_amacron - XKB_KEY_Amacron);
|
||||
break;
|
||||
case 6: /* Cyrillic */
|
||||
/* Assume the KeySym is a legal value (ignore discontinuities) */
|
||||
if (sym >= XKB_KEY_Serbian_DJE && sym <= XKB_KEY_Cyrillic_DZHE)
|
||||
*lower -= (XKB_KEY_Serbian_DJE - XKB_KEY_Serbian_dje);
|
||||
else if (sym >= XKB_KEY_Serbian_dje && sym <= XKB_KEY_Cyrillic_dzhe)
|
||||
*upper += (XKB_KEY_Serbian_DJE - XKB_KEY_Serbian_dje);
|
||||
else if (sym >= XKB_KEY_Cyrillic_YU && sym <= XKB_KEY_Cyrillic_HARDSIGN)
|
||||
*lower -= (XKB_KEY_Cyrillic_YU - XKB_KEY_Cyrillic_yu);
|
||||
else if (sym >= XKB_KEY_Cyrillic_yu && sym <= XKB_KEY_Cyrillic_hardsign)
|
||||
*upper += (XKB_KEY_Cyrillic_YU - XKB_KEY_Cyrillic_yu);
|
||||
break;
|
||||
case 7: /* Greek */
|
||||
/* Assume the KeySym is a legal value (ignore discontinuities) */
|
||||
if (sym >= XKB_KEY_Greek_ALPHAaccent && sym <= XKB_KEY_Greek_OMEGAaccent)
|
||||
*lower += (XKB_KEY_Greek_alphaaccent - XKB_KEY_Greek_ALPHAaccent);
|
||||
else if (sym >= XKB_KEY_Greek_alphaaccent && sym <= XKB_KEY_Greek_omegaaccent &&
|
||||
sym != XKB_KEY_Greek_iotaaccentdieresis &&
|
||||
sym != XKB_KEY_Greek_upsilonaccentdieresis)
|
||||
*upper -= (XKB_KEY_Greek_alphaaccent - XKB_KEY_Greek_ALPHAaccent);
|
||||
else if (sym >= XKB_KEY_Greek_ALPHA && sym <= XKB_KEY_Greek_OMEGA)
|
||||
*lower += (XKB_KEY_Greek_alpha - XKB_KEY_Greek_ALPHA);
|
||||
else if (sym >= XKB_KEY_Greek_alpha && sym <= XKB_KEY_Greek_omega &&
|
||||
sym != XKB_KEY_Greek_finalsmallsigma)
|
||||
*upper -= (XKB_KEY_Greek_alpha - XKB_KEY_Greek_ALPHA);
|
||||
break;
|
||||
case 0x13: /* Latin 9 */
|
||||
if (sym == XKB_KEY_OE)
|
||||
*lower = XKB_KEY_oe;
|
||||
else if (sym == XKB_KEY_oe)
|
||||
*upper = XKB_KEY_OE;
|
||||
else if (sym == XKB_KEY_Ydiaeresis)
|
||||
*lower = XKB_KEY_ydiaeresis;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
/*
|
||||
* Copyright 1985, 1987, 1990, 1998 The Open Group
|
||||
*
|
||||
* 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 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 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.
|
||||
*
|
||||
* Except as contained in this notice, the names of the authors or their
|
||||
* institutions shall not be used in advertising or otherwise to promote the
|
||||
* sale, use or other dealings in this Software without prior written
|
||||
* authorization from the authors.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright © 2009 Dan Nicholson
|
||||
*
|
||||
* 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 KEYSYM_H
|
||||
#define KEYSYM_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "xkbcommon/xkbcommon.h"
|
||||
|
||||
/*
|
||||
* NOTE: this is not defined in xkbcommon.h, because if we did, it may add
|
||||
* overhead for library user: when handling keysyms they would also need to
|
||||
* check min keysym when previously there was no reason to.
|
||||
*/
|
||||
/** Minimum keysym value */
|
||||
#define XKB_KEYSYM_MIN 0x00000000
|
||||
/** Minimum keysym value assigned */
|
||||
#define XKB_KEYSYM_MIN_ASSIGNED ((xkb_keysym_t)0x00000000)
|
||||
/** Maximum keysym value assigned */
|
||||
#define XKB_KEYSYM_MAX_ASSIGNED 0x1008ffb8
|
||||
/** Minimum keysym value with explicit name */
|
||||
#define XKB_KEYSYM_MIN_EXPLICIT 0x00000000
|
||||
/** Maximum keysym value with explicit name */
|
||||
#define XKB_KEYSYM_MAX_EXPLICIT 0x1008ffb8
|
||||
/** Count of keysym value with explicit name */
|
||||
#define XKB_KEYSYM_COUNT_EXPLICIT 2446
|
||||
/** Offset to use when converting a Unicode code point to a keysym */
|
||||
#define XKB_KEYSYM_UNICODE_OFFSET 0x01000000
|
||||
/** Minimum Unicode keysym. NOTE: code points in 0..0xff cannot be converted. */
|
||||
#define XKB_KEYSYM_UNICODE_MIN 0x01000100
|
||||
/** Maximum Unicode keysym, correspoding to the maximum Unicode code point */
|
||||
#define XKB_KEYSYM_UNICODE_MAX 0x0110ffff
|
||||
/** Maximum keysym name length */
|
||||
#define XKB_KEYSYM_NAME_MAX_SIZE 27
|
||||
|
||||
bool
|
||||
xkb_keysym_is_assigned(xkb_keysym_t ks);
|
||||
|
||||
struct xkb_keysym_iterator;
|
||||
|
||||
struct xkb_keysym_iterator*
|
||||
xkb_keysym_iterator_new(bool explicit);
|
||||
|
||||
struct xkb_keysym_iterator*
|
||||
xkb_keysym_iterator_unref(struct xkb_keysym_iterator *iter);
|
||||
|
||||
bool
|
||||
xkb_keysym_iterator_next(struct xkb_keysym_iterator *iter);
|
||||
|
||||
xkb_keysym_t
|
||||
xkb_keysym_iterator_get_keysym(struct xkb_keysym_iterator *iter);
|
||||
|
||||
int
|
||||
xkb_keysym_iterator_get_name(struct xkb_keysym_iterator *iter,
|
||||
char *buffer, size_t size);
|
||||
|
||||
bool
|
||||
xkb_keysym_iterator_is_explicitly_named(struct xkb_keysym_iterator *iter);
|
||||
|
||||
bool
|
||||
xkb_keysym_is_lower(xkb_keysym_t keysym);
|
||||
|
||||
bool
|
||||
xkb_keysym_is_upper(xkb_keysym_t keysym);
|
||||
|
||||
bool
|
||||
xkb_keysym_is_keypad(xkb_keysym_t keysym);
|
||||
|
||||
bool
|
||||
xkb_keysym_is_modifier(xkb_keysym_t keysym);
|
||||
|
||||
#endif
|
||||
@@ -1,118 +0,0 @@
|
||||
/*
|
||||
* Copyright 1985, 1987, 1990, 1998 The Open Group
|
||||
*
|
||||
* 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 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 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.
|
||||
*
|
||||
* Except as contained in this notice, the names of the authors or their
|
||||
* institutions shall not be used in advertising or otherwise to promote the
|
||||
* sale, use or other dealings in this Software without prior written
|
||||
* authorization from the authors.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright © 2009 Dan Nicholson
|
||||
*
|
||||
* 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 KEYSYM_H
|
||||
#define KEYSYM_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "xkbcommon/xkbcommon.h"
|
||||
|
||||
/*
|
||||
* NOTE: this is not defined in xkbcommon.h, because if we did, it may add
|
||||
* overhead for library user: when handling keysyms they would also need to
|
||||
* check min keysym when previously there was no reason to.
|
||||
*/
|
||||
/** Minimum keysym value */
|
||||
#define XKB_KEYSYM_MIN 0x00000000
|
||||
/** Minimum keysym value assigned */
|
||||
#define XKB_KEYSYM_MIN_ASSIGNED ((xkb_keysym_t){{ XKB_KEYSYM_MIN_ASSIGNED | keysym }})
|
||||
/** Maximum keysym value assigned */
|
||||
#define XKB_KEYSYM_MAX_ASSIGNED {{ XKB_KEYSYM_MAX_ASSIGNED | keysym }}
|
||||
/** Minimum keysym value with explicit name */
|
||||
#define XKB_KEYSYM_MIN_EXPLICIT {{ XKB_KEYSYM_MIN_EXPLICIT | keysym }}
|
||||
/** Maximum keysym value with explicit name */
|
||||
#define XKB_KEYSYM_MAX_EXPLICIT {{ XKB_KEYSYM_MAX_EXPLICIT | keysym }}
|
||||
/** Count of keysym value with explicit name */
|
||||
#define XKB_KEYSYM_COUNT_EXPLICIT {{ XKB_KEYSYM_COUNT_EXPLICIT }}
|
||||
/** Offset to use when converting a Unicode code point to a keysym */
|
||||
#define XKB_KEYSYM_UNICODE_OFFSET 0x01000000
|
||||
/** Minimum Unicode keysym. NOTE: code points in 0..0xff cannot be converted. */
|
||||
#define XKB_KEYSYM_UNICODE_MIN 0x01000100
|
||||
/** Maximum Unicode keysym, correspoding to the maximum Unicode code point */
|
||||
#define XKB_KEYSYM_UNICODE_MAX 0x0110ffff
|
||||
/** Maximum keysym name length */
|
||||
#define XKB_KEYSYM_NAME_MAX_SIZE {{ XKB_KEYSYM_NAME_MAX_SIZE }}
|
||||
|
||||
bool
|
||||
xkb_keysym_is_assigned(xkb_keysym_t ks);
|
||||
|
||||
struct xkb_keysym_iterator;
|
||||
|
||||
struct xkb_keysym_iterator*
|
||||
xkb_keysym_iterator_new(bool explicit);
|
||||
|
||||
struct xkb_keysym_iterator*
|
||||
xkb_keysym_iterator_unref(struct xkb_keysym_iterator *iter);
|
||||
|
||||
bool
|
||||
xkb_keysym_iterator_next(struct xkb_keysym_iterator *iter);
|
||||
|
||||
xkb_keysym_t
|
||||
xkb_keysym_iterator_get_keysym(struct xkb_keysym_iterator *iter);
|
||||
|
||||
int
|
||||
xkb_keysym_iterator_get_name(struct xkb_keysym_iterator *iter,
|
||||
char *buffer, size_t size);
|
||||
|
||||
bool
|
||||
xkb_keysym_iterator_is_explicitly_named(struct xkb_keysym_iterator *iter);
|
||||
|
||||
bool
|
||||
xkb_keysym_is_lower(xkb_keysym_t keysym);
|
||||
|
||||
bool
|
||||
xkb_keysym_is_upper(xkb_keysym_t keysym);
|
||||
|
||||
bool
|
||||
xkb_keysym_is_keypad(xkb_keysym_t keysym);
|
||||
|
||||
bool
|
||||
xkb_keysym_is_modifier(xkb_keysym_t keysym);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,134 +0,0 @@
|
||||
// NOTE: This file has been generated automatically by “update-message-registry.py”.
|
||||
// Do not edit manually!
|
||||
|
||||
#ifndef MESSAGES_H
|
||||
#define MESSAGES_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* Special case when no message identifier is defined.
|
||||
*/
|
||||
#define XKB_LOG_MESSAGE_NO_ID 0
|
||||
|
||||
/**
|
||||
* @name Codes of the log messages
|
||||
*/
|
||||
enum xkb_message_code {
|
||||
_XKB_LOG_MESSAGE_MIN_CODE = 34,
|
||||
/** Warn on malformed number literals */
|
||||
XKB_ERROR_MALFORMED_NUMBER_LITERAL = 34,
|
||||
/** Conflicting “preserve” entries in a key type */
|
||||
XKB_WARNING_CONFLICTING_KEY_TYPE_PRESERVE_ENTRIES = 43,
|
||||
/** Warn on unsupported modifier mask */
|
||||
XKB_ERROR_UNSUPPORTED_MODIFIER_MASK = 60,
|
||||
/** Expected an array entry, but the index is missing */
|
||||
XKB_ERROR_EXPECTED_ARRAY_ENTRY = 77,
|
||||
/** Illegal keycode alias with the name of a real key */
|
||||
XKB_WARNING_ILLEGAL_KEYCODE_ALIAS = 101,
|
||||
/** Warn on unrecognized keysyms */
|
||||
XKB_WARNING_UNRECOGNIZED_KEYSYM = 107,
|
||||
/** A virtual modifier is used before being declared */
|
||||
XKB_ERROR_UNDECLARED_VIRTUAL_MODIFIER = 123,
|
||||
/** A buffer has an insufficient size */
|
||||
XKB_ERROR_INSUFFICIENT_BUFFER_SIZE = 134,
|
||||
/** The type of the statement is not allowed in the context */
|
||||
XKB_ERROR_WRONG_STATEMENT_TYPE = 150,
|
||||
/** Geometry sections are not supported */
|
||||
XKB_WARNING_UNSUPPORTED_GEOMETRY_SECTION = 172,
|
||||
/** Warn if no key type can be inferred */
|
||||
XKB_WARNING_CANNOT_INFER_KEY_TYPE = 183,
|
||||
/** Invalid escape sequence in a string */
|
||||
XKB_WARNING_INVALID_ESCAPE_SEQUENCE = 193,
|
||||
/** The result of a key type “preserve” entry must be a subset of its input modifiers. */
|
||||
XKB_WARNING_ILLEGAL_KEY_TYPE_PRESERVE_RESULT = 195,
|
||||
/** Syntax error in the include statement */
|
||||
XKB_ERROR_INVALID_INCLUDE_STATEMENT = 203,
|
||||
/** A modmap entry is invalid */
|
||||
XKB_ERROR_INVALID_MODMAP_ENTRY = 206,
|
||||
/** Warn when a group index is not supported */
|
||||
XKB_ERROR_UNSUPPORTED_GROUP_INDEX = 237,
|
||||
/** The name of a key type level is defined multiple times. */
|
||||
XKB_WARNING_CONFLICTING_KEY_TYPE_LEVEL_NAMES = 239,
|
||||
/** Invalid statement setting default values */
|
||||
XKB_ERROR_INVALID_SET_DEFAULT_STATEMENT = 254,
|
||||
/** Conflicting “map” entries in type definition */
|
||||
XKB_WARNING_CONFLICTING_KEY_TYPE_MAP_ENTRY = 266,
|
||||
/** Warn if using an undefined key type */
|
||||
XKB_WARNING_UNDEFINED_KEY_TYPE = 286,
|
||||
/** Warn if a group name was defined for group other than the first one */
|
||||
XKB_WARNING_NON_BASE_GROUP_NAME = 305,
|
||||
/** Warn when a shift level is not supported */
|
||||
XKB_ERROR_UNSUPPORTED_SHIFT_LEVEL = 312,
|
||||
/** Could not find a file used in an include statement */
|
||||
XKB_ERROR_INCLUDED_FILE_NOT_FOUND = 338,
|
||||
/** Use of an operator that is unknown and thus unsupported */
|
||||
XKB_ERROR_UNKNOWN_OPERATOR = 345,
|
||||
/** An entry is duplicated and will be ignored */
|
||||
XKB_WARNING_DUPLICATE_ENTRY = 378,
|
||||
/** Included files form cycle */
|
||||
XKB_ERROR_RECURSIVE_INCLUDE = 386,
|
||||
/** Conflicting definitions of a key type */
|
||||
XKB_WARNING_CONFLICTING_KEY_TYPE_DEFINITIONS = 407,
|
||||
/** A global defaults statement is in a wrong scope and should be moved */
|
||||
XKB_ERROR_GLOBAL_DEFAULTS_WRONG_SCOPE = 428,
|
||||
/** Missing default section in included file */
|
||||
XKB_WARNING_MISSING_DEFAULT_SECTION = 433,
|
||||
/** Warn if there are conflicting keysyms while merging keys */
|
||||
XKB_WARNING_CONFLICTING_KEY_SYMBOL = 461,
|
||||
/** The operation is invalid in the context */
|
||||
XKB_ERROR_INVALID_OPERATION = 478,
|
||||
/** Warn on numeric keysym (other than 0-9) */
|
||||
XKB_WARNING_NUMERIC_KEYSYM = 489,
|
||||
/** TODO: add description */
|
||||
XKB_WARNING_EXTRA_SYMBOLS_IGNORED = 516,
|
||||
/** Conflicting definitions of a key name or alias */
|
||||
XKB_WARNING_CONFLICTING_KEY_NAME = 523,
|
||||
/** Cannot allocate memory */
|
||||
XKB_ERROR_ALLOCATION_ERROR = 550,
|
||||
/** Warn when a field has not the expected type */
|
||||
XKB_ERROR_WRONG_FIELD_TYPE = 578,
|
||||
/** Invalid _real_ modifier */
|
||||
XKB_ERROR_INVALID_REAL_MODIFIER = 623,
|
||||
/** Warn on unknown escape sequence in string literal */
|
||||
XKB_WARNING_UNKNOWN_CHAR_ESCAPE_SEQUENCE = 645,
|
||||
/** The target file of an include statement could not be processed */
|
||||
XKB_ERROR_INVALID_INCLUDED_FILE = 661,
|
||||
/** Warn if a key defines multiple groups at once */
|
||||
XKB_WARNING_MULTIPLE_GROUPS_AT_ONCE = 700,
|
||||
/** A legacy X11 symbol field is not supported */
|
||||
XKB_WARNING_UNSUPPORTED_SYMBOLS_FIELD = 711,
|
||||
/** The syntax is invalid and the file cannot be parsed */
|
||||
XKB_ERROR_INVALID_SYNTAX = 769,
|
||||
/** Reference to an undefined keycode */
|
||||
XKB_WARNING_UNDEFINED_KEYCODE = 770,
|
||||
/** An expression has not the expected type */
|
||||
XKB_ERROR_INVALID_EXPRESSION_TYPE = 784,
|
||||
/** A value is invalid and will be ignored */
|
||||
XKB_ERROR_INVALID_VALUE = 796,
|
||||
/** Warn if there are conflicting modmap definitions */
|
||||
XKB_WARNING_CONFLICTING_MODMAP = 800,
|
||||
/** A field is unknown and will be ignored */
|
||||
XKB_ERROR_UNKNOWN_FIELD = 812,
|
||||
/** Warn if there are conflicting actions while merging keys */
|
||||
XKB_WARNING_CONFLICTING_KEY_ACTION = 883,
|
||||
/** Warn if there are conflicting key types while merging groups */
|
||||
XKB_WARNING_CONFLICTING_KEY_TYPE_MERGING_GROUPS = 893,
|
||||
/** Conflicting symbols entry for a key */
|
||||
XKB_ERROR_CONFLICTING_KEY_SYMBOLS_ENTRY = 901,
|
||||
/** Missing group index in a group name entry */
|
||||
XKB_WARNING_MISSING_SYMBOLS_GROUP_NAME_INDEX = 903,
|
||||
/** Warn if there are conflicting fields while merging keys */
|
||||
XKB_WARNING_CONFLICTING_KEY_FIELDS = 935,
|
||||
/** An identifier is used but is not built-in */
|
||||
XKB_ERROR_INVALID_IDENTIFIER = 949,
|
||||
/** Warn if using a symbol not defined in the keymap */
|
||||
XKB_WARNING_UNRESOLVED_KEYMAP_SYMBOL = 965,
|
||||
/** Some modifiers used in a key type “map” or “preserve” entry are not declared */
|
||||
XKB_WARNING_UNDECLARED_MODIFIERS_IN_KEY_TYPE = 971,
|
||||
_XKB_LOG_MESSAGE_MAX_CODE = 971
|
||||
};
|
||||
|
||||
typedef uint32_t xkb_message_code_t;
|
||||
|
||||
#endif
|
||||
@@ -1,28 +0,0 @@
|
||||
// NOTE: This file has been generated automatically by “{{script}}”.
|
||||
// Do not edit manually!
|
||||
|
||||
#ifndef MESSAGES_H
|
||||
#define MESSAGES_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* Special case when no message identifier is defined.
|
||||
*/
|
||||
#define XKB_LOG_MESSAGE_NO_ID 0
|
||||
|
||||
/**
|
||||
* @name Codes of the log messages
|
||||
*/
|
||||
enum xkb_message_code {
|
||||
_XKB_LOG_MESSAGE_MIN_CODE = {{ entries[0].code }},
|
||||
{% for entry in entries %}
|
||||
/** {{ entry.description }} */
|
||||
{{ entry.message_code_constant }} = {{ entry.code }},
|
||||
{% endfor %}
|
||||
_XKB_LOG_MESSAGE_MAX_CODE = {{ entries[-1].code }}
|
||||
};
|
||||
|
||||
typedef uint32_t xkb_message_code_t;
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,244 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2012 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 XKBCOMP_SCANNER_UTILS_H
|
||||
#define XKBCOMP_SCANNER_UTILS_H
|
||||
|
||||
/* Point to some substring in the file; used to avoid copying. */
|
||||
struct sval {
|
||||
const char *start;
|
||||
unsigned int len;
|
||||
};
|
||||
typedef darray(struct sval) darray_sval;
|
||||
|
||||
static inline bool
|
||||
svaleq(struct sval s1, struct sval s2)
|
||||
{
|
||||
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 && memcmp(s1.start, s2.start, s1.len) == 0;
|
||||
}
|
||||
|
||||
struct scanner {
|
||||
const char *s;
|
||||
size_t pos;
|
||||
size_t len;
|
||||
char buf[1024];
|
||||
size_t buf_pos;
|
||||
size_t line, column;
|
||||
/* The line/column of the start of the current token. */
|
||||
size_t token_line, token_column;
|
||||
const char *file_name;
|
||||
struct xkb_context *ctx;
|
||||
void *priv;
|
||||
};
|
||||
|
||||
#define scanner_log_with_code(scanner, level, log_msg_id, fmt, ...) \
|
||||
xkb_log_with_code((scanner)->ctx, (level), 0, log_msg_id, \
|
||||
"%s:%zu:%zu: " fmt "\n", \
|
||||
(scanner)->file_name, \
|
||||
(scanner)->token_line, \
|
||||
(scanner)->token_column, ##__VA_ARGS__)
|
||||
|
||||
#define scanner_log(scanner, level, fmt, ...) \
|
||||
xkb_log((scanner)->ctx, (level), 0, \
|
||||
"%s:%zu:%zu: " fmt "\n", \
|
||||
(scanner)->file_name, \
|
||||
(scanner)->token_line, (scanner)->token_column, ##__VA_ARGS__)
|
||||
|
||||
#define scanner_err_with_code(scanner, id, fmt, ...) \
|
||||
scanner_log_with_code(scanner, XKB_LOG_LEVEL_ERROR, id, fmt, ##__VA_ARGS__)
|
||||
|
||||
#define scanner_err(scanner, fmt, ...) \
|
||||
scanner_log(scanner, XKB_LOG_LEVEL_ERROR, fmt, ##__VA_ARGS__)
|
||||
|
||||
#define scanner_warn_with_code(scanner, id, fmt, ...) \
|
||||
scanner_log_with_code(scanner, XKB_LOG_LEVEL_WARNING, id, fmt, ##__VA_ARGS__)
|
||||
|
||||
#define scanner_warn(scanner, fmt, ...) \
|
||||
scanner_log(scanner, XKB_LOG_LEVEL_WARNING, fmt, ##__VA_ARGS__)
|
||||
|
||||
static inline void
|
||||
scanner_init(struct scanner *s, struct xkb_context *ctx,
|
||||
const char *string, size_t len, const char *file_name,
|
||||
void *priv)
|
||||
{
|
||||
s->s = string;
|
||||
s->len = len;
|
||||
s->pos = 0;
|
||||
s->line = s->column = 1;
|
||||
s->token_line = s->token_column = 1;
|
||||
s->file_name = file_name;
|
||||
s->ctx = ctx;
|
||||
s->priv = priv;
|
||||
}
|
||||
|
||||
static inline char
|
||||
scanner_peek(struct scanner *s)
|
||||
{
|
||||
if (unlikely(s->pos >= s->len))
|
||||
return '\0';
|
||||
return s->s[s->pos];
|
||||
}
|
||||
|
||||
static inline bool
|
||||
scanner_eof(struct scanner *s)
|
||||
{
|
||||
return s->pos >= s->len;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
scanner_eol(struct scanner *s)
|
||||
{
|
||||
return scanner_peek(s) == '\n';
|
||||
}
|
||||
|
||||
static inline void
|
||||
scanner_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
|
||||
scanner_next(struct scanner *s)
|
||||
{
|
||||
if (unlikely(scanner_eof(s)))
|
||||
return '\0';
|
||||
if (unlikely(scanner_eol(s))) {
|
||||
s->line++;
|
||||
s->column = 1;
|
||||
}
|
||||
else {
|
||||
s->column++;
|
||||
}
|
||||
return s->s[s->pos++];
|
||||
}
|
||||
|
||||
static inline bool
|
||||
scanner_chr(struct scanner *s, char ch)
|
||||
{
|
||||
if (likely(scanner_peek(s) != ch))
|
||||
return false;
|
||||
s->pos++; s->column++;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
scanner_str(struct scanner *s, const char *string, size_t len)
|
||||
{
|
||||
if (s->len - s->pos < len)
|
||||
return false;
|
||||
if (memcmp(s->s + s->pos, string, len) != 0)
|
||||
return false;
|
||||
s->pos += len; s->column += len;
|
||||
return true;
|
||||
}
|
||||
|
||||
#define scanner_lit(s, literal) scanner_str(s, literal, sizeof(literal) - 1)
|
||||
|
||||
static inline bool
|
||||
scanner_buf_append(struct scanner *s, char ch)
|
||||
{
|
||||
if (s->buf_pos + 1 >= sizeof(s->buf))
|
||||
return false;
|
||||
s->buf[s->buf_pos++] = ch;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
scanner_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
|
||||
scanner_oct(struct scanner *s, uint8_t *out)
|
||||
{
|
||||
int i;
|
||||
for (i = 0, *out = 0; scanner_peek(s) >= '0' && scanner_peek(s) <= '7' && i < 3; i++)
|
||||
/* Test overflow */
|
||||
if (*out < 040) {
|
||||
*out = *out * 8 + scanner_next(s) - '0';
|
||||
} else {
|
||||
/* Consume valid digit, but mark result as invalid */
|
||||
scanner_next(s);
|
||||
return false;
|
||||
}
|
||||
return i > 0;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
scanner_hex(struct scanner *s, uint8_t *out)
|
||||
{
|
||||
int i;
|
||||
for (i = 0, *out = 0; is_xdigit(scanner_peek(s)) && i < 2; i++) {
|
||||
const char c = scanner_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;
|
||||
}
|
||||
|
||||
/* Basic detection of wrong character encoding based on the first bytes */
|
||||
static inline bool
|
||||
scanner_check_supported_char_encoding(struct scanner *scanner)
|
||||
{
|
||||
/* Skip UTF-8 encoded BOM (U+FEFF)
|
||||
* See: https://www.unicode.org/faq/utf_bom.html#bom5 */
|
||||
if (scanner_str(scanner, "\xef\xbb\xbf", 3) || scanner->len < 2) {
|
||||
/* Assume UTF-8 encoding or trivial short input */
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Early detection of wrong file encoding, e.g. UTF-16 or UTF-32 */
|
||||
if (scanner->s[0] == '\0' || scanner->s[1] == '\0') {
|
||||
if (scanner->s[0] != '\0')
|
||||
scanner->token_column++;
|
||||
scanner_err(scanner, "unexpected NULL character.");
|
||||
return false;
|
||||
}
|
||||
/* Enforce the first character to be ASCII.
|
||||
See the note before the use of this function, that explains the relevant
|
||||
parts of the grammars of rules, keymap components and Compose. */
|
||||
if (!is_ascii(scanner->s[0])) {
|
||||
scanner_err(scanner, "unexpected non-ASCII character.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,352 +0,0 @@
|
||||
/************************************************************
|
||||
* Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose and without
|
||||
* fee is hereby granted, 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 Silicon Graphics not be
|
||||
* used in advertising or publicity pertaining to distribution
|
||||
* of the software without specific prior written permission.
|
||||
* Silicon Graphics makes no representation about the suitability
|
||||
* of this software for any purpose. It is provided "as is"
|
||||
* without any express or implied warranty.
|
||||
*
|
||||
* SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
|
||||
* GRAPHICS 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.
|
||||
*
|
||||
********************************************************/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "keymap.h"
|
||||
#include "keysym.h"
|
||||
#include "text.h"
|
||||
|
||||
bool
|
||||
LookupString(const LookupEntry tab[], const char *string,
|
||||
unsigned int *value_rtrn)
|
||||
{
|
||||
if (!string)
|
||||
return false;
|
||||
|
||||
for (const LookupEntry *entry = tab; entry->name; entry++) {
|
||||
if (istreq(entry->name, string)) {
|
||||
*value_rtrn = entry->value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *
|
||||
LookupValue(const LookupEntry tab[], unsigned int value)
|
||||
{
|
||||
for (const LookupEntry *entry = tab; entry->name; entry++)
|
||||
if (entry->value == value)
|
||||
return entry->name;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const LookupEntry ctrlMaskNames[] = {
|
||||
{ "RepeatKeys", CONTROL_REPEAT },
|
||||
{ "Repeat", CONTROL_REPEAT },
|
||||
{ "AutoRepeat", CONTROL_REPEAT },
|
||||
{ "SlowKeys", CONTROL_SLOW },
|
||||
{ "BounceKeys", CONTROL_DEBOUNCE },
|
||||
{ "StickyKeys", CONTROL_STICKY },
|
||||
{ "MouseKeys", CONTROL_MOUSEKEYS },
|
||||
{ "MouseKeysAccel", CONTROL_MOUSEKEYS_ACCEL },
|
||||
{ "AccessXKeys", CONTROL_AX },
|
||||
{ "AccessXTimeout", CONTROL_AX_TIMEOUT },
|
||||
{ "AccessXFeedback", CONTROL_AX_FEEDBACK },
|
||||
{ "AudibleBell", CONTROL_BELL },
|
||||
{ "IgnoreGroupLock", CONTROL_IGNORE_GROUP_LOCK },
|
||||
{ "all", CONTROL_ALL },
|
||||
{ "none", 0 },
|
||||
{ "Overlay1", 0 },
|
||||
{ "Overlay2", 0 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
const LookupEntry modComponentMaskNames[] = {
|
||||
{ "base", XKB_STATE_MODS_DEPRESSED },
|
||||
{ "latched", XKB_STATE_MODS_LATCHED },
|
||||
{ "locked", XKB_STATE_MODS_LOCKED },
|
||||
{ "effective", XKB_STATE_MODS_EFFECTIVE },
|
||||
{ "compat", XKB_STATE_MODS_EFFECTIVE },
|
||||
{ "any", XKB_STATE_MODS_EFFECTIVE },
|
||||
{ "none", 0 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
const LookupEntry groupComponentMaskNames[] = {
|
||||
{ "base", XKB_STATE_LAYOUT_DEPRESSED },
|
||||
{ "latched", XKB_STATE_LAYOUT_LATCHED },
|
||||
{ "locked", XKB_STATE_LAYOUT_LOCKED },
|
||||
{ "effective", XKB_STATE_LAYOUT_EFFECTIVE },
|
||||
{ "any", XKB_STATE_LAYOUT_EFFECTIVE },
|
||||
{ "none", 0 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
const LookupEntry groupMaskNames[] = {
|
||||
{ "Group1", 0x01 },
|
||||
{ "Group2", 0x02 },
|
||||
{ "Group3", 0x04 },
|
||||
{ "Group4", 0x08 },
|
||||
{ "Group5", 0x10 },
|
||||
{ "Group6", 0x20 },
|
||||
{ "Group7", 0x40 },
|
||||
{ "Group8", 0x80 },
|
||||
{ "none", 0x00 },
|
||||
{ "all", 0xff },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
const LookupEntry groupNames[] = {
|
||||
{ "Group1", 1 },
|
||||
{ "Group2", 2 },
|
||||
{ "Group3", 3 },
|
||||
{ "Group4", 4 },
|
||||
{ "Group5", 5 },
|
||||
{ "Group6", 6 },
|
||||
{ "Group7", 7 },
|
||||
{ "Group8", 8 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
const LookupEntry levelNames[] = {
|
||||
{ "Level1", 1 },
|
||||
{ "Level2", 2 },
|
||||
{ "Level3", 3 },
|
||||
{ "Level4", 4 },
|
||||
{ "Level5", 5 },
|
||||
{ "Level6", 6 },
|
||||
{ "Level7", 7 },
|
||||
{ "Level8", 8 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
const LookupEntry buttonNames[] = {
|
||||
{ "Button1", 1 },
|
||||
{ "Button2", 2 },
|
||||
{ "Button3", 3 },
|
||||
{ "Button4", 4 },
|
||||
{ "Button5", 5 },
|
||||
{ "default", 0 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
const LookupEntry useModMapValueNames[] = {
|
||||
{ "LevelOne", 1 },
|
||||
{ "Level1", 1 },
|
||||
{ "AnyLevel", 0 },
|
||||
{ "any", 0 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
const LookupEntry actionTypeNames[] = {
|
||||
{ "NoAction", ACTION_TYPE_NONE },
|
||||
{ "SetMods", ACTION_TYPE_MOD_SET },
|
||||
{ "LatchMods", ACTION_TYPE_MOD_LATCH },
|
||||
{ "LockMods", ACTION_TYPE_MOD_LOCK },
|
||||
{ "SetGroup", ACTION_TYPE_GROUP_SET },
|
||||
{ "LatchGroup", ACTION_TYPE_GROUP_LATCH },
|
||||
{ "LockGroup", ACTION_TYPE_GROUP_LOCK },
|
||||
{ "MovePtr", ACTION_TYPE_PTR_MOVE },
|
||||
{ "MovePointer", ACTION_TYPE_PTR_MOVE },
|
||||
{ "PtrBtn", ACTION_TYPE_PTR_BUTTON },
|
||||
{ "PointerButton", ACTION_TYPE_PTR_BUTTON },
|
||||
{ "LockPtrBtn", ACTION_TYPE_PTR_LOCK },
|
||||
{ "LockPtrButton", ACTION_TYPE_PTR_LOCK },
|
||||
{ "LockPointerButton", ACTION_TYPE_PTR_LOCK },
|
||||
{ "LockPointerBtn", ACTION_TYPE_PTR_LOCK },
|
||||
{ "SetPtrDflt", ACTION_TYPE_PTR_DEFAULT },
|
||||
{ "SetPointerDefault", ACTION_TYPE_PTR_DEFAULT },
|
||||
{ "Terminate", ACTION_TYPE_TERMINATE },
|
||||
{ "TerminateServer", ACTION_TYPE_TERMINATE },
|
||||
{ "SwitchScreen", ACTION_TYPE_SWITCH_VT },
|
||||
{ "SetControls", ACTION_TYPE_CTRL_SET },
|
||||
{ "LockControls", ACTION_TYPE_CTRL_LOCK },
|
||||
{ "Private", ACTION_TYPE_PRIVATE },
|
||||
/* deprecated actions below here - unused */
|
||||
{ "RedirectKey", ACTION_TYPE_NONE },
|
||||
{ "Redirect", ACTION_TYPE_NONE },
|
||||
{ "ISOLock", ACTION_TYPE_NONE },
|
||||
{ "ActionMessage", ACTION_TYPE_NONE },
|
||||
{ "MessageAction", ACTION_TYPE_NONE },
|
||||
{ "Message", ACTION_TYPE_NONE },
|
||||
{ "DeviceBtn", ACTION_TYPE_NONE },
|
||||
{ "DevBtn", ACTION_TYPE_NONE },
|
||||
{ "DevButton", ACTION_TYPE_NONE },
|
||||
{ "DeviceButton", ACTION_TYPE_NONE },
|
||||
{ "LockDeviceBtn", ACTION_TYPE_NONE },
|
||||
{ "LockDevBtn", ACTION_TYPE_NONE },
|
||||
{ "LockDevButton", ACTION_TYPE_NONE },
|
||||
{ "LockDeviceButton", ACTION_TYPE_NONE },
|
||||
{ "DeviceValuator", ACTION_TYPE_NONE },
|
||||
{ "DevVal", ACTION_TYPE_NONE },
|
||||
{ "DeviceVal", ACTION_TYPE_NONE },
|
||||
{ "DevValuator", ACTION_TYPE_NONE },
|
||||
{ NULL, 0 },
|
||||
};
|
||||
|
||||
const LookupEntry symInterpretMatchMaskNames[] = {
|
||||
{ "NoneOf", MATCH_NONE },
|
||||
{ "AnyOfOrNone", MATCH_ANY_OR_NONE },
|
||||
{ "AnyOf", MATCH_ANY },
|
||||
{ "AllOf", MATCH_ALL },
|
||||
{ "Exactly", MATCH_EXACTLY },
|
||||
{ NULL, 0 },
|
||||
};
|
||||
|
||||
const char *
|
||||
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 == XKB_MOD_NONE)
|
||||
return "None";
|
||||
|
||||
if (ndx >= mods->num_mods)
|
||||
return NULL;
|
||||
|
||||
return xkb_atom_text(ctx, mods->mods[ndx].name);
|
||||
}
|
||||
|
||||
const char *
|
||||
ActionTypeText(enum xkb_action_type type)
|
||||
{
|
||||
const char *name = LookupValue(actionTypeNames, type);
|
||||
return name ? name : "Private";
|
||||
}
|
||||
|
||||
const char *
|
||||
KeysymText(struct xkb_context *ctx, xkb_keysym_t sym)
|
||||
{
|
||||
char *buffer = xkb_context_get_buffer(ctx, XKB_KEYSYM_NAME_MAX_SIZE);
|
||||
xkb_keysym_get_name(sym, buffer, XKB_KEYSYM_NAME_MAX_SIZE);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
const char *
|
||||
KeyNameText(struct xkb_context *ctx, xkb_atom_t name)
|
||||
{
|
||||
const char *sname = xkb_atom_text(ctx, name);
|
||||
size_t len = strlen_safe(sname) + 3;
|
||||
char *buf = xkb_context_get_buffer(ctx, len);
|
||||
snprintf(buf, len, "<%s>", strempty(sname));
|
||||
return buf;
|
||||
}
|
||||
|
||||
const char *
|
||||
SIMatchText(enum xkb_match_operation type)
|
||||
{
|
||||
return LookupValue(symInterpretMatchMaskNames, type);
|
||||
}
|
||||
|
||||
const char *
|
||||
ModMaskText(struct xkb_context *ctx, const struct xkb_mod_set *mods,
|
||||
xkb_mod_mask_t mask)
|
||||
{
|
||||
char buf[1024] = {0};
|
||||
size_t pos = 0;
|
||||
xkb_mod_index_t i;
|
||||
const struct xkb_mod *mod;
|
||||
|
||||
if (mask == 0)
|
||||
return "none";
|
||||
|
||||
if (mask == MOD_REAL_MASK_ALL)
|
||||
return "all";
|
||||
|
||||
xkb_mods_enumerate(i, mod, mods) {
|
||||
int ret;
|
||||
|
||||
if (!(mask & (1u << i)))
|
||||
continue;
|
||||
|
||||
ret = snprintf(buf + pos, sizeof(buf) - pos, "%s%s",
|
||||
pos == 0 ? "" : "+",
|
||||
xkb_atom_text(ctx, mod->name));
|
||||
if (ret <= 0 || pos + ret >= sizeof(buf))
|
||||
break;
|
||||
else
|
||||
pos += ret;
|
||||
}
|
||||
|
||||
return strcpy(xkb_context_get_buffer(ctx, pos + 1), buf);
|
||||
}
|
||||
|
||||
const char *
|
||||
LedStateMaskText(struct xkb_context *ctx, enum xkb_state_component mask)
|
||||
{
|
||||
char buf[1024];
|
||||
size_t pos = 0;
|
||||
|
||||
if (mask == 0)
|
||||
return "0";
|
||||
|
||||
for (unsigned i = 0; mask; i++) {
|
||||
int ret;
|
||||
|
||||
if (!(mask & (1u << i)))
|
||||
continue;
|
||||
|
||||
mask &= ~(1u << i);
|
||||
|
||||
ret = snprintf(buf + pos, sizeof(buf) - pos, "%s%s",
|
||||
pos == 0 ? "" : "+",
|
||||
LookupValue(modComponentMaskNames, 1u << i));
|
||||
if (ret <= 0 || pos + ret >= sizeof(buf))
|
||||
break;
|
||||
else
|
||||
pos += ret;
|
||||
}
|
||||
|
||||
return strcpy(xkb_context_get_buffer(ctx, pos + 1), buf);
|
||||
}
|
||||
|
||||
const char *
|
||||
ControlMaskText(struct xkb_context *ctx, enum xkb_action_controls mask)
|
||||
{
|
||||
char buf[1024];
|
||||
size_t pos = 0;
|
||||
|
||||
if (mask == 0)
|
||||
return "none";
|
||||
|
||||
if (mask == CONTROL_ALL)
|
||||
return "all";
|
||||
|
||||
for (unsigned i = 0; mask; i++) {
|
||||
int ret;
|
||||
|
||||
if (!(mask & (1u << i)))
|
||||
continue;
|
||||
|
||||
mask &= ~(1u << i);
|
||||
|
||||
ret = snprintf(buf + pos, sizeof(buf) - pos, "%s%s",
|
||||
pos == 0 ? "" : "+",
|
||||
LookupValue(ctrlMaskNames, 1u << i));
|
||||
if (ret <= 0 || pos + ret >= sizeof(buf))
|
||||
break;
|
||||
else
|
||||
pos += ret;
|
||||
}
|
||||
|
||||
return strcpy(xkb_context_get_buffer(ctx, pos + 1), buf);
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2009 Dan Nicholson
|
||||
*
|
||||
* 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 TEXT_H
|
||||
#define TEXT_H
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
unsigned int value;
|
||||
} LookupEntry;
|
||||
|
||||
bool
|
||||
LookupString(const LookupEntry tab[], const char *string,
|
||||
unsigned int *value_rtrn);
|
||||
|
||||
const char *
|
||||
LookupValue(const LookupEntry tab[], unsigned int value);
|
||||
|
||||
extern const LookupEntry ctrlMaskNames[];
|
||||
extern const LookupEntry modComponentMaskNames[];
|
||||
extern const LookupEntry groupComponentMaskNames[];
|
||||
extern const LookupEntry groupMaskNames[];
|
||||
extern const LookupEntry groupNames[];
|
||||
extern const LookupEntry levelNames[];
|
||||
extern const LookupEntry buttonNames[];
|
||||
extern const LookupEntry useModMapValueNames[];
|
||||
extern const LookupEntry actionTypeNames[];
|
||||
extern const LookupEntry symInterpretMatchMaskNames[];
|
||||
|
||||
const char *
|
||||
ModMaskText(struct xkb_context *ctx, const struct xkb_mod_set *mods,
|
||||
xkb_mod_mask_t mask);
|
||||
|
||||
const char *
|
||||
ModIndexText(struct xkb_context *ctx, const struct xkb_mod_set *mods,
|
||||
xkb_mod_index_t ndx);
|
||||
|
||||
const char *
|
||||
ActionTypeText(enum xkb_action_type type);
|
||||
|
||||
const char *
|
||||
KeysymText(struct xkb_context *ctx, xkb_keysym_t sym);
|
||||
|
||||
const char *
|
||||
KeyNameText(struct xkb_context *ctx, xkb_atom_t name);
|
||||
|
||||
const char *
|
||||
SIMatchText(enum xkb_match_operation type);
|
||||
|
||||
const char *
|
||||
LedStateMaskText(struct xkb_context *ctx, enum xkb_state_component mask);
|
||||
|
||||
const char *
|
||||
ControlMaskText(struct xkb_context *ctx, enum xkb_action_controls mask);
|
||||
|
||||
#endif /* TEXT_H */
|
||||
@@ -1,152 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2012 Intel Corporation
|
||||
* 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.
|
||||
*
|
||||
* Author: Rob Bradford <rob@linux.intel.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "utf8.h"
|
||||
|
||||
/* Conformant encoding form conversion from UTF-32 to UTF-8.
|
||||
*
|
||||
* See https://www.unicode.org/versions/Unicode15.0.0/ch03.pdf#G28875
|
||||
* for further details.
|
||||
*/
|
||||
int
|
||||
utf32_to_utf8(uint32_t unichar, char *buffer)
|
||||
{
|
||||
int count, shift, length;
|
||||
uint8_t head;
|
||||
|
||||
if (unichar <= 0x007f) {
|
||||
buffer[0] = unichar;
|
||||
buffer[1] = '\0';
|
||||
return 2;
|
||||
}
|
||||
else if (unichar <= 0x07FF) {
|
||||
length = 2;
|
||||
head = 0xc0;
|
||||
}
|
||||
/* Handle surrogates */
|
||||
else if (0xd800 <= unichar && unichar <= 0xdfff) {
|
||||
goto ill_formed_code_unit_subsequence;
|
||||
}
|
||||
else if (unichar <= 0xffff) {
|
||||
length = 3;
|
||||
head = 0xe0;
|
||||
}
|
||||
else if (unichar <= 0x10ffff) {
|
||||
length = 4;
|
||||
head = 0xf0;
|
||||
}
|
||||
else {
|
||||
goto ill_formed_code_unit_subsequence;
|
||||
}
|
||||
|
||||
for (count = length - 1, shift = 0; count > 0; count--, shift += 6)
|
||||
buffer[count] = 0x80 | ((unichar >> shift) & 0x3f);
|
||||
|
||||
buffer[0] = head | ((unichar >> shift) & 0x3f);
|
||||
buffer[length] = '\0';
|
||||
|
||||
return length + 1;
|
||||
|
||||
ill_formed_code_unit_subsequence:
|
||||
buffer[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
is_valid_utf8(const char *ss, size_t len)
|
||||
{
|
||||
size_t i = 0;
|
||||
size_t tail_bytes = 0;
|
||||
const uint8_t *s = (const uint8_t *) ss;
|
||||
|
||||
/* This beauty is from:
|
||||
* The Unicode Standard Version 6.2 - Core Specification, Table 3.7
|
||||
* https://www.unicode.org/versions/Unicode6.2.0/ch03.pdf#G7404
|
||||
* We can optimize if needed. */
|
||||
while (i < len)
|
||||
{
|
||||
if (s[i] <= 0x7F) {
|
||||
tail_bytes = 0;
|
||||
}
|
||||
else if (s[i] >= 0xC2 && s[i] <= 0xDF) {
|
||||
tail_bytes = 1;
|
||||
}
|
||||
else if (s[i] == 0xE0) {
|
||||
i++;
|
||||
if (i >= len || !(s[i] >= 0xA0 && s[i] <= 0xBF))
|
||||
return false;
|
||||
tail_bytes = 1;
|
||||
}
|
||||
else if (s[i] >= 0xE1 && s[i] <= 0xEC) {
|
||||
tail_bytes = 2;
|
||||
}
|
||||
else if (s[i] == 0xED) {
|
||||
i++;
|
||||
if (i >= len || !(s[i] >= 0x80 && s[i] <= 0x9F))
|
||||
return false;
|
||||
tail_bytes = 1;
|
||||
}
|
||||
else if (s[i] >= 0xEE && s[i] <= 0xEF) {
|
||||
tail_bytes = 2;
|
||||
}
|
||||
else if (s[i] == 0xF0) {
|
||||
i++;
|
||||
if (i >= len || !(s[i] >= 0x90 && s[i] <= 0xBF))
|
||||
return false;
|
||||
tail_bytes = 2;
|
||||
}
|
||||
else if (s[i] >= 0xF1 && s[i] <= 0xF3) {
|
||||
tail_bytes = 3;
|
||||
}
|
||||
else if (s[i] == 0xF4) {
|
||||
i++;
|
||||
if (i >= len || !(s[i] >= 0x80 && s[i] <= 0x8F))
|
||||
return false;
|
||||
tail_bytes = 2;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
i++;
|
||||
|
||||
while (i < len && tail_bytes > 0 && s[i] >= 0x80 && s[i] <= 0xBF) {
|
||||
i++;
|
||||
tail_bytes--;
|
||||
}
|
||||
|
||||
if (tail_bytes != 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2012 Intel Corporation
|
||||
* 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.
|
||||
*
|
||||
* Author: Rob Bradford <rob@linux.intel.com>
|
||||
*/
|
||||
|
||||
#ifndef XKBCOMMON_UTF8_H
|
||||
#define XKBCOMMON_UTF8_H
|
||||
|
||||
int
|
||||
utf32_to_utf8(uint32_t unichar, char *buffer);
|
||||
|
||||
bool
|
||||
is_valid_utf8(const char *ss, size_t len);
|
||||
|
||||
#endif
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2008-2011 Kristian Høgsberg
|
||||
* Copyright © 2011 Intel Corporation
|
||||
* Copyright © 2013-2015 Red Hat, Inc.
|
||||
*
|
||||
* 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 "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "util-list.h"
|
||||
|
||||
void
|
||||
list_init(struct list *list)
|
||||
{
|
||||
list->prev = list;
|
||||
list->next = list;
|
||||
}
|
||||
|
||||
void
|
||||
list_insert(struct list *list, struct list *elm)
|
||||
{
|
||||
assert((list->next != NULL && list->prev != NULL) ||
|
||||
!"list->next|prev is NULL, possibly missing list_init()");
|
||||
assert(((elm->next == NULL && elm->prev == NULL) || list_empty(elm)) ||
|
||||
!"elm->next|prev is not NULL, list node used twice?");
|
||||
|
||||
elm->prev = list;
|
||||
elm->next = list->next;
|
||||
list->next = elm;
|
||||
elm->next->prev = elm;
|
||||
}
|
||||
|
||||
void
|
||||
list_append(struct list *list, struct list *elm)
|
||||
{
|
||||
assert((list->next != NULL && list->prev != NULL) ||
|
||||
!"list->next|prev is NULL, possibly missing list_init()");
|
||||
assert(((elm->next == NULL && elm->prev == NULL) || list_empty(elm)) ||
|
||||
!"elm->next|prev is not NULL, list node used twice?");
|
||||
|
||||
elm->next = list;
|
||||
elm->prev = list->prev;
|
||||
list->prev = elm;
|
||||
elm->prev->next = elm;
|
||||
}
|
||||
|
||||
void
|
||||
list_remove(struct list *elm)
|
||||
{
|
||||
assert((elm->next != NULL && elm->prev != NULL) ||
|
||||
!"list->next|prev is NULL, possibly missing list_init()");
|
||||
|
||||
elm->prev->next = elm->next;
|
||||
elm->next->prev = elm->prev;
|
||||
elm->next = NULL;
|
||||
elm->prev = NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
list_empty(const struct list *list)
|
||||
{
|
||||
assert((list->next != NULL && list->prev != NULL) ||
|
||||
!"list->next|prev is NULL, possibly missing list_init()");
|
||||
|
||||
return list->next == list;
|
||||
}
|
||||
|
||||
bool
|
||||
list_is_last(const struct list *list, const struct list *elm)
|
||||
{
|
||||
return elm->next == list;
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2008-2011 Kristian Høgsberg
|
||||
* Copyright © 2011 Intel Corporation
|
||||
* Copyright © 2013-2015 Red Hat, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/*
|
||||
* This list data structure is a verbatim copy from wayland-util.h from the
|
||||
* Wayland project; except that wl_ prefix has been removed.
|
||||
*/
|
||||
|
||||
struct list {
|
||||
struct list *prev;
|
||||
struct list *next;
|
||||
};
|
||||
|
||||
void list_init(struct list *list);
|
||||
void list_insert(struct list *list, struct list *elm);
|
||||
void list_append(struct list *list, struct list *elm);
|
||||
void list_remove(struct list *elm);
|
||||
bool list_empty(const struct list *list);
|
||||
bool list_is_last(const struct list *list, const struct list *elm);
|
||||
|
||||
#define container_of(ptr, type, member) \
|
||||
(__typeof__(type) *)((char *)(ptr) - \
|
||||
offsetof(__typeof__(type), member))
|
||||
|
||||
#define list_first_entry(head, pos, member) \
|
||||
container_of((head)->next, __typeof__(*pos), member)
|
||||
|
||||
#define list_last_entry(head, pos, member) \
|
||||
container_of((head)->prev, __typeof__(*pos), member)
|
||||
|
||||
#define list_for_each(pos, head, member) \
|
||||
for (pos = 0, pos = list_first_entry(head, pos, member); \
|
||||
&pos->member != (head); \
|
||||
pos = list_first_entry(&pos->member, pos, member))
|
||||
|
||||
#define list_for_each_safe(pos, tmp, head, member) \
|
||||
for (pos = 0, tmp = 0, \
|
||||
pos = list_first_entry(head, pos, member), \
|
||||
tmp = list_first_entry(&pos->member, tmp, member); \
|
||||
&pos->member != (head); \
|
||||
pos = tmp, \
|
||||
tmp = list_first_entry(&pos->member, tmp, member))
|
||||
@@ -1,47 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright © 2020 Red Hat, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "config.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
static inline void*
|
||||
_steal(void *ptr) {
|
||||
void **original = (void**)ptr;
|
||||
void *swapped = *original;
|
||||
*original = NULL;
|
||||
return swapped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the pointer content and resets the data to NULL.
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
#define steal(ptr_) \
|
||||
_steal(ptr_)
|
||||
#else
|
||||
#define steal(ptr_) \
|
||||
(__typeof__(*ptr_))_steal(ptr_)
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user