diff --git a/.autom4te.cfg b/.autom4te.cfg new file mode 100644 index 0000000..4e07782 --- /dev/null +++ b/.autom4te.cfg @@ -0,0 +1,6 @@ +# Disable autom4te cache to ensure that any change to the version extraction +# script triggers a rebuild of the configure script. See +# . +begin-language: "Autoconf-without-aclocal-m4" +args: --no-cache +end-language: "Autoconf-without-aclocal-m4" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..c69988e --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,63 @@ +name: CI +on: + push: + pull_request: + +jobs: + test-debian-like: + strategy: + fail-fast: false + matrix: + image: + - ubuntu:latest + - ubuntu:22.04 + - debian:testing + - debian:stable + runs-on: ubuntu-latest + container: + image: ${{ matrix.image }} + steps: + - name: install dependencies + run: | + apt-get update && + apt-get install -y --no-install-recommends \ + automake \ + build-essential \ + ca-certificates \ + git \ + pkg-config \ + python3 \ + scdoc \ + && + { + # /usr/share/pkgconfig/systemd.pc was moved from the systemd + # package to a new systemd-dev package in systemd 253-2 (Debian 13 + # (trixie) and later, Ubuntu 23.10 (mantic) and later). + apt-get install -y --no-install-recommends systemd-dev || + apt-get install -y --no-install-recommends systemd + } + env: + DEBIAN_FRONTEND: noninteractive + - uses: actions/checkout@v4 + with: + # Fetch all commits and tags so that build-aux/git-version-gen can + # discover the version number. + fetch-depth: 0 + # https://github.com/actions/checkout/issues/1169 + - name: fix git permissions + run: git config --system --add safe.directory $(pwd) + - name: autogen + run: ./autogen + - name: configure + run: ./configure + - name: check + run: make VERBOSE=1 AM_COLOR_TESTS=always check + - name: distcheck + run: make VERBOSE=1 AM_COLOR_TESTS=always distcheck + - name: distribution tarball is complete + run: ./.github/workflows/scripts/dist-tarball-check + - if: ${{ matrix.image == 'debian:testing' }} + uses: actions/upload-artifact@v4 + with: + name: distribution-tarball + path: keyd-*.tar.gz diff --git a/.github/workflows/scripts/dist-tarball-check b/.github/workflows/scripts/dist-tarball-check new file mode 100755 index 0000000..6382a01 --- /dev/null +++ b/.github/workflows/scripts/dist-tarball-check @@ -0,0 +1,59 @@ +#!/bin/sh + +pecho() { printf %s\\n "$*"; } +log() { pecho "$@"; } +warning() { log "::warning::$@"; } +error() { log "::error::$@"; } +fatal() { error "$@"; exit 1; } +try() { "$@" || fatal "'$@' failed"; } + +dist_tarball=$(ls keyd-*.tar.gz) \ + || fatal "'make dist' must be run before this test" + +tmpdir=$(try mktemp -d) || exit 1 + +log "Copying contents of Git repository..." +try git archive --format=tar --prefix=git-repo/ HEAD \ + | try tar -C "${tmpdir}" -xv || exit 1 +( + try cd "${tmpdir}"/git-repo + # Delete files checked into Git that shouldn't be in the distribution + # tarball. + try rm -rf \ + .gitattributes \ + .github \ + .gitignore \ + ; +) || exit 1 + +log "Extracting distribution tarball..." +try tar -C "${tmpdir}" -xvzf "${dist_tarball}" +try mv "${tmpdir}/${dist_tarball%.tar.gz}" "${tmpdir}"/dist-tarball +( + try cd "${tmpdir}"/dist-tarball + # Delete generated files + try rm -rf \ + .dist-version \ + Makefile.in \ + aclocal.m4 \ + autoconfig.h.in \ + build-aux/compile \ + build-aux/depcomp \ + build-aux/install-sh \ + build-aux/missing \ + build-aux/test-driver \ + configure \ + ; +) || exit 1 + +log "Comparing Git repository with distribution tarball..." +cd "${tmpdir}" +diff -qNr git-repo dist-tarball >/dev/null || { + error "Unexpected diff between the repo and the distribution tarball." + error "You may need to add a file to EXTRA_DIST in Makefile.am." + error "Diff output:" + diff -uNr git-repo dist-tarball \ + | while IFS= read -r line; do error "${line}"; done + exit 1 +} +log "No difference" diff --git a/.gitignore b/.gitignore index c7371c6..f7c9e62 100644 --- a/.gitignore +++ b/.gitignore @@ -6,9 +6,33 @@ tags bin/ *.o *.gch +.deps/ +.dirstamp +/*.1 +/.dist-version +/Makefile +/Makefile.in +/aclocal.m4 +/autoconfig.h +/autoconfig.h.in +/autom4te.cache/ +/build-aux/* +!/build-aux/git-version-gen +/compose.stamp +/compose.stamp.tmp +/config.log +/config.status +/configure +/keyd +/keyd-*.tar.gz +/keyd-application-mapper +/keyd.compose +/src/unicode.c +/stamp-h1 +/t/*.log +/t/*.trs +/test-io +/test-suite.log __pycache__ test.log keyd.service -/data/*.1.gz -/data/keyd.compose -/src/unicode.c diff --git a/Makefile b/Makefile deleted file mode 100644 index 3ae1276..0000000 --- a/Makefile +++ /dev/null @@ -1,118 +0,0 @@ -.PHONY: all clean install uninstall debug man compose test-harness -VERSION=2.5.0 -COMMIT=$(shell git describe --no-match --always --abbrev=7 --dirty) -VKBD=uinput -PREFIX?=/usr/local - -CONFIG_DIR?=/etc/keyd -SOCKET_PATH=/var/run/keyd.socket - -# If this variable is set to the empty string, no systemd unit files will be -# installed. -SYSTEMD_SYSTEM_DIR = /usr/lib/systemd/system - -CFLAGS:=-DVERSION=\"v$(VERSION)\ \($(COMMIT)\)\" \ - -I/usr/local/include \ - -L/usr/local/lib \ - -Wall \ - -Wextra \ - -Wno-unused \ - -std=c11 \ - -DSOCKET_PATH=\"$(SOCKET_PATH)\" \ - -DCONFIG_DIR=\"$(CONFIG_DIR)\" \ - -DDATA_DIR=\"$(PREFIX)/share/keyd\" \ - -D_FORTIFY_SOURCE=2 \ - -D_DEFAULT_SOURCE \ - -Werror=format-security \ - $(CFLAGS) - -platform=$(shell uname -s) - -ifeq ($(platform), Linux) - COMPAT_FILES= -else - LDFLAGS+=-linotify - COMPAT_FILES= -endif - -all: compose man - mkdir -p bin - cp scripts/keyd-application-mapper bin/ - $(CC) $(CFLAGS) -O3 $(COMPAT_FILES) src/*.c src/vkbd/$(VKBD).c -lpthread -o bin/keyd $(LDFLAGS) -debug: - CFLAGS="-g -fsanitize=address -Wunused" $(MAKE) -compose: - mkdir -p data - ./scripts/generate_xcompose -man: - for f in docs/*.scdoc; do \ - target=$${f%%.scdoc}.1.gz; \ - target=data/$${target##*/}; \ - scdoc < "$$f" | gzip > "$$target"; \ - done -install: - - @if [ -n '$(SYSTEMD_SYSTEM_DIR)' ]; then \ - sed -e 's#@PREFIX@#$(PREFIX)#' keyd.service.in > keyd.service; \ - mkdir -p '$(DESTDIR)$(SYSTEMD_SYSTEM_DIR)'; \ - install -Dm644 keyd.service '$(DESTDIR)$(SYSTEMD_SYSTEM_DIR)/keyd.service'; \ - fi - - @if [ "$(VKBD)" = "usb-gadget" ]; then \ - if [ -n '$(SYSTEMD_SYSTEM_DIR)' ]; then \ - sed -e 's#@PREFIX@#$(PREFIX)#' src/vkbd/usb-gadget.service.in > src/vkbd/usb-gadget.service; \ - install -Dm644 src/vkbd/usb-gadget.service '$(DESTDIR)$(SYSTEMD_SYSTEM_DIR)/keyd-usb-gadget.service'; \ - fi; \ - install -Dm755 src/vkbd/usb-gadget.sh $(DESTDIR)$(PREFIX)/bin/keyd-usb-gadget.sh; \ - fi - - mkdir -p $(DESTDIR)$(CONFIG_DIR) - mkdir -p $(DESTDIR)$(PREFIX)/bin/ - mkdir -p $(DESTDIR)$(PREFIX)/share/keyd/ - mkdir -p $(DESTDIR)$(PREFIX)/share/keyd/layouts/ - mkdir -p $(DESTDIR)$(PREFIX)/share/man/man1/ - mkdir -p $(DESTDIR)$(PREFIX)/share/doc/keyd/ - mkdir -p $(DESTDIR)$(PREFIX)/share/doc/keyd/examples/ - - -groupadd keyd - install -m755 bin/* $(DESTDIR)$(PREFIX)/bin/ - install -m644 docs/*.md $(DESTDIR)$(PREFIX)/share/doc/keyd/ - install -m644 examples/* $(DESTDIR)$(PREFIX)/share/doc/keyd/examples/ - install -m644 layouts/* $(DESTDIR)$(PREFIX)/share/keyd/layouts - cp -r data/gnome-* $(DESTDIR)$(PREFIX)/share/keyd - install -m644 data/*.1.gz $(DESTDIR)$(PREFIX)/share/man/man1/ - install -m644 data/keyd.compose $(DESTDIR)$(PREFIX)/share/keyd/ - -uninstall: - -groupdel keyd - [ -z '$(SYSTEMD_SYSTEM_DIR)' ] || rm -f \ - '$(DESTDIR)$(SYSTEMD_SYSTEM_DIR)/keyd.service' \ - '$(DESTDIR)$(SYSTEMD_SYSTEM_DIR)/keyd-usb-gadget.service' - rm -rf $(DESTDIR)$(PREFIX)/bin/keyd \ - $(DESTDIR)$(PREFIX)/bin/keyd-application-mapper \ - $(DESTDIR)$(PREFIX)/share/doc/keyd/ \ - $(DESTDIR)$(PREFIX)/share/man/man1/keyd*.gz \ - $(DESTDIR)$(PREFIX)/share/keyd/ \ - $(DESTDIR)$(PREFIX)/bin/keyd-usb-gadget.sh -clean: - rm -rf bin data/*.1.gz data/keyd.compose keyd.service src/unicode.c src/vkbd/usb-gadget.service -test: - @cd t; \ - for f in *.sh; do \ - ./$$f; \ - done -test-io: - mkdir -p bin - $(CC) \ - -DDATA_DIR= \ - -o bin/test-io \ - t/test-io.c \ - src/keyboard.c \ - src/string.c \ - src/macro.c \ - src/config.c \ - src/log.c \ - src/ini.c \ - src/keys.c \ - src/unicode.c && \ - ./bin/test-io t/test.conf t/*.t diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..1d97c55 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,359 @@ +AM_DISTCHECK_CONFIGURE_FLAGS = +bin_PROGRAMS = +bin_SCRIPTS = +pkgdata_DATA = +BUILT_SOURCES = +CLEANFILES = +EXTRA_DIST = \ + .autom4te.cfg \ + CONTRIBUTING.md \ + LICENSE \ + README.md \ + autogen \ + scripts/dump-xkb-config \ + src/vkbd/usb-gadget.md + +AM_CPPFLAGS = \ + -D'CONFIG_DIR="$(sysconfdir)/keyd"' \ + -D'DATA_DIR="$(pkgdatadir)"' \ + -D'SOCKET_PATH="$(runstatedir)/keyd.socket"' + +bin_PROGRAMS += keyd +keyd_SOURCES = \ + src/config.c \ + src/config.h \ + src/daemon.c \ + src/device.c \ + src/device.h \ + src/evloop.c \ + src/ini.c \ + src/ini.h \ + src/ipc.c \ + src/keyboard.c \ + src/keyboard.h \ + src/keyd.c \ + src/keyd.h \ + src/keys.c \ + src/keys.h \ + src/log.c \ + src/log.h \ + src/macro.c \ + src/macro.h \ + src/monitor.c \ + src/strutil.c \ + src/strutil.h \ + src/unicode.h \ + src/util.c \ + src/vkbd.h +nodist_keyd_SOURCES = \ + src/unicode.c +BUILT_SOURCES += $(nodist_keyd_SOURCES) +CLEANFILES += $(nodist_keyd_SOURCES) +keyd_CPPFLAGS = $(AM_CPPFLAGS) -Isrc -I$(srcdir)/src + +if USB_GADGET +nodist_keyd_SOURCES += src/vkbd/usb-gadget.h +bin_SCRIPTS += keyd-usb-gadget.sh +CLEANFILES += keyd-usb-gadget.sh +keyd-usb-gadget.sh: src/vkbd/usb-gadget.sh + sed -e '1s;^#!.*;#!$(BASH);' $< >$@.tmp + chmod +x $@.tmp + mv $@.tmp $@ +endif USB_GADGET +nodist_keyd_SOURCES += src/vkbd/$(VKBD).c +EXTRA_DIST += \ + src/vkbd/stdout.c \ + src/vkbd/uinput.c \ + src/vkbd/usb-gadget.c \ + src/vkbd/usb-gadget.h \ + src/vkbd/usb-gadget.sh + +systemdsystemunit_DATA = +if SYSTEMD_SYSTEM_UNIT +systemdsystemunit_DATA += keyd.service +if USB_GADGET +systemdsystemunit_DATA += src/vkbd/usb-gadget.service +endif USB_GADGET +# `make distcheck` simulates installation by an unprivileged user by setting $prefix to a temporary +# directory and $DESTDIR to the empty string, so absolute paths like /lib/systemd/system cause `make +# distcheck` to fail. Fool it by pretending the systemd unit files can be installed in +# ${prefix}/lib/systemd/system. +AM_DISTCHECK_CONFIGURE_FLAGS += --with-systemd-system-unit='$${prefix}$(systemdsystemunitdir)' +else !SYSTEMD_SYSTEM_UNIT +AM_DISTCHECK_CONFIGURE_FLAGS += --without-systemd-system-unit +endif !SYSTEMD_SYSTEM_UNIT +$(systemdsystemunit_DATA): %.service: %.service.in + sed -e 's,[@]PREFIX[@],$(prefix),g' <$< >$@.tmp + mv $@.tmp $@ +EXTRA_DIST += keyd.service.in src/vkbd/usb-gadget.service.in +CLEANFILES += $(systemdsystemunit_DATA) + +bin_SCRIPTS += keyd-application-mapper +CLEANFILES += keyd-application-mapper +EXTRA_DIST += scripts/keyd-application-mapper +keyd-application-mapper: scripts/keyd-application-mapper + sed -e '1s;^#!.*;#!$(PYTHON);' $< >$@.tmp + chmod +x $@.tmp + mv $@.tmp $@ + +dist_doc_DATA = \ + docs/CHANGELOG.md \ + docs/DESIGN.md +examplesdir = $(docdir)/examples +dist_examples_DATA = \ + examples/capslock-esc-basic.conf \ + examples/capslock-escape-with-vim-mode.conf \ + examples/international-glyphs.conf \ + examples/macos.conf \ + examples/nav-layer.conf + +pkgdata_DATA += keyd.compose +EXTRA_DIST += \ + data/unicode.txt \ + scripts/generate_xcompose +CLEANFILES += compose.stamp keyd.compose +compose.stamp: data/unicode.txt scripts/generate_xcompose + @rm -f $@.tmp + @touch $@.tmp + @mkdir -p src + $(PYTHON) $(srcdir)/scripts/generate_xcompose $< keyd.compose src/unicode.c + @mv -f $@.tmp $@ +src/unicode.c keyd.compose: compose.stamp + @test -f $@ || rm -f $< + @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) $< + +gnomeexdir = $(pkgdatadir)/gnome-extension +dist_gnomeex_DATA = \ + data/gnome-extension/extension.js \ + data/gnome-extension/metadata.json +gnomeex45dir = $(pkgdatadir)/gnome-extension-45 +dist_gnomeex45_DATA = \ + data/gnome-extension-45/extension.js \ + data/gnome-extension-45/metadata.json + +layouts = \ + af \ + al \ + am \ + ara \ + at \ + au \ + az \ + ba \ + bd \ + be \ + bg \ + br \ + brai \ + bt \ + bw \ + by \ + ca \ + cd \ + ch \ + cm \ + cn \ + colemak \ + cz \ + de \ + dk \ + dvorak \ + dz \ + ee \ + epo \ + es \ + et \ + fi \ + fo \ + fr \ + gb \ + ge \ + gh \ + gn \ + gr \ + hr \ + hu \ + id \ + ie \ + il \ + in \ + iq \ + ir \ + is \ + it \ + jp \ + jv \ + ke \ + kg \ + kh \ + kr \ + kz \ + la \ + latam \ + lk \ + lt \ + lv \ + ma \ + mao \ + md \ + me \ + mk \ + ml \ + mm \ + mn \ + mt \ + mv \ + my \ + ng \ + nl \ + no \ + np \ + ph \ + pk \ + pl \ + pt \ + ro \ + rs \ + ru \ + se \ + si \ + sk \ + sn \ + sy \ + tg \ + th \ + tj \ + tm \ + tr \ + tw \ + tz \ + ua \ + uz \ + vn \ + workman \ + za +layoutsdir = $(pkgdatadir)/layouts +dist_layouts_DATA = $(layouts:%=layouts/%) + +man1_MANS = keyd.1 keyd-application-mapper.1 +CLEANFILES += $(man1_MANS) +EXTRA_DIST += $(man1_MANS:%.1=docs/%.scdoc) +$(man1_MANS): %.1: docs/%.scdoc + $(SCDOC) <$< >$@.tmp + mv $@.tmp $@ + +EXTRA_DIST += build-aux/git-version-gen +dist-hook: + printf %s\\n '$(VERSION)' >$(distdir)/.dist-version + +test: check +check_PROGRAMS = test-io +test_io_SOURCES = \ + src/config.c \ + src/ini.c \ + src/keyboard.c \ + src/keys.c \ + src/keys.h \ + src/log.c \ + src/macro.c \ + src/strutil.c \ + t/test-io.c +nodist_test_io_SOURCES = \ + src/unicode.c +test_io_CPPFLAGS = $(AM_CPPFLAGS) -Isrc -I$(srcdir)/src +TEST_EXTENSIONS = .t +T_LOG_COMPILER = ./test-io '$(srcdir)'/t/test.conf +handwritten_tests = \ + t/altgr-modifier-guard.t \ + t/chord-disambiguate.t \ + t/chord-double.t \ + t/chord-hold.t \ + t/chord.t \ + t/chord2.t \ + t/chord3.t \ + t/clear.t \ + t/composite.t \ + t/composite2.t \ + t/composite3.t \ + t/composite4.t \ + t/control.t \ + t/disarm.t \ + t/disarm2.t \ + t/disarm3.t \ + t/layer.t \ + t/layer1.t \ + t/layer2.t \ + t/layer3.t \ + t/layer4.t \ + t/layerm.t \ + t/layout-mods.t \ + t/layout-mods2.t \ + t/layout-seq.t \ + t/layout.t \ + t/layout2.t \ + t/macro-disarm.t \ + t/macro-hold-1.t \ + t/macro-hold-2.t \ + t/macro-hold.t \ + t/macro-nested.t \ + t/macro-unicode-2.t \ + t/macro-unicode.t \ + t/macro.t \ + t/meta.t \ + t/mod.t \ + t/mod2.t \ + t/mod3.t \ + t/oneshot+overload.t \ + t/oneshot-single-key.t \ + t/oneshot.t \ + t/oneshot10.t \ + t/oneshot11.t \ + t/oneshot12.t \ + t/oneshot14.t \ + t/oneshot2.t \ + t/oneshot3.t \ + t/oneshot4.t \ + t/oneshot5.t \ + t/oneshot6.t \ + t/oneshot9.t \ + t/oneshotm.t \ + t/oneshotn.t \ + t/oneshotn3.t \ + t/overload-expire.t \ + t/overload-expire2.t \ + t/overload-nested.t \ + t/overload-nested2.t \ + t/overload-oneshot.t \ + t/overload-same-key.t \ + t/overload-swap.t \ + t/overload.t \ + t/overload1.t \ + t/overload2.t \ + t/overload3.t \ + t/overload4.t \ + t/overload5.t \ + t/overload_2-2.t \ + t/overload_2.t \ + t/overload_3.t \ + t/swap-oneshot.t \ + t/swap-toggle.t \ + t/swap.t \ + t/swap2.t \ + t/swap3.t \ + t/swap4.t \ + t/swap5.t \ + t/swap6.t \ + t/swap8.t \ + t/swap9.t \ + t/timeout1.t \ + t/timeout2.t \ + t/toggle-2.t \ + t/toggle.t \ + t/toggle2.t +generated_tests = +TESTS = $(handwritten_tests) $(generated_tests) +EXTRA_DIST += $(handwritten_tests) \ + t/keys.py \ + t/run.sh \ + t/runner.py \ + t/test.conf diff --git a/autogen b/autogen new file mode 100755 index 0000000..806d54e --- /dev/null +++ b/autogen @@ -0,0 +1,2 @@ +#!/bin/sh +cd "${0%/*}" && exec autoreconf -fviW all diff --git a/build-aux/git-version-gen b/build-aux/git-version-gen new file mode 100755 index 0000000..3b87c15 --- /dev/null +++ b/build-aux/git-version-gen @@ -0,0 +1,233 @@ +#!/bin/sh +# Print a version string. +scriptversion=2024-07-04.10; # UTC + +# Copyright (C) 2007-2024 Free Software Foundation, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Originally downloaded from gnulib source repository: +# https://git.savannah.gnu.org/cgit/gnulib.git/tree/build-aux/git-version-gen +# Local modifications from the upstream gnulib version: +# 2024-01-08 Add this comment block +# 2024-01-08 Pass '--tags' to 'git describe' + +# This script is derived from GIT-VERSION-GEN from GIT: https://git-scm.com/. +# It may be run two ways: +# - from a git repository in which the "git describe" command below +# produces useful output (thus requiring at least one signed tag) +# - from a non-git-repo directory containing a .tarball-version file, which +# presumes this script is invoked like "./git-version-gen .tarball-version". + +# In order to use intra-version strings in your project, you will need two +# separate generated version string files: +# +# .tarball-version - present only in a distribution tarball, and not in +# a checked-out repository. Created with contents that were learned at +# the last time autoconf was run, and used by git-version-gen. Must not +# be present in either $(srcdir) or $(builddir) for git-version-gen to +# give accurate answers during normal development with a checked out tree, +# but must be present in a tarball when there is no version control system. +# Therefore, it cannot be used in any dependencies. GNUmakefile has +# hooks to force a reconfigure at distribution time to get the value +# correct, without penalizing normal development with extra reconfigures. +# +# .version - present in a checked-out repository and in a distribution +# tarball. Usable in dependencies, particularly for files that don't +# want to depend on config.h but do want to track version changes. +# Delete this file prior to any autoconf run where you want to rebuild +# files to pick up a version string change; and leave it stale to +# minimize rebuild time after unrelated changes to configure sources. +# +# As with any generated file in a VC'd directory, you should add +# /.version to .gitignore, so that you don't accidentally commit it. +# .tarball-version is never generated in a VC'd directory, so needn't +# be listed there. +# +# Use the following line in your configure.ac, so that $(VERSION) will +# automatically be up-to-date each time configure is run (and note that +# since configure.ac no longer includes a version string, Makefile rules +# should not depend on configure.ac for version updates). +# +# AC_INIT([GNU project], +# m4_esyscmd([build-aux/git-version-gen .tarball-version]), +# [bug-project@example]) +# +# Then use the following lines in your Makefile.am, so that .version +# will be present for dependencies, and so that .version and +# .tarball-version will exist in distribution tarballs. +# +# EXTRA_DIST = $(top_srcdir)/.version +# BUILT_SOURCES = $(top_srcdir)/.version +# $(top_srcdir)/.version: +# echo '$(VERSION)' > $@-t +# mv $@-t $@ +# dist-hook: +# echo '$(VERSION)' > $(distdir)/.tarball-version + + +me=$0 + +year=`expr "$scriptversion" : '\([^-]*\)'` +version="git-version-gen $scriptversion + +Copyright (C) ${year} Free Software Foundation, Inc. +License GPLv3+: GNU GPL version 3 or later . +This is free software: you are free to change and redistribute it. +There is NO WARRANTY, to the extent permitted by law." + +usage="\ +Usage: $me [OPTION]... \$srcdir/.tarball-version [TAG-NORMALIZATION-SED-SCRIPT] +Print a version string. + +Options: + + --prefix PREFIX prefix of git tags (default 'v') + --fallback VERSION + fallback version to use if \"git --version\" fails + + --help display this help and exit + --version output version information and exit + +Send patches and bug reports to ." + +prefix=v +fallback= + +while test $# -gt 0; do + case $1 in + --help) echo "$usage"; exit 0;; + --version) echo "$version"; exit 0;; + --prefix) shift; prefix=${1?};; + --fallback) shift; fallback=${1?};; + -*) + echo "$0: Unknown option '$1'." >&2 + echo "$0: Try '--help' for more information." >&2 + exit 1;; + *) + if test "x$tarball_version_file" = x; then + tarball_version_file="$1" + elif test "x$tag_sed_script" = x; then + tag_sed_script="$1" + else + echo "$0: extra non-option argument '$1'." >&2 + exit 1 + fi;; + esac + shift +done + +if test "x$tarball_version_file" = x; then + echo "$usage" + exit 1 +fi + +tag_sed_script="${tag_sed_script:-s/x/x/}" + +nl=' +' + +# Avoid meddling by environment variable of the same name. +v= +v_from_git= + +# First see if there is a tarball-only version file. +# then try "git describe", then default. +if test -f $tarball_version_file +then + v=`cat $tarball_version_file` || v= + case $v in + *$nl*) v= ;; # reject multi-line output + esac + test "x$v" = x \ + && echo "$0: WARNING: $tarball_version_file is damaged" 1>&2 +fi + +if test "x$v" != x +then + : # use $v +# Otherwise, if there is at least one git commit involving the working +# directory, and "git describe" output looks sensible, use that to +# derive a version string. +elif test "`git log -1 --pretty=format:x . 2>&1`" = x \ + && v=`git describe --abbrev=4 --match="$prefix*" --tags HEAD 2>/dev/null \ + || git describe --abbrev=4 --tags HEAD 2>/dev/null` \ + && v=`printf '%s\n' "$v" | sed "$tag_sed_script"` \ + && case $v in + $prefix[0-9]*) ;; + *) (exit 1) ;; + esac +then + # Is this a new git that lists number of commits since the last + # tag or the previous older version that did not? + # Newer: v6.10-77-g0f8faeb + # Older: v6.10-g0f8faeb + vprefix=`expr "X$v" : 'X\(.*\)-g[^-]*$'` || vprefix=$v + case $vprefix in + *-*) : git describe is probably okay three part flavor ;; + *) + : git describe is older two part flavor + # Recreate the number of commits and rewrite such that the + # result is the same as if we were using the newer version + # of git describe. + vtag=`echo "$v" | sed 's/-.*//'` + commit_list=`git rev-list "$vtag"..HEAD 2>/dev/null` \ + || { commit_list=failed; + echo "$0: WARNING: git rev-list failed" 1>&2; } + numcommits=`echo "$commit_list" | wc -l` + v=`echo "$v" | sed "s/\(.*\)-\(.*\)/\1-$numcommits-\2/"`; + test "$commit_list" = failed && v=UNKNOWN + ;; + esac + + # Change the penultimate "-" to ".", for version-comparing tools. + # Remove the "g" to save a byte. + v=`echo "$v" | sed 's/-\([^-]*\)-g\([^-]*\)$/.\1-\2/'`; + v_from_git=1 +elif test "x$fallback" = x || git --version >/dev/null 2>&1; then + v=UNKNOWN +else + v=$fallback +fi + +v=`echo "$v" |sed "s/^$prefix//"` + +# Test whether to append the "-dirty" suffix only if the version +# string we're using came from git. I.e., skip the test if it's "UNKNOWN" +# or if it came from .tarball-version. +if test "x$v_from_git" != x; then + # Don't declare a version "dirty" merely because a timestamp has changed. + git update-index --refresh > /dev/null 2>&1 + + dirty=`exec 2>/dev/null;git diff-index --name-only HEAD` || dirty= + case "$dirty" in + '') ;; + *) # Append the suffix only if there isn't one already. + case $v in + *-dirty) ;; + *) v="$v-dirty" ;; + esac ;; + esac +fi + +# Omit the trailing newline, so that m4_esyscmd can use the result directly. +printf %s "$v" + +# Local variables: +# eval: (add-hook 'before-save-hook 'time-stamp nil t) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..5c0f25f --- /dev/null +++ b/configure.ac @@ -0,0 +1,91 @@ +AC_PREREQ([2.63b]) +AC_INIT([keyd], + dnl Get the version from Git. The m4_dquote macro is used instead of quotes to ensure that the + dnl command is only run once. The command outputs m4 quotes to prevent incidental expansion (the + dnl m4_esyscmd macro does not quote the command output itself, so the command output is subject to + dnl expansion). + m4_dquote(m4_esyscmd([printf "[%s]" "$(build-aux/git-version-gen .dist-version)"])), + [https://github.com/rvaiya/keyd/issues], + [], + [https://github.com/rvaiya/keyd]) +AC_SUBST([CONFIGURE_DEPENDENCIES], ['$(top_srcdir)/build-aux/git-version-gen']) +AC_CONFIG_SRCDIR([src/keyd.c]) +AC_CONFIG_AUX_DIR([build-aux]) +AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects]) + +AC_PROG_CC +AC_MSG_CHECKING([whether C11 is supported]) +_keyd_cver=` + AS_ECHO(["$ac_prog_cc_stdc"]) | + [sed -e ' + s/^c\([0-9]\{4\}\)$/\1/; t + s/^c\([8-9][0-9]\)$/19\1/; t + s/^c\([0-9]\{2\}\)$/20\1/; t + s/.*/0/ + '] +` +# Assumption: Future versions of the C standard are always backwards compatible. +AS_IF([test "${_keyd_cver}" -ge 2011], + [AC_MSG_RESULT([yes ($ac_prog_cc_stdc)])], + [ + _keyd_cver_msg=$ac_prog_cc_stdc + AS_IF([test "x$ac_prog_cc_stdc" != xno], [_keyd_cver_msg="no ($_keyd_cver_msg)"]) + AC_MSG_RESULT([$_keyd_cver_msg]) + AC_MSG_FAILURE([a C compiler that supports C11 is required]) + ]) + +AC_CONFIG_HEADERS([autoconfig.h]) +AC_PATH_PROG([BASH], [bash], []) +AS_IF([test -z "$BASH"], [AC_MSG_FAILURE([bash is required])]) +AC_PATH_PROG([SCDOC], [scdoc], []) +AS_IF([test -z "$SCDOC"], [AC_MSG_FAILURE([scdoc is required])]) +AM_PATH_PYTHON([3.8]) + +AC_ARG_WITH([vkbd], + [AS_HELP_STRING( + [--with-vkbd=ARG], + [the virtual keyboard driver to use, one of: stdout uinput usb-gadget @<:@default=uinput@:>@])], + [], + [with_vkbd=uinput]) +AC_SUBST([VKBD], [$with_vkbd]) +AM_CONDITIONAL([USB_GADGET], [test "x${with_vkbd}" = xusb-gadget]) + +AC_ARG_WITH([systemd-system-unit], + [AS_HELP_STRING( + [--with-systemd-system-unit@<:@=DIR@:>@], + [install systemd system unit files to DIR; 'yes' means autodetect, 'no' or blank means do not + install any systemd system unit files @<:@default=yes@:>@])], + [], + [with_systemd_system_unit=yes]) +AS_IF( + [test "x$with_systemd_system_unit" = xno], [with_systemd_system_unit=], + [test "x$with_systemd_system_unit" = xyes], [ + m4_ifdef([PKG_CHECK_VAR], [ + PKG_CHECK_VAR([SYSTEMD_SYSTEM_UNIT_DIR], [systemd], [systemdsystemunitdir], [ + with_systemd_system_unit=$SYSTEMD_SYSTEM_UNIT_DIR + ], [ + AC_MSG_ERROR([m4_normalize([ + failed to locate systemd system unit directory. If your system does not use systemd, + please pass --without-systemd-system-unit to $srcdir/configure + ])]) + ]) + ], [ + AC_MSG_ERROR([m4_normalize([ + unable to detect systemd system unit directory because the pkg-config autoconf macros were + not available when the configure script was built. Please install pkg-config and run + $srcdir/autogen to rebuild $srcdir/configure, then re-run $srcdir/configure. + Alternatively, pass --without-systemd-system-unit to $srcdir/configure to disable the + creation and installation of the systemd system unit files + ])]) + ]) + ]) +AC_MSG_CHECKING([whether to install systemd system unit files]) +AS_IF([test -n "$with_systemd_system_unit"], [AC_MSG_RESULT([yes, to $with_systemd_system_unit])], + [AC_MSG_RESULT([no])]) +AC_SUBST([systemdsystemunitdir], [$with_systemd_system_unit]) +AM_CONDITIONAL([SYSTEMD_SYSTEM_UNIT], [test -n "$with_systemd_system_unit"]) + +AC_CONFIG_FILES([ + Makefile +]) +AC_OUTPUT diff --git a/scripts/generate_xcompose b/scripts/generate_xcompose index d1edb6f..e6d7f7d 100755 --- a/scripts/generate_xcompose +++ b/scripts/generate_xcompose @@ -2,8 +2,10 @@ import sys +infile, outcompose, outc = (sys.argv + [None, None, None])[1:4] + codes = [] -for line in open('data/unicode.txt').readlines(): # Original source: https://www.unicode.org/Public/14.0.0/ucd/UnicodeData.txt +for line in open(infile or 'data/unicode.txt').readlines(): # Original source: https://www.unicode.org/Public/14.0.0/ucd/UnicodeData.txt try: code = int(line.split(';')[0], 16) @@ -36,7 +38,7 @@ for n, code in enumerate(codes): data += ' '.join(f'<{c}>' for c in base36(n)) data += f' : "{chr(code)}"\n' -open('data/keyd.compose', 'w').write(data) +open(outcompose or 'data/keyd.compose', 'w').write(data) # Generate the corresponding src/unicode.c @@ -44,7 +46,7 @@ open('data/keyd.compose', 'w').write(data) # table to capitalize on codepoint contiguity, but 35k is small enough to # warrant keeping the entire thing in memory. -open('src/unicode.c', 'w').write(f''' +open(outc or 'src/unicode.c', 'w').write(f''' /* GENERATED BY {sys.argv[0]}, DO NOT MODIFY BY HAND. */ #include diff --git a/src/config.c b/src/config.c index d3b301c..28f8a6e 100644 --- a/src/config.c +++ b/src/config.c @@ -21,7 +21,7 @@ #include "ini.h" #include "keys.h" #include "log.h" -#include "string.h" +#include "strutil.h" #include "unicode.h" #define MAX_FILE_SZ 65536 diff --git a/src/keyd.h b/src/keyd.h index 6318939..c5274c9 100644 --- a/src/keyd.h +++ b/src/keyd.h @@ -6,6 +6,8 @@ #ifndef KEYD_H_ #define KEYD_H_ +#include + #include #include #include @@ -44,7 +46,7 @@ #include "keyboard.h" #include "keys.h" #include "vkbd.h" -#include "string.h" +#include "strutil.h" #define MAX_IPC_MESSAGE_SIZE 4096 diff --git a/src/string.c b/src/strutil.c similarity index 98% rename from src/string.c rename to src/strutil.c index dfcdc60..4cdb641 100644 --- a/src/string.c +++ b/src/strutil.c @@ -5,7 +5,7 @@ */ #include -#include "string.h" +#include "strutil.h" int utf8_read_char(const char *_s, uint32_t *code) { diff --git a/src/string.h b/src/strutil.h similarity index 88% rename from src/string.h rename to src/strutil.h index 3e374cc..eb6ea46 100644 --- a/src/string.h +++ b/src/strutil.h @@ -3,8 +3,8 @@ * * © 2019 Raheman Vaiya (see also: LICENSE). */ -#ifndef STRING_H -#define STRING_H +#ifndef STRUTIL_H +#define STRUTIL_H #include #include