├── .dir-locals.el ├── .travis.yml ├── AUTHORS ├── COPYING ├── Makefile.am ├── NEWS ├── README ├── README.md ├── autogen.sh ├── configure.ac ├── docs └── Makefile.am ├── git.mk ├── lcov.mk ├── libskk ├── Makefile.am ├── candidate-list.vala ├── candidate.vala ├── cdb-dict.vala ├── completion.vala ├── config.vapi ├── context.vala ├── dict.vala ├── encoding.vala ├── expr.vala ├── file-dict.vala ├── key-event-filter.vala ├── key-event.vala ├── keymap.vala ├── keysyms.vala ├── libskk.pc.in ├── map-file.vala ├── nicola.vala ├── rom-kana.vala ├── rule.vala ├── skk-1.0.deps ├── skkserv.vala ├── state.vala ├── user-dict.vala ├── util.vala └── xkbcommon.vapi ├── m4 └── vala.m4 ├── po ├── LINGUAS ├── Makevars ├── POTFILES.in ├── POTFILES.skip └── ja.po ├── rules ├── Makefile.am ├── README.rules ├── act │ ├── keymap │ │ ├── default.json │ │ ├── hankaku-katakana.json │ │ ├── hiragana.json │ │ ├── katakana.json │ │ ├── latin.json │ │ └── wide-latin.json │ ├── metadata.json │ └── rom-kana │ │ └── default.json ├── act09 │ ├── keymap │ │ ├── default.json │ │ ├── hankaku-katakana.json │ │ ├── hiragana.json │ │ ├── katakana.json │ │ ├── latin.json │ │ └── wide-latin.json │ ├── metadata.json │ └── rom-kana │ │ └── default.json ├── azik │ ├── keymap │ │ ├── common.json │ │ ├── default.json │ │ ├── hankaku-katakana.json │ │ ├── hiragana.json │ │ ├── katakana.json │ │ ├── latin.json │ │ └── wide-latin.json │ ├── metadata.json │ └── rom-kana │ │ └── default.json ├── default │ ├── keymap │ │ ├── default.json │ │ ├── hankaku-katakana.json │ │ ├── hiragana.json │ │ ├── katakana.json │ │ ├── latin.json │ │ └── wide-latin.json │ ├── metadata.json │ └── rom-kana │ │ └── default.json ├── kzik │ ├── keymap │ │ ├── common.json │ │ ├── default.json │ │ ├── hankaku-katakana.json │ │ ├── hiragana.json │ │ ├── katakana.json │ │ ├── latin.json │ │ └── wide-latin.json │ ├── metadata.json │ └── rom-kana │ │ └── default.json ├── nicola │ ├── keymap │ │ ├── default.json │ │ ├── hankaku-katakana.json │ │ ├── hiragana.json │ │ ├── kana.json │ │ ├── katakana.json │ │ ├── latin.json │ │ └── wide-latin.json │ ├── metadata.json │ └── rom-kana │ │ └── default.json ├── tcode │ ├── keymap │ │ ├── hankaku-katakana.json │ │ ├── hiragana.json │ │ ├── katakana.json │ │ ├── latin.json │ │ └── wide-latin.json │ ├── metadata.json │ └── rom-kana │ │ └── default.json ├── trycode │ ├── keymap │ │ ├── hankaku-katakana.json │ │ ├── hiragana.json │ │ ├── katakana.json │ │ ├── latin.json │ │ └── wide-latin.json │ ├── metadata.json │ └── rom-kana │ │ └── default.json ├── tutcode-touch16x │ ├── keymap │ │ ├── hankaku-katakana.json │ │ ├── hiragana.json │ │ ├── katakana.json │ │ ├── latin.json │ │ └── wide-latin.json │ ├── metadata.json │ └── rom-kana │ │ └── default.json └── tutcode │ ├── keymap │ ├── hankaku-katakana.json │ ├── hiragana.json │ ├── katakana.json │ ├── latin.json │ └── wide-latin.json │ ├── metadata.json │ └── rom-kana │ └── default.json ├── tests ├── Makefile.am ├── basic.c ├── cdb-dict.c ├── cdb-dict.dat ├── common.c ├── common.h ├── context.c ├── file-dict.c ├── file-dict.dat ├── rom-kana.c ├── rule.c ├── rules │ ├── test-aborts │ │ ├── keymap │ │ │ └── hiragana.json │ │ ├── metadata.json │ │ └── rom-kana │ │ │ └── default.json │ ├── test-inherit-rule-for-dict-edit │ │ ├── keymap │ │ │ └── hiragana.json │ │ ├── metadata.json │ │ └── rom-kana │ │ │ └── default.json │ ├── test-selection │ │ ├── keymap │ │ │ ├── default.json │ │ │ ├── hankaku-katakana.json │ │ │ ├── hiragana.json │ │ │ ├── katakana.json │ │ │ ├── latin.json │ │ │ └── wide-latin.json │ │ ├── metadata.json │ │ └── rom-kana │ │ │ └── default.json │ └── test-sticky │ │ ├── keymap │ │ └── hiragana.json │ │ ├── metadata.json │ │ └── rom-kana │ │ └── default.json ├── skkserv.c └── user-dict.c └── tools ├── Makefile.am ├── fep.vala ├── skk.1 ├── skk.vala ├── skkfep.1 └── skkfep.in /.dir-locals.el: -------------------------------------------------------------------------------- 1 | ((c-mode . ((indent-tabs-mode . nil))) 2 | (vala-mode . ((indent-tabs-mode . nil))) 3 | (js-mode . ((indent-tabs-mode . nil)))) 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | 3 | language: c 4 | 5 | env: 6 | - BUILD_OPTS="--prefix=/usr --libdir=/usr/lib64" 7 | - BUILD_OPTS="--prefix=/usr --libdir=/usr/lib64 --enable-docs" DOCS=yes EXTRA_PKGS="gtk-doc valadoc valadoc-devel" 8 | - BUILD_OPTS="--prefix=/usr --libdir=/usr/lib64 --enable-code-coverage" COVERAGE=yes EXTRA_PKGS="python-pip" 9 | - BUILD_OPTS="--prefix=/usr --libdir=/usr/lib64 CFLAGS='-fsanitize=address -g -fno-common -U_FORTIFY_SOURCE' CXXFLAGS='-fsanitize=address -g -fno-common -U_FORTIFY_SOURCE' LDFLAGS='-fsanitize=address -g -fno-common -U_FORTIFY_SOURCE' LIBS='-ldl -lpthread'" EXTRA_PKGS="libasan" 10 | - BUILD_OPTS="--prefix=/usr --libdir=/usr/lib64 CFLAGS='-fsanitize=undefined -g -fno-common -U_FORTIFY_SOURCE' CXXFLAGS='-fsanitize=undefined -g -fno-common -U_FORTIFY_SOURCE' LDFLAGS='-fsanitize=undefined -g -fno-common -U_FORTIFY_SOURCE' LIBS='-ldl -lpthread'" EXTRA_PKGS="libubsan" 11 | 12 | services: 13 | - docker 14 | 15 | before_install: 16 | - docker pull fedora 17 | - export CONTAINER=$(docker run --cap-add SYS_PTRACE -d fedora sleep 1800) 18 | - docker exec $CONTAINER dnf -y install 'dnf-command(builddep)' 19 | - docker exec $CONTAINER dnf -y builddep libskk 20 | - docker exec $CONTAINER dnf -y install libtool make which gcc-c++ vala vala-devel git libxkbcommon-devel $EXTRA_PKGS 21 | - docker exec $CONTAINER useradd user 22 | 23 | install: 24 | - docker cp . $CONTAINER:/srcdir 25 | - docker exec $CONTAINER chown -R user /srcdir 26 | 27 | script: 28 | - docker exec $CONTAINER su - user sh -c "cd /srcdir && NOCONFIGURE=1 ./autogen.sh" 29 | - docker exec $CONTAINER su - user sh -c "cd /srcdir && ./configure $BUILD_OPTS" 30 | - docker exec $CONTAINER su - user sh -c "cd /srcdir && make V=1 && touch po/libskk.pot && make check V=1" 31 | 32 | after_failure: 33 | - docker exec $CONTAINER su - user sh -c "cd /srcdir && cat tests/test-suite.log" 34 | - docker exec $CONTAINER su - user sh -c "cd /srcdir && cat config.log" 35 | 36 | after_success: 37 | - | 38 | if test x"$COVERAGE" = xyes; then 39 | docker exec $CONTAINER pip install cpp-coveralls 40 | docker exec -e TRAVIS_JOB_ID="$TRAVIS_JOB_ID" -e TRAVIS_BRANCH="$TRAVIS_BRANCH" $CONTAINER sh -c "cd /srcdir && coveralls --exclude tools --exclude tests --gcov-options '\-lp'" 41 | fi 42 | - | 43 | if test x"$DOCS" = xyes; then 44 | mkdir dist 45 | docker cp $CONTAINER:/srcdir/docs/libskk/libskk dist/vala 46 | docker cp $CONTAINER:/srcdir/docs/gtk-doc/libskk/html dist/c 47 | fi 48 | 49 | deploy: 50 | provider: pages 51 | skip_cleanup: true 52 | github_token: $GITHUB_TOKEN 53 | local_dir: dist 54 | on: 55 | branch: master 56 | condition: $DOCS = yes 57 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ueno/libskk/d5e9726fa5c439518bed2a74d1796d3b99b861ce/AUTHORS -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011-2018 Daiki Ueno 2 | # Copyright (C) 2011-2018 Red Hat, Inc. 3 | 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | 17 | SUBDIRS = libskk rules tools tests po 18 | DISTCHECK_CONFIGURE_FLAGS = --enable-docs --enable-fep 19 | ACLOCAL_AMFLAGS = -I m4 20 | 21 | if HAVE_VALADOC 22 | SUBDIRS += docs 23 | endif 24 | 25 | DIST_SUBDIRS = libskk rules tools tests docs po 26 | 27 | GITIGNOREFILES = \ 28 | ABOUT-NLS \ 29 | config.rpath \ 30 | INSTALL \ 31 | aclocal.m4 \ 32 | compile \ 33 | config.guess \ 34 | config.h.in \ 35 | config.sub \ 36 | depcomp \ 37 | install-sh \ 38 | ltmain.sh \ 39 | missing \ 40 | mkinstalldirs \ 41 | `find "m4" -type f -name "*.m4" ! -name "vala.m4" -print` \ 42 | $(top_builddir)/lcov.html/* \ 43 | $(top_builddir)/docs/gtk-doc \ 44 | $(top_builddir)/docs/libskk \ 45 | po/Makevars.template \ 46 | po/Rules-quot \ 47 | po/boldquot.sed \ 48 | po/en@boldquot.header \ 49 | po/en@quot.header \ 50 | po/insert-header.sin \ 51 | po/quot.sed \ 52 | po/remove-potcdate.sed \ 53 | po/remove-potcdate.sin \ 54 | po/stamp-po \ 55 | test-driver \ 56 | $(NULL) 57 | 58 | distclean-local: 59 | if test "x$(srcdir)" = "x."; then :; else \ 60 | rm -f ChangeLog; \ 61 | fi 62 | 63 | MAINTAINERCLEANFILES = \ 64 | $(top_builddir)/lcov.info \ 65 | $(srcdir)/ChangeLog \ 66 | $(NULL) 67 | 68 | EXTRA_DIST = lcov.mk 69 | 70 | maintainer-clean-local: maintainer-clean-local-lcov 71 | maintainer-clean-local-lcov: 72 | rm -rf $(top_builddir)/lcov.html 73 | 74 | .PHONY: maintainer-clean-local-lcov 75 | 76 | ChangeLog: 77 | @echo Creating $@ 78 | @if test -d "$(srcdir)/.git"; then \ 79 | (GIT_DIR=$(top_srcdir)/.git ./missing --run git log --stat) | fmt --split-only > $@.tmp \ 80 | && mv -f $@.tmp $@ \ 81 | || ($(RM) $@.tmp; \ 82 | echo Failed to generate ChangeLog, your ChangeLog may be outdated >&2; \ 83 | (test -f $@ || echo git-log is required to generate this file >> $@)); \ 84 | else \ 85 | test -f $@ || \ 86 | (echo A git checkout and git-log is required to generate ChangeLog >&2 && \ 87 | echo A git checkout and git-log is required to generate this file >> $@); \ 88 | fi 89 | 90 | .PHONY: ChangeLog 91 | 92 | # Code coverage support 93 | include $(top_srcdir)/lcov.mk 94 | 95 | -include $(top_srcdir)/git.mk 96 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | Noteworthy changes in version 1.0.5 (2018-09-15) 2 | ------------------------------------------------ 3 | 4 | * build: Use libxkbcommon to resolve keysyms [#54] 5 | 6 | Noteworthy changes in version 1.0.4 (2018-06-26) 7 | ------------------------------------------------ 8 | 9 | * Don't consume key release events [#52] 10 | * Improve hankaku katakana conversion [#51] 11 | * Use the same typing rule in dict-edit mode [#50] 12 | * Add `abort-to-latin` and `abort-to-latin-unhandled` command [#48] 13 | * Add more z-* shortcuts from DDSKK 14 | * Fix memory leak caused by Vala array conversion 15 | * Bump build requirements (glib >= 2.36, valadoc >= 0.40) 16 | 17 | Noteworthy changes in version 1.0.3 (2017-11-10) 18 | ------------------------------------------------ 19 | 20 | * Fix hiragana to katakana conversion in abbrev mode [#41] 21 | * Make "commit-unhandled" actually commit in abbrev mode [#39] 22 | * Avoid redundant dictionary lookup in non-numeric conversion cases [#36] 23 | * Fix KZIK rules [#35, #37] 24 | * Fix okuri-ari word registration [#33, #34] 25 | * Add command for sticky-shift [#32] 26 | * Don't crash when a rule has no default metadata [#31] 27 | * Bind C-j to go back to hiragana in AZIK latin [#30] 28 | * Build fixes [#42, #43] 29 | 30 | Noteworthy changes in version 1.0.2 (2014-09-09) 31 | ------------------------------------------------ 32 | 33 | * Migrate to libgee 0.8 from 0.6 (Issue#29). 34 | * rules: new ACT09 rule contributed by Naoki Mizuno (Issue#28). 35 | * Consume key event for "commit" command (Issue#26). Use 36 | "commit-unhandled" for the previous behavior. 37 | * Consume C-j in abbrev mode (Issue#24). 38 | 39 | Noteworthy changes in version 1.0.1 (2013-04-01) 40 | ------------------------------------------------ 41 | 42 | * Cancel okuri-ari conversion only if there is no candidate (Issue#23). 43 | * Allow clients to populate lookup table before setting cursor pos 44 | (ibus-skk Issue#51). 45 | * rules: inherit AZIK keymap from the default keymap (Issue#22). 46 | * Don't use type-punning when converting bytes to uint32 (Issue#20). 47 | 48 | Noteworthy changes in version 1.0.0 (2012-08-27) 49 | ------------------------------------------------ 50 | 51 | * Make sure to create parent directory of user-dict (Debian bug#685745). 52 | * Clear output and preedit on context reset. 53 | * Fix header include in tests (Issue#19). 54 | 55 | Noteworthy changes in version 0.0.13 (2012-07-02) 56 | ------------------------------------------------ 57 | 58 | * Fix segfault on 64-bit FreeBSD (Issue#18). 59 | * Update required Vala version from 0.12.0 to 0.14.0 (Issue#17). 60 | * Fix CDB dictionary integer alignment issue on ARM (Debian bug#674471). 61 | * Map files that simply include "default" are now optional. 62 | 63 | Noteworthy changes in version 0.0.12 (2012-03-29) 64 | ------------------------------------------------ 65 | 66 | * Improve AZIK, KZIK, and ACT tables (Issue#16). 67 | "upper-" command is added to keymap. 68 | * Fix "nq" and "nl" handling in hiragana input mode (Issue#15). 69 | * Fix "NA" handling in hiragana input mode. 70 | * Fix okuri-ari conversion in katakana input mode (Issue#12). 71 | * --preedit-style option is added to skkfep. 72 | 73 | Noteworthy changes in version 0.0.11 (2012-02-11) 74 | ------------------------------------------------ 75 | 76 | * Fix for candidate list hiding bug (ibus-skk Issue#47). 77 | * Decorate selected candidate in FEP mode. 78 | 79 | Noteworthy changes in version 0.0.10 (2012-02-03) 80 | ------------------------------------------------ 81 | 82 | * Respect coding cookie in file dictionaries (Issue#10). 83 | * Change DictEdit preedit format to make Firefox forms happy. 84 | * Support libfep and add skkfep replacement. 85 | To enable, pass --enable-fep to configure. 86 | 87 | Noteworthy changes in version 0.0.9 (2012-01-25) 88 | ------------------------------------------------ 89 | 90 | * Import skk.1 manual page from Debian. 91 | * Adopt code coverage testing with lcov. 92 | To enable, pass --enable-code-coverage to configure. 93 | * Support running test cases under valgrind. 94 | To enable, pass --enable-valgrind-tests to configure. 95 | 96 | Noteworthy changes in version 0.0.8 (2012-01-11) 97 | ------------------------------------------------ 98 | 99 | * Fix user dictionary handling (ibus-skk Issue#44). 100 | 101 | Noteworthy changes in version 0.0.7 (2012-01-05) 102 | ------------------------------------------------ 103 | 104 | * Improve candidate list traversal with "x" and SPC keys. 105 | * Reduce the number of property notifications for performance. 106 | 107 | Noteworthy changes in version 0.0.6 (2011-12-28) 108 | ------------------------------------------------ 109 | 110 | * Support re-conversion based on surrounding text. 111 | 112 | Noteworthy changes in version 0.0.5 (2011-12-25) 113 | ------------------------------------------------ 114 | 115 | * Fix buffer overrun when using skkserv (Issue#2). 116 | 117 | Noteworthy changes in version 0.0.4 (2011-12-20) 118 | ------------------------------------------------ 119 | 120 | * Improve kanagaki input okuri-ari conversion. 121 | 122 | Noteworthy changes in version 0.0.3 (2011-12-20) 123 | ------------------------------------------------ 124 | 125 | * Support (concat ...). 126 | 127 | Noteworthy changes in version 0.0.2 (2011-12-16) 128 | ------------------------------------------------ 129 | 130 | * New test tool "skk". 131 | 132 | Noteworthy changes in version 0.0.1 (2011-11-30) 133 | ------------------------------------------------ 134 | 135 | * First release of libskk. 136 | 137 | Copyright (C) 2011-2018 Daiki Ueno 138 | Copyright (C) 2011-2018 Red Hat, Inc. 139 | 140 | This file is free software; as a special exception the author gives 141 | unlimited permission to copy and/or distribute it, with or without 142 | modifications, as long as this notice is preserved. 143 | 144 | This file is distributed in the hope that it will be useful, but 145 | WITHOUT ANY WARRANTY, to the extent permitted by law; without even the 146 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 147 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | libskk -- a library to deal with Japanese kana-to-kanji conversion method 2 | 3 | Features: 4 | 5 | * Support basic features of SKK including: new word registration, 6 | completion, numeric conversion, abbrev mode, kuten input, 7 | hankaku-katakana input, Lisp expression evaluation (concat only), 8 | and re-conversion. 9 | 10 | * Support various typing rules including: romaji-to-kana, AZIK, 11 | TUT-Code, and NICOLA. 12 | 13 | * Support various dictionary types including: file dictionary (such as 14 | SKK-JISYO.[SML]), user dictionary, skkserv, and CDB format 15 | dictionary. 16 | 17 | * GObject based API with gobject-introspection support. 18 | 19 | Documentation: 20 | 21 | * file:tests/context.c for basic usage 22 | * file:rules/README.rules for keymap and romaji-to-kana table customization 23 | * http://du-a.org/docs/libskk/libskk/ for Vala binding reference 24 | * http://du-a.org/docs/gtk-doc/libskk/html/ for C binding reference 25 | 26 | Test: 27 | 28 | $ echo "A i SPC" | skk 29 | { "input": "A i SPC", "output": "", "preedit": "▼愛" } 30 | $ echo "K a p a SPC K a SPC" | skk 31 | { "input": "K a p a SPC K a SPC", "output": "", "preedit": "▼かぱ【▼蚊】" } 32 | $ echo "r k" | skk -r tutcode 33 | { "input": "r k", "output": "あ", "preedit": "" } 34 | $ echo "a (usleep 50000) b (usleep 200000)" | skk -r nicola 35 | { "input": "a (usleep 50000) b (usleep 200000)", "output": "うへ", "preedit": "" } 36 | 37 | License: 38 | 39 | GPLv3+ 40 | 41 | Copyright (C) 2011-2018 Daiki Ueno 42 | Copyright (C) 2011-2018 Red Hat, Inc. 43 | 44 | This file is free software; as a special exception the author gives 45 | unlimited permission to copy and/or distribute it, with or without 46 | modifications, as long as this notice is preserved. 47 | 48 | This file is distributed in the hope that it will be useful, but 49 | WITHOUT ANY WARRANTY, to the extent permitted by law; without even the 50 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 51 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | libskk -- a library to deal with Japanese kana-to-kanji conversion method 2 | ====== 3 | [![Build Status](https://travis-ci.org/ueno/libskk.svg?branch=master)](https://travis-ci.org/ueno/libskk) [![Coverage Status](https://img.shields.io/coveralls/ueno/libskk.svg)](https://coveralls.io/r/ueno/libskk) 4 | 5 | Features 6 | ------ 7 | 8 | * Support basic features of SKK including: new word registration, 9 | completion, numeric conversion, abbrev mode, kuten input, 10 | hankaku-katakana input, Lisp expression evaluation (concat only), 11 | and re-conversion. 12 | 13 | * Support various typing rules including: romaji-to-kana, AZIK, 14 | TUT-Code, and NICOLA. 15 | 16 | * Support various dictionary types including: file dictionary (such as 17 | SKK-JISYO.[SML]), user dictionary, skkserv, and CDB format 18 | dictionary. 19 | 20 | * GObject based API with gobject-introspection support. 21 | 22 | Documentation 23 | ------ 24 | 25 | * [Basic usage](https://github.com/ueno/libskk/blob/master/tests/context.c) 26 | * [Keymap and Romaji-to-Kana table customization](https://github.com/ueno/libskk/blob/master/rules/README.rules) 27 | * [Vala binding reference](https://ueno.github.io/libskk/vala/) 28 | * [C binding reference](https://ueno.github.io/libskk/c/) 29 | 30 | Test 31 | ------ 32 | ``` 33 | $ echo "A i SPC" | skk 34 | { "input": "A i SPC", "output": "", "preedit": "▼愛" } 35 | $ echo "K a p a SPC K a SPC" | skk 36 | { "input": "K a p a SPC K a SPC", "output": "", "preedit": "▼かぱ【▼蚊】" } 37 | $ echo "r k" | skk -r tutcode 38 | { "input": "r k", "output": "あ", "preedit": "" } 39 | $ echo "a (usleep 50000) b (usleep 200000)" | skk -r nicola 40 | { "input": "a (usleep 50000) b (usleep 200000)", "output": "うへ", "preedit": "" } 41 | ``` 42 | 43 | License 44 | ------ 45 | ``` 46 | GPLv3+ 47 | 48 | Copyright (C) 2011-2018 Daiki Ueno 49 | Copyright (C) 2011-2018 Red Hat, Inc. 50 | 51 | This file is free software; as a special exception the author gives 52 | unlimited permission to copy and/or distribute it, with or without 53 | modifications, as long as this notice is preserved. 54 | 55 | This file is distributed in the hope that it will be useful, but 56 | WITHOUT ANY WARRANTY, to the extent permitted by law; without even the 57 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 58 | ``` -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Run this to generate all the initial makefiles, etc. 3 | test -n "$srcdir" || srcdir=$(dirname "$0") 4 | test -n "$srcdir" || srcdir=. 5 | 6 | olddir=$(pwd) 7 | 8 | cd $srcdir 9 | 10 | (test -f configure.ac) || { 11 | echo "*** ERROR: Directory '$srcdir' does not look like the top-level project directory ***" 12 | exit 1 13 | } 14 | 15 | # shellcheck disable=SC2016 16 | PKG_NAME=libskk 17 | 18 | if [ "$#" = 0 -a "x$NOCONFIGURE" = "x" ]; then 19 | echo "*** WARNING: I am going to run 'configure' with no arguments." >&2 20 | echo "*** If you wish to pass any to it, please specify them on the" >&2 21 | echo "*** '$0' command line." >&2 22 | echo "" >&2 23 | fi 24 | 25 | autoreconf --verbose --force --install || exit 1 26 | 27 | cd "$olddir" 28 | if [ "$NOCONFIGURE" = "" ]; then 29 | $srcdir/configure "$@" || exit 1 30 | 31 | if [ "$1" = "--help" ]; then 32 | exit 0 33 | else 34 | echo "Now type 'make' to compile $PKG_NAME" || exit 1 35 | fi 36 | else 37 | echo "Skipping configure process." 38 | fi 39 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011-2018 Daiki Ueno 2 | # Copyright (C) 2011-2018 Red Hat, Inc. 3 | 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | 17 | AC_PREREQ(2.63) 18 | AC_CONFIG_MACRO_DIR([m4]) 19 | 20 | AC_INIT([libskk], [1.0.5], [ueno@gnu.org]) 21 | 22 | SKK_API_VERSION=1.0 23 | SKK_API_MAJOR_VERSION=1 24 | SKK_API_MINOR_VERSION=0 25 | SKK_API_PC_VERSION=1.0 26 | SKK_LIBRARY_SUFFIX="-$SKK_API_VERSION" 27 | 28 | AC_SUBST([SKK_API_VERSION]) 29 | AC_SUBST([SKK_API_MAJOR_VERSION]) 30 | AC_SUBST([SKK_API_MINOR_VERSION]) 31 | AC_SUBST([SKK_API_PC_VERSION]) 32 | AC_SUBST([SKK_LIBRARY_SUFFIX]) 33 | AC_SUBST([SKK_LIBRARY_SUFFIX_U],[AS_TR_SH([$SKK_LIBRARY_SUFFIX])]) 34 | 35 | dnl Init automake 36 | AM_INIT_AUTOMAKE([1.11.1 dist-xz no-dist-gzip]) 37 | AM_MAINTAINER_MODE([enable]) 38 | AC_GNU_SOURCE 39 | 40 | dnl Check for programs 41 | AC_PROG_CC 42 | AM_PROG_CC_C_O 43 | AC_PROG_CC_STDC 44 | AC_PROG_INSTALL 45 | AM_GNU_GETTEXT([external]) 46 | AM_GNU_GETTEXT_VERSION([0.19.8]) 47 | 48 | # define PACKAGE_VERSION_* variables 49 | AM_DISABLE_STATIC 50 | AC_ISC_POSIX 51 | AC_HEADER_STDC 52 | LT_INIT 53 | 54 | # If library source has changed since last release, increment revision 55 | # If public symbols have been added, removed or changed since last release, 56 | # increment current and set revision to 0 57 | # If public symbols have been added since last release, increment age 58 | # If public symbols have been removed since last release, set age to 0 59 | m4_define([libskk_lt_current], [0]) 60 | m4_define([libskk_lt_revision], [0]) 61 | m4_define([libskk_lt_age], [0]) 62 | LT_CURRENT=libskk_lt_current 63 | LT_REVISION=libskk_lt_revision 64 | LT_AGE=libskk_lt_age 65 | AC_SUBST([LT_CURRENT]) 66 | AC_SUBST([LT_REVISION]) 67 | AC_SUBST([LT_AGE]) 68 | 69 | # check gio 70 | PKG_CHECK_MODULES([GIO], [gio-2.0 >= 2.36], , 71 | [AC_MSG_ERROR([can't find gio-2.0])]) 72 | 73 | # check gee 74 | PKG_CHECK_MODULES([GEE], [gee-0.8], , 75 | [AC_MSG_ERROR([can't find gee-0.8])]) 76 | 77 | # check json-glib 78 | PKG_CHECK_MODULES([JSON_GLIB], [json-glib-1.0], , 79 | [AC_MSG_ERROR([can't find json-glib-1.0])]) 80 | 81 | # check xkbcommon 82 | PKG_CHECK_MODULES([XKBCOMMON], [xkbcommon], , 83 | [AC_MSG_ERROR([can't find xkbcommon])]) 84 | 85 | LIBSKK_CFLAGS="$GIO_CFLAGS $GEE_CFLAGS $JSON_GLIB_CFLAGS $XKBCOMMON_CFLAGS" 86 | AC_SUBST(LIBSKK_CFLAGS) 87 | LIBSKK_LIBS="$GIO_LIBS $GEE_LIBS $JSON_GLIB_LIBS $XKBCOMMON_LIBS" 88 | AC_SUBST(LIBSKK_LIBS) 89 | 90 | GOBJECT_INTROSPECTION_CHECK([0.9.0]) 91 | 92 | AM_PROG_VALAC([0.14.0]) 93 | AC_SUBST(VALAC) 94 | AC_SUBST(VALAFLAGS) 95 | 96 | # define GETTEXT_* variables 97 | GETTEXT_PACKAGE=libskk 98 | AC_SUBST(GETTEXT_PACKAGE) 99 | AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE", [Define to the read-only architecture-independent data directory.]) 100 | 101 | AC_ARG_ENABLE([fep], 102 | AS_HELP_STRING([--enable-fep], 103 | [compile with libfep]), 104 | [enable_fep=$enableval], [enable_fep=no]) 105 | if test x$enable_fep = xyes; then 106 | PKG_CHECK_MODULES([LIBFEP], [libfep-glib >= 0.0.7], , enable_fep=no) 107 | VALA_CHECK_PACKAGES([libfep-glib], , enable_fep=no) 108 | AC_PATH_PROG([FEP], [fep]) 109 | fi 110 | AM_CONDITIONAL([ENABLE_FEP], [test x$enable_fep = xyes]) 111 | 112 | AC_ARG_ENABLE([docs], 113 | AS_HELP_STRING([--enable-docs],[Enable documentation generation]), 114 | [enable_docs=$enableval], [enable_docs=no]) 115 | AM_CONDITIONAL([ENABLE_DOCS], [test x$enable_docs = xyes]) 116 | 117 | have_valadoc=no 118 | if test x$enable_docs = xyes; then 119 | AC_PATH_PROG([VALADOC], [valadoc], [:]) 120 | AS_IF([test "$VALADOC" != :], have_valadoc=yes) 121 | fi 122 | AM_CONDITIONAL([HAVE_VALADOC], [test x$have_valadoc = xyes]) 123 | 124 | if test "x$enable_docs" = "xyes" -a "x$have_valadoc" != "xyes"; then 125 | AC_MSG_ERROR([Doc building requested but valadoc not installed.]) 126 | fi 127 | 128 | AC_ARG_ENABLE([code-coverage], 129 | AS_HELP_STRING([--enable-code-coverage], 130 | [compile with code coverage code]), 131 | [enable_code_coverage=$enableval], [enable_code_coverage=no]) 132 | 133 | # Only enable code coverage if this isn't a release. 134 | if test "x$enable_code_coverage" = "xyes"; then 135 | CODE_COVERAGE_CFLAGS="-fprofile-arcs -ftest-coverage -O0 -ggdb" 136 | CODE_COVERAGE_LDFLAGS="-lgcov" 137 | fi 138 | 139 | AC_SUBST([CODE_COVERAGE_CFLAGS]) 140 | AC_SUBST([CODE_COVERAGE_LDFLAGS]) 141 | 142 | AC_ARG_ENABLE([valgrind-tests], 143 | AS_HELP_STRING([--enable-valgrind-tests], 144 | [run self tests under valgrind]), 145 | [enable_valgrind_tests=$enableval], [enable_valgrind_tests=no]) 146 | 147 | # Run self-tests under valgrind? 148 | if test "x$enable_valgrind_tests" = "xyes"; then 149 | AC_CHECK_PROGS(VALGRIND, valgrind) 150 | fi 151 | 152 | if test -n "$VALGRIND"; then 153 | VALGRIND_OPTS="--leak-check=full --show-reachable=no --gen-suppressions=all --num-callers=20 --error-exitcode=0 --log-file=valgrind.log.%p" 154 | AC_SUBST(VALGRIND_OPTS) 155 | fi 156 | 157 | AC_CONFIG_HEADERS([config.h]) 158 | AC_CONFIG_FILES([Makefile 159 | libskk/Makefile 160 | libskk/libskk.pc 161 | rules/Makefile 162 | tools/Makefile 163 | tests/Makefile 164 | docs/Makefile 165 | po/Makefile.in]) 166 | AC_OUTPUT 167 | -------------------------------------------------------------------------------- /docs/Makefile.am: -------------------------------------------------------------------------------- 1 | distclean_dirs = \ 2 | libskk \ 3 | gtk-doc \ 4 | $(NULL) 5 | 6 | docs = \ 7 | libskk-doc \ 8 | libskk-gtk-doc \ 9 | $(NULL) 10 | 11 | libskkdocdir=$(datadir)/devhelp/references/libskk 12 | libskkimgdir=$(datadir)/devhelp/references/libskk/img 13 | 14 | libskkgtkdocdir=$(datadir)/gtk-doc/html/libskk 15 | 16 | common_doc_files = \ 17 | *.css \ 18 | *.png \ 19 | *.js \ 20 | index.htm \ 21 | *.html \ 22 | $(NULL) 23 | 24 | libskkdoc_DATA = \ 25 | libskk/libskk/libskk.devhelp2 \ 26 | $(addprefix libskk/libskk/,$(common_doc_files)) \ 27 | $(NULL) 28 | 29 | libskkgtkdoc_DATA = gtk-doc/libskk/html/* 30 | 31 | libskkimg_DATA = \ 32 | libskk/libskk/img/*.png \ 33 | $(NULL) 34 | 35 | $(libskkdoc_DATA) $(libskkimg_DATA): libskk-doc.stamp 36 | $(libskkgtkdoc_DATA): libskk-gtk-doc.stamp 37 | 38 | valadoc_flags = \ 39 | --force \ 40 | --package-version $(PACKAGE_VERSION) \ 41 | --no-protected \ 42 | --driver "$(shell valac --api-version)" \ 43 | $(NULL) 44 | 45 | # libskk documentation 46 | libskk_doc_files_blacklist = \ 47 | $(top_srcdir)/libskk/kana-kan.vala \ 48 | $(NULL) 49 | # this expands the list of files, so we can filter out elements 50 | libskk_doc_files_all = \ 51 | $(wildcard $(top_srcdir)/libskk/*.vala) \ 52 | $(NULL) 53 | # FIXME: sort the files manually to work around the native doclet portion of 54 | # bgo#662784 55 | libskk_doc_files = \ 56 | $(sort \ 57 | $(filter-out $(libskk_doc_files_blacklist),$(libskk_doc_files_all))) 58 | libskk_doc_deps = \ 59 | config \ 60 | glib-2.0 \ 61 | gio-2.0 \ 62 | gee-0.8 \ 63 | posix \ 64 | json-glib-1.0 \ 65 | xkbcommon \ 66 | $(NULL) 67 | valadoc_flags_libskk = \ 68 | $(valadoc_flags) \ 69 | -X $(top_srcdir)/libskk/libskk.h \ 70 | $(addprefix --pkg=,$(libskk_doc_deps)) \ 71 | --vapidir=$(top_srcdir)/libskk \ 72 | $(libskk_doc_files) \ 73 | $(NULL) 74 | 75 | libskk-doc.stamp: $(libskk_doc_files) 76 | $(AM_V_GEN)$(VALADOC) \ 77 | -o libskk/ \ 78 | --doclet=devhelp \ 79 | $(valadoc_flags_libskk) \ 80 | $(NULL) 81 | @touch $@ 82 | 83 | libskk-gtk-doc.stamp: $(libskk_doc_files) 84 | $(AM_V_GEN)$(VALADOC) \ 85 | -X -l -X $(top_builddir)/libskk/.libs/libskk.so \ 86 | -o gtk-doc/libskk \ 87 | --doclet=gtkdoc \ 88 | $(valadoc_flags_libskk) \ 89 | $(NULL) 90 | @touch $@ 91 | 92 | stamps = libskk-doc.stamp libskk-gtk-doc.stamp 93 | 94 | all: $(stamps) 95 | 96 | CLEANFILES = $(stamps) 97 | 98 | distclean-local: distclean-docs 99 | distclean-docs: 100 | rm -rf $(distclean_dirs) 101 | 102 | GITIGNOREFILES = \ 103 | $(distclean_dirs) \ 104 | $(NULL) 105 | 106 | -include $(top_srcdir)/git.mk 107 | -------------------------------------------------------------------------------- /git.mk: -------------------------------------------------------------------------------- 1 | # git.mk 2 | # 3 | # Copyright 2009, Red Hat, Inc. 4 | # Copyright 2010,2011 Behdad Esfahbod 5 | # Written by Behdad Esfahbod 6 | # 7 | # Copying and distribution of this file, with or without modification, 8 | # are permitted in any medium without royalty provided the copyright 9 | # notice and this notice are preserved. 10 | # 11 | # The canonical source for this file is https://github.com/behdad/git.mk. 12 | # 13 | # To use in your project, import this file in your git repo's toplevel, 14 | # then do "make -f git.mk". This modifies all Makefile.am files in 15 | # your project to -include git.mk. Remember to add that line to new 16 | # Makefile.am files you create in your project, or just rerun the 17 | # "make -f git.mk". 18 | # 19 | # This enables automatic .gitignore generation. If you need to ignore 20 | # more files, add them to the GITIGNOREFILES variable in your Makefile.am. 21 | # But think twice before doing that. If a file has to be in .gitignore, 22 | # chances are very high that it's a generated file and should be in one 23 | # of MOSTLYCLEANFILES, CLEANFILES, DISTCLEANFILES, or MAINTAINERCLEANFILES. 24 | # 25 | # The only case that you need to manually add a file to GITIGNOREFILES is 26 | # when remove files in one of mostlyclean-local, clean-local, distclean-local, 27 | # or maintainer-clean-local make targets. 28 | # 29 | # Note that for files like editor backup, etc, there are better places to 30 | # ignore them. See "man gitignore". 31 | # 32 | # If "make maintainer-clean" removes the files but they are not recognized 33 | # by this script (that is, if "git status" shows untracked files still), send 34 | # me the output of "git status" as well as your Makefile.am and Makefile for 35 | # the directories involved and I'll diagnose. 36 | # 37 | # For a list of toplevel files that should be in MAINTAINERCLEANFILES, see 38 | # Makefile.am.sample in the git.mk git repo. 39 | # 40 | # Don't EXTRA_DIST this file. It is supposed to only live in git clones, 41 | # not tarballs. It serves no useful purpose in tarballs and clutters the 42 | # build dir. 43 | # 44 | # This file knows how to handle autoconf, automake, libtool, gtk-doc, 45 | # gnome-doc-utils, yelp.m4, mallard, intltool, gsettings. 46 | # 47 | # 48 | # KNOWN ISSUES: 49 | # 50 | # - Recursive configure doesn't work as $(top_srcdir)/git.mk inside the 51 | # submodule doesn't find us. If you have configure.{in,ac} files in 52 | # subdirs, add a proxy git.mk file in those dirs that simply does: 53 | # "include $(top_srcdir)/../git.mk". Add more ..'s to your taste. 54 | # And add those files to git. See vte/gnome-pty-helper/git.mk for 55 | # example. 56 | # 57 | 58 | git-all: git-mk-install 59 | 60 | git-mk-install: 61 | @echo Installing git makefile 62 | @any_failed=; \ 63 | find "`test -z "$(top_srcdir)" && echo . || echo "$(top_srcdir)"`" -name Makefile.am | while read x; do \ 64 | if grep 'include .*/git.mk' $$x >/dev/null; then \ 65 | echo $$x already includes git.mk; \ 66 | else \ 67 | failed=; \ 68 | echo "Updating $$x"; \ 69 | { cat $$x; \ 70 | echo ''; \ 71 | echo '-include $$(top_srcdir)/git.mk'; \ 72 | } > $$x.tmp || failed=1; \ 73 | if test x$$failed = x; then \ 74 | mv $$x.tmp $$x || failed=1; \ 75 | fi; \ 76 | if test x$$failed = x; then : else \ 77 | echo Failed updating $$x; >&2 \ 78 | any_failed=1; \ 79 | fi; \ 80 | fi; done; test -z "$$any_failed" 81 | 82 | .PHONY: git-all git-mk-install 83 | 84 | 85 | ### .gitignore generation 86 | 87 | $(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk 88 | $(AM_V_GEN) \ 89 | { \ 90 | if test "x$(DOC_MODULE)" = x -o "x$(DOC_MAIN_SGML_FILE)" = x; then :; else \ 91 | for x in \ 92 | $(DOC_MODULE)-decl-list.txt \ 93 | $(DOC_MODULE)-decl.txt \ 94 | tmpl/$(DOC_MODULE)-unused.sgml \ 95 | "tmpl/*.bak" \ 96 | xml html \ 97 | ; do echo /$$x; done; \ 98 | fi; \ 99 | if test "x$(DOC_MODULE)$(DOC_ID)" = x -o "x$(DOC_LINGUAS)" = x; then :; else \ 100 | for x in \ 101 | $(_DOC_C_DOCS) \ 102 | $(_DOC_LC_DOCS) \ 103 | $(_DOC_OMF_ALL) \ 104 | $(_DOC_DSK_ALL) \ 105 | $(_DOC_HTML_ALL) \ 106 | $(_DOC_MOFILES) \ 107 | $(_DOC_POFILES) \ 108 | $(DOC_H_FILE) \ 109 | "*/.xml2po.mo" \ 110 | "*/*.omf.out" \ 111 | ; do echo /$$x; done; \ 112 | fi; \ 113 | if test "x$(HELP_ID)" = x -o "x$(HELP_LINGUAS)" = x; then :; else \ 114 | for x in \ 115 | $(_HELP_LC_FILES) \ 116 | $(_HELP_LC_STAMPS) \ 117 | $(_HELP_MOFILES) \ 118 | ; do echo /$$x; done; \ 119 | fi; \ 120 | if test "x$(gsettings_SCHEMAS)" = x; then :; else \ 121 | for x in \ 122 | $(gsettings_SCHEMAS:.xml=.valid) \ 123 | $(gsettings__enum_file) \ 124 | ; do echo /$$x; done; \ 125 | fi; \ 126 | if test -f $(srcdir)/po/Makefile.in.in; then \ 127 | for x in \ 128 | po/Makefile.in.in \ 129 | po/Makefile.in \ 130 | po/Makefile \ 131 | po/POTFILES \ 132 | po/stamp-it \ 133 | po/.intltool-merge-cache \ 134 | "po/*.gmo" \ 135 | "po/*.mo" \ 136 | po/$(GETTEXT_PACKAGE).pot \ 137 | intltool-extract.in \ 138 | intltool-merge.in \ 139 | intltool-update.in \ 140 | ; do echo /$$x; done; \ 141 | fi; \ 142 | if test -f $(srcdir)/configure; then \ 143 | for x in \ 144 | autom4te.cache \ 145 | configure \ 146 | config.h \ 147 | stamp-h1 \ 148 | libtool \ 149 | config.lt \ 150 | ; do echo /$$x; done; \ 151 | fi; \ 152 | for x in \ 153 | .gitignore \ 154 | $(GITIGNOREFILES) \ 155 | $(CLEANFILES) \ 156 | $(PROGRAMS) \ 157 | $(check_PROGRAMS) \ 158 | $(EXTRA_PROGRAMS) \ 159 | $(LTLIBRARIES) \ 160 | so_locations \ 161 | .libs _libs \ 162 | $(MOSTLYCLEANFILES) \ 163 | "*.$(OBJEXT)" \ 164 | "*.lo" \ 165 | $(DISTCLEANFILES) \ 166 | $(am__CONFIG_DISTCLEAN_FILES) \ 167 | $(CONFIG_CLEAN_FILES) \ 168 | TAGS ID GTAGS GRTAGS GSYMS GPATH tags \ 169 | "*.tab.c" \ 170 | $(MAINTAINERCLEANFILES) \ 171 | $(BUILT_SOURCES) \ 172 | $(DEPDIR) \ 173 | Makefile \ 174 | Makefile.in \ 175 | "*.orig" \ 176 | "*.rej" \ 177 | "*.bak" \ 178 | "*~" \ 179 | ".*.sw[nop]" \ 180 | ".dirstamp" \ 181 | ; do echo /$$x; done; \ 182 | } | \ 183 | sed "s@^/`echo "$(srcdir)" | sed 's/\(.\)/[\1]/g'`/@/@" | \ 184 | sed 's@/[.]/@/@g' | \ 185 | LC_ALL=C sort | uniq > $@.tmp && \ 186 | mv $@.tmp $@; 187 | 188 | all: $(srcdir)/.gitignore gitignore-recurse-maybe 189 | gitignore-recurse-maybe: 190 | @if test "x$(SUBDIRS)" = "x$(DIST_SUBDIRS)"; then :; else \ 191 | $(MAKE) $(AM_MAKEFLAGS) gitignore-recurse; \ 192 | fi; 193 | gitignore-recurse: 194 | @for subdir in $(DIST_SUBDIRS); do \ 195 | case " $(SUBDIRS) " in \ 196 | *" $$subdir "*) :;; \ 197 | *) test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) .gitignore gitignore-recurse || echo "Skipping $$subdir");; \ 198 | esac; \ 199 | done 200 | gitignore: $(srcdir)/.gitignore gitignore-recurse 201 | 202 | maintainer-clean: gitignore-clean 203 | gitignore-clean: 204 | -rm -f $(srcdir)/.gitignore 205 | 206 | .PHONY: gitignore-clean gitignore gitignore-recurse gitignore-recurse-maybe 207 | -------------------------------------------------------------------------------- /lcov.mk: -------------------------------------------------------------------------------- 1 | # From http://cgit.freedesktop.org/telepathy/telepathy-glib/tree/tools/lcov.am 2 | 3 | lcov-reset: 4 | lcov --directory @top_srcdir@ --zerocounters 5 | 6 | lcov-report: 7 | lcov --directory @top_srcdir@ --capture \ 8 | --output-file @top_builddir@/lcov.info 9 | $(mkdir_p) @top_builddir@/lcov.html 10 | git_commit=`GIT_DIR=@top_srcdir@/.git git log -1 --pretty=format:%h 2>/dev/null`;\ 11 | genhtml --title "@PACKAGE_STRING@ $$git_commit" \ 12 | --output-directory @top_builddir@/lcov.html lcov.info 13 | @echo 14 | @echo 'lcov report can be found in:' 15 | @echo 'file://@abs_top_builddir@/lcov.html/index.html' 16 | @echo 17 | 18 | lcov-check: 19 | $(MAKE) lcov-reset 20 | $(MAKE) check $(LCOV_CHECK_ARGS) 21 | $(MAKE) lcov-report 22 | 23 | ## vim:set ft=automake: 24 | -------------------------------------------------------------------------------- /libskk/Makefile.am: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011-2018 Daiki Ueno 2 | # Copyright (C) 2011-2018 Red Hat, Inc. 3 | 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | 17 | # force include config.h before gi18n.h. 18 | AM_CPPFLAGS = -include $(CONFIG_HEADER) 19 | 20 | lib_LTLIBRARIES = libskk.la 21 | 22 | libskk_la_VALAFLAGS = \ 23 | --includedir=libskk \ 24 | -H libskk.h \ 25 | --vapi skk-@SKK_API_VERSION@.vapi \ 26 | -h libskk-internals.h \ 27 | --vapidir=. \ 28 | --pkg config \ 29 | --pkg glib-2.0 \ 30 | --pkg gio-2.0 \ 31 | --pkg gee-0.8 \ 32 | --pkg posix \ 33 | --pkg json-glib-1.0 \ 34 | --pkg xkbcommon \ 35 | --internal-vapi skk-internals-@SKK_API_VERSION@.vapi \ 36 | --library skk-@SKK_API_VERSION@ \ 37 | --gir Skk-@SKK_API_VERSION@.gir \ 38 | --symbols libskk.symbols \ 39 | $(VALAFLAGS) \ 40 | $(NULL) 41 | 42 | libskk_la_CFLAGS = \ 43 | $(CODE_COVERAGE_CFLAGS) \ 44 | $(LIBSKK_CFLAGS) \ 45 | -DPKGDATADIR=\"$(pkgdatadir)\" \ 46 | $(NULL) 47 | libskk_la_LIBADD = $(LIBSKK_LIBS) 48 | libskk_la_LDFLAGS = \ 49 | $(CODE_COVERAGE_LDFLAGS) \ 50 | -version-info "$(LT_CURRENT)":"$(LT_REVISION)":"$(LT_AGE)" \ 51 | -export-dynamic \ 52 | -export-symbols $(srcdir)/libskk.symbols \ 53 | $(NULL) 54 | 55 | libskkincludedir = $(includedir)/libskk 56 | libskkinclude_HEADERS = libskk.h 57 | 58 | libskk_la_SOURCES = \ 59 | rom-kana.vala \ 60 | encoding.vala \ 61 | dict.vala \ 62 | file-dict.vala \ 63 | cdb-dict.vala \ 64 | user-dict.vala \ 65 | skkserv.vala \ 66 | key-event.vala \ 67 | key-event-filter.vala \ 68 | keymap.vala \ 69 | rule.vala \ 70 | map-file.vala \ 71 | state.vala \ 72 | context.vala \ 73 | candidate.vala \ 74 | candidate-list.vala \ 75 | nicola.vala \ 76 | expr.vala \ 77 | util.vala \ 78 | keysyms.vala \ 79 | completion.vala \ 80 | $(NULL) 81 | 82 | if HAVE_INTROSPECTION 83 | girdir = $(datadir)/gir-1.0 84 | gir_DATA = Skk-@SKK_API_VERSION@.gir 85 | 86 | typelibdir = $(libdir)/girepository-1.0 87 | typelib_DATA = Skk-@SKK_API_VERSION@.typelib 88 | 89 | Skk-@SKK_API_VERSION@.typelib: Skk-@SKK_API_VERSION@.gir 90 | @INTROSPECTION_COMPILER@ --shared-library=libskk -o $@ $^ 91 | endif 92 | 93 | Skk-@SKK_API_VERSION@.gir skk-internals-@SKK_API_VERSION@.vapi skk-@SKK_API_VERSION@.vapi: libskk.la 94 | 95 | GITIGNOREFILES = \ 96 | $(libskk_la_SOURCES:.vala=.c) \ 97 | libskk_la_vala.stamp \ 98 | libskk.h \ 99 | libskk-internals.h \ 100 | libskk.symbols \ 101 | $(NULL) 102 | 103 | CLEANFILES = \ 104 | skk-@SKK_API_VERSION@.vapi \ 105 | skk-internals-@SKK_API_VERSION@.vapi \ 106 | Skk-@SKK_API_VERSION@.typelib \ 107 | Skk-@SKK_API_VERSION@.gir \ 108 | libskk.pc \ 109 | $(NULL) 110 | 111 | pkgconfigdir = $(libdir)/pkgconfig 112 | pkgconfig_DATA = libskk.pc 113 | 114 | vapi_DATA = skk-1.0.vapi skk-1.0.deps 115 | vapidir = $(datadir)/vala/vapi 116 | 117 | EXTRA_DIST = config.vapi skk-1.0.deps libskk.symbols xkbcommon.vapi 118 | 119 | -include $(top_srcdir)/git.mk 120 | -------------------------------------------------------------------------------- /libskk/candidate.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011-2018 Daiki Ueno 3 | * Copyright (C) 2011-2018 Red Hat, Inc. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | using Gee; 19 | 20 | namespace Skk { 21 | /** 22 | * Object representing a candidate in dictionaries. 23 | */ 24 | public class Candidate : Object { 25 | /** 26 | * Midasi word which generated this candidate. 27 | */ 28 | public string midasi { get; private set; } 29 | 30 | /** 31 | * Flag to indicate whether this candidate is generated as a 32 | * result of okuri-ari conversion. 33 | */ 34 | public bool okuri { get; private set; } 35 | 36 | /** 37 | * Base string value of the candidate. 38 | */ 39 | public string text { get; set; } 40 | 41 | /** 42 | * Optional annotation text associated with the candidate. 43 | */ 44 | public string? annotation { get; set; } 45 | 46 | /** 47 | * Output string shown instead of text. 48 | * 49 | * This is particularly useful to display a candidate of 50 | * numeric conversion. 51 | */ 52 | public string output { get; set; } 53 | 54 | /** 55 | * Convert the candidate to string. 56 | * @return a string representing the candidate 57 | */ 58 | public string to_string () { 59 | if (annotation != null) { 60 | return text + ";" + annotation; 61 | } else { 62 | return text; 63 | } 64 | } 65 | 66 | /** 67 | * Create a new Candidate. 68 | * 69 | * @param midasi midasi (index) word which generate the candidate 70 | * @param okuri whether the candidate is a result of okuri-ari conversion 71 | * @param text base string value of the candidate 72 | * @param annotation optional annotation text to the candidate 73 | * @param output optional output text used instead of text 74 | * 75 | * @return a new SkkCandidate 76 | */ 77 | public Candidate (string midasi, 78 | bool okuri, 79 | string text, 80 | string? annotation = null, 81 | string? output = null) 82 | { 83 | this.midasi = midasi; 84 | this.okuri = okuri; 85 | this.text = text; 86 | this.annotation = annotation; 87 | this.output = output == null ? text : output; 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /libskk/cdb-dict.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011-2018 Daiki Ueno 3 | * Copyright (C) 2011-2018 Red Hat, Inc. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | namespace Skk { 19 | /** 20 | * CDB based implementation of Dict. 21 | */ 22 | public class CdbDict : Dict { 23 | static uint32 hash (char[] chars) { 24 | uint32 h = 5381; 25 | foreach (var c in chars) { 26 | h = ((h << 5) + h) ^ ((uint8) c); 27 | } 28 | return h; 29 | } 30 | 31 | /** 32 | * {@inheritDoc} 33 | */ 34 | public override void reload () throws GLib.Error { 35 | #if VALA_0_16 36 | string attributes = FileAttribute.ETAG_VALUE; 37 | #else 38 | string attributes = FILE_ATTRIBUTE_ETAG_VALUE; 39 | #endif 40 | FileInfo info = file.query_info (attributes, 41 | FileQueryInfoFlags.NONE); 42 | if (info.get_etag () != etag) { 43 | try { 44 | mmap.remap (); 45 | etag = info.get_etag (); 46 | } catch (SkkDictError e) { 47 | warning ("error loading file dictionary %s %s", 48 | file.get_path (), e.message); 49 | } 50 | } 51 | } 52 | 53 | static uint32 read_uint32 (uint8 *p) { 54 | // Make sure that Q does not stride across 4-byte 55 | // alignment on ARM (Debian bug#674471). 56 | uint8 q[4] = (uint8[]) p; 57 | return (q[3] << 24) | (q[2] << 16) | (q[1] << 8) | q[0]; 58 | } 59 | 60 | /** 61 | * {@inheritDoc} 62 | */ 63 | public override Candidate[] lookup (string midasi, bool okuri = false) { 64 | if (mmap.memory == null) 65 | return new Candidate[0]; 66 | 67 | string _midasi; 68 | try { 69 | _midasi = converter.encode (midasi); 70 | } catch (GLib.Error e) { 71 | warning ("can't encode %s: %s", midasi, e.message); 72 | return new Candidate[0]; 73 | } 74 | 75 | uint32 h = hash (_midasi.to_utf8 ()); 76 | uint8 *p = (uint8 *) mmap.memory + (h % 256) * 8; 77 | uint32 hash_offset = read_uint32 (p); 78 | uint32 hash_length = read_uint32 (p + 4); 79 | 80 | uint32 start = (h >> 8) % hash_length; 81 | p = (uint8 *) mmap.memory + hash_offset; 82 | for (var i = 0; i < hash_length; i++) { 83 | uint8 *q = p + 8 * ((i + start) % hash_length); 84 | uint32 _h = read_uint32 (q); 85 | uint32 record_offset = read_uint32 (q + 4); 86 | if (record_offset == 0) 87 | break; 88 | if (_h == h) { 89 | uint8 *r = (uint8 *) mmap.memory + record_offset; 90 | uint32 key_length = read_uint32 (r); 91 | uint32 data_length = read_uint32 (r + 4); 92 | if (Memory.cmp (r + 8, _midasi, key_length) == 0) { 93 | char[] data = new char[data_length + 1]; 94 | Memory.copy (data, r + 8 + key_length, data_length); 95 | data.length--; 96 | string _data; 97 | try { 98 | _data = converter.decode ((string) data); 99 | } catch (GLib.Error e) { 100 | warning ("can't decode data %s: %s", 101 | (string) data, e.message); 102 | break; 103 | } 104 | return split_candidates (midasi, okuri, _data); 105 | } 106 | } 107 | } 108 | return new Candidate[0]; 109 | } 110 | 111 | /** 112 | * {@inheritDoc} 113 | * 114 | * This always returns an empty array since CDB format does 115 | * not provide key enumeration. 116 | */ 117 | public override string[] complete (string midasi) { 118 | return new string[0]; 119 | } 120 | 121 | /** 122 | * {@inheritDoc} 123 | */ 124 | public override bool read_only { 125 | get { 126 | return true; 127 | } 128 | } 129 | 130 | File file; 131 | MemoryMappedFile mmap; 132 | string etag; 133 | EncodingConverter converter; 134 | 135 | /** 136 | * Create a new CdbDict. 137 | * 138 | * @param path a path to the file 139 | * @param encoding encoding of the file (default EUC-JP) 140 | * 141 | * @return a new FileDict 142 | * @throws GLib.Error if opening the file is failed 143 | */ 144 | public CdbDict (string path, 145 | string encoding = "EUC-JP") throws GLib.Error 146 | { 147 | this.file = File.new_for_path (path); 148 | this.mmap = new MemoryMappedFile (file); 149 | this.etag = ""; 150 | this.converter = new EncodingConverter (encoding); 151 | reload (); 152 | } 153 | } 154 | } 155 | 156 | -------------------------------------------------------------------------------- /libskk/completion.vala: -------------------------------------------------------------------------------- 1 | using Gee; 2 | 3 | namespace Skk { 4 | public abstract class CompletionSource : Object { 5 | public abstract ArrayList get_completions(string midasi); 6 | public int priority { get; set; } 7 | } 8 | 9 | public class DictCompletionSource : CompletionSource { 10 | private Dict dict; 11 | 12 | public DictCompletionSource(Dict dict, int priority) { 13 | this.dict = dict; 14 | this.priority = priority; 15 | } 16 | 17 | public override ArrayList get_completions(string midasi) { 18 | ArrayList completions = new ArrayList(); 19 | string[] dict_completions = dict.complete(midasi); 20 | if (dict_completions != null && dict_completions.length > 0) { 21 | completions.add_all_array(dict_completions); 22 | completions.sort((a, b) => a.collate(b)); 23 | } 24 | return completions; 25 | } 26 | } 27 | 28 | public class CompletionService { 29 | private Gee.List sources = new Gee.ArrayList(); 30 | 31 | public CompletionService() {} 32 | 33 | public void add_source(Object source_object, int priority) { 34 | CompletionSource completion_source; 35 | if (source_object is Dict) { 36 | completion_source = new DictCompletionSource((Dict)source_object, priority); 37 | } else if (source_object is CompletionSource) { 38 | completion_source = (CompletionSource)source_object; 39 | completion_source.priority = priority; 40 | } else { 41 | warning("Unsupported source type: %s", source_object.get_type().name()); 42 | return; 43 | } 44 | 45 | sources.add(completion_source); 46 | sources.sort((a, b) => b.priority - a.priority); 47 | } 48 | 49 | public ArrayList get_completions(string midasi) { 50 | var completions = new ArrayList(); 51 | var completion_set = new HashSet(); 52 | 53 | foreach (var source in sources) { 54 | var source_completions = source.get_completions(midasi); 55 | foreach (var completion in source_completions) { 56 | if (completion_set.add(completion)) { 57 | completions.add(completion); 58 | } 59 | } 60 | } 61 | 62 | return completions; 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /libskk/config.vapi: -------------------------------------------------------------------------------- 1 | [CCode (cprefix = "", lower_case_cprefix = "", cheader_filename = "config.h")] 2 | namespace Config 3 | { 4 | public const string PACKAGE_DATADIR; 5 | public const string PACKAGE_NAME; 6 | public const string PACKAGE_VERSION; 7 | public const string DATADIR; 8 | public const string PKGDATADIR; 9 | public const string LOCALEDIR; 10 | public const string GETTEXT_PACKAGE; 11 | } 12 | -------------------------------------------------------------------------------- /libskk/dict.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011-2018 Daiki Ueno 3 | * Copyright (C) 2011-2018 Red Hat, Inc. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | namespace Skk { 19 | /** 20 | * Base abstract class of dictionaries. 21 | */ 22 | public abstract class Dict : Object { 23 | /** 24 | * Parse a line consisting of candidates separated by "/". 25 | * 26 | * @param line a line consisting of candidates 27 | * @return an array of Candidates 28 | */ 29 | protected Candidate[] split_candidates (string midasi, 30 | bool okuri, 31 | string line) 32 | { 33 | var strv = line.strip ().slice (1, -1).split ("/"); 34 | Candidate[] candidates = new Candidate[strv.length]; 35 | for (int i = 0; i < strv.length; i++) { 36 | var text_annotation = strv[i].split (";", 2); 37 | string text, annotation; 38 | if (text_annotation.length == 2) { 39 | text = text_annotation[0]; 40 | annotation = text_annotation[1]; 41 | } else { 42 | text = strv[i]; 43 | annotation = null; 44 | } 45 | candidates[i] = new Candidate (midasi, 46 | okuri, 47 | text, 48 | annotation); 49 | } 50 | return candidates; 51 | } 52 | 53 | /** 54 | * Format an array of Candidates to be saved in a dictionary file. 55 | * 56 | * @param candidates an array of Candidate 57 | * @return a string 58 | */ 59 | protected string join_candidates (Candidate[] candidates) { 60 | var strv = new string[candidates.length]; 61 | for (int i = 0; i < candidates.length; i++) { 62 | strv[i] = candidates[i].to_string (); 63 | } 64 | return "/" + string.joinv ("/", strv) + "/"; 65 | } 66 | 67 | /** 68 | * Reload the dictionary. 69 | * 70 | * @throws GLib.Error when reading the dictionary failed. 71 | */ 72 | public abstract void reload () throws GLib.Error; 73 | 74 | /** 75 | * Lookup candidates in the dictionary. 76 | * 77 | * @param midasi a midasi (title) string to lookup 78 | * @param okuri whether to search okuri-ari entries or 79 | * okuri-nasi entries 80 | * 81 | * @return an array of Candidate 82 | */ 83 | public abstract Candidate[] lookup (string midasi, bool okuri = false); 84 | 85 | /** 86 | * Return an array of strings which matches midasi. 87 | * 88 | * @param midasi a midasi (title) string to lookup 89 | * 90 | * @return an array of strings 91 | */ 92 | public abstract string[] complete (string midasi); 93 | 94 | /** 95 | * Flag to indicate whether the dictionary is read only. 96 | */ 97 | public abstract bool read_only { get; } 98 | 99 | /** 100 | * Select a candidate in the dictionary. 101 | * 102 | * @param candidate an Candidate 103 | * 104 | * @return `true` if the dictionary is modified, `false` otherwise. 105 | */ 106 | public virtual bool select_candidate (Candidate candidate) 107 | { 108 | // FIXME: throw an error when the dictionary is read only 109 | return false; 110 | } 111 | 112 | /** 113 | * Purge a candidate in the dictionary. 114 | * 115 | * @param candidate an Candidate 116 | * 117 | * @return `true` if the dictionary is modified, `false` otherwise. 118 | */ 119 | public virtual bool purge_candidate (Candidate candidate) 120 | { 121 | // FIXME: throw an error when the dictionary is read only 122 | return false; 123 | } 124 | 125 | /** 126 | * Save the dictionary on disk. 127 | * 128 | * @throws GLib.Error if the dictionary cannot be saved. 129 | */ 130 | public virtual void save () throws GLib.Error { 131 | // FIXME: throw an error when the dictionary is read only 132 | } 133 | } 134 | 135 | /** 136 | * Null implementation of Dict. 137 | */ 138 | public class EmptyDict : Dict { 139 | /** 140 | * {@inheritDoc} 141 | */ 142 | public override void reload () throws GLib.Error { 143 | } 144 | 145 | /** 146 | * {@inheritDoc} 147 | */ 148 | public override Candidate[] lookup (string midasi, bool okuri = false) { 149 | return new Candidate[0]; 150 | } 151 | 152 | /** 153 | * {@inheritDoc} 154 | */ 155 | public override string[] complete (string midasi) { 156 | return new string[0]; 157 | } 158 | 159 | /** 160 | * {@inheritDoc} 161 | */ 162 | public override bool read_only { 163 | get { 164 | return true; 165 | } 166 | } 167 | } 168 | 169 | errordomain SkkDictError { 170 | NOT_READABLE, 171 | MALFORMED_INPUT 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /libskk/encoding.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011-2018 Daiki Ueno 3 | * Copyright (C) 2011-2018 Red Hat, Inc. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | namespace Skk { 19 | // XXX: we use Vala string to represent byte array, assuming that 20 | // it does not contain null element 21 | class EncodingConverter : Object { 22 | const int BUFSIZ = 4096; 23 | const string INTERNAL_ENCODING = "UTF-8"; 24 | 25 | const Entry ENCODING_TO_CODING_SYSTEM_RULE[] = { 26 | { "UTF-8", "utf-8" }, 27 | { "EUC-JP", "euc-jp" }, 28 | { "Shift_JIS", "shift_jis" }, 29 | { "ISO-2022-JP", "iso-2022-jp" }, 30 | { "EUC-JISX0213", "euc-jisx0213" }, 31 | { "EUC-JISX0213", "euc-jis-2004" }, 32 | { "SHIFT_JISX0213", "shift_jis-2004" } 33 | }; 34 | 35 | static Regex coding_cookie_regex; 36 | 37 | static construct { 38 | try { 39 | coding_cookie_regex = new Regex ( 40 | "-\\*-.*[ \t]coding:[ \t]*([^ \t;]+?)[ \t;].*-\\*-"); 41 | } catch (GLib.RegexError e) { 42 | assert_not_reached (); 43 | } 44 | } 45 | 46 | internal static string? extract_coding_system (string line) { 47 | MatchInfo info = null; 48 | if (coding_cookie_regex.match (line, 0, out info)) { 49 | return info.fetch (1); 50 | } 51 | return null; 52 | } 53 | 54 | internal string? get_coding_system () { 55 | foreach (var entry in ENCODING_TO_CODING_SYSTEM_RULE) { 56 | if (entry.key == encoding) { 57 | return entry.value; 58 | } 59 | } 60 | return null; 61 | } 62 | 63 | internal string encoding { get; private set; } 64 | 65 | CharsetConverter encoder; 66 | CharsetConverter decoder; 67 | 68 | internal EncodingConverter (string encoding) throws GLib.Error { 69 | this.encoding = encoding; 70 | encoder = new CharsetConverter (encoding, INTERNAL_ENCODING); 71 | decoder = new CharsetConverter (INTERNAL_ENCODING, encoding); 72 | } 73 | 74 | internal EncodingConverter.from_coding_system (string coding) throws GLib.Error { 75 | foreach (var entry in ENCODING_TO_CODING_SYSTEM_RULE) { 76 | if (entry.value == coding) { 77 | this (entry.key); 78 | return; 79 | } 80 | } 81 | assert_not_reached (); 82 | } 83 | 84 | string convert (CharsetConverter converter, string str) throws GLib.Error { 85 | uint8[] inbuf = str.data; 86 | uint8[] outbuf = new uint8[BUFSIZ]; 87 | StringBuilder builder = new StringBuilder (); 88 | size_t total_bytes_read = 0; 89 | while (total_bytes_read < inbuf.length) { 90 | size_t bytes_read, bytes_written; 91 | // FIXME: we could split inbuf to small segments (< 92 | // BUFSIZ) here to reduce memory copy. However it 93 | // requires proper error handling when the end of 94 | // segmented buffer lies across a UTF-8 character 95 | // boundary. 96 | converter.convert (inbuf[total_bytes_read : inbuf.length], 97 | outbuf, 98 | ConverterFlags.INPUT_AT_END, 99 | out bytes_read, 100 | out bytes_written); 101 | for (int i = 0; i < bytes_written; i++) 102 | builder.append_c ((char)outbuf[i]); 103 | total_bytes_read += bytes_read; 104 | } 105 | return builder.str; 106 | } 107 | 108 | internal string encode (string internal_str) throws GLib.Error { 109 | return convert (encoder, internal_str); 110 | } 111 | 112 | internal string decode (string external_str) throws GLib.Error { 113 | return convert (decoder, external_str); 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /libskk/expr.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011-2018 Daiki Ueno 3 | * Copyright (C) 2011-2018 Red Hat, Inc. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | using Gee; 19 | 20 | namespace Skk { 21 | enum ExprNodeType { 22 | ARRAY, 23 | SYMBOL, 24 | STRING 25 | } 26 | 27 | struct ExprNode { 28 | public ExprNodeType type; 29 | public LinkedList nodes; 30 | public string data; 31 | public ExprNode (ExprNodeType type) { 32 | this.type = type; 33 | } 34 | } 35 | 36 | class ExprReader : Object { 37 | public ExprNode read_symbol (string expr, ref int index) { 38 | var builder = new StringBuilder (); 39 | bool stop = false; 40 | unichar uc = '\0'; 41 | while (!stop && expr.get_next_char (ref index, out uc)) { 42 | switch (uc) { 43 | case '\\': 44 | if (expr.get_next_char (ref index, out uc)) { 45 | builder.append_unichar (uc); 46 | } 47 | break; 48 | case '(': case ')': case '"': case ' ': 49 | stop = true; 50 | break; 51 | default: 52 | builder.append_unichar (uc); 53 | break; 54 | } 55 | } 56 | var node = ExprNode (ExprNodeType.SYMBOL); 57 | node.data = builder.str; 58 | return node; 59 | } 60 | 61 | public ExprNode? read_string (string expr, ref int index) { 62 | return_val_if_fail (index < expr.length && expr[index] == '"', 63 | null); 64 | var builder = new StringBuilder (); 65 | index++; 66 | bool stop = false; 67 | unichar uc = '\0'; 68 | while (!stop && expr.get_next_char (ref index, out uc)) { 69 | switch (uc) { 70 | case '\\': 71 | if (expr.get_next_char (ref index, out uc)) { 72 | switch (uc) { 73 | case '0': case '1': case '2': case '3': 74 | case '4': case '5': case '6': case '7': 75 | int start = index; 76 | int advance = 0; 77 | int num = (int) uc - '0'; 78 | while (expr.get_next_char (ref index, out uc)) { 79 | if (index - start == 3) 80 | break; 81 | if (uc < '0' || uc > '7') 82 | break; 83 | num <<= 3; 84 | num += (int) uc - '0'; 85 | advance++; 86 | } 87 | index = start + advance; 88 | uc = (unichar) num; 89 | break; 90 | case 'x': 91 | int start = index; 92 | int advance = 0; 93 | int num = 0; 94 | while (expr.get_next_char (ref index, out uc)) { 95 | uc = uc.tolower (); 96 | if ('0' <= uc && uc <= '9') { 97 | num <<= 4; 98 | num += (int) uc - '0'; 99 | } else if ('a' <= uc && uc <= 'f') { 100 | num <<= 4; 101 | num += (int) uc - 'a' + 10; 102 | } else 103 | break; 104 | advance++; 105 | } 106 | index = start + advance; 107 | uc = (unichar) num; 108 | break; 109 | default: 110 | break; 111 | } 112 | builder.append_unichar (uc); 113 | } 114 | break; 115 | case '\"': 116 | stop = true; 117 | break; 118 | default: 119 | builder.append_unichar (uc); 120 | break; 121 | } 122 | } 123 | var node = ExprNode (ExprNodeType.STRING); 124 | node.data = builder.str; 125 | return node; 126 | } 127 | 128 | public ExprNode? read_expr (string expr, ref int index) { 129 | return_val_if_fail (index < expr.length && expr[index] == '(', 130 | null); 131 | var nodes = new LinkedList (); 132 | bool stop = false; 133 | index++; 134 | unichar uc = '\0'; 135 | while (!stop && expr.get_next_char (ref index, out uc)) { 136 | switch (uc) { 137 | case ' ': 138 | break; 139 | case ')': 140 | index++; 141 | stop = true; 142 | break; 143 | case '(': 144 | index--; 145 | nodes.add (read_expr (expr, ref index)); 146 | break; 147 | case '"': 148 | index--; 149 | nodes.add (read_string (expr, ref index)); 150 | break; 151 | default: 152 | index--; 153 | nodes.add (read_symbol (expr, ref index)); 154 | break; 155 | } 156 | } 157 | var node = ExprNode (ExprNodeType.ARRAY); 158 | node.nodes = nodes; 159 | return node; 160 | } 161 | } 162 | 163 | class ExprEvaluator : Object { 164 | public string? eval (ExprNode node) { 165 | if (node.type == ExprNodeType.ARRAY) { 166 | var iter = node.nodes.list_iterator (); 167 | if (iter.next ()) { 168 | var funcall = iter.get (); 169 | if (funcall.type == ExprNodeType.SYMBOL) { 170 | // FIXME support other functions in more extensible way 171 | if (funcall.data == "concat") { 172 | var builder = new StringBuilder (); 173 | while (iter.next ()) { 174 | var arg = iter.get (); 175 | if (arg.type == ExprNodeType.STRING) { 176 | builder.append (arg.data); 177 | } 178 | } 179 | return builder.str; 180 | } 181 | else if (funcall.data == "current-time-string") { 182 | var datetime = new DateTime.now_local (); 183 | return datetime.format ("%a, %d %b %Y %T %z"); 184 | } 185 | else if (funcall.data == "pwd") { 186 | return Environment.get_current_dir (); 187 | } 188 | else if (funcall.data == "skk-version") { 189 | return "%s/%s".printf (Config.PACKAGE_NAME, 190 | Config.PACKAGE_VERSION); 191 | } 192 | } 193 | } 194 | } 195 | return null; 196 | } 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /libskk/key-event-filter.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011-2018 Daiki Ueno 3 | * Copyright (C) 2011-2018 Red Hat, Inc. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | namespace Skk { 19 | /** 20 | * Base class of a key event filter. 21 | */ 22 | public abstract class KeyEventFilter : Object { 23 | /** 24 | * Convert a key event to another. 25 | * 26 | * @param key a key event 27 | * 28 | * @return a KeyEvent or `null` if the result cannot be 29 | * fetched immediately 30 | */ 31 | public abstract KeyEvent? filter_key_event (KeyEvent key); 32 | 33 | /** 34 | * Signal emitted when a new key event is generated in the filter. 35 | * 36 | * @param key a key event 37 | */ 38 | public signal void forwarded (KeyEvent key); 39 | 40 | /** 41 | * Reset the filter. 42 | */ 43 | public virtual void reset () { 44 | } 45 | } 46 | 47 | /** 48 | * Simple implementation of a key event filter. 49 | * 50 | * This class is rarely used in programs but specified as "filter" 51 | * property in rule metadata. 52 | * 53 | * @see Rule 54 | */ 55 | class SimpleKeyEventFilter : KeyEventFilter { 56 | /** 57 | * {@inheritDoc} 58 | */ 59 | public override KeyEvent? filter_key_event (KeyEvent key) { 60 | // ignore key release event 61 | if ((key.modifiers & ModifierType.RELEASE_MASK) != 0) 62 | return null; 63 | // clear shift mask 64 | key.modifiers &= ~ModifierType.SHIFT_MASK; 65 | return key; 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /libskk/key-event.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011-2018 Daiki Ueno 3 | * Copyright (C) 2011-2018 Red Hat, Inc. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | using Gee; 19 | 20 | namespace Skk { 21 | public errordomain KeyEventFormatError { 22 | PARSE_FAILED, 23 | KEYSYM_NOT_FOUND 24 | } 25 | 26 | /** 27 | * A set of bit-flags to indicate the state of modifier keys. 28 | */ 29 | [Flags] 30 | public enum ModifierType { 31 | NONE = 0, 32 | SHIFT_MASK = 1 << 0, 33 | LOCK_MASK = 1 << 1, 34 | CONTROL_MASK = 1 << 2, 35 | MOD1_MASK = 1 << 3, 36 | MOD2_MASK = 1 << 4, 37 | MOD3_MASK = 1 << 5, 38 | MOD4_MASK = 1 << 6, 39 | MOD5_MASK = 1 << 7, 40 | 41 | // dummy modifiers for NICOLA 42 | LSHIFT_MASK = 1 << 22, 43 | RSHIFT_MASK = 1 << 23, 44 | USLEEP_MASK = 1 << 24, 45 | 46 | SUPER_MASK = 1 << 26, 47 | HYPER_MASK = 1 << 27, 48 | META_MASK = 1 << 28, 49 | RELEASE_MASK = 1 << 30 50 | } 51 | 52 | /** 53 | * Object representing a key event. 54 | */ 55 | public class KeyEvent : Object { 56 | /** 57 | * The base name of the KeyEvent. 58 | * 59 | * This is exclusive to {@link code}. 60 | */ 61 | public string? name { get; private set; } 62 | 63 | /** 64 | * The base code of the KeyEvent. 65 | * 66 | * This is exclusive to {@link name}. 67 | */ 68 | public unichar code { get; private set; } 69 | 70 | /** 71 | * Modifier mask. 72 | */ 73 | public ModifierType modifiers { get; set; } 74 | 75 | /** 76 | * Create a key event. 77 | * 78 | * @param name a key name 79 | * @param code a character code 80 | * @param modifiers state of modifier keys 81 | * 82 | * @return a new KeyEvent 83 | */ 84 | public KeyEvent (string? name, 85 | unichar code, 86 | ModifierType modifiers) { 87 | this.name = name; 88 | this.code = code; 89 | this.modifiers = modifiers; 90 | } 91 | 92 | /** 93 | * Create a copy of the key event. 94 | * 95 | * @return a new KeyEvent 96 | */ 97 | public KeyEvent copy () { 98 | return new KeyEvent (name, code, modifiers); 99 | } 100 | 101 | /** 102 | * Create a key event from string. 103 | * 104 | * @param key a string representation of a key event 105 | * 106 | * @return a new KeyEvent 107 | */ 108 | public KeyEvent.from_string (string key) throws KeyEventFormatError { 109 | ModifierType _modifiers = 0; 110 | uint _keyval = Keysyms.VoidSymbol; 111 | if (key.has_prefix ("(usleep ") && key.has_suffix (")")) { 112 | // special key event for SKK-NICOLA 113 | var strv = key[1:-1].split (" "); 114 | if (strv.length != 2) { 115 | throw new KeyEventFormatError.PARSE_FAILED ( 116 | "usleep requires duration"); 117 | } 118 | name = strv[1]; 119 | code = '\0'; 120 | modifiers |= ModifierType.USLEEP_MASK; 121 | } else if (key.has_prefix ("(") && key.has_suffix (")")) { 122 | var strv = key[1:-1].split (" "); 123 | int index = 0; 124 | for (; index < strv.length - 1; index++) { 125 | if (strv[index] == "shift") { 126 | _modifiers |= ModifierType.SHIFT_MASK; 127 | } else if (strv[index] == "control") { 128 | _modifiers |= ModifierType.CONTROL_MASK; 129 | } else if (strv[index] == "meta") { 130 | _modifiers |= ModifierType.META_MASK; 131 | } else if (strv[index] == "hyper") { 132 | _modifiers |= ModifierType.HYPER_MASK; 133 | } else if (strv[index] == "super") { 134 | _modifiers |= ModifierType.SUPER_MASK; 135 | } else if (strv[index] == "alt") { 136 | _modifiers |= ModifierType.MOD1_MASK; 137 | } else if (strv[index] == "lshift") { 138 | _modifiers |= ModifierType.LSHIFT_MASK; 139 | } else if (strv[index] == "rshift") { 140 | _modifiers |= ModifierType.RSHIFT_MASK; 141 | } else if (strv[index] == "release") { 142 | _modifiers |= ModifierType.RELEASE_MASK; 143 | } else { 144 | throw new KeyEventFormatError.PARSE_FAILED ( 145 | "unknown modifier %s", strv[index]); 146 | } 147 | } 148 | // special key event for SKK-NICOLA 149 | if (strv[index] == "lshift" || strv[index] == "rshift") { 150 | name = strv[index]; 151 | code = '\0'; 152 | modifiers = ModifierType.NONE; 153 | } else { 154 | _keyval = KeyEventUtils.keyval_from_name (strv[index]); 155 | if (_keyval == Keysyms.VoidSymbol) 156 | throw new KeyEventFormatError.PARSE_FAILED ( 157 | "unknown keyval %s", strv[index]); 158 | name = KeyEventUtils.keyval_name (_keyval); 159 | code = KeyEventUtils.keyval_unicode (_keyval); 160 | modifiers = _modifiers; 161 | } 162 | } else if (key.has_prefix ("[") && key.has_suffix ("]") && 163 | key.char_count () == 4) { 164 | // special double key press events (SKK-NICOLA extension) 165 | name = key; 166 | code = '\0'; 167 | modifiers = ModifierType.NONE; 168 | } else { 169 | int index = key.last_index_of ("-"); 170 | string? _name = null; 171 | if (index > 0) { 172 | // support only limited modifiers in this form 173 | string[] mods = key.substring (0, index).split ("-"); 174 | foreach (var mod in mods) { 175 | if (mod == "S") { 176 | _modifiers |= ModifierType.SHIFT_MASK; 177 | } else if (mod == "C") { 178 | _modifiers |= ModifierType.CONTROL_MASK; 179 | } else if (mod == "A") { 180 | _modifiers |= ModifierType.MOD1_MASK; 181 | } else if (mod == "M") { 182 | _modifiers |= ModifierType.META_MASK; 183 | } else if (mod == "G") { 184 | _modifiers |= ModifierType.MOD5_MASK; 185 | } 186 | } 187 | _name = key.substring (index + 1); 188 | } else { 189 | _modifiers = ModifierType.NONE; 190 | _name = key; 191 | } 192 | _keyval = KeyEventUtils.keyval_from_name (_name); 193 | if (_keyval == Keysyms.VoidSymbol) 194 | throw new KeyEventFormatError.PARSE_FAILED ( 195 | "unknown keyval %s", _name); 196 | name = KeyEventUtils.keyval_name (_keyval); 197 | code = KeyEventUtils.keyval_unicode (_keyval); 198 | modifiers = _modifiers; 199 | } 200 | } 201 | 202 | /** 203 | * Convert the KeyEvent to string. 204 | * 205 | * @return a string representing the KeyEvent 206 | */ 207 | public string to_string () { 208 | string _base = name != null ? name : code.to_string (); 209 | if (modifiers != 0) { 210 | ArrayList elements = new ArrayList (); 211 | if ((modifiers & ModifierType.CONTROL_MASK) != 0) { 212 | elements.add ("control"); 213 | } 214 | if ((modifiers & ModifierType.META_MASK) != 0) { 215 | elements.add ("meta"); 216 | } 217 | if ((modifiers & ModifierType.HYPER_MASK) != 0) { 218 | elements.add ("hyper"); 219 | } 220 | if ((modifiers & ModifierType.SUPER_MASK) != 0) { 221 | elements.add ("super"); 222 | } 223 | if ((modifiers & ModifierType.MOD1_MASK) != 0) { 224 | elements.add ("alt"); 225 | } 226 | if ((modifiers & ModifierType.LSHIFT_MASK) != 0) { 227 | elements.add ("lshift"); 228 | } 229 | if ((modifiers & ModifierType.RSHIFT_MASK) != 0) { 230 | elements.add ("rshift"); 231 | } 232 | if ((modifiers & ModifierType.USLEEP_MASK) != 0) { 233 | elements.add ("usleep"); 234 | } 235 | if ((modifiers & ModifierType.RELEASE_MASK) != 0) { 236 | elements.add ("release"); 237 | } 238 | elements.add (_base); 239 | elements.add (null); // make sure that strv ends with null 240 | // newer valac thinks null in a fixed length array as 241 | // an empty string 242 | var array = elements.to_array (); 243 | // Change length of strv may make vala no able to free it 244 | // correctly. Save the length and restore it later. 245 | var old_length = array.length; 246 | array.length = -1; 247 | var key_string = "(" + string.joinv (" ", array) + ")"; 248 | array.length = old_length; 249 | return key_string; 250 | } else { 251 | return _base; 252 | } 253 | } 254 | 255 | /** 256 | * Create a key event from an X keysym and modifiers. 257 | * 258 | * @param keyval an X keysym 259 | * @param modifiers modifier mask 260 | * 261 | * @return a new KeyEvent 262 | */ 263 | public KeyEvent.from_x_keysym (uint keyval, 264 | ModifierType modifiers) throws KeyEventFormatError { 265 | name = KeyEventUtils.keyval_name (keyval); 266 | code = KeyEventUtils.keyval_unicode (keyval); 267 | 268 | this.modifiers = modifiers; 269 | } 270 | 271 | /** 272 | * Compare two key events ignoring modifiers. 273 | * 274 | * @param key a KeyEvent 275 | * 276 | * @return `true` if those base components are equal, `false` otherwise 277 | */ 278 | public bool base_equal (KeyEvent key) { 279 | return code == key.code && name == key.name; 280 | } 281 | } 282 | } 283 | -------------------------------------------------------------------------------- /libskk/keymap.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011-2018 Daiki Ueno 3 | * Copyright (C) 2011-2018 Red Hat, Inc. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | using Gee; 19 | 20 | namespace Skk { 21 | class Keymap : Object { 22 | Map entries = new HashMap (); 23 | 24 | public new void @set (string key, string command) { 25 | try { 26 | var ev = new KeyEvent.from_string (key); 27 | entries.set (ev.to_string (), command); 28 | } catch (KeyEventFormatError e) { 29 | warning ("can't get key event from string %s: %s", 30 | key, e.message); 31 | } 32 | } 33 | 34 | public string? lookup_key (KeyEvent key) { 35 | return entries.get (key.to_string ()); 36 | } 37 | 38 | public KeyEvent? where_is (string command) { 39 | var iter = entries.map_iterator (); 40 | while (iter.next ()) { 41 | if (iter.get_value () == command) { 42 | var key = iter.get_key (); 43 | try { 44 | return new KeyEvent.from_string (key); 45 | } catch (KeyEventFormatError e) { 46 | warning ("can't get key event from string %s: %s", 47 | key, e.message); 48 | } 49 | } 50 | } 51 | return null; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /libskk/libskk.pc.in: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011 Daiki Ueno 2 | # Copyright (C) 2011 Red Hat, Inc. 3 | 4 | # This library is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU Lesser General Public License 6 | # as published by the Free Software Foundation; either version 2 of 7 | # the License, or (at your option) any later version. 8 | 9 | # This library is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # Lesser General Public License for more details. 13 | 14 | # You should have received a copy of the GNU Lesser General Public 15 | # License along with this library; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 | # 02110-1301 USA 18 | 19 | prefix=@prefix@ 20 | exec_prefix=@exec_prefix@ 21 | libdir=@libdir@ 22 | includedir=@includedir@ 23 | 24 | Name: libskk 25 | Description: a library to deal with Japanese kana-to-kanji conversion method 26 | Version: @VERSION@ 27 | Requires: gobject-2.0 gio-2.0 gee-0.8 28 | Libs: -L${libdir} -lskk 29 | Cflags: -I${includedir}/skk-@SKK_API_VERSION@ 30 | -------------------------------------------------------------------------------- /libskk/map-file.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011-2018 Daiki Ueno 3 | * Copyright (C) 2011-2018 Red Hat, Inc. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | using Gee; 19 | 20 | namespace Skk { 21 | abstract class MapFile : Object { 22 | Map> maps = 23 | new HashMap> (); 24 | 25 | void load_map (Map map, Json.Object object) { 26 | var keys = object.get_members (); 27 | foreach (var key in keys) { 28 | var value = object.get_member (key); 29 | if (value.get_node_type () == Json.NodeType.NULL) { 30 | map.unset (key); 31 | } else { 32 | map.set (key, value); 33 | } 34 | } 35 | } 36 | 37 | void load (RuleMetadata metadata, 38 | string type, 39 | string name, 40 | Set included) throws RuleParseError 41 | { 42 | var filename = metadata.locate_map_file (type, name); 43 | if (filename == null) { 44 | throw new RuleParseError.FAILED ("no such file %s", filename); 45 | } 46 | 47 | Json.Parser parser = new Json.Parser (); 48 | try { 49 | if (!parser.load_from_file (filename)) 50 | throw new RuleParseError.FAILED (""); 51 | } catch (GLib.Error e) { 52 | throw new RuleParseError.FAILED ( 53 | "can't load %s: %s".printf (filename, e.message)); 54 | } 55 | var root = parser.get_root (); 56 | if (root.get_node_type () != Json.NodeType.OBJECT) { 57 | throw new RuleParseError.FAILED ( 58 | "root element must be an object"); 59 | } 60 | var object = root.get_object (); 61 | 62 | Json.Node member; 63 | if (object.has_member ("include")) { 64 | member = object.get_member ("include"); 65 | if (member.get_node_type () != Json.NodeType.ARRAY) { 66 | throw new RuleParseError.FAILED ( 67 | "\"include\" element must be an array"); 68 | } 69 | var include = member.get_array (); 70 | var elements = include.get_elements (); 71 | foreach (var element in elements) { 72 | var parent = element.get_string (); 73 | if (parent in included) 74 | continue; 75 | string parent_rule, parent_name; 76 | var index = parent.index_of ("/"); 77 | if (index < 0) { 78 | parent_rule = metadata.name; 79 | parent_name = parent; 80 | } else { 81 | parent_rule = parent[0:index]; 82 | parent_name = parent[index + 1:parent.length]; 83 | } 84 | var parent_metadata = Rule.find_rule (parent_rule); 85 | if (parent_metadata == null) { 86 | throw new RuleParseError.FAILED ("can't find rule %s", 87 | parent_rule); 88 | } 89 | load (parent_metadata, type, parent_name, included); 90 | included.add (parent); 91 | } 92 | } 93 | 94 | if (object.has_member ("define")) { 95 | member = object.get_member ("define"); 96 | if (member.get_node_type () != Json.NodeType.OBJECT) { 97 | throw new RuleParseError.FAILED ( 98 | "\"define\" element must be an object"); 99 | } 100 | var define = member.get_object (); 101 | var keys = define.get_members (); 102 | foreach (var key in keys) { 103 | if (!maps.has_key (key)) { 104 | var map = new HashMap (); 105 | maps.set (key, map); 106 | } 107 | member = define.get_member (key); 108 | if (member.get_node_type () != Json.NodeType.OBJECT) { 109 | throw new RuleParseError.FAILED ( 110 | "map element must be an object"); 111 | } 112 | load_map (maps.get (key), member.get_object ()); 113 | } 114 | } 115 | } 116 | 117 | internal MapFile (RuleMetadata metadata, 118 | string type, 119 | string name) throws RuleParseError 120 | { 121 | Set included = new HashSet (); 122 | load (metadata, type, name, included); 123 | } 124 | 125 | internal bool has_map (string name) { 126 | return maps.has_key (name); 127 | } 128 | 129 | internal new Map @get (string name) { 130 | return maps.get (name); 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /libskk/nicola.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011-2018 Daiki Ueno 3 | * Copyright (C) 2011-2018 Red Hat, Inc. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | using Gee; 19 | 20 | namespace Skk { 21 | /** 22 | * Get the current timer count. 23 | */ 24 | public delegate int64 GetTime (); 25 | 26 | /** 27 | * Key event filter implementing NICOLA (thumb shift) input 28 | * 29 | * This class is rarely used in programs but specified as "filter" 30 | * property in rule metadata. 31 | * 32 | * @see Rule 33 | */ 34 | public class NicolaKeyEventFilter : KeyEventFilter { 35 | static int64 get_time () { 36 | var tv = TimeVal (); 37 | return (((int64) tv.tv_sec) * 1000000) + tv.tv_usec; 38 | } 39 | 40 | public GetTime get_time_func = get_time; 41 | 42 | /** 43 | * Duration where a single key press event is committed 44 | * without a corresponding key release event. 45 | */ 46 | public int64 timeout = 100000; 47 | 48 | /** 49 | * Duration between two overlapping key press events, so they 50 | * are considered as a doule key press/release event. 51 | */ 52 | public int64 overlap = 50000; 53 | 54 | /** 55 | * Maximum duration to wait for the next key event. 56 | */ 57 | public int64 maxwait = 10000000; 58 | 59 | const string[] SPECIAL_DOUBLES = { 60 | "[fj]", "[gh]", "[dk]", "[LR]" 61 | }; 62 | 63 | /** 64 | * Special double key press events (SKK-NICOLA extension). 65 | * 66 | * By default, "[fj]" (f + j), "[gh]" (g + h), "[dk]" (d + k), 67 | * and "[LR]" (left shift + right shift) are registered. 68 | */ 69 | public string[] special_doubles; 70 | 71 | class TimedEntry { 72 | public T data; 73 | public int64 time; 74 | 75 | public TimedEntry (T data, int64 time) { 76 | this.data = data; 77 | this.time = time; 78 | } 79 | } 80 | 81 | LinkedList> pending = new LinkedList> (); 82 | 83 | // we can't use normal constructor here since KeyEventFilter 84 | // is constructed with Object.new (type). 85 | construct { 86 | special_doubles = SPECIAL_DOUBLES; 87 | } 88 | 89 | static bool is_char (KeyEvent key) { 90 | return key.code != 0; 91 | } 92 | 93 | static bool is_lshift (KeyEvent key) { 94 | return key.name == "lshift" || key.name == "Muhenkan"; 95 | } 96 | 97 | static bool is_rshift (KeyEvent key) { 98 | return key.name == "rshift" || key.name == "Henkan"; 99 | } 100 | 101 | static bool is_shift (KeyEvent key) { 102 | return is_lshift (key) || is_rshift (key); 103 | } 104 | 105 | static string get_special_double_name (KeyEvent a, KeyEvent b) { 106 | if (is_shift (a) && is_shift (b)) { 107 | return "[LR]"; 108 | } else if (is_char (a) && is_char (b)) { 109 | unichar ac, bc; 110 | if (a.code < b.code) { 111 | ac = a.code; 112 | bc = b.code; 113 | } else { 114 | ac = b.code; 115 | bc = a.code; 116 | } 117 | return @"[$ac$bc]"; 118 | } else { 119 | return_val_if_reached (null); 120 | } 121 | } 122 | 123 | KeyEvent? queue (KeyEvent key, int64 time, out int64 wait) { 124 | // press/release a same key 125 | if ((key.modifiers & ModifierType.RELEASE_MASK) != 0) { 126 | if (pending.size > 0 && pending.get (0).data.base_equal (key)) { 127 | var entry = pending.get (0); 128 | wait = get_next_wait (key, time); 129 | pending.clear (); 130 | return entry.data; 131 | } 132 | } 133 | // ignore key repeat 134 | else { 135 | if (pending.size > 0 && pending.get (0).data.base_equal (key)) { 136 | pending.get (0).time = time; 137 | wait = get_next_wait (key, time); 138 | return key; 139 | } 140 | else { 141 | if (pending.size > 2) { 142 | var iter = pending.bidir_list_iterator (); 143 | iter.last (); 144 | do { 145 | iter.remove (); 146 | } while (pending.size > 2 && iter.previous ()); 147 | } 148 | pending.insert (0, new TimedEntry (key, time)); 149 | } 150 | } 151 | wait = maxwait; 152 | return null; 153 | } 154 | 155 | int64 get_next_wait (KeyEvent key, int64 time) { 156 | if (pending.size > 0) { 157 | var iter = pending.bidir_list_iterator (); 158 | iter.last (); 159 | do { 160 | var entry = iter.get (); 161 | if (time - entry.time > timeout) { 162 | iter.remove (); 163 | } 164 | } while (iter.previous ()); 165 | } 166 | if (pending.size > 0) { 167 | return timeout - (time - pending.last ().time); 168 | } else { 169 | return maxwait; 170 | } 171 | } 172 | 173 | KeyEvent? dispatch_single (int64 time) { 174 | var entry = pending.peek (); 175 | if (time - entry.time > timeout) { 176 | pending.clear (); 177 | return entry.data; 178 | } 179 | return null; 180 | } 181 | 182 | void apply_shift (KeyEvent s, KeyEvent c) { 183 | if (is_lshift (s)) { 184 | c.modifiers |= ModifierType.LSHIFT_MASK; 185 | } else if (is_rshift (s)) { 186 | c.modifiers |= ModifierType.RSHIFT_MASK; 187 | } 188 | } 189 | 190 | KeyEvent? dispatch (int64 time) { 191 | if (pending.size == 3) { 192 | var b = pending.get (0); 193 | var s = pending.get (1); 194 | var a = pending.get (2); 195 | var t1 = s.time - a.time; 196 | var t2 = b.time - s.time; 197 | if (t1 <= t2) { 198 | pending.clear (); 199 | pending.offer_head (b); 200 | var r = dispatch_single (time); 201 | apply_shift (s.data, a.data); 202 | forwarded (a.data); 203 | return r; 204 | } else { 205 | pending.clear (); 206 | apply_shift (s.data, b.data); 207 | forwarded (a.data); 208 | return b.data; 209 | } 210 | } else if (pending.size == 2) { 211 | var b = pending.get (0); 212 | var a = pending.get (1); 213 | if (b.time - a.time > overlap) { 214 | pending.clear (); 215 | pending.offer_head (b); 216 | var r = dispatch_single (time); 217 | forwarded (a.data); 218 | return r; 219 | } else if ((is_char (a.data) && is_char (b.data)) || 220 | (is_shift (a.data) && is_shift (b.data))) { 221 | // skk-nicola uses some combinations of 2 character 222 | // keys ([fj], [gh], etc.) and 2 shift keys ([LR]). 223 | var name = get_special_double_name (b.data, a.data); 224 | if (name in special_doubles) { 225 | pending.clear (); 226 | return new KeyEvent (name, 227 | (unichar) 0, 228 | ModifierType.NONE); 229 | } else { 230 | pending.clear (); 231 | pending.offer_head (b); 232 | var r = dispatch_single (time); 233 | forwarded (a.data); 234 | return r; 235 | } 236 | } else if (time - a.time > timeout) { 237 | pending.clear (); 238 | if (is_shift (b.data)) { 239 | apply_shift (b.data, a.data); 240 | return a.data; 241 | } else { 242 | apply_shift (a.data, b.data); 243 | return b.data; 244 | } 245 | } 246 | } else if (pending.size == 1) { 247 | return dispatch_single (time); 248 | } 249 | 250 | return null; 251 | } 252 | 253 | bool timeout_func () { 254 | int64 time = get_time_func (); 255 | var r = dispatch (time); 256 | if (r != null) { 257 | forwarded (r); 258 | } 259 | return false; 260 | } 261 | 262 | uint timeout_id = 0; 263 | 264 | /** 265 | * {@inheritDoc} 266 | */ 267 | public override KeyEvent? filter_key_event (KeyEvent key) { 268 | // clear shift mask 269 | key.modifiers &= ~ModifierType.SHIFT_MASK; 270 | KeyEvent? output = null; 271 | int64 time; 272 | if ((key.modifiers & ModifierType.USLEEP_MASK) != 0) { 273 | Thread.usleep ((long) int.parse (key.name)); 274 | time = get_time_func (); 275 | } else if ((key.modifiers & ~ModifierType.RELEASE_MASK) == 0 && 276 | (is_shift (key) || 277 | (0x20 <= key.code && key.code <= 0x7E))) { 278 | time = get_time_func (); 279 | int64 wait; 280 | output = queue (key, time, out wait); 281 | if (wait > 0) { 282 | if (timeout_id > 0) { 283 | Source.remove (timeout_id); 284 | } 285 | timeout_id = Timeout.add ((uint) wait, timeout_func); 286 | } 287 | } else { 288 | if ((key.modifiers & ModifierType.RELEASE_MASK) == 0) { 289 | return key; 290 | } 291 | return null; 292 | } 293 | if (output == null) { 294 | output = dispatch (time); 295 | } 296 | return output; 297 | } 298 | 299 | /** 300 | * {@inheritDoc} 301 | */ 302 | public override void reset () { 303 | pending.clear (); 304 | } 305 | } 306 | } 307 | -------------------------------------------------------------------------------- /libskk/rom-kana.vala: -------------------------------------------------------------------------------- 1 | // -*- coding: utf-8 -*- 2 | /* 3 | * Copyright (C) 2011-2018 Daiki Ueno 4 | * Copyright (C) 2011-2018 Red Hat, Inc. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | using Gee; 20 | 21 | namespace Skk { 22 | struct RomKanaEntry { 23 | string rom; 24 | string carryover; 25 | 26 | // we can't simply use string kana[3] here because array 27 | // initializer in Vala does not support it 28 | string hiragana; 29 | string katakana; 30 | string hankaku_katakana; 31 | 32 | internal string get_kana (KanaMode kana_mode) { 33 | if (kana_mode == KanaMode.HIRAGANA) 34 | return hiragana; 35 | else if (kana_mode == KanaMode.KATAKANA) 36 | return katakana; 37 | else if (kana_mode == KanaMode.HANKAKU_KATAKANA) 38 | return hankaku_katakana; 39 | return ""; 40 | } 41 | } 42 | 43 | const string[] PERIOD_RULE = {"。、", ".,", "。,", ".、"}; 44 | 45 | class RomKanaNode : Object { 46 | internal RomKanaEntry? entry; 47 | internal weak RomKanaNode parent; 48 | internal RomKanaNode children[128]; 49 | internal char c; 50 | internal uint n_children = 0; 51 | internal bool valid[128]; 52 | 53 | internal RomKanaNode (RomKanaEntry? entry) { 54 | this.entry = entry; 55 | for (int i = 0; i < children.length; i++) { 56 | children[i] = null; 57 | } 58 | } 59 | 60 | internal void insert (string key, RomKanaEntry entry) { 61 | var node = this; 62 | for (var i = 0; i < key.length; i++) { 63 | if (node.children[key[i]] == null) { 64 | var child = node.children[key[i]] = new RomKanaNode (null); 65 | child.parent = node; 66 | } 67 | node.n_children++; 68 | node = node.children[key[i]]; 69 | valid[key[i]] = true; 70 | } 71 | node.entry = entry; 72 | } 73 | 74 | #if 0 75 | RomKanaNode? lookup_node (string key) { 76 | var node = this; 77 | for (var i = 0; i < key.length; i++) { 78 | node = node.children[key[i]]; 79 | if (node == null) 80 | return null; 81 | } 82 | return node; 83 | } 84 | 85 | internal RomKanaEntry? lookup (string key) { 86 | var node = lookup_node (key); 87 | if (node == null) 88 | return null; 89 | return node.entry; 90 | } 91 | 92 | void remove_child (RomKanaNode node) { 93 | children[node.c] = null; 94 | if (--n_children == 0 && parent != null) { 95 | parent.remove_child (this); 96 | } 97 | } 98 | 99 | internal void @remove (string key) { 100 | var node = lookup_node (key); 101 | if (node != null) { 102 | return_if_fail (node.parent != null); 103 | node.parent.remove_child (node); 104 | } 105 | } 106 | #endif 107 | } 108 | 109 | /** 110 | * Type representing kana scripts. 111 | */ 112 | public enum KanaMode { 113 | /** 114 | * Hiragana like "あいう...". 115 | */ 116 | HIRAGANA, 117 | 118 | /** 119 | * Katakana like "アイウ...". 120 | */ 121 | KATAKANA, 122 | 123 | /** 124 | * Half-width katakana like "アイウ...". 125 | */ 126 | HANKAKU_KATAKANA 127 | } 128 | 129 | /** 130 | * Type to specify how "." and "," are converted. 131 | */ 132 | public enum PeriodStyle { 133 | /** 134 | * Use "。" and "、" for "." and ",". 135 | */ 136 | JA_JA, 137 | 138 | /** 139 | * Use "." and "," for "." and ",". 140 | */ 141 | EN_EN, 142 | 143 | /** 144 | * Use "。" and "," for "." and ",". 145 | */ 146 | JA_EN, 147 | 148 | /** 149 | * Use "." and "、" for "." and ",". 150 | */ 151 | EN_JA 152 | } 153 | 154 | /** 155 | * Romaji-to-kana converter. 156 | */ 157 | public class RomKanaConverter : Object { 158 | RomKanaMapFile _rule; 159 | internal RomKanaMapFile rule { 160 | get { 161 | return _rule; 162 | } 163 | set { 164 | _rule = value; 165 | current_node = _rule.root_node; 166 | } 167 | } 168 | 169 | RomKanaNode current_node; 170 | 171 | public KanaMode kana_mode { get; set; default = KanaMode.HIRAGANA; } 172 | public PeriodStyle period_style { get; set; default = PeriodStyle.JA_JA; } 173 | 174 | StringBuilder _output = new StringBuilder (); 175 | StringBuilder _preedit = new StringBuilder (); 176 | 177 | public string output { 178 | get { 179 | return _output.str; 180 | } 181 | internal set { 182 | _output.assign (value); 183 | } 184 | } 185 | public string preedit { 186 | get { 187 | return _preedit.str; 188 | } 189 | } 190 | 191 | const string[] NN = { "ん", "ン", "ン" }; 192 | 193 | public RomKanaConverter () { 194 | try { 195 | var metadata = Rule.find_rule ("default"); 196 | if (metadata == null) { 197 | throw new RuleParseError.FAILED ("can't find default rule"); 198 | } 199 | _rule = new RomKanaMapFile (metadata); 200 | current_node = _rule.root_node; 201 | } catch (RuleParseError e) { 202 | warning ("can't find default rom-kana rule: %s", 203 | e.message); 204 | assert_not_reached (); 205 | } 206 | } 207 | 208 | public bool is_valid (unichar uc) { 209 | if (uc > 128) 210 | return false; 211 | return _rule.root_node.valid[(int)uc]; 212 | } 213 | 214 | /** 215 | * Output "nn" if preedit ends with "n". 216 | */ 217 | public bool output_nn_if_any () { 218 | if (_preedit.str == "n") { 219 | _output.append (NN[kana_mode]); 220 | _preedit.erase (); 221 | current_node = rule.root_node; 222 | return true; 223 | } 224 | return false; 225 | } 226 | 227 | /** 228 | * Append text to the internal buffer. 229 | * 230 | * @param text a string 231 | */ 232 | public void append_text (string text) { 233 | int index = 0; 234 | unichar c; 235 | while (text.get_next_char (ref index, out c)) { 236 | append (c); 237 | } 238 | } 239 | 240 | /** 241 | * Append a character to the internal buffer. 242 | * 243 | * @param uc an ASCII character 244 | * 245 | * @return `true` if the character is handled, `false` otherwise 246 | */ 247 | public bool append (unichar uc) { 248 | var child_node = current_node.children[uc]; 249 | if (child_node == null) { 250 | // no such transition path in trie 251 | var retval = output_nn_if_any (); 252 | // XXX: index_of_char does not work with '\0' 253 | var index = uc != '\0' ? ".,".index_of_char (uc) : -1; 254 | if (index >= 0) { 255 | index = PERIOD_RULE[period_style].index_of_nth_char (index); 256 | unichar period = PERIOD_RULE[period_style].get_char (index); 257 | string kana_period = Util.convert_by_input_mode( 258 | period.to_string(), 259 | (InputMode)kana_mode); 260 | _output.append (kana_period); 261 | _preedit.erase (); 262 | current_node = rule.root_node; 263 | return true; 264 | } else if (rule.root_node.children[uc] == null) { 265 | _output.append_unichar (uc); 266 | _preedit.erase (); 267 | current_node = rule.root_node; 268 | // there may be "NN" output 269 | return retval; 270 | } else { 271 | // abandon current preedit and restart lookup from 272 | // the root with uc 273 | _preedit.erase (); 274 | current_node = rule.root_node; 275 | return append (uc); 276 | } 277 | } else if (child_node.n_children > 0) { 278 | // node is not a terminal 279 | _preedit.append_unichar (uc); 280 | current_node = child_node; 281 | return true; 282 | } else { 283 | _output.append (child_node.entry.get_kana (kana_mode)); 284 | _preedit.erase (); 285 | current_node = rule.root_node; 286 | for (int i = 0; i < child_node.entry.carryover.length; i++) { 287 | append (child_node.entry.carryover[i]); 288 | } 289 | return true; 290 | } 291 | } 292 | 293 | /** 294 | * Check if a character will be consumed by the current conversion. 295 | * 296 | * @param uc an ASCII character 297 | * @param preedit_only only checks if preedit is active 298 | * @param no_carryover return false if there will be carryover 299 | * @return `true` if the character can be consumed 300 | */ 301 | public bool can_consume (unichar uc, 302 | bool preedit_only = false, 303 | bool no_carryover = true) 304 | { 305 | if (preedit_only && _preedit.len == 0) 306 | return false; 307 | var child_node = current_node.children[uc]; 308 | if (child_node == null) 309 | return false; 310 | if (no_carryover && 311 | child_node.entry != null && child_node.entry.carryover != "") 312 | return false; 313 | return true; 314 | } 315 | 316 | /** 317 | * Reset the internal state of the converter. 318 | */ 319 | public void reset () { 320 | _output.erase (); 321 | _preedit.erase (); 322 | current_node = rule.root_node; 323 | } 324 | 325 | /** 326 | * Delete the trailing character from the internal buffer. 327 | * 328 | * @return `true` if any character is removed, `false` otherwise 329 | */ 330 | public bool delete () { 331 | if (_preedit.len > 0) { 332 | current_node = current_node.parent; 333 | if (current_node == null) 334 | current_node = rule.root_node; 335 | _preedit.truncate ( 336 | _preedit.str.index_of_nth_char ( 337 | _preedit.str.char_count () - 1)); 338 | return true; 339 | } 340 | if (_output.len > 0) { 341 | _output.truncate ( 342 | _output.str.index_of_nth_char ( 343 | _output.str.char_count () - 1)); 344 | return true; 345 | } 346 | return false; 347 | } 348 | } 349 | } 350 | -------------------------------------------------------------------------------- /libskk/skk-1.0.deps: -------------------------------------------------------------------------------- 1 | glib-2.0 2 | gio-2.0 3 | gee-0.8 4 | posix 5 | json-glib-1.0 6 | -------------------------------------------------------------------------------- /libskk/skkserv.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011-2018 Daiki Ueno 3 | * Copyright (C) 2011-2018 Red Hat, Inc. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | namespace Skk { 19 | errordomain SkkServError { 20 | NOT_READABLE, 21 | INVALID_RESPONSE 22 | } 23 | 24 | /** 25 | * Network based Implementation of Dict. 26 | */ 27 | public class SkkServ : Dict { 28 | SocketConnection? connection; 29 | uint8 buffer[4096]; 30 | string host; 31 | uint16 port; 32 | 33 | void close_connection () { 34 | if (connection != null) { 35 | try { 36 | buffer[0] = '0'; 37 | size_t bytes_written; 38 | connection.output_stream.write_all (buffer[0:1], 39 | out bytes_written); 40 | connection.output_stream.flush (); 41 | connection.close (); 42 | } catch (GLib.Error e) { 43 | warning ("can't close skkserv: %s", e.message); 44 | } 45 | connection = null; 46 | } 47 | } 48 | 49 | /** 50 | * {@inheritDoc} 51 | */ 52 | public override void reload () { 53 | close_connection (); 54 | try { 55 | var client = new SocketClient (); 56 | connection = client.connect_to_host (host, port); 57 | buffer[0] = '2'; 58 | size_t bytes_written; 59 | connection.output_stream.write_all (buffer[0:1], 60 | out bytes_written); 61 | connection.output_stream.flush (); 62 | ssize_t len = connection.input_stream.read (buffer); 63 | if (len <= 0) { 64 | close_connection (); 65 | } 66 | } catch (GLib.Error e) { 67 | warning ("can't open skkserv at %s:%u: %s", 68 | host, port, e.message); 69 | close_connection (); 70 | } 71 | } 72 | 73 | string read_response () throws SkkServError, GLib.IOError { 74 | StringBuilder builder = new StringBuilder (); 75 | // skksearch does not terminate the line with LF on 76 | // error (ibus-skk Issue#30) 77 | while (builder.str.index_of_char ('\n') < 0) { 78 | ssize_t len = connection.input_stream.read (buffer); 79 | if (len < 0) { 80 | throw new SkkServError.NOT_READABLE ("read error"); 81 | } 82 | else if (len == 0) { 83 | break; 84 | } 85 | else if (len > 0) { 86 | if (buffer[0] != '1') { 87 | throw new SkkServError.INVALID_RESPONSE ( 88 | "invalid response code"); 89 | } 90 | // make sure to null terminate the string 91 | char[] data = new char[len + 1]; 92 | Memory.copy (data, buffer, len); 93 | data.length--; 94 | builder.append ((string)data); 95 | } 96 | } 97 | var index = builder.str.index_of_char ('\n'); 98 | if (index < 0) { 99 | throw new SkkServError.INVALID_RESPONSE ("missing newline"); 100 | } 101 | return builder.str[0:index]; 102 | } 103 | 104 | /** 105 | * {@inheritDoc} 106 | */ 107 | public override Candidate[] lookup (string midasi, bool okuri = false) { 108 | if (connection == null) 109 | return new Candidate[0]; 110 | string _midasi; 111 | try { 112 | _midasi = converter.encode (midasi); 113 | } catch (GLib.Error e) { 114 | return new Candidate[0]; 115 | } 116 | try { 117 | size_t bytes_written; 118 | connection.output_stream.write_all ( 119 | "1%s ".printf (_midasi).data, out bytes_written); 120 | connection.output_stream.flush (); 121 | var response = read_response (); 122 | if (response.length == 0) 123 | return new Candidate[0]; 124 | return split_candidates (midasi, 125 | okuri, 126 | converter.decode ( 127 | response[1:response.length])); 128 | } catch (SkkServError e) { 129 | return new Candidate[0]; 130 | } catch (GLib.Error e) { 131 | return new Candidate[0]; 132 | } 133 | } 134 | 135 | /** 136 | * {@inheritDoc} 137 | */ 138 | public override string[] complete (string midasi) { 139 | if (connection == null) 140 | return new string[0]; 141 | string _midasi; 142 | try { 143 | _midasi = converter.encode (midasi); 144 | } catch (GLib.Error e) { 145 | return new string[0]; 146 | } 147 | try { 148 | size_t bytes_written; 149 | connection.output_stream.write_all ( 150 | "4%s ".printf (_midasi).data, out bytes_written); 151 | connection.output_stream.flush (); 152 | var response = read_response (); 153 | if (response.length < 2) 154 | return new string[0]; 155 | return converter.decode ( 156 | response[2:-1]).split ("/"); 157 | } catch (SkkServError e) { 158 | warning ("server completion failed %s", e.message); 159 | return new string[0]; 160 | } catch (GLib.Error e) { 161 | warning ("server completion failed %s", e.message); 162 | return new string[0]; 163 | } 164 | } 165 | 166 | /** 167 | * {@inheritDoc} 168 | */ 169 | public override bool read_only { 170 | get { 171 | return true; 172 | } 173 | } 174 | 175 | EncodingConverter converter; 176 | 177 | /** 178 | * Create a new SkkServ. 179 | * 180 | * @param host host to connect 181 | * @param port port at the host 182 | * @param encoding encoding to convert text over network traffic 183 | * 184 | * @return a new SkkServ. 185 | * @throws GLib.Error if opening a connection is failed 186 | */ 187 | public SkkServ (string host, uint16 port = 1178, string encoding = "EUC-JP") throws GLib.Error { 188 | this.host = host; 189 | this.port = port; 190 | this.converter = new EncodingConverter (encoding); 191 | reload (); 192 | } 193 | 194 | ~SkkServ () { 195 | close_connection (); 196 | } 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /libskk/xkbcommon.vapi: -------------------------------------------------------------------------------- 1 | [CCode (cprefix = "xkb_", lower_case_cprefix = "xkb_", cheader_filename = "xkbcommon/xkbcommon.h")] 2 | namespace Xkb 3 | { 4 | namespace Keysym { 5 | [CCode (cname = "XKB_KEY_NoSymbol")] 6 | public const uint32 NoSymbol; 7 | } 8 | 9 | public enum KeysymFlags { 10 | [CCode (cname = "XKB_KEYSYM_NO_FLAGS")] 11 | NO_FLAGS = 0, 12 | CASE_INSENSITIVE = (1 << 0) 13 | } 14 | 15 | public int keysym_get_name(uint32 keysym, [CCode (array_length_cname = "size", array_length_pos = 2.1, array_length_type = "size_t")] uint8[] buffer); 16 | public uint32 keysym_from_name(string name, KeysymFlags flags); 17 | public int keysym_to_utf8(uint32 keysym, [CCode (array_length_cname = "size", array_length_pos = 2.1, array_length_type = "size_t")] uint8[] buffer); 18 | } 19 | -------------------------------------------------------------------------------- /m4/vala.m4: -------------------------------------------------------------------------------- 1 | dnl vala.m4 2 | dnl 3 | dnl Copyright 2010 Marc-Andre Lureau 4 | dnl 5 | dnl This library is free software; you can redistribute it and/or 6 | dnl modify it under the terms of the GNU Lesser General Public 7 | dnl License as published by the Free Software Foundation; either 8 | dnl version 2.1 of the License, or (at your option) any later version. 9 | dnl 10 | dnl This library is distributed in the hope that it will be useful, 11 | dnl but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | dnl Lesser General Public License for more details. 14 | dnl 15 | dnl You should have received a copy of the GNU Lesser General Public 16 | dnl License along with this library; if not, write to the Free Software 17 | dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | 19 | # _VALA_CHECK_COMPILE_WITH_ARGS(ARGS, [ACTION-IF-TRUE], 20 | # [ACTION-IF-FALSE]) 21 | # -------------------------------------- 22 | # Check that Vala compile with ARGS. 23 | # 24 | AC_DEFUN([_VALA_CHECK_COMPILE_WITH_ARGS], 25 | [AC_REQUIRE([AM_PROG_VALAC])[]dnl 26 | 27 | cat <<_ACEOF >conftest.vala 28 | void main(){} 29 | _ACEOF 30 | 31 | AS_IF([vala_error=`$VALAC $1 -q -o conftest$ac_exeext conftest.vala 2>&1`], 32 | [$2], [$3]) 33 | ]) 34 | 35 | ])# _VALA_CHECK_COMPILE_WITH_ARGS 36 | 37 | # VALA_CHECK_PACKAGES(PKGS, [ACTION-IF-FOUND], 38 | # [ACTION-IF-NOT-FOUND]) 39 | # -------------------------------------- 40 | # Check that PKGS Vala bindings are installed and usable. 41 | # 42 | AC_DEFUN([VALA_CHECK_PACKAGES], 43 | [ 44 | ac_save_ifs="$IFS"; unset IFS 45 | for vala_pkg in $(echo "$1"); do 46 | vala_pkgs="$vala_pkgs --pkg $vala_pkg" 47 | vala_bindings="$vala_bindings $vala_pkg" 48 | done 49 | IFS="$ac_save_ifs" 50 | AC_MSG_CHECKING([for $vala_bindings vala bindings]) 51 | _VALA_CHECK_COMPILE_WITH_ARGS([$vala_pkgs], 52 | [vala_pkg_exists=yes], 53 | [vala_pkg_exists=no]) 54 | 55 | AS_IF([test x${vala_pkg_exists} = xno],[ 56 | ifelse([$3], , [AC_MSG_ERROR([]dnl 57 | [Package requirements were not met: $1 58 | 59 | $vala_error 60 | 61 | Consider adjusting the XDG_DATA_DIRS environment variable if you 62 | installed bindings in a non-standard prefix. 63 | ])], 64 | [AC_MSG_RESULT([no]) 65 | $3])],[ 66 | AC_MSG_RESULT([yes]) 67 | ifelse([$2], , :, [$2])[]dnl 68 | ]) 69 | 70 | ])# VALA_CHECK_PACKAGES 71 | -------------------------------------------------------------------------------- /po/LINGUAS: -------------------------------------------------------------------------------- 1 | ja 2 | -------------------------------------------------------------------------------- /po/Makevars: -------------------------------------------------------------------------------- 1 | # Makefile variables for PO directory in any package using GNU gettext. 2 | 3 | # Usually the message domain is the same as the package name. 4 | DOMAIN = $(PACKAGE) 5 | 6 | # These two variables depend on the location of this directory. 7 | subdir = po 8 | top_builddir = .. 9 | 10 | # These options get passed to xgettext. 11 | XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ 12 | 13 | # This is the copyright holder that gets inserted into the header of the 14 | # $(DOMAIN).pot file. Set this to the copyright holder of the surrounding 15 | # package. (Note that the msgstr strings, extracted from the package's 16 | # sources, belong to the copyright holder of the package.) Translators are 17 | # expected to transfer the copyright for their translations to this person 18 | # or entity, or to disclaim their copyright. The empty string stands for 19 | # the public domain; in this case the translators are expected to disclaim 20 | # their copyright. 21 | COPYRIGHT_HOLDER = Daiki Ueno 22 | 23 | # This tells whether or not to prepend "GNU " prefix to the package 24 | # name that gets inserted into the header of the $(DOMAIN).pot file. 25 | # Possible values are "yes", "no", or empty. If it is empty, try to 26 | # detect it automatically by scanning the files in $(top_srcdir) for 27 | # "GNU packagename" string. 28 | PACKAGE_GNU = no 29 | 30 | # This is the email address or URL to which the translators shall report 31 | # bugs in the untranslated strings: 32 | # - Strings which are not entire sentences, see the maintainer guidelines 33 | # in the GNU gettext documentation, section 'Preparing Strings'. 34 | # - Strings which use unclear terms or require additional context to be 35 | # understood. 36 | # - Strings which make invalid assumptions about notation of date, time or 37 | # money. 38 | # - Pluralisation problems. 39 | # - Incorrect English spelling. 40 | # - Incorrect formatting. 41 | # It can be your email address, or a mailing list address where translators 42 | # can write to without being subscribed, or the URL of a web page through 43 | # which the translators can contact you. 44 | MSGID_BUGS_ADDRESS = 45 | 46 | # This is the list of locale categories, beyond LC_MESSAGES, for which the 47 | # message catalogs shall be used. It is usually empty. 48 | EXTRA_LOCALE_CATEGORIES = 49 | 50 | # This tells whether the $(DOMAIN).pot file contains messages with an 'msgctxt' 51 | # context. Possible values are "yes" and "no". Set this to yes if the 52 | # package uses functions taking also a message context, like pgettext(), or 53 | # if in $(XGETTEXT_OPTIONS) you define keywords with a context argument. 54 | USE_MSGCTXT = no 55 | 56 | # These options get passed to msgmerge. 57 | # Useful options are in particular: 58 | # --previous to keep previous msgids of translated messages, 59 | # --quiet to reduce the verbosity. 60 | MSGMERGE_OPTIONS = 61 | 62 | # These options get passed to msginit. 63 | # If you want to disable line wrapping when writing PO files, add 64 | # --no-wrap to MSGMERGE_OPTIONS, XGETTEXT_OPTIONS, and 65 | # MSGINIT_OPTIONS. 66 | MSGINIT_OPTIONS = 67 | 68 | # This tells whether or not to regenerate a PO file when $(DOMAIN).pot 69 | # has changed. Possible values are "yes" and "no". Set this to no if 70 | # the POT file is checked in the repository and the version control 71 | # program ignores timestamps. 72 | PO_DEPENDS_ON_POT = no 73 | 74 | # This tells whether or not to forcibly update $(DOMAIN).pot and 75 | # regenerate PO files on "make dist". Possible values are "yes" and 76 | # "no". Set this to no if the POT file and PO files are maintained 77 | # externally. 78 | DIST_DEPENDS_ON_UPDATE_PO = no 79 | -------------------------------------------------------------------------------- /po/POTFILES.in: -------------------------------------------------------------------------------- 1 | libskk/context.vala 2 | libskk/state.vala 3 | tools/skk.vala 4 | tools/fep.vala 5 | -------------------------------------------------------------------------------- /po/POTFILES.skip: -------------------------------------------------------------------------------- 1 | libskk/context.c 2 | libskk/state.c 3 | tools/skk.c 4 | tools/fep.c 5 | -------------------------------------------------------------------------------- /po/ja.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: libskk 0.0.1\n" 9 | "Report-Msgid-Bugs-To: \n" 10 | "POT-Creation-Date: 2014-03-06 18:38+0900\n" 11 | "PO-Revision-Date: 2014-03-06 18:39+0900\n" 12 | "Last-Translator: Daiki Ueno \n" 13 | "Language-Team: Japanese\n" 14 | "Language: \n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | 19 | #: ../libskk/state.vala:649 20 | msgid "Kuten([MM]KKTT) " 21 | msgstr "区点([MM]KKTT)" 22 | 23 | #: ../tools/skk.vala:28 ../tools/fep.vala:35 24 | msgid "Path to a file dictionary" 25 | msgstr "ファイル辞書へのパス" 26 | 27 | #: ../tools/skk.vala:30 ../tools/fep.vala:37 28 | msgid "Path to a user dictionary" 29 | msgstr "ユーザ辞書へのパス" 30 | 31 | #: ../tools/skk.vala:32 ../tools/fep.vala:39 32 | msgid "Host and port running skkserv (HOST:PORT)" 33 | msgstr "skkserv が動いているホストとポート (HOST:PORT)" 34 | 35 | #: ../tools/skk.vala:34 ../tools/fep.vala:41 36 | msgid "Typing rule (default: \"default\")" 37 | msgstr "タイピング方式 (既定値: \"default\")" 38 | 39 | #: ../tools/skk.vala:36 ../tools/fep.vala:43 40 | msgid "List typing rules" 41 | msgstr "タイピング方式を一覧表示" 42 | 43 | #: ../tools/skk.vala:47 ../tools/fep.vala:56 44 | msgid "- emulate SKK input method on the command line" 45 | msgstr "コマンドライン上で SKK 入力メソッドをエミュレート" 46 | 47 | #: ../tools/fep.vala:45 48 | msgid "Preedit style" 49 | msgstr "編集中のテキストのスタイル" 50 | 51 | #: ../tools/fep.vala:151 52 | #, c-format 53 | msgid "unknown preedit style %s" 54 | msgstr "未知のスタイル %s" 55 | -------------------------------------------------------------------------------- /rules/Makefile.am: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011-2018 Daiki Ueno 2 | # Copyright (C) 2011-2018 Red Hat, Inc. 3 | 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | 17 | rulesdir = $(pkgdatadir)/rules 18 | 19 | default_files = \ 20 | default/metadata.json \ 21 | default/keymap/default.json \ 22 | default/keymap/hankaku-katakana.json \ 23 | default/keymap/hiragana.json \ 24 | default/keymap/katakana.json \ 25 | default/keymap/latin.json \ 26 | default/keymap/wide-latin.json \ 27 | default/rom-kana/default.json \ 28 | $(NULL) 29 | 30 | act_files = \ 31 | act/metadata.json \ 32 | act/keymap/default.json \ 33 | act/keymap/hankaku-katakana.json \ 34 | act/keymap/hiragana.json \ 35 | act/keymap/katakana.json \ 36 | act/keymap/latin.json \ 37 | act/keymap/wide-latin.json \ 38 | act/rom-kana/default.json \ 39 | $(NULL) 40 | 41 | act09_files = \ 42 | act09/metadata.json \ 43 | act09/keymap/default.json \ 44 | act09/keymap/hankaku-katakana.json \ 45 | act09/keymap/hiragana.json \ 46 | act09/keymap/katakana.json \ 47 | act09/keymap/latin.json \ 48 | act09/keymap/wide-latin.json \ 49 | act09/rom-kana/default.json \ 50 | $(NULL) 51 | 52 | azik_files = \ 53 | azik/metadata.json \ 54 | azik/keymap/common.json \ 55 | azik/keymap/default.json \ 56 | azik/keymap/hankaku-katakana.json \ 57 | azik/keymap/hiragana.json \ 58 | azik/keymap/katakana.json \ 59 | azik/keymap/latin.json \ 60 | azik/keymap/wide-latin.json \ 61 | azik/rom-kana/default.json \ 62 | $(NULL) 63 | 64 | kzik_files = \ 65 | kzik/metadata.json \ 66 | kzik/keymap/common.json \ 67 | kzik/keymap/default.json \ 68 | kzik/keymap/hankaku-katakana.json \ 69 | kzik/keymap/hiragana.json \ 70 | kzik/keymap/katakana.json \ 71 | kzik/keymap/latin.json \ 72 | kzik/keymap/wide-latin.json \ 73 | kzik/rom-kana/default.json \ 74 | $(NULL) 75 | 76 | tutcode_files = \ 77 | tutcode/metadata.json \ 78 | tutcode/keymap/hankaku-katakana.json \ 79 | tutcode/keymap/hiragana.json \ 80 | tutcode/keymap/katakana.json \ 81 | tutcode/keymap/latin.json \ 82 | tutcode/keymap/wide-latin.json \ 83 | tutcode/rom-kana/default.json \ 84 | $(NULL) 85 | 86 | tutcode_touch16x_files = \ 87 | tutcode-touch16x/metadata.json \ 88 | tutcode-touch16x/keymap/hankaku-katakana.json \ 89 | tutcode-touch16x/keymap/hiragana.json \ 90 | tutcode-touch16x/keymap/katakana.json \ 91 | tutcode-touch16x/keymap/latin.json \ 92 | tutcode-touch16x/keymap/wide-latin.json \ 93 | tutcode-touch16x/rom-kana/default.json \ 94 | $(NULL) 95 | 96 | nicola_files = \ 97 | nicola/metadata.json \ 98 | nicola/keymap/default.json \ 99 | nicola/keymap/kana.json \ 100 | nicola/keymap/latin.json \ 101 | nicola/keymap/katakana.json \ 102 | nicola/keymap/hankaku-katakana.json \ 103 | nicola/keymap/wide-latin.json \ 104 | nicola/keymap/hiragana.json \ 105 | nicola/rom-kana/default.json \ 106 | $(NULL) 107 | 108 | tcode_files = \ 109 | tcode/rom-kana/default.json \ 110 | tcode/metadata.json \ 111 | tcode/keymap/latin.json \ 112 | tcode/keymap/katakana.json \ 113 | tcode/keymap/hankaku-katakana.json \ 114 | tcode/keymap/wide-latin.json \ 115 | tcode/keymap/hiragana.json \ 116 | $(NULL) 117 | 118 | trycode_files = \ 119 | trycode/rom-kana/default.json \ 120 | trycode/metadata.json \ 121 | trycode/keymap/latin.json \ 122 | trycode/keymap/katakana.json \ 123 | trycode/keymap/hankaku-katakana.json \ 124 | trycode/keymap/wide-latin.json \ 125 | trycode/keymap/hiragana.json \ 126 | $(NULL) 127 | 128 | nobase_dist_rules_DATA = \ 129 | $(default_files) \ 130 | $(act_files) \ 131 | $(act09_files) \ 132 | $(azik_files) \ 133 | $(kzik_files) \ 134 | $(tutcode_files) \ 135 | $(tutcode_touch16x_files) \ 136 | $(nicola_files) \ 137 | $(tcode_files) \ 138 | $(trycode_files) \ 139 | README.rules \ 140 | $(NULL) 141 | 142 | -include $(top_srcdir)/git.mk 143 | -------------------------------------------------------------------------------- /rules/README.rules: -------------------------------------------------------------------------------- 1 | * Rules overview 2 | 3 | libskk supports various typing rules such as AZIK, ACT, TUT-Code, 4 | which define keyboard shortcuts and romaji-to-kana conversion table. 5 | Rules are normally read from ~/.config/libskk/rules and 6 | /usr/share/libskk/rules. 7 | 8 | * Rule directory structure 9 | 10 | A rule consists of the following directory structure: 11 | 12 | 13 | metadata.json 14 | keymap/ 15 | 16 | ... 17 | rom-kana/ 18 | 19 | ... 20 | 21 | * Rule metadata 22 | 23 | Each rule must have metadata.json in the top level directory, with the 24 | following content: 25 | 26 | { 27 | "name": , 28 | "description": , 29 | "filter": 30 | } 31 | 32 | 33 | * Format of map files 34 | 35 | Each file under keymaps/ and rom-kana/ directories is used to define 36 | some key-value mappings. They are in the following format: 37 | 38 | { 39 | "include": [ 40 | , 41 | ... 42 | ], 43 | "define": { 44 | : { 45 | : , 46 | ... 47 | }, 48 | ... 49 | } 50 | } 51 | 52 | The value associated with "include" is an array of parent map files, 53 | which will be included before evaluating the map file itself. The 54 | value associated with "define" is an object which binds some variables 55 | to values. 56 | 57 | ** Path name resolution 58 | 59 | Each element in "include" may be either a relative or absolute path. 60 | 61 | A relative path does not include "/" while absolute one does. 62 | 63 | If path is relative, the map file is located under the same directory 64 | of the current map file. Otherwise, libskk looks for the map file 65 | outside of the diretory where the current map file is located. 66 | 67 | Example: 68 | 69 | If the current map file is /foo/rom-kana/foo.json and it contains: 70 | 71 | "include": [ "default" ] 72 | 73 | it looks for /foo/rom-kana/default.json. 74 | 75 | If the current map file is /foo/rom-kana/bar.json and it contains: 76 | 77 | "include": [ "default/default" ] 78 | 79 | it looks for /default/rom-kana/default.json. 80 | 81 | ** Format of keymap rule files 82 | 83 | The map name "keymap" is used to associate a key event to a command name. 84 | 85 | Example: 86 | 87 | { 88 | "include": [ 89 | "default" 90 | ], 91 | "define": { 92 | "keymap": { 93 | "Q": null, 94 | "C-@": "start-preedit" 95 | } 96 | } 97 | } 98 | 99 | This map file includes "default" map file first, replace mapping of 100 | "start-preedit" from "Q" to "C-@" (control + "@"). 101 | 102 | The current available commands are: 103 | 104 | abbrev 105 | abort 106 | abort-to-latin 107 | abort-to-latin-unhandled 108 | commit 109 | commit-unhandled 110 | complete 111 | delete 112 | insert-kana- 113 | kuten 114 | next-candidate 115 | previous-candidate 116 | set-input-mode- 117 | special-midasi 118 | start-preedit 119 | start-preedit-kana 120 | start-preedit-no-delete 121 | upper- 122 | 123 | ** Format of rom-kana map files 124 | 125 | The map name "rom-kana" is used to define romaji-to-kana conversion 126 | tables. The value is an object which maps a string to either an array 127 | or null. 128 | 129 | If the value is an array, a new mapping is defined. In that case each 130 | array can contain 2 to 4 elements. The first two elements are 131 | and . is a string which will be 132 | added to preedit after the transition (for example, when "bb" is 133 | typed, "b" is which will be added to the next preedit). 134 | is an output in hiragana. The rest of those elements are 135 | and , which are optional output strings 136 | in katakana and hankaku-katakana input mode (automatically derived 137 | from if they are omitted). 138 | 139 | If the value is null, existing mapping of the corresponding key is 140 | removed from the parent map file. 141 | 142 | Example: 143 | 144 | { 145 | "include": [ 146 | "default" 147 | ], 148 | "define": { 149 | "rom-kana": { 150 | "xka": [ "", "か", "ヵ", "カ" ], 151 | "b.": [ "", "ぶ" ], 152 | "dha": null 153 | } 154 | } 155 | } 156 | 157 | This map file includes "default" map file first, defines new mappings 158 | for "xka" and "b.", and removes a mapping "dha" from the current map 159 | file. 160 | 161 | Copyright (C) 2011-2018 Daiki Ueno 162 | Copyright (C) 2011-2018 Red Hat, Inc. 163 | 164 | This file is free software; as a special exception the author gives 165 | unlimited permission to copy and/or distribute it, with or without 166 | modifications, as long as this notice is preserved. 167 | 168 | This file is distributed in the hope that it will be useful, but 169 | WITHOUT ANY WARRANTY, to the extent permitted by law; without even the 170 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 171 | -------------------------------------------------------------------------------- /rules/act/keymap/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/default" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /rules/act/keymap/hankaku-katakana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/hankaku-katakana" 4 | ], 5 | "define": { 6 | "keymap": { 7 | "|": "start-preedit", 8 | "\\": "set-input-mode-hiragana" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /rules/act/keymap/hiragana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/hiragana" 4 | ], 5 | "define": { 6 | "keymap": { 7 | "|": "start-preedit", 8 | "\\": "set-input-mode-katakana" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /rules/act/keymap/katakana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/katakana" 4 | ], 5 | "define": { 6 | "keymap": { 7 | "|": "start-preedit", 8 | "\\": "set-input-mode-hiragana" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /rules/act/keymap/latin.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/latin" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /rules/act/keymap/wide-latin.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/wide-latin" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /rules/act/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ACT", 3 | "description": "Extended romaji input method based on AZIK for Dvorak keyboard layout, developed by Kiyoshi Kimura " 4 | } 5 | -------------------------------------------------------------------------------- /rules/act09/keymap/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/default" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /rules/act09/keymap/hankaku-katakana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/hankaku-katakana" 4 | ], 5 | "define": { 6 | "keymap": { 7 | "|": "start-preedit", 8 | "\\": "set-input-mode-hiragana" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /rules/act09/keymap/hiragana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/hiragana" 4 | ], 5 | "define": { 6 | "keymap": { 7 | "|": "start-preedit", 8 | "\\": "set-input-mode-katakana" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /rules/act09/keymap/katakana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/katakana" 4 | ], 5 | "define": { 6 | "keymap": { 7 | "|": "start-preedit", 8 | "\\": "set-input-mode-hiragana" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /rules/act09/keymap/latin.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/latin" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /rules/act09/keymap/wide-latin.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/wide-latin" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /rules/act09/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ACT09", 3 | "description": "Improved version of ACT " 4 | } 5 | -------------------------------------------------------------------------------- /rules/azik/keymap/common.json: -------------------------------------------------------------------------------- 1 | { 2 | "define": { 3 | "keymap": { 4 | ":": "upper-;" 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /rules/azik/keymap/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/default", 4 | "common" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /rules/azik/keymap/hankaku-katakana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default" 4 | ], 5 | "define": { 6 | "keymap": { 7 | "\\": "set-input-mode-hiragana" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /rules/azik/keymap/hiragana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "common", 4 | "default/hiragana" 5 | ], 6 | "define": { 7 | "keymap": { 8 | "[": "set-input-mode-katakana", 9 | "q": null, 10 | "Q": "start-preedit insert-kana-ん" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /rules/azik/keymap/katakana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "common", 4 | "default/katakana" 5 | ], 6 | "define": { 7 | "keymap": { 8 | "[": "set-input-mode-hiragana", 9 | "q": null, 10 | "Q": "start-preedit insert-kana-ン" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /rules/azik/keymap/latin.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/latin", 4 | "common" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /rules/azik/keymap/wide-latin.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/wide-latin", 4 | "common" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /rules/azik/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "AZIK", 3 | "description": "Extended romaji input method developed by Kiyoshi Kimura " 4 | } 5 | -------------------------------------------------------------------------------- /rules/default/keymap/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "define": { 3 | "keymap": { 4 | "C-g": "abort", 5 | "\n": "commit-unhandled", 6 | "C-m": "commit-unhandled", 7 | "\b": "delete", 8 | "C-h": "delete", 9 | "/": "abbrev", 10 | "\\": "kuten", 11 | " ": "next-candidate", 12 | "\t": "complete", 13 | "C-i": "complete", 14 | ">": "special-midasi", 15 | "x": "previous-candidate", 16 | "X": "purge-candidate", 17 | "C-f": "expand-preedit", 18 | "C-b": "shrink-preedit", 19 | "Right": "expand-preedit", 20 | "Left": "shrink-preedit" 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /rules/default/keymap/hankaku-katakana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default" 4 | ], 5 | "define": { 6 | "keymap": { 7 | "q": "set-input-mode-hiragana", 8 | "Q": "start-preedit", 9 | "l": "set-input-mode-latin", 10 | "L": "set-input-mode-wide-latin", 11 | "C-q": "set-input-mode-hiragana", 12 | "C-j": "commit" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /rules/default/keymap/hiragana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default" 4 | ], 5 | "define": { 6 | "keymap": { 7 | "q": "set-input-mode-katakana", 8 | "Q": "start-preedit", 9 | "l": "set-input-mode-latin", 10 | "L": "set-input-mode-wide-latin", 11 | "C-q": "set-input-mode-hankaku-katakana", 12 | "C-j": "commit" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /rules/default/keymap/katakana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default" 4 | ], 5 | "define": { 6 | "keymap": { 7 | "q": "set-input-mode-hiragana", 8 | "Q": "start-preedit", 9 | "l": "set-input-mode-latin", 10 | "L": "set-input-mode-wide-latin", 11 | "C-q": "set-input-mode-hankaku-katakana", 12 | "C-j": "commit" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /rules/default/keymap/latin.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default" 4 | ], 5 | "define": { 6 | "keymap": { 7 | "C-j": "set-input-mode-hiragana" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /rules/default/keymap/wide-latin.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default" 4 | ], 5 | "define": { 6 | "keymap": { 7 | "C-j": "set-input-mode-hiragana" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /rules/default/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Default", 3 | "description": "Default typing rule" 4 | } 5 | -------------------------------------------------------------------------------- /rules/default/rom-kana/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "define": { 3 | "rom-kana": { 4 | "a": ["", "あ" ], 5 | "bb": ["b", "っ" ], 6 | "ba": ["", "ば" ], 7 | "be": ["", "べ" ], 8 | "bi": ["", "び" ], 9 | "bo": ["", "ぼ" ], 10 | "bu": ["", "ぶ" ], 11 | "bya": ["", "びゃ" ], 12 | "bye": ["", "びぇ" ], 13 | "byi": ["", "びぃ" ], 14 | "byo": ["", "びょ" ], 15 | "byu": ["", "びゅ" ], 16 | "cc": ["c", "っ" ], 17 | "cha": ["", "ちゃ" ], 18 | "che": ["", "ちぇ" ], 19 | "chi": ["", "ち" ], 20 | "cho": ["", "ちょ" ], 21 | "chu": ["", "ちゅ" ], 22 | "cya": ["", "ちゃ" ], 23 | "cye": ["", "ちぇ" ], 24 | "cyi": ["", "ちぃ" ], 25 | "cyo": ["", "ちょ" ], 26 | "cyu": ["", "ちゅ" ], 27 | "dd": ["d", "っ" ], 28 | "da": ["", "だ" ], 29 | "de": ["", "で" ], 30 | "dha": ["", "でゃ" ], 31 | "dhe": ["", "でぇ" ], 32 | "dhi": ["", "でぃ" ], 33 | "dho": ["", "でょ" ], 34 | "dhu": ["", "でゅ" ], 35 | "di": ["", "ぢ" ], 36 | "do": ["", "ど" ], 37 | "du": ["", "づ" ], 38 | "dya": ["", "ぢゃ" ], 39 | "dye": ["", "ぢぇ" ], 40 | "dyi": ["", "ぢぃ" ], 41 | "dyo": ["", "ぢょ" ], 42 | "dyu": ["", "ぢゅ" ], 43 | "e": ["", "え" ], 44 | "ff": ["f", "っ" ], 45 | "fa": ["", "ふぁ" ], 46 | "fe": ["", "ふぇ" ], 47 | "fi": ["", "ふぃ" ], 48 | "fo": ["", "ふぉ" ], 49 | "fu": ["", "ふ" ], 50 | "fya": ["", "ふゃ" ], 51 | "fye": ["", "ふぇ" ], 52 | "fyi": ["", "ふぃ" ], 53 | "fyo": ["", "ふょ" ], 54 | "fyu": ["", "ふゅ" ], 55 | "gg": ["g", "っ" ], 56 | "ga": ["", "が" ], 57 | "ge": ["", "げ" ], 58 | "gi": ["", "ぎ" ], 59 | "go": ["", "ご" ], 60 | "gu": ["", "ぐ" ], 61 | "gya": ["", "ぎゃ" ], 62 | "gye": ["", "ぎぇ" ], 63 | "gyi": ["", "ぎぃ" ], 64 | "gyo": ["", "ぎょ" ], 65 | "gyu": ["", "ぎゅ" ], 66 | "ha": ["", "は" ], 67 | "he": ["", "へ" ], 68 | "hh": ["h", "っ" ], 69 | "hi": ["", "ひ" ], 70 | "ho": ["", "ほ" ], 71 | "hu": ["", "ふ" ], 72 | "hya": ["", "ひゃ" ], 73 | "hye": ["", "ひぇ" ], 74 | "hyi": ["", "ひぃ" ], 75 | "hyo": ["", "ひょ" ], 76 | "hyu": ["", "ひゅ" ], 77 | "i": ["", "い" ], 78 | "jj": ["j", "っ" ], 79 | "ja": ["", "じゃ" ], 80 | "je": ["", "じぇ" ], 81 | "ji": ["", "じ" ], 82 | "jo": ["", "じょ" ], 83 | "ju": ["", "じゅ" ], 84 | "jya": ["", "じゃ" ], 85 | "jye": ["", "じぇ" ], 86 | "jyi": ["", "じぃ" ], 87 | "jyo": ["", "じょ" ], 88 | "jyu": ["", "じゅ" ], 89 | "kk": ["k", "っ" ], 90 | "ka": ["", "か" ], 91 | "ke": ["", "け" ], 92 | "ki": ["", "き" ], 93 | "ko": ["", "こ" ], 94 | "ku": ["", "く" ], 95 | "kya": ["", "きゃ" ], 96 | "kye": ["", "きぇ" ], 97 | "kyi": ["", "きぃ" ], 98 | "kyo": ["", "きょ" ], 99 | "kyu": ["", "きゅ" ], 100 | "ma": ["", "ま" ], 101 | "me": ["", "め" ], 102 | "mi": ["", "み" ], 103 | "mm": ["m", "っ" ], 104 | "mo": ["", "も" ], 105 | "mu": ["", "む" ], 106 | "mya": ["", "みゃ" ], 107 | "mye": ["", "みぇ" ], 108 | "myi": ["", "みぃ" ], 109 | "myo": ["", "みょ" ], 110 | "myu": ["", "みゅ" ], 111 | "n'": ["", "ん" ], 112 | "na": ["", "な" ], 113 | "ne": ["", "ね" ], 114 | "ni": ["", "に" ], 115 | "nn": ["", "ん" ], 116 | "no": ["", "の" ], 117 | "nu": ["", "ぬ" ], 118 | "nya": ["", "にゃ" ], 119 | "nye": ["", "にぇ" ], 120 | "nyi": ["", "にぃ" ], 121 | "nyo": ["", "にょ" ], 122 | "nyu": ["", "にゅ" ], 123 | "o": ["", "お" ], 124 | "pp": ["p", "っ" ], 125 | "pa": ["", "ぱ" ], 126 | "pe": ["", "ぺ" ], 127 | "pi": ["", "ぴ" ], 128 | "po": ["", "ぽ" ], 129 | "pu": ["", "ぷ" ], 130 | "pya": ["", "ぴゃ" ], 131 | "pye": ["", "ぴぇ" ], 132 | "pyi": ["", "ぴぃ" ], 133 | "pyo": ["", "ぴょ" ], 134 | "pyu": ["", "ぴゅ" ], 135 | "rr": ["r", "っ" ], 136 | "ra": ["", "ら" ], 137 | "re": ["", "れ" ], 138 | "ri": ["", "り" ], 139 | "ro": ["", "ろ" ], 140 | "ru": ["", "る" ], 141 | "rya": ["", "りゃ" ], 142 | "rye": ["", "りぇ" ], 143 | "ryi": ["", "りぃ" ], 144 | "ryo": ["", "りょ" ], 145 | "ryu": ["", "りゅ" ], 146 | "ss": ["s", "っ" ], 147 | "sa": ["", "さ" ], 148 | "se": ["", "せ" ], 149 | "sha": ["", "しゃ" ], 150 | "she": ["", "しぇ" ], 151 | "shi": ["", "し" ], 152 | "sho": ["", "しょ" ], 153 | "shu": ["", "しゅ" ], 154 | "si": ["", "し" ], 155 | "so": ["", "そ" ], 156 | "su": ["", "す" ], 157 | "sya": ["", "しゃ" ], 158 | "sye": ["", "しぇ" ], 159 | "syi": ["", "しぃ" ], 160 | "syo": ["", "しょ" ], 161 | "syu": ["", "しゅ" ], 162 | "tt": ["t", "っ" ], 163 | "ta": ["", "た" ], 164 | "te": ["", "て" ], 165 | "tha": ["", "てぁ" ], 166 | "the": ["", "てぇ" ], 167 | "thi": ["", "てぃ" ], 168 | "tho": ["", "てょ" ], 169 | "thu": ["", "てゅ" ], 170 | "ti": ["", "ち" ], 171 | "to": ["", "と" ], 172 | "tsu": ["", "つ" ], 173 | "tu": ["", "つ" ], 174 | "tya": ["", "ちゃ" ], 175 | "tye": ["", "ちぇ" ], 176 | "tyi": ["", "ちぃ" ], 177 | "tyo": ["", "ちょ" ], 178 | "tyu": ["", "ちゅ" ], 179 | "u": ["", "う" ], 180 | "vv": ["v", "っ" ], 181 | "va": ["", "う゛ぁ" ], 182 | "ve": ["", "う゛ぇ" ], 183 | "vi": ["", "う゛ぃ" ], 184 | "vo": ["", "う゛ぉ" ], 185 | "vu": ["", "う゛" ], 186 | "ww": ["w", "っ" ], 187 | "wa": ["", "わ" ], 188 | "we": ["", "うぇ" ], 189 | "wi": ["", "うぃ" ], 190 | "wo": ["", "を" ], 191 | "wu": ["", "う" ], 192 | "xx": ["x", "っ" ], 193 | "xa": ["", "ぁ" ], 194 | "xe": ["", "ぇ" ], 195 | "xi": ["", "ぃ" ], 196 | "xka": [ "", "か", "ヵ" ], 197 | "xke": [ "", "け", "ヶ" ], 198 | "xo": ["", "ぉ" ], 199 | "xtsu": ["", "っ" ], 200 | "xtu": ["", "っ" ], 201 | "xu": ["", "ぅ" ], 202 | "xwa": ["", "ゎ" ], 203 | "xwe": ["", "ゑ" ], 204 | "xwi": ["", "ゐ" ], 205 | "xya": ["", "ゃ" ], 206 | "xyo": ["", "ょ" ], 207 | "xyu": ["", "ゅ" ], 208 | "yy": ["y", "っ" ], 209 | "ya": ["", "や" ], 210 | "ye": ["", "いぇ" ], 211 | "yo": ["", "よ" ], 212 | "yu": ["", "ゆ" ], 213 | "zz": ["z", "っ" ], 214 | "z ": ["", " "], 215 | "z*": ["", "※"], 216 | "z,": ["", "‥" ], 217 | "z-": ["", "〜" ], 218 | "z.": ["", "…" ], 219 | "z/": ["", "・" ], 220 | "z0": ["", "○"], 221 | "z:": ["", "゜"], 222 | "z;": ["", "゛"], 223 | "z@": ["", "◎"], 224 | "z[": ["", "『" ], 225 | "z]": ["", "』" ], 226 | "z{": ["", "【"], 227 | "z}": ["", "】"], 228 | "z(": ["", "("], 229 | "z)": ["", ")"], 230 | "za": ["", "ざ" ], 231 | "ze": ["", "ぜ" ], 232 | "zh": ["", "←" ], 233 | "zi": ["", "じ" ], 234 | "zj": ["", "↓" ], 235 | "zk": ["", "↑" ], 236 | "zl": ["", "→" ], 237 | "zL": ["", "⇒"], 238 | "zo": ["", "ぞ" ], 239 | "zu": ["", "ず" ], 240 | "zya": ["", "じゃ" ], 241 | "zye": ["", "じぇ" ], 242 | "zyi": ["", "じぃ" ], 243 | "zyo": ["", "じょ" ], 244 | "zyu": ["", "じゅ" ], 245 | "-": ["", "ー" ], 246 | ":": ["", ":" ], 247 | ";": ["", ";" ], 248 | "?": ["", "?" ], 249 | "[": ["", "「" ], 250 | "]": ["", "」" ] 251 | } 252 | } 253 | } 254 | -------------------------------------------------------------------------------- /rules/kzik/keymap/common.json: -------------------------------------------------------------------------------- 1 | { 2 | "define": { 3 | "keymap": { 4 | ":": "upper-;" 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /rules/kzik/keymap/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/default", 4 | "common" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /rules/kzik/keymap/hankaku-katakana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default" 4 | ], 5 | "define": { 6 | "keymap": { 7 | "\\": "set-input-mode-hiragana" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /rules/kzik/keymap/hiragana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "common", 4 | "default/hiragana" 5 | ], 6 | "define": { 7 | "keymap": { 8 | "\\": "set-input-mode-katakana", 9 | "q": null, 10 | "Q": "start-preedit insert-kana-ん" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /rules/kzik/keymap/katakana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "common", 4 | "default/katakana" 5 | ], 6 | "define": { 7 | "keymap": { 8 | "\\": "set-input-mode-hiragana", 9 | "q": null, 10 | "Q": "start-preedit insert-kana-ン" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /rules/kzik/keymap/latin.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/latin", 4 | "common" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /rules/kzik/keymap/wide-latin.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/wide-latin", 4 | "common" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /rules/kzik/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "KZIK", 3 | "description": "Extended romaji input method based on AZIK, developed by OHASHI Hideya " 4 | } 5 | -------------------------------------------------------------------------------- /rules/nicola/keymap/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "define": { 3 | "keymap": { 4 | "C-g": "abort", 5 | "\n": "commit-unhandled", 6 | "C-m": "commit-unhandled", 7 | "\b": "delete", 8 | "C-h": "delete", 9 | "[gh]": "abbrev", 10 | "C": "kuten", 11 | " ": "next-candidate", 12 | "\t": "complete", 13 | "C-i": "complete", 14 | ">": "special-midasi", 15 | "C-p": "previous-candidate", 16 | "X": "purge-candidate" 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /rules/nicola/keymap/hankaku-katakana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "kana" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /rules/nicola/keymap/hiragana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "kana" 4 | ], 5 | "define": { 6 | "keymap": { 7 | "[dk]": "set-input-mode-katakana" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /rules/nicola/keymap/kana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default" 4 | ], 5 | "define": { 6 | "keymap": { 7 | "q": "insert-kana-。", 8 | "(lshift q)": "insert-kana-ぁ", 9 | "(rshift q)": null, 10 | 11 | "w": "insert-kana-か", 12 | "(lshift w)": "insert-kana-え", 13 | "(rshift w)": "insert-kana-が", 14 | 15 | "e": "insert-kana-た", 16 | "(lshift e)": "insert-kana-り", 17 | "(rshift e)": "insert-kana-だ", 18 | 19 | "r": "insert-kana-こ", 20 | "(lshift r)": "insert-kana-ゃ", 21 | "(rshift r)": "insert-kana-ご", 22 | 23 | "t": "insert-kana-さ", 24 | "(lshift t)": "insert-kana-れ", 25 | "(rshift t)": "insert-kana-ざ", 26 | 27 | "y": "insert-kana-ら", 28 | "(lshift y)": "insert-kana-ぱ", 29 | "(rshift y)": "insert-kana-よ", 30 | 31 | "u": "insert-kana-ち", 32 | "(lshift u)": "insert-kana-ぢ", 33 | "(rshift u)": "insert-kana-に", 34 | 35 | "i": "insert-kana-く", 36 | "(lshift i)": "insert-kana-ぐ", 37 | "(rshift i)": "insert-kana-る", 38 | 39 | "o": "insert-kana-つ", 40 | "(lshift o)": "insert-kana-づ", 41 | "(rshift o)": "insert-kana-ま", 42 | 43 | "p": "insert-kana-,", 44 | "(lshift p)": "insert-kana-ぴ", 45 | "(rshift p)": "insert-kana-ぇ", 46 | 47 | "@": "insert-kana-、", 48 | "(lshift @)": null, 49 | "(rshift @)": null, 50 | 51 | "[": "insert-kana-゛", 52 | "(lshift [)": null, 53 | "(rshift [)": "insert-kana-゜", 54 | 55 | "a": "insert-kana-う", 56 | "(lshift a)": "insert-kana-を", 57 | "(rshift a)": null, 58 | 59 | "s": "insert-kana-し", 60 | "(lshift s)": "insert-kana-あ", 61 | "(rshift s)": "insert-kana-じ", 62 | 63 | "d": "insert-kana-て", 64 | "(lshift d)": "insert-kana-な", 65 | "(rshift d)": "insert-kana-で", 66 | 67 | "f": "insert-kana-け", 68 | "(lshift f)": "insert-kana-ゅ", 69 | "(rshift f)": "insert-kana-げ", 70 | 71 | "g": "insert-kana-せ", 72 | "(lshift g)": "insert-kana-も", 73 | "(rshift g)": "insert-kana-ぜ", 74 | 75 | "h": "insert-kana-は", 76 | "(lshift h)": "insert-kana-ば", 77 | "(rshift h)": "insert-kana-み", 78 | 79 | "j": "insert-kana-と", 80 | "(lshift j)": "insert-kana-ど", 81 | "(rshift j)": "insert-kana-お", 82 | 83 | "k": "insert-kana-き", 84 | "(lshift k)": "insert-kana-ぎ", 85 | "(rshift k)": "insert-kana-の", 86 | 87 | "l": "insert-kana-い", 88 | "(lshift l)": "insert-kana-ぽ", 89 | "(rshift l)": "insert-kana-ょ", 90 | 91 | ";": "insert-kana-ん", 92 | "(lshift ;)": null, 93 | "(rshift ;)": "insert-kana-っ", 94 | 95 | "z": "insert-kana-.", 96 | "(lshift z)": "insert-kana-ぅ", 97 | "(rshift z)": null, 98 | 99 | "x": "insert-kana-ひ", 100 | "(lshift x)": "insert-kana-ー", 101 | "(rshift x)": "insert-kana-び", 102 | 103 | "c": "insert-kana-す", 104 | "(lshift c)": "insert-kana-ろ", 105 | "(rshift c)": "insert-kana-ず", 106 | 107 | "v": "insert-kana-ふ", 108 | "(lshift v)": "insert-kana-や", 109 | "(rshift v)": "insert-kana-ぶ", 110 | 111 | "b": "insert-kana-へ", 112 | "(lshift b)": "insert-kana-ぃ", 113 | "(rshift b)": "insert-kana-べ", 114 | 115 | "n": "insert-kana-め", 116 | "(lshift n)": "insert-kana-ぷ", 117 | "(rshift n)": "insert-kana-ぬ", 118 | 119 | "m": "insert-kana-そ", 120 | "(lshift m)": "insert-kana-ぞ", 121 | "(rshift m)": "insert-kana-ゆ", 122 | 123 | ",": "insert-kana-ね", 124 | "(lshift ,)": "insert-kana-ぺ", 125 | "(rshift ,)": "insert-kana-む", 126 | 127 | ".": "insert-kana-ほ", 128 | "(lshift .)": "insert-kana-ぼ", 129 | "(rshift .)": "insert-kana-わ", 130 | 131 | "/": "insert-kana-・", 132 | "(lshift /)": null, 133 | "(rshift /)": "insert-kana-ぉ", 134 | 135 | "1": "insert-kana-1", 136 | "(lshift 1)": "insert-kana-?", 137 | "(rshift 1)": null, 138 | 139 | "2": "insert-kana-2", 140 | "(lshift 2)": "insert-kana-/", 141 | "(rshift 2)": null, 142 | 143 | "4": "insert-kana-4", 144 | "(lshift 4)": "insert-kana-「", 145 | "(rshift 4)": null, 146 | 147 | "5": "insert-kana-5", 148 | "(lshift 5)": "insert-kana-」", 149 | "(rshift 5)": null, 150 | 151 | "6": "insert-kana-6", 152 | "(lshift 6)": null, 153 | "(rshift 6)": "insert-kana-[", 154 | 155 | "7": "insert-kana-7", 156 | "(lshift 7)": null, 157 | "(rshift 7)": "insert-kana-]", 158 | 159 | "8": "insert-kana-8", 160 | "(lshift 8)": null, 161 | "(rshift 8)": "insert-kana-(", 162 | 163 | "9": "insert-kana-9", 164 | "(lshift 9)": null, 165 | "(rshift 9)": "insert-kana-)", 166 | 167 | "\\": "insert-kana-¥", 168 | "(lshift \\)": null, 169 | "(rshift \\)": null, 170 | 171 | "[fj]": "start-preedit-kana", 172 | "[gh]": "abbrev", 173 | "[LR]": "set-input-mode-latin", 174 | "A": "set-input-mode-latin", 175 | "Z": "set-input-mode-wide-latin", 176 | "L": "set-input-mode-wide-latin", 177 | "Q": "start-preedit" 178 | } 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /rules/nicola/keymap/katakana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "kana" 4 | ], 5 | "define": { 6 | "keymap": { 7 | "[dk]": "set-input-mode-hiragana" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /rules/nicola/keymap/latin.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/default" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /rules/nicola/keymap/wide-latin.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/default" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /rules/nicola/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "NICOLA", 3 | "description": "Input method using thumb shift keyboard developed by the NICOLA (NIhongo-nyuuryoku COnsortium LAyout) project ", 4 | "filter": "nicola" 5 | } 6 | -------------------------------------------------------------------------------- /rules/nicola/rom-kana/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "define": { 3 | "rom-kana": { 4 | } 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /rules/tcode/keymap/hankaku-katakana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/default" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /rules/tcode/keymap/hiragana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/default" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /rules/tcode/keymap/katakana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/default" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /rules/tcode/keymap/latin.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/default" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /rules/tcode/keymap/wide-latin.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/default" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /rules/tcode/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "T-Code", 3 | "description": "Japanese direct input method developed by the T-Code project " 4 | } 5 | -------------------------------------------------------------------------------- /rules/trycode/keymap/hankaku-katakana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/default" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /rules/trycode/keymap/hiragana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/default" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /rules/trycode/keymap/katakana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/default" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /rules/trycode/keymap/latin.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/default" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /rules/trycode/keymap/wide-latin.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/default" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /rules/trycode/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "TRY-CODE", 3 | "description": "Japanese direct input method based on T-Code, developed by Naoto Takahashi " 4 | } 5 | -------------------------------------------------------------------------------- /rules/tutcode-touch16x/keymap/hankaku-katakana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "tutcode/default" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /rules/tutcode-touch16x/keymap/hiragana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "tutcode/default" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /rules/tutcode-touch16x/keymap/katakana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "tutcode/default" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /rules/tutcode-touch16x/keymap/latin.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "tutcode/default" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /rules/tutcode-touch16x/keymap/wide-latin.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "tutcode/default" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /rules/tutcode-touch16x/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "TUT-Code (Touch16+)", 3 | "description": "TUT-Code with Touch16+ extension" 4 | } 5 | -------------------------------------------------------------------------------- /rules/tutcode-touch16x/rom-kana/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "tutcode/default" 4 | ], 5 | "define": { 6 | "rom-kana": { 7 | "tld": [ "", "ぱ" ], 8 | "tle": [ "", "ぴ" ], 9 | "tlr": [ "", "ぷ" ], 10 | "tlg": [ "", "ぺ" ], 11 | "tlf": [ "", "ぽ" ], 12 | "dlr": [ "", "づ" ], 13 | "alu": [ "", "ヴ" ], 14 | "eld": [ "", "ヵ" ], 15 | "elg": [ "", "ヶ" ] 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /rules/tutcode/keymap/hankaku-katakana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/default" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /rules/tutcode/keymap/hiragana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/default" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /rules/tutcode/keymap/katakana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/default" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /rules/tutcode/keymap/latin.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/default" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /rules/tutcode/keymap/wide-latin.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/default" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /rules/tutcode/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "TUT-Code", 3 | "description": "Japanese direct input method developed by Hajime Ohiwa and Takaaki Takashima " 4 | } 5 | -------------------------------------------------------------------------------- /tests/Makefile.am: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011-2018 Daiki Ueno 2 | # Copyright (C) 2011-2018 Red Hat, Inc. 3 | 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | 17 | TESTS_ENVIRONMENT = \ 18 | G_DEBUG=${G_DEBUG:+"${G_DEBUG},"}gc-friendly \ 19 | G_SLICE=${G_SLICE},always-malloc \ 20 | LIBSKK_DATA_PATH=$(top_srcdir):$(top_srcdir)/tests 21 | LOG_COMPILER = $(LIBTOOL) --mode=execute $(VALGRIND) $(VALGRIND_OPTS) 22 | check_PROGRAMS = rom-kana file-dict user-dict cdb-dict skkserv rule context basic 23 | TESTS = $(check_PROGRAMS) 24 | noinst_PROGRAMS = $(TESTS) 25 | noinst_HEADERS = common.h 26 | 27 | AM_CPPFLAGS = \ 28 | -I$(top_srcdir) $(LIBSKK_CFLAGS) \ 29 | -DLIBSKK_FILE_DICT=\"$(top_srcdir)/tests/file-dict.dat\" \ 30 | -DLIBSKK_CDB_DICT=\"$(top_srcdir)/tests/cdb-dict.dat\" \ 31 | $(NULL) 32 | 33 | rom_kana_SOURCES = rom-kana.c 34 | rom_kana_LDADD = $(top_builddir)/libskk/libskk.la $(LIBSKK_LIBS) 35 | 36 | file_dict_SOURCES = file-dict.c 37 | file_dict_LDADD = $(top_builddir)/libskk/libskk.la $(LIBSKK_LIBS) 38 | 39 | cdb_dict_SOURCES = cdb-dict.c 40 | cdb_dict_LDADD = $(top_builddir)/libskk/libskk.la $(LIBSKK_LIBS) 41 | 42 | skkserv_SOURCES = skkserv.c 43 | skkserv_LDADD = $(top_builddir)/libskk/libskk.la $(LIBSKK_LIBS) 44 | 45 | user_dict_SOURCES = user-dict.c common.c 46 | user_dict_LDADD = $(top_builddir)/libskk/libskk.la $(LIBSKK_LIBS) 47 | 48 | rule_SOURCES = rule.c common.c 49 | rule_LDADD = $(top_builddir)/libskk/libskk.la $(LIBSKK_LIBS) 50 | 51 | context_SOURCES = context.c common.c 52 | context_LDADD = $(top_builddir)/libskk/libskk.la $(LIBSKK_LIBS) 53 | 54 | basic_SOURCES = basic.c common.c 55 | basic_LDADD = $(top_builddir)/libskk/libskk.la $(LIBSKK_LIBS) 56 | 57 | EXTRA_DIST = file-dict.dat cdb-dict.dat rules 58 | CLEANFILES = user-dict.dat valgrind.log.* 59 | 60 | -include $(top_srcdir)/git.mk 61 | -------------------------------------------------------------------------------- /tests/cdb-dict.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static void 4 | cdb_dict (void) 5 | { 6 | GError *error = NULL; 7 | SkkCdbDict *dict = skk_cdb_dict_new (LIBSKK_CDB_DICT, "EUC-JP", &error); 8 | g_assert_no_error (error); 9 | 10 | gint len; 11 | SkkCandidate **candidates; 12 | gchar **completion; 13 | gboolean read_only; 14 | 15 | g_assert (skk_dict_get_read_only (SKK_DICT (dict))); 16 | g_object_get (dict, "read-only", &read_only, NULL); 17 | g_assert (read_only); 18 | 19 | candidates = skk_dict_lookup (SKK_DICT (dict), 20 | "かんじ", 21 | FALSE, 22 | &len); 23 | g_assert_cmpint (len, ==, 2); 24 | while (--len >= 0) { 25 | g_object_unref (candidates[len]); 26 | } 27 | g_free (candidates); 28 | 29 | candidates = skk_dict_lookup (SKK_DICT (dict), 30 | "あu", 31 | TRUE, 32 | &len); 33 | g_assert_cmpint (len, ==, 4); 34 | while (--len >= 0) { 35 | g_object_unref (candidates[len]); 36 | } 37 | g_free (candidates); 38 | 39 | /* completion is always empty with CDB dict */ 40 | completion = skk_dict_complete (SKK_DICT (dict), "か", &len); 41 | g_assert_cmpint (len, ==, 0); 42 | g_free (completion); 43 | 44 | error = NULL; 45 | skk_dict_save (SKK_DICT (dict), &error); 46 | g_assert_no_error (error); 47 | 48 | g_object_unref (dict); 49 | } 50 | 51 | int 52 | main (int argc, char **argv) 53 | { 54 | skk_init (); 55 | g_test_init (&argc, &argv, NULL); 56 | g_test_add_func ("/libskk/cdb-dict", cdb_dict); 57 | return g_test_run (); 58 | } 59 | -------------------------------------------------------------------------------- /tests/cdb-dict.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ueno/libskk/d5e9726fa5c439518bed2a74d1796d3b99b861ce/tests/cdb-dict.dat -------------------------------------------------------------------------------- /tests/common.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "common.h" 4 | 5 | SkkContext * 6 | create_context (gboolean use_user_dict, 7 | gboolean use_file_dict) 8 | { 9 | SkkDict *dictionaries[3]; 10 | gint n_dictionaries = 0; 11 | SkkEmptyDict *empty_dict; 12 | SkkUserDict *user_dict = NULL; 13 | SkkFileDict *file_dict = NULL; 14 | SkkContext *context; 15 | GError *error; 16 | 17 | error = NULL; 18 | empty_dict = skk_empty_dict_new (); 19 | g_assert_no_error (error); 20 | dictionaries[n_dictionaries++] = SKK_DICT (empty_dict); 21 | 22 | if (use_user_dict) { 23 | error = NULL; 24 | user_dict = skk_user_dict_new ("user-dict.dat", "EUC-JP", &error); 25 | g_assert_no_error (error); 26 | dictionaries[n_dictionaries++] = SKK_DICT (user_dict); 27 | } 28 | 29 | if (use_file_dict) { 30 | error = NULL; 31 | file_dict = skk_file_dict_new (LIBSKK_FILE_DICT, "EUC-JP", &error); 32 | g_assert_no_error (error); 33 | dictionaries[n_dictionaries++] = SKK_DICT (file_dict); 34 | } 35 | 36 | context = skk_context_new (dictionaries, n_dictionaries); 37 | 38 | g_object_unref (empty_dict); 39 | if (user_dict) 40 | g_object_unref (user_dict); 41 | if (file_dict) 42 | g_object_unref (file_dict); 43 | 44 | return context; 45 | } 46 | 47 | void 48 | destroy_context (SkkContext *context) 49 | { 50 | unlink ("user-dict.dat"); 51 | g_object_unref (context); 52 | } 53 | 54 | void 55 | check_transitions (SkkContext *context, 56 | const SkkTransition *transitions) 57 | { 58 | gint i; 59 | 60 | for (i = 0; transitions[i].keys != NULL; i++) { 61 | const gchar *preedit; 62 | gchar *output; 63 | SkkInputMode input_mode; 64 | skk_context_reset (context); 65 | output = skk_context_poll_output (context); 66 | g_free (output); 67 | 68 | skk_context_set_input_mode (context, transitions[i].input_mode); 69 | skk_context_process_key_events (context, transitions[i].keys); 70 | preedit = skk_context_get_preedit (context); 71 | g_assert_cmpstr (preedit, ==, transitions[i].preedit); 72 | output = skk_context_poll_output (context); 73 | g_assert_cmpstr (output, ==, transitions[i].output); 74 | g_free (output); 75 | input_mode = skk_context_get_input_mode (context); 76 | g_assert_cmpint (input_mode, ==, transitions[i].next_input_mode); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /tests/common.h: -------------------------------------------------------------------------------- 1 | #ifndef __COMMON_H__ 2 | #define __COMMON_H__ 1 3 | 4 | #include 5 | 6 | struct _SkkTransition { 7 | SkkInputMode input_mode; 8 | const gchar *keys; 9 | const gchar *preedit; 10 | const gchar *output; 11 | SkkInputMode next_input_mode; 12 | }; 13 | typedef struct _SkkTransition SkkTransition; 14 | 15 | SkkContext *create_context (gboolean use_user_dict, 16 | gboolean use_file_dict); 17 | void destroy_context (SkkContext *context); 18 | void check_transitions (SkkContext *context, 19 | const SkkTransition *transitions); 20 | 21 | #endif /* __COMMON_H__ */ 22 | -------------------------------------------------------------------------------- /tests/context.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "common.h" 3 | 4 | static void 5 | dictionary (void) 6 | { 7 | SkkContext *context = create_context (TRUE, TRUE); 8 | SkkEmptyDict *dict = skk_empty_dict_new (); 9 | SkkDict **dictionaries; 10 | gint n_dictionaries; 11 | 12 | skk_context_add_dictionary (context, SKK_DICT (dict)); 13 | 14 | dictionaries = skk_context_get_dictionaries (context, &n_dictionaries); 15 | g_assert_cmpint (n_dictionaries, ==, 4); 16 | skk_context_set_dictionaries (context, dictionaries, n_dictionaries); 17 | while (--n_dictionaries >= 0) { 18 | g_object_unref (dictionaries[n_dictionaries]); 19 | } 20 | g_free (dictionaries); 21 | 22 | skk_context_remove_dictionary (context, SKK_DICT (dict)); 23 | 24 | g_object_unref (dict); 25 | 26 | destroy_context (context); 27 | } 28 | 29 | static void 30 | basic (void) 31 | { 32 | SkkContext *context = create_context (TRUE, TRUE); 33 | gboolean retval; 34 | const gchar *preedit; 35 | gchar *output; 36 | guint offset, nchars; 37 | 38 | retval = skk_context_process_key_events (context, "a i r"); 39 | g_assert (retval); 40 | 41 | output = skk_context_peek_output (context); 42 | g_assert_cmpstr (output, ==, "あい"); 43 | g_free (output); 44 | skk_context_clear_output (context); 45 | 46 | preedit = skk_context_get_preedit (context); 47 | g_assert_cmpstr (preedit, ==, "r"); 48 | 49 | skk_context_get_preedit_underline (context, &offset, &nchars); 50 | g_assert_cmpint (offset, ==, 0); 51 | g_assert_cmpint (nchars, ==, 0); 52 | 53 | skk_context_reset (context); 54 | skk_context_clear_output (context); 55 | retval = skk_context_process_key_events (context, "A"); 56 | g_assert (retval); 57 | 58 | preedit = skk_context_get_preedit (context); 59 | g_assert_cmpstr (preedit, ==, "▽あ"); 60 | 61 | retval = skk_context_process_key_events (context, "i"); 62 | g_assert (retval); 63 | 64 | output = skk_context_poll_output (context); 65 | g_assert_cmpstr (output, ==, ""); 66 | g_free (output); 67 | 68 | preedit = skk_context_get_preedit (context); 69 | g_assert_cmpstr (preedit, ==, "▽あい"); 70 | 71 | retval = skk_context_process_key_events (context, "SPC"); 72 | g_assert (retval); 73 | 74 | preedit = skk_context_get_preedit (context); 75 | g_assert_cmpstr (preedit, ==, "▼愛"); 76 | 77 | retval = skk_context_process_key_events (context, "\n"); 78 | g_assert (!retval); 79 | 80 | output = skk_context_poll_output (context); 81 | g_assert_cmpstr (output, ==, "愛"); 82 | g_free (output); 83 | 84 | retval = skk_context_process_key_events (context, "\n"); 85 | g_assert (!retval); 86 | 87 | skk_context_reset (context); 88 | skk_context_clear_output (context); 89 | 90 | retval = skk_context_process_key_events (context, "A U"); 91 | 92 | preedit = skk_context_get_preedit (context); 93 | g_assert_cmpstr (preedit, ==, "▼合う"); 94 | 95 | destroy_context (context); 96 | } 97 | 98 | int 99 | main (int argc, char **argv) { 100 | skk_init (); 101 | g_test_init (&argc, &argv, NULL); 102 | g_test_add_func ("/libskk/context/dictionary", 103 | dictionary); 104 | g_test_add_func ("/libskk/context/basic", basic); 105 | return g_test_run (); 106 | } 107 | -------------------------------------------------------------------------------- /tests/file-dict.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static void 4 | file_dict (void) 5 | { 6 | GError *error = NULL; 7 | SkkFileDict *dict = skk_file_dict_new (LIBSKK_FILE_DICT, "EUC-JP", &error); 8 | g_assert_no_error (error); 9 | 10 | gint len; 11 | SkkCandidate **candidates; 12 | gboolean read_only; 13 | 14 | g_assert (skk_dict_get_read_only (SKK_DICT (dict))); 15 | g_object_get (dict, "read-only", &read_only, NULL); 16 | g_assert (read_only); 17 | 18 | candidates = skk_dict_lookup (SKK_DICT (dict), 19 | "かんじ", 20 | FALSE, 21 | &len); 22 | g_assert_cmpint (len, ==, 2); 23 | while (--len >= 0) { 24 | g_object_unref (candidates[len]); 25 | } 26 | g_free (candidates); 27 | 28 | candidates = skk_dict_lookup (SKK_DICT (dict), 29 | "あu", 30 | TRUE, 31 | &len); 32 | g_assert_cmpint (len, ==, 4); 33 | while (--len >= 0) { 34 | g_object_unref (candidates[len]); 35 | } 36 | g_free (candidates); 37 | 38 | g_object_unref (dict); 39 | } 40 | 41 | int 42 | main (int argc, char **argv) 43 | { 44 | skk_init (); 45 | g_test_init (&argc, &argv, NULL); 46 | g_test_add_func ("/libskk/file-dict", file_dict); 47 | return g_test_run (); 48 | } 49 | -------------------------------------------------------------------------------- /tests/file-dict.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ueno/libskk/d5e9726fa5c439518bed2a74d1796d3b99b861ce/tests/file-dict.dat -------------------------------------------------------------------------------- /tests/rom-kana.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static void 4 | rom_kana (void) 5 | { 6 | SkkRomKanaConverter *converter = skk_rom_kana_converter_new (); 7 | const gchar *preedit, *output; 8 | 9 | skk_rom_kana_converter_append_text (converter, "m"); 10 | preedit = skk_rom_kana_converter_get_preedit (converter); 11 | g_assert_cmpstr (preedit, ==, "m"); 12 | output = skk_rom_kana_converter_get_output (converter); 13 | g_assert_cmpstr (output, ==, ""); 14 | 15 | skk_rom_kana_converter_append_text (converter, "u"); 16 | preedit = skk_rom_kana_converter_get_preedit (converter); 17 | g_assert_cmpstr (preedit, ==, ""); 18 | output = skk_rom_kana_converter_get_output (converter); 19 | g_assert_cmpstr (output, ==, "む"); 20 | 21 | skk_rom_kana_converter_reset (converter); 22 | skk_rom_kana_converter_set_kana_mode (converter, SKK_KANA_MODE_KATAKANA); 23 | skk_rom_kana_converter_append_text (converter, "min"); 24 | skk_rom_kana_converter_output_nn_if_any (converter); 25 | output = skk_rom_kana_converter_get_output (converter); 26 | g_assert_cmpstr (output, ==, "ミン"); 27 | 28 | skk_rom_kana_converter_reset (converter); 29 | skk_rom_kana_converter_set_kana_mode (converter, SKK_KANA_MODE_HIRAGANA); 30 | skk_rom_kana_converter_append_text (converter, "desu."); 31 | skk_rom_kana_converter_output_nn_if_any (converter); 32 | output = skk_rom_kana_converter_get_output (converter); 33 | g_assert_cmpstr (output, ==, "です。"); 34 | 35 | skk_rom_kana_converter_reset (converter); 36 | skk_rom_kana_converter_set_kana_mode (converter, SKK_KANA_MODE_HIRAGANA); 37 | skk_rom_kana_converter_append_text (converter, "ww"); 38 | preedit = skk_rom_kana_converter_get_preedit (converter); 39 | g_assert_cmpstr (preedit, ==, "w"); 40 | output = skk_rom_kana_converter_get_output (converter); 41 | g_assert_cmpstr (output, ==, "っ"); 42 | 43 | g_object_unref (converter); 44 | } 45 | 46 | int 47 | main (int argc, char **argv) { 48 | skk_init (); 49 | g_test_init (&argc, &argv, NULL); 50 | g_test_add_func ("/libskk/rom-kana", rom_kana); 51 | return g_test_run (); 52 | } 53 | -------------------------------------------------------------------------------- /tests/rule.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "common.h" 3 | 4 | static void 5 | list (void) { 6 | SkkRuleMetadata *rules; 7 | gint len; 8 | 9 | rules = skk_rule_list (&len); 10 | g_assert_cmpint (len, >, 0); 11 | while (--len >= 0) { 12 | skk_rule_metadata_destroy (&rules[len]); 13 | } 14 | g_free (rules); 15 | } 16 | 17 | static void 18 | azik (void) 19 | { 20 | SkkContext *context; 21 | GError *error; 22 | SkkRule *rule; 23 | SkkTransition transitions[] = { 24 | { SKK_INPUT_MODE_HIRAGANA, "x x a", "", "ぁ", SKK_INPUT_MODE_HIRAGANA }, 25 | { SKK_INPUT_MODE_HIRAGANA, "Y o :", "▼酔っ", "", SKK_INPUT_MODE_HIRAGANA }, 26 | { SKK_INPUT_MODE_HIRAGANA, "l", "", "", SKK_INPUT_MODE_LATIN }, 27 | { SKK_INPUT_MODE_HIRAGANA, "q", "", "ん", SKK_INPUT_MODE_HIRAGANA }, 28 | { SKK_INPUT_MODE_HIRAGANA, "Q", "▽ん", "", SKK_INPUT_MODE_HIRAGANA }, 29 | { 0, NULL } 30 | }; 31 | 32 | context = create_context (TRUE, TRUE); 33 | error = NULL; 34 | rule = skk_rule_new ("azik", &error); 35 | g_assert_no_error (error); 36 | skk_context_set_typing_rule (context, rule); 37 | g_object_unref (rule); 38 | check_transitions (context, transitions); 39 | destroy_context (context); 40 | } 41 | 42 | static void 43 | kzik (void) 44 | { 45 | SkkContext *context; 46 | GError *error; 47 | SkkRule *rule; 48 | SkkTransition transitions[] = { 49 | { SKK_INPUT_MODE_HIRAGANA, "b g d", "", "びぇん", SKK_INPUT_MODE_HIRAGANA }, 50 | { SKK_INPUT_MODE_HIRAGANA, "s q", "", "さい", SKK_INPUT_MODE_HIRAGANA }, 51 | { SKK_INPUT_MODE_HIRAGANA, "d l", "", "どん", SKK_INPUT_MODE_HIRAGANA }, 52 | { SKK_INPUT_MODE_HIRAGANA, "l", "", "", SKK_INPUT_MODE_LATIN }, 53 | { SKK_INPUT_MODE_HIRAGANA, "q", "", "ん", SKK_INPUT_MODE_HIRAGANA }, 54 | { SKK_INPUT_MODE_HIRAGANA, "Q", "▽ん", "", SKK_INPUT_MODE_HIRAGANA }, 55 | { SKK_INPUT_MODE_HIRAGANA, "l C-j", "", "", SKK_INPUT_MODE_HIRAGANA }, 56 | { SKK_INPUT_MODE_HIRAGANA, "L C-j", "", "", SKK_INPUT_MODE_HIRAGANA }, 57 | { 0, NULL } 58 | }; 59 | 60 | context = create_context (TRUE, TRUE); 61 | error = NULL; 62 | rule = skk_rule_new ("kzik", &error); 63 | g_assert_no_error (error); 64 | skk_context_set_typing_rule (context, rule); 65 | g_object_unref (rule); 66 | check_transitions (context, transitions); 67 | destroy_context (context); 68 | } 69 | 70 | static void 71 | nicola (void) 72 | { 73 | SkkContext *context; 74 | SkkRule *rule; 75 | SkkTransition transitions[] = { 76 | /* single key - timeout */ 77 | { SKK_INPUT_MODE_HIRAGANA, "a (usleep 200000)", "", "う", SKK_INPUT_MODE_HIRAGANA }, 78 | /* single key - release */ 79 | { SKK_INPUT_MODE_HIRAGANA, "a (release a)", "", "う", SKK_INPUT_MODE_HIRAGANA }, 80 | /* single key - overlap */ 81 | { SKK_INPUT_MODE_HIRAGANA, "a (usleep 50000) b", "", "う", SKK_INPUT_MODE_HIRAGANA }, 82 | { SKK_INPUT_MODE_HIRAGANA, "a (usleep 50000) b (usleep 200000)", "", "うへ", SKK_INPUT_MODE_HIRAGANA }, 83 | /* double key - shifted */ 84 | { SKK_INPUT_MODE_HIRAGANA, "a (usleep 10000) (lshift) (usleep 200000)", "", "を", SKK_INPUT_MODE_HIRAGANA }, 85 | /* double key - shifted reverse */ 86 | { SKK_INPUT_MODE_HIRAGANA, "(lshift) (usleep 10000) a (usleep 200000)", "", "を", SKK_INPUT_MODE_HIRAGANA }, 87 | /* double key - shifted expired */ 88 | { SKK_INPUT_MODE_HIRAGANA, "a (usleep 60000) (lshift)", "", "う", SKK_INPUT_MODE_HIRAGANA }, 89 | /* double key - skk-nicola */ 90 | { SKK_INPUT_MODE_HIRAGANA, "f (usleep 30000) j", "▽", "", SKK_INPUT_MODE_HIRAGANA }, 91 | /* double key - skk-nicola reverse */ 92 | { SKK_INPUT_MODE_HIRAGANA, "j (usleep 30000) f", "▽", "", SKK_INPUT_MODE_HIRAGANA }, 93 | /* double key - skk-nicola (shift only) */ 94 | { SKK_INPUT_MODE_HIRAGANA, "(lshift) (usleep 30000) (rshift)", "", "", SKK_INPUT_MODE_LATIN }, 95 | /* triple key t1 <= t2 */ 96 | { SKK_INPUT_MODE_HIRAGANA, "a (usleep 10000) (lshift) (usleep 20000) b", "", "を", SKK_INPUT_MODE_HIRAGANA }, 97 | { SKK_INPUT_MODE_HIRAGANA, "a (usleep 20000) (lshift) (usleep 10000) b", "", "うぃ", SKK_INPUT_MODE_HIRAGANA }, 98 | /* preedit */ 99 | { SKK_INPUT_MODE_HIRAGANA, "f (usleep 30000) j a (release a)", "▽う", "", SKK_INPUT_MODE_HIRAGANA }, 100 | /* preedit: okuri-ari */ 101 | { SKK_INPUT_MODE_HIRAGANA, "f (usleep 30000) j a (release a) f (usleep 30000) j", "▽う*", "", SKK_INPUT_MODE_HIRAGANA }, 102 | /* preedit: okuri-ari */ 103 | { SKK_INPUT_MODE_HIRAGANA, "f (usleep 30000) j a (release a) f (usleep 30000) j i (release i)", "▼受く", "", SKK_INPUT_MODE_HIRAGANA }, 104 | /* preedit: okuri-nasi */ 105 | { SKK_INPUT_MODE_HIRAGANA, "f (usleep 30000) j a (release a) c (release c)", "▽うす", "", SKK_INPUT_MODE_HIRAGANA }, 106 | /* preedit: okuri-nasi */ 107 | { SKK_INPUT_MODE_HIRAGANA, "f (usleep 30000) j a (release a) c (release c) SPC (usleep 200000)", "▼臼", "", SKK_INPUT_MODE_HIRAGANA }, 108 | /* hiragana -> katakana */ 109 | { SKK_INPUT_MODE_HIRAGANA, "d (usleep 30000) k a (release a)", "", "ウ", SKK_INPUT_MODE_KATAKANA }, 110 | /* hiragana -> latin */ 111 | { SKK_INPUT_MODE_HIRAGANA, "A (release A)", "", "", SKK_INPUT_MODE_LATIN }, 112 | /* hiragana -> wide latin */ 113 | { SKK_INPUT_MODE_HIRAGANA, "Z (release Z)", "", "", SKK_INPUT_MODE_WIDE_LATIN }, 114 | { 0, NULL } 115 | }; 116 | GError *error; 117 | 118 | context = create_context (TRUE, TRUE); 119 | error = NULL; 120 | rule = skk_rule_new ("nicola", &error); 121 | g_assert_no_error (error); 122 | skk_context_set_typing_rule (context, rule); 123 | g_object_unref (rule); 124 | check_transitions (context, transitions); 125 | destroy_context (context); 126 | } 127 | 128 | int 129 | main (int argc, char **argv) { 130 | skk_init (); 131 | g_test_init (&argc, &argv, NULL); 132 | g_test_add_func ("/libskk/list", list); 133 | g_test_add_func ("/libskk/azik", azik); 134 | g_test_add_func ("/libskk/kzik", kzik); 135 | g_test_add_func ("/libskk/nicola", nicola); 136 | return g_test_run (); 137 | } 138 | -------------------------------------------------------------------------------- /tests/rules/test-aborts/keymap/hiragana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/hiragana" 4 | ], 5 | "define": { 6 | "keymap": { 7 | "C-l": "abort-to-latin", 8 | "Q": "abort-to-latin-unhandled" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/rules/test-aborts/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "abort-to-latin* test rule", 3 | "description": "Test case for abort-to-latin and abort-to-latin-unhandled" 4 | } 5 | -------------------------------------------------------------------------------- /tests/rules/test-aborts/rom-kana/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["default/default"] 3 | } 4 | -------------------------------------------------------------------------------- /tests/rules/test-inherit-rule-for-dict-edit/keymap/hiragana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/hiragana" 4 | ], 5 | "define": { 6 | "keymap": { 7 | "C-a": "abort" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/rules/test-inherit-rule-for-dict-edit/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Typing rule inheritance test rule", 3 | "description": "Test case to ensure that typing rule is inherited for dict edit" 4 | } 5 | -------------------------------------------------------------------------------- /tests/rules/test-inherit-rule-for-dict-edit/rom-kana/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["default/default"], 3 | "define": { 4 | "rom-kana": { 5 | "pgo": ["", "ぽよ"] 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/rules/test-selection/keymap/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "define": { 3 | "keymap": { 4 | "C-g": "abort", 5 | "\n": "commit-unhandled", 6 | "C-m": "commit-unhandled", 7 | "C-y": "register", 8 | " ": "next-candidate", 9 | "/": "abbrev" 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/rules/test-selection/keymap/hankaku-katakana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default" 4 | ], 5 | "define": { 6 | "keymap": { 7 | "Q": "start-preedit" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/rules/test-selection/keymap/hiragana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default" 4 | ], 5 | "define": { 6 | "keymap": { 7 | "Q": "start-preedit", 8 | "C-j": "commit" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/rules/test-selection/keymap/katakana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default" 4 | ], 5 | "define": { 6 | "keymap": { 7 | "Q": "start-preedit" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/rules/test-selection/keymap/latin.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /tests/rules/test-selection/keymap/wide-latin.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /tests/rules/test-selection/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "request_selection_text signal test rule", 3 | "description": "Test case for selection signal." 4 | } 5 | -------------------------------------------------------------------------------- /tests/rules/test-selection/rom-kana/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["default/default"] 3 | } 4 | -------------------------------------------------------------------------------- /tests/rules/test-sticky/keymap/hiragana.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "default/hiragana" 4 | ], 5 | "define": { 6 | "keymap": { 7 | "@": "start-preedit-no-delete" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/rules/test-sticky/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Sticky-shift test rule", 3 | "description": "Test case for start-preedit-no-delete" 4 | } 5 | -------------------------------------------------------------------------------- /tests/rules/test-sticky/rom-kana/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["default/default"] 3 | } 4 | -------------------------------------------------------------------------------- /tests/skkserv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct _SkkServTransaction { 6 | gchar *request; 7 | gchar *response; 8 | }; 9 | typedef struct _SkkServTransaction SkkServTransaction; 10 | 11 | struct _SkkServData { 12 | GSocket *server; 13 | GThread *thread; 14 | SkkServTransaction *transactions; 15 | gsize n_transactions; 16 | }; 17 | typedef struct _SkkServData SkkServData; 18 | 19 | static gpointer 20 | skkserv_thread (gpointer user_data) 21 | { 22 | SkkServData *data = user_data; 23 | GSocket *socket; 24 | GError *error = NULL; 25 | gssize nread; 26 | gchar buf[4096]; /* large enough */ 27 | GSocketConnection *connection; 28 | GOutputStream *output; 29 | 30 | socket = g_socket_accept (data->server, NULL, &error); 31 | g_assert_no_error (error); 32 | connection = g_socket_connection_factory_create_connection (socket); 33 | output = g_io_stream_get_output_stream (G_IO_STREAM (connection)); 34 | 35 | while (TRUE) 36 | { 37 | gint i; 38 | 39 | nread = g_socket_receive (socket, buf, sizeof (buf), NULL, &error); 40 | g_assert_no_error (error); 41 | g_assert_cmpint (nread, >=, 0); 42 | 43 | if (nread == 0) 44 | break; 45 | 46 | for (i = 0; i < data->n_transactions; i++) 47 | { 48 | gsize bytes_written; 49 | SkkServTransaction *transaction = &data->transactions[i]; 50 | if (strncmp (buf, transaction->request, nread) == 0) 51 | { 52 | error = NULL; 53 | g_output_stream_write_all (output, 54 | transaction->response, 55 | strlen (transaction->response), 56 | &bytes_written, 57 | NULL, 58 | &error); 59 | g_assert_no_error (error); 60 | g_output_stream_flush (output, NULL, &error); 61 | g_assert_no_error (error); 62 | break; 63 | } 64 | } 65 | } 66 | 67 | g_object_unref (connection); 68 | g_socket_close (socket, &error); 69 | g_assert_no_error (error); 70 | g_object_unref (socket); 71 | return NULL; 72 | } 73 | 74 | static SkkServData * 75 | create_server () 76 | { 77 | SkkServData *data; 78 | GSocket *server; 79 | GError *error = NULL; 80 | GSocketAddress *addr; 81 | GInetAddress *iaddr; 82 | 83 | data = g_slice_new (SkkServData); 84 | data->server = server = g_socket_new (G_SOCKET_FAMILY_IPV4, 85 | G_SOCKET_TYPE_STREAM, 86 | G_SOCKET_PROTOCOL_DEFAULT, 87 | &error); 88 | g_assert_no_error (error); 89 | 90 | g_socket_set_blocking (server, TRUE); 91 | 92 | iaddr = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4); 93 | addr = g_inet_socket_address_new (iaddr, 0); 94 | g_object_unref (iaddr); 95 | 96 | g_socket_bind (server, addr, TRUE, &error); 97 | g_assert_no_error (error); 98 | g_object_unref (addr); 99 | 100 | g_socket_listen (server, &error); 101 | g_assert_no_error (error); 102 | 103 | data->thread = g_thread_create (skkserv_thread, data, TRUE, &error); 104 | g_assert_no_error (error); 105 | 106 | return data; 107 | } 108 | 109 | static void 110 | skkserv (void) 111 | { 112 | GError *error; 113 | SkkServData *data; 114 | GSocketAddress *addr; 115 | gchar *host; 116 | guint16 port; 117 | GInetAddress *iaddr; 118 | SkkSkkServ *dict; 119 | gint len; 120 | SkkCandidate **candidates; 121 | gboolean read_only; 122 | gchar **completion; 123 | SkkServTransaction transactions[] = { 124 | { "2", "0.0 " }, 125 | { "1あい ", "1/愛/哀/相/挨/\n" }, 126 | { "1あぱ ", "4" }, 127 | { "4あ ", "1/あい/あいさつ/\n" }, 128 | { "4あぱ ", "4" }, 129 | }; 130 | 131 | data = create_server (); 132 | data->transactions = transactions; 133 | data->n_transactions = G_N_ELEMENTS (transactions); 134 | 135 | error = NULL; 136 | addr = g_socket_get_local_address (data->server, &error); 137 | g_assert_no_error (error); 138 | 139 | port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr)); 140 | iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (addr)); 141 | host = g_inet_address_to_string (iaddr); 142 | g_object_unref (addr); 143 | 144 | error = NULL; 145 | dict = skk_skk_serv_new (host, port, "UTF-8", &error); 146 | g_free (host); 147 | g_assert_no_error (error); 148 | 149 | g_assert (skk_dict_get_read_only (SKK_DICT (dict))); 150 | g_object_get (dict, "read-only", &read_only, NULL); 151 | g_assert (read_only); 152 | 153 | candidates = skk_dict_lookup (SKK_DICT (dict), "あい", FALSE, &len); 154 | g_assert_cmpint (len, ==, 4); 155 | while (--len >= 0) { 156 | g_object_unref (candidates[len]); 157 | } 158 | g_free (candidates); 159 | 160 | completion = skk_dict_complete (SKK_DICT (dict), "あ", &len); 161 | g_assert_cmpint (len, ==, 2); 162 | g_strfreev (completion); 163 | 164 | g_object_unref (dict); 165 | g_thread_join (data->thread); 166 | g_object_unref (data->server); 167 | g_slice_free (SkkServData, data); 168 | } 169 | 170 | int 171 | main (int argc, char **argv) 172 | { 173 | skk_init (); 174 | g_test_init (&argc, &argv, NULL); 175 | g_test_add_func ("/libskk/skkserv", skkserv); 176 | return g_test_run (); 177 | } 178 | -------------------------------------------------------------------------------- /tests/user-dict.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "common.h" 3 | 4 | static void 5 | user_dict (void) 6 | { 7 | GError *error = NULL; 8 | SkkUserDict *dict = skk_user_dict_new ("user-dict.dat", "EUC-JP", &error); 9 | g_assert_no_error (error); 10 | gboolean read_only; 11 | 12 | g_assert (skk_dict_get_read_only (SKK_DICT (dict)) == FALSE); 13 | g_object_get (dict, "read-only", &read_only, NULL); 14 | g_assert (read_only == FALSE); 15 | g_object_unref (dict); 16 | } 17 | 18 | static void 19 | save (void) 20 | { 21 | SkkContext *context; 22 | gboolean retval; 23 | GError *error; 24 | 25 | context = create_context (TRUE, TRUE); 26 | 27 | retval = skk_context_process_key_events (context, "A i SPC RET"); 28 | g_assert (retval); 29 | 30 | error = NULL; 31 | skk_context_save_dictionaries (context, &error); 32 | g_assert_no_error (error); 33 | 34 | g_object_unref (context); 35 | } 36 | 37 | static void 38 | completion (void) 39 | { 40 | SkkContext *context0, *context; 41 | gboolean retval; 42 | const gchar *preedit; 43 | GError *error; 44 | 45 | /* prepare user dict with four candidates */ 46 | context0 = create_context (TRUE, TRUE); 47 | 48 | retval = skk_context_process_key_events (context0, "A i SPC RET"); 49 | g_assert (retval); 50 | 51 | retval = skk_context_process_key_events (context0, "A i s a t s u SPC RET"); 52 | g_assert (retval); 53 | 54 | retval = skk_context_process_key_events (context0, "A I SPC RET"); 55 | g_assert (retval); 56 | 57 | retval = skk_context_process_key_events (context0, "A U SPC RET"); 58 | g_assert (retval); 59 | 60 | error = NULL; 61 | skk_context_save_dictionaries (context0, &error); 62 | g_assert_no_error (error); 63 | 64 | /* perform completion */ 65 | context = create_context (TRUE, FALSE); 66 | 67 | retval = skk_context_process_key_events (context, "A TAB"); 68 | g_assert (retval); 69 | 70 | preedit = skk_context_get_preedit (context); 71 | g_assert_cmpstr (preedit, ==, "▽あい"); 72 | 73 | retval = skk_context_process_key_events (context, "TAB"); 74 | g_assert (retval); 75 | 76 | preedit = skk_context_get_preedit (context); 77 | g_assert_cmpstr (preedit, ==, "▽あいさつ"); 78 | 79 | destroy_context (context); 80 | destroy_context (context0); 81 | } 82 | 83 | int 84 | main (int argc, char **argv) { 85 | skk_init (); 86 | g_test_init (&argc, &argv, NULL); 87 | g_test_add_func ("/libskk/user-dict", user_dict); 88 | g_test_add_func ("/libskk/save", save); 89 | g_test_add_func ("/libskk/completion", completion); 90 | return g_test_run (); 91 | } 92 | -------------------------------------------------------------------------------- /tools/Makefile.am: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011-2018 Daiki Ueno 2 | # Copyright (C) 2011-2018 Red Hat, Inc. 3 | 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | 17 | # force include config.h before gi18n.h. 18 | AM_CPPFLAGS = -include $(CONFIG_HEADER) 19 | 20 | bin_PROGRAMS = skk 21 | 22 | skk_VALAFLAGS = \ 23 | --vapidir=$(top_srcdir)/libskk \ 24 | --vapidir=$(top_srcdir)/tools \ 25 | --pkg config \ 26 | --pkg skk-1.0 \ 27 | $(VALAFLAGS) 28 | 29 | skk_CFLAGS = \ 30 | -I$(top_srcdir) \ 31 | $(LIBSKK_CFLAGS) \ 32 | -DDATADIR=\"$(datadir)\" \ 33 | -DPKGDATADIR=\"$(pkgdatadir)\" \ 34 | -DLOCALEDIR=\"$(datadir)/locale\" \ 35 | $(NULL) 36 | skk_LDADD = $(top_builddir)/libskk/libskk.la $(LIBSKK_LIBS) 37 | skk_SOURCES = skk.vala 38 | 39 | dist_man_MANS = skk.1 40 | 41 | if ENABLE_FEP 42 | libexec_PROGRAMS = skkfep-client 43 | skkfep_client_VALAFLAGS = \ 44 | --vapidir=$(top_srcdir)/libskk \ 45 | --vapidir=$(top_srcdir)/tools \ 46 | --pkg config \ 47 | --pkg skk-1.0 \ 48 | --pkg libfep-glib \ 49 | $(VALAFLAGS) 50 | skkfep_client_CFLAGS = \ 51 | -I$(top_srcdir) \ 52 | $(LIBSKK_CFLAGS) \ 53 | $(LIBFEP_CFLAGS) \ 54 | -DDATADIR=\"$(datadir)\" \ 55 | -DPKGDATADIR=\"$(pkgdatadir)\" \ 56 | -DLOCALEDIR=\"$(datadir)/locale\" \ 57 | $(NULL) 58 | skkfep_client_LDADD = \ 59 | $(top_builddir)/libskk/libskk.la \ 60 | $(LIBSKK_LIBS) \ 61 | $(LIBFEP_LIBS) \ 62 | $(NULL) 63 | skkfep_client_SOURCES = fep.vala 64 | dist_man_MANS += skkfep.1 65 | 66 | EXTRA_DIST = skkfep.in 67 | DISTCLEANFILES = skkfep 68 | 69 | bin_SCRIPTS = skkfep 70 | 71 | skkfep: skkfep.in 72 | $(AM_V_GEN) sed -e "s!@FEP\@!"$(FEP)"!" \ 73 | -e "s!@CLIENT\@!"$(libexecdir)/skkfep-client"!" \ 74 | $< > $@.tmp && \ 75 | mv $@.tmp $@ 76 | endif 77 | 78 | GITIGNOREFILES = \ 79 | $(skk_SOURCES:.vala=.c) \ 80 | skk_vala.stamp \ 81 | $(skkfep_client_SOURCES:.vala=.c) \ 82 | skkfep_client_vala.stamp \ 83 | $(NULL) 84 | 85 | -include $(top_srcdir)/git.mk 86 | -------------------------------------------------------------------------------- /tools/skk.1: -------------------------------------------------------------------------------- 1 | .\" Hey, EMACS: -*- nroff -*- 2 | .TH LIBSKK 1 "5 Jan 2012" 3 | .SH NAME 4 | skk \- program that emulates Japanese SKK input method 5 | .SH SYNOPSIS 6 | .B skk 7 | .RI [ options ] 8 | .br 9 | .SH DESCRIPTION 10 | \fBskk\fP is a tool that reads key sequences from the standard input 11 | and converts them to Japanese text according to a Japanese input 12 | method called SKK (Simple Kana to Kanji conversion program). 13 | .PP 14 | More information about the SKK input method itself can be found at: 15 | \m[blue]\fB\%http://openlab.jp/skk/\fR\m[]\& 16 | .SH OPTIONS 17 | The \fBskk\fP command follows the usual GNU command line syntax, with 18 | long options starting with two dashes (`-'). A summary of options is 19 | included below. 20 | .TP 21 | .B \-h, \-\-help 22 | Show summary of options. 23 | .TP 24 | .B \-f, \-\-file-dict=\fIFILE\fR 25 | Specify path to a file dictionary. 26 | .TP 27 | .B \-u, \-\-user-dict=\fIFILE\fR 28 | Specify path to a user dictionary. 29 | .TP 30 | .B \-s, \-\-skkserv=\fIHOST\fR:\fIPORT\fR 31 | Specify host and port running skkserv. 32 | .TP 33 | .B \-r, \-\-rule=\fIRULE\fR 34 | Specify typing rule. 35 | .TP 36 | .B \-l, \-\-list-rules 37 | List typing rules. 38 | .SH EXAMPLE 39 | .TP 40 | echo "A i SPC" | skk 41 | Converts a capital letter "A" followed by lowercase letter "i" and a space. 42 | .TP 43 | echo "K a p a SPC K a SPC" | skk 44 | Converts a capital letter "K" followed by lowercase letters "a", "p", "a", and 45 | a space. Then converts a capital letter "K" followed by "a" and a space. 46 | .TP 47 | echo "r k" | skk \-r tutcode 48 | Converts two lowercase letters "r" and "k" with TUT-Code typing rule. 49 | .TP 50 | echo "a (usleep 50000) b (usleep 200000)" | skk \-r nicola 51 | Converts two lowercase letters "a" and "b" typed with a 50000 micro 52 | seconds interval, and wait 200000 micro seconds, with NICOLA typing 53 | rule. 54 | .SH AUTHOR 55 | libskk was written by Daiki Ueno . 56 | -------------------------------------------------------------------------------- /tools/skk.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011-2018 Daiki Ueno 3 | * Copyright (C) 2011-2018 Red Hat, Inc. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | using Gee; 19 | 20 | static string opt_file_dict; 21 | static string opt_user_dict; 22 | static string opt_skkserv; 23 | static string opt_typing_rule; 24 | static bool opt_list_typing_rules; 25 | 26 | static const OptionEntry[] options = { 27 | { "file-dict", 'f', 0, OptionArg.STRING, ref opt_file_dict, 28 | N_("Path to a file dictionary"), null }, 29 | { "user-dict", 'u', 0, OptionArg.STRING, ref opt_user_dict, 30 | N_("Path to a user dictionary"), null }, 31 | { "skkserv", 's', 0, OptionArg.STRING, ref opt_skkserv, 32 | N_("Host and port running skkserv (HOST:PORT)"), null }, 33 | { "rule", 'r', 0, OptionArg.STRING, ref opt_typing_rule, 34 | N_("Typing rule (default: \"default\")"), null }, 35 | { "list-rules", 'l', 0, OptionArg.NONE, ref opt_list_typing_rules, 36 | N_("List typing rules"), null }, 37 | { null } 38 | }; 39 | 40 | static int main (string[] args) { 41 | Intl.setlocale (LocaleCategory.ALL, ""); 42 | Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.LOCALEDIR); 43 | Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8"); 44 | Intl.textdomain (Config.GETTEXT_PACKAGE); 45 | 46 | var option_context = new OptionContext ( 47 | _("- emulate SKK input method on the command line")); 48 | option_context.add_main_entries (options, "libskk"); 49 | try { 50 | option_context.parse (ref args); 51 | } catch (OptionError e) { 52 | stderr.printf ("%s\n", e.message); 53 | return 1; 54 | } 55 | 56 | Skk.init (); 57 | 58 | if (opt_list_typing_rules) { 59 | var rules = Skk.Rule.list (); 60 | foreach (var rule in rules) { 61 | stdout.printf ("%s - %s: %s\n", 62 | rule.name, 63 | rule.label, 64 | rule.description); 65 | } 66 | return 0; 67 | } 68 | 69 | ArrayList dictionaries = new ArrayList (); 70 | if (opt_user_dict != null) { 71 | try { 72 | dictionaries.add (new Skk.UserDict (opt_user_dict)); 73 | } catch (GLib.Error e) { 74 | stderr.printf ("can't open user dict %s: %s", 75 | opt_user_dict, e.message); 76 | return 1; 77 | } 78 | } 79 | 80 | if (opt_file_dict == null) { 81 | opt_file_dict = Path.build_filename (Config.DATADIR, 82 | "skk", "SKK-JISYO.L"); 83 | } 84 | 85 | if (opt_file_dict.has_suffix (".cdb")) { 86 | try { 87 | dictionaries.add (new Skk.CdbDict (opt_file_dict)); 88 | } catch (GLib.Error e) { 89 | stderr.printf ("can't open CDB dict %s: %s", 90 | opt_file_dict, e.message); 91 | return 1; 92 | } 93 | } else { 94 | try { 95 | dictionaries.add (new Skk.FileDict (opt_file_dict)); 96 | } catch (GLib.Error e) { 97 | stderr.printf ("can't open file dict %s: %s", 98 | opt_file_dict, e.message); 99 | return 1; 100 | } 101 | } 102 | 103 | if (opt_skkserv != null) { 104 | var index = opt_skkserv.last_index_of (":"); 105 | string host; 106 | uint16 port; 107 | if (index < 0) { 108 | host = opt_skkserv; 109 | port = 1178; 110 | } else { 111 | host = opt_skkserv[0:index]; 112 | port = (uint16) int.parse ( 113 | opt_skkserv[index + 1:opt_skkserv.length]); 114 | } 115 | try { 116 | dictionaries.add (new Skk.SkkServ (host, port)); 117 | } catch (GLib.Error e) { 118 | stderr.printf ("can't connect to skkserv at %s:%d: %s", 119 | host, port, e.message); 120 | return 1; 121 | } 122 | } 123 | 124 | var context = new Skk.Context (dictionaries.to_array ()); 125 | 126 | if (opt_typing_rule != null) { 127 | try { 128 | context.typing_rule = new Skk.Rule (opt_typing_rule); 129 | } catch (Skk.RuleParseError e) { 130 | stderr.printf ("can't load rule \"%s\": %s\n", 131 | opt_typing_rule, 132 | e.message); 133 | return 1; 134 | } 135 | } 136 | 137 | var repl = new Repl (context); 138 | if (!repl.run ()) 139 | return 1; 140 | return 0; 141 | } 142 | 143 | class Repl : Object { 144 | Skk.Context context; 145 | 146 | public bool run () { 147 | string? line; 148 | while ((line = stdin.read_line ()) != null) { 149 | context.process_key_events (line); 150 | var output = context.poll_output (); 151 | var preedit = context.preedit; 152 | stdout.printf ( 153 | "{ \"input\": \"%s\", " + 154 | "\"output\": \"%s\", " + 155 | "\"preedit\": \"%s\" }\n", 156 | line.replace ("\"", "\\\""), 157 | output.replace ("\"", "\\\""), 158 | preedit.replace ("\"", "\\\"")); 159 | context.reset (); 160 | context.clear_output (); 161 | } 162 | return true; 163 | } 164 | 165 | public Repl (Skk.Context context) { 166 | this.context = context; 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /tools/skkfep.1: -------------------------------------------------------------------------------- 1 | .\" Hey, EMACS: -*- nroff -*- 2 | .TH LIBSKK 1 "5 Jan 2012" 3 | .SH NAME 4 | skkfep \- Japanese SKK input method on text terminal 5 | .SH SYNOPSIS 6 | .B skkfep 7 | .br 8 | .SH DESCRIPTION 9 | \fBskkfep\fP is a tool that allows to use Japanese input method called 10 | SKK (Simple Kana to Kanji conversion program) on ANSI compliant text 11 | terminals. 12 | .PP 13 | More information about the SKK input method itself can be found at: 14 | \m[blue]\fB\%http://openlab.jp/skk/\fR\m[]\& 15 | .SH AUTHOR 16 | libskk was written by Daiki Ueno . 17 | -------------------------------------------------------------------------------- /tools/skkfep.in: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright (C) 2011-2018 Daiki Ueno 3 | # Copyright (C) 2011-2018 Red Hat, Inc. 4 | 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | : ${FEP:=@FEP@} 19 | : ${CLIENT:=@CLIENT@} 20 | 21 | # XXX: handle --help here because the help output from the client will 22 | # be erased by the terminal reset. 23 | case "$1" in 24 | --help|-h) 25 | exec "$CLIENT" --help 26 | ;; 27 | esac 28 | 29 | exec "$FEP" -- "$CLIENT" "$@" 30 | --------------------------------------------------------------------------------