├── .dir-locals.el ├── .gitignore ├── COPYING ├── Makefile.am ├── NEWS.md ├── README.en.md ├── README.md ├── autogen.sh ├── configure.ac ├── lisp ├── Makefile.am ├── tr-ime-debug.el ├── tr-ime-documentfeed.el ├── tr-ime-download.el ├── tr-ime-font.el ├── tr-ime-hook.el ├── tr-ime-isearch.el ├── tr-ime-openstatus.el ├── tr-ime-prefix-key.el ├── tr-ime-reconversion.el ├── tr-ime-recv-notify.el ├── tr-ime-subclassify.el ├── tr-ime-sync.el ├── tr-ime-thread-message.el ├── tr-ime-workaround-inconsistent.el ├── tr-ime-workaround-isearch.el ├── tr-ime-workaround-prefix-key.el └── tr-ime.el ├── m4 ├── .gitignore └── ax_cxx_compile_stdcxx.m4 └── src ├── Makefile.am ├── debug-message.cc ├── debug-message.hh ├── emacs-27.1 └── emacs-module.h ├── get_msg_hook.cc ├── get_msg_hook.hh ├── get_msg_proc.cc ├── get_msg_proc.hh ├── lisp-in-cc.cc ├── lisp-in-cc.hh ├── message.cc ├── message.hh ├── queue.cc ├── queue.hh ├── subclass_proc.cc ├── subclass_proc.hh ├── tr-ime-mod-resource.rc ├── tr-ime-mod.c ├── tr-ime-modadv-resource.rc └── tr-ime-modadv.cc /.dir-locals.el: -------------------------------------------------------------------------------- 1 | ;;; Directory Local Variables 2 | ;;; See Info node `(emacs) Directory Variables' for more information. 3 | 4 | ((c-mode 5 | (c-file-style . "gnu") 6 | (indent-tabs-mode . nil)) 7 | (c++-mode 8 | (c-file-style . "gnu") 9 | (indent-tabs-mode . nil)) 10 | (emacs-lisp-mode 11 | (indent-tabs-mode . nil)) 12 | (autoconf-mode 13 | (indent-tabs-mode . nil)) 14 | (shell-script-mode 15 | (indent-tabs-mode . nil)) 16 | (markdown-mode 17 | (indent-tabs-mode . nil))) 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .*~ 2 | *~ 3 | autom4te.cache/ 4 | aclocal.m4 5 | ar-lib 6 | build 7 | config.h.in 8 | compile 9 | config.guess 10 | config.sub 11 | configure 12 | depcomp 13 | install-sh 14 | ltmain.sh 15 | Makefile.in 16 | missing 17 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = lisp src 2 | dist_doc_DATA = README.md README.en.md COPYING NEWS.md 3 | EXTRA_DIST = autogen.sh 4 | 5 | ACLOCAL_AMFLAGS = -I m4 6 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | * Release 0.5.0 (2022-06-04): 2 | * Add dispatch thread WM_TIMER messages 3 | * WM_TIMER スレッドメッセージ(hwnd が NULL のメッセージ) 4 | をディスパッチして WM_NULL にすり替えて握りつぶす機構を追加しました 5 | * Emacs 27, 28 のメッセージポンプ(メッセージループ)は 6 | スレッドメッセージをディスパッチしないため IME の動作が 7 | おかしくなることがあります 8 | * tr-ime 0.4.x までは、メッセージフックで 9 | すべてのスレッドメッセージをディスパッチする機構を用意して 10 | おかしくならないようにしていました 11 | * しかし、将来の Emacs でメッセージポンプが修正され、 12 | スレッドメッセージをディスパッチするようになったら 13 | 二重にディスパッチすることになり 14 | Emacs の動作がおかしくなる危険性がありました 15 | * そこで、スレッドメッセージでも WM_TIMER のみをディスパッチし、 16 | さらにそれを WM_NULL にすり替えて握りつぶすことで将来の Emacs 17 | での二重ディスパッチを防ぐ方法を新設しました 18 | * デフォルト設定も新方式が有効になるよう変更しています 19 | * Advanced 用モジュール DLL 機能の追加に伴い ABI バージョンを 1 から 20 | 2 へ変更し、ファイル名が変わっています 21 | * 新しいモジュール DLL が必要になります 22 | * Standard 用モジュール DLL は従来のものがそのまま使えますが、 23 | バイナリリリースは再ビルドしたものを入れてあります 24 | 25 | * Release 0.4.1 (2020-11-28): 26 | * Included into MELPA 27 | * MELPA に掲載されました 28 | * MELPA 掲載に伴い、インストール方法や、 29 | 関連する関数名、変数名、設定方法などを整理して変更しました 30 | * 必要なモジュール DLL が load-path 上で見つからない場合、 31 | 自動ダウンロードする機能を追加しました 32 | * コンソールで byte-compile 時にロードされてエラーになる 33 | ことに対する対策を追加しました 34 | * unload-feature されるとき正常にアンロードできるよう対策を追加しました 35 | * 未確定文字列フォント設定で、 36 | コマンド実行後に反映する場合の動作を修正しました 37 | * Emacs 28 で standard で使用する際の IME 状態変更関数について、 38 | スレッドの切り替えを考慮する処理を追加しました 39 | * Emacs 28 で standard で使用する際の IME 状態変更関数の 40 | 状態確認回数上限のデフォルトを 3 から 10 に増やしました 41 | * モジュール DLL は Release 0.4.0 と同じで変更ありません 42 | * バイナリリリースの DLL ファイルは 0.4.0 と同じです 43 | * ソースからビルドすると 0.4.1 の DLL ができますが、 44 | 機能は 0.4.0 とまったく同じです 45 | 46 | * Release 0.4.0 (2020-10-31): 47 | * Changed package name, file names, function names, varible names, 48 | setting methods, etc. 49 | * パッケージ名、ファイル名、関数名、変数名、 50 | 設定方法などを整理して変更しました 51 | 52 | * Release 0.3.0 (2020-09-25): 53 | * Improve Module2 54 | * 再変換 (RECONVERSION) および 55 | 前後の確定済文字列を参照した変換 (DOCUMENTFEED)に対応しました 56 | * 今のところデフォルト無効にしていますので、 57 | 使用したい場合は設定してください 58 | * デバッグ出力レベルを変更できるようにしました 59 | * Module1, 2 双方で、emacsclient でのバッファが変更が検知できず、 60 | IME/IM 同期できなくなることがありましたので対応する設定を追加しました 61 | * Module1 で IME 状態食い違い検出ワークアラウンドを使っていると 62 | 気が付きにくいものですが、Module2 だと簡単に再現しました 63 | * Module2 のプレフィックスキー検出、Module1 のプレフィックスキー検出 64 | ワークアラウンド双方で IME 状態復帰を post-command-hook から 65 | pre-command-hook に変更しました 66 | * emacsclient でファイルを開いて編集してから、IME ON のまま 67 | C-x C-s C-x # のような操作を素早く実行すると、 68 | C-x C-s の保存動作完了前に次の C-x を押してしまうことがあり、 69 | そうすると保存動作の完了後の post-command-hook で 70 | IME ON に復帰していると # が IME に吸われて未確定文字に 71 | なってしまうことがありました 72 | 73 | * Release 0.2.0 (2020-09-20): 74 | * Improve Module2 75 | * Module2 で UI スレッドから Lisp への通知をできるようにし、 76 | これによりこれまで実現できなかった機能を実装しました 77 | * 通知機能により実現した Module2 の新機能は以下の通りです 78 | * すべての IME ON/OFF 方法に対応 79 | (IME 状態変更通知による IME/IM 状態同期) 80 | * その他に Module2 で実装した新機能は以下の通りです 81 | * 未確定文字列フォント設定でファミリとサイズ以外の属性にも対応 82 | * isearch-mode 中の未確定文字列表示がチラつくのを改善 83 | * IME 状態取得・設定方法を Microsoft のドキュメントに 84 | 記載されている方法で実施するよう変更 85 | 86 | * Release 0.1.0 (2020-09-17): 87 | * Add Module2 88 | * メッセージフックやサブクラス化といった多少複雑な機構で、 89 | より高度な機能を実装した実験的な Module2 を追加しました。 90 | これまでの最低限の単純で基本的な機能のみを実装したモジュールを 91 | Module1 と呼ぶことにします。 92 | * Module2 で実現できる機能は以下の通りです。 93 | * C-s など isearch-mode の検索中に未確定文字列を 94 | ミニバッファの 文字入力位置に表示できる 95 | * 未確定文字列のフォントが設定できる 96 | * IME ON/OFF に連動してタスクバーの 97 | IME 状態表示アイコンが切り替わる 98 | * IME ON の状態で C-x, C-c, C-h など、 99 | コマンドのキーシーケンスになる最初の文字 100 | (以下、プレフィックスキー) 101 | を押すと自動的に IME OFF になる 102 | 103 | * Release 0.0.0 (2020-09-04): 104 | * Initial release 105 | * フックやサブクラス化を使わないで実現できる機能は、 106 | ひと段落したのでリリースします。 107 | -------------------------------------------------------------------------------- /README.en.md: -------------------------------------------------------------------------------- 1 | [![MELPA](https://melpa.org/packages/tr-ime-badge.svg)](https://melpa.org/#/tr-ime) 2 | 3 | [ [Japanese](./README.md) / English ] 4 | 5 | # Emulator of GNU Emacs IME patch for Windows (tr-ime) 6 | 7 | Emulator of GNU Emacs IME patch for Windows (tr-ime) emulates the C 8 | implementation part of an IME patch for GNU Emacs that allows to input 9 | Japanese using the Windows IME (Input Method Editor). On Emacs 26.2 or 10 | later, Japanese input using the IME is now possible even without the IME 11 | patch. However, some of the features of the IME patch are not implemented 12 | in current Emacs, so it is possible to type Japanese on Emacs without the 13 | IME patch, but it is not convenient. 14 | 15 | w32-ime.el in the 16 | [w32-ime package](https://github.com/trueroad/w32-ime.el) 17 | manages the upper layer of the IME 18 | patch and provides the convenient features but it could not be used on 19 | emacs.exe without the IME patch applied. tr-ime emulates the lower 20 | layers of the IME patches and can interact with w32-ime.el. So, using 21 | tr-ime, w32-ime.el can be used on emacs.exe without the IME patch applied. 22 | 23 | By using tr-ime and w32-ime.el together, emacs.exe without the IME patch 24 | can use the same convenient features as the IME patched emacs.exe. They 25 | can display the on/off state of the IME in the mode line as UI/UX features. 26 | They also have hooks to call when the IME state is changed. With these 27 | hooks, you can change the color and shape of the cursor depending on the 28 | IME on/off status to be visually known to the IME state. 29 | 30 | To use standard features (stable but less functionality) of the tr-ime 31 | package, add the following code to your init.el or .emacs 32 | It loads the tr-ime-mod DLL module if you use Emacs 27. 33 | 34 | ```el 35 | (tr-ime-standard-install) 36 | (setq default-input-method "W32-IME") 37 | (w32-ime-initialize) 38 | ``` 39 | 40 | To use advanced features (experimental but more functionality) of the 41 | tr-ime package, add the following code to your init.el or .emacs 42 | It loads the tr-ime-modadv DLL module. 43 | 44 | ```el 45 | (tr-ime-advanced-install) 46 | (setq default-input-method "W32-IME") 47 | (w32-ime-initialize) 48 | ``` 49 | 50 | ## News 51 | 52 | [NEWS.md](./NEWS.md) 53 | 54 | ## License 55 | 56 | Copyright (C) 2020-2022 Masamichi Hosoda 57 | 58 | Emulator of GNU Emacs IME patch for Windows (tr-ime) 59 | is free software: you can redistribute it and/or modify 60 | it under the terms of the GNU General Public License as published by 61 | the Free Software Foundation, either version 3 of the License, or 62 | (at your option) any later version. 63 | 64 | Emulator of GNU Emacs IME patch for Windows (tr-ime) 65 | is distributed in the hope that it will be useful, 66 | but WITHOUT ANY WARRANTY; without even the implied warranty of 67 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 68 | GNU General Public License for more details. 69 | 70 | You should have received a copy of the GNU General Public License 71 | along with tr-ime. 72 | If not, see . 73 | 74 | [COPYING](./COPYING) 75 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | autoreconf -v -i 4 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ([2.71]) 5 | AC_INIT([Emulator of GNU Emacs IME patch for Windows], [0.5.0],, [tr-ime], 6 | [https://github.com/trueroad/tr-emacs-ime-module]) 7 | AC_CANONICAL_TARGET 8 | AM_INIT_AUTOMAKE([-Wall -Werror foreign]) 9 | 10 | AC_CONFIG_SRCDIR([src/tr-ime-mod.c]) 11 | AC_CONFIG_HEADERS([src/config.h]) 12 | AC_CONFIG_MACRO_DIRS([m4]) 13 | 14 | PACKAGE_FILEVERSION='0,5,0,0' 15 | PACKAGE_PRODUCTVERSION='0,5,0,0' 16 | PACKAGE_COPYRIGHT='Copyright (C) 2020-2022 Masamichi Hosoda.' 17 | PACKAGE_LICENSE='License: GPL3+' 18 | 19 | AC_DEFINE_UNQUOTED([PACKAGE_FILEVERSION], [$PACKAGE_FILEVERSION], 20 | [Define to the FILEVERSION of this package.]) 21 | AC_DEFINE_UNQUOTED([PACKAGE_PRODUCTVERSION], [$PACKAGE_PRODUCTVERSION], 22 | [Define to the PRODUCTVERSION of this package.]) 23 | AC_DEFINE_UNQUOTED([PACKAGE_COPYRIGHT], ["$PACKAGE_COPYRIGHT"], 24 | [Define to the copyright of this package.]) 25 | AC_DEFINE_UNQUOTED([PACKAGE_LICENSE], ["$PACKAGE_LICENSE"], 26 | [Define to the license of this package.]) 27 | 28 | MOD_ABI_VERSION='1' 29 | MODADV_ABI_VERSION='2' 30 | 31 | AC_DEFINE_UNQUOTED([MOD_ABI_VERSION], ["$MOD_ABI_VERSION"], 32 | [Define to the module ABI version of this package.]) 33 | AC_DEFINE_UNQUOTED([MODADV_ABI_VERSION], ["$MODADV_ABI_VERSION"], 34 | [Define to the advanced module ABI version of this package.]) 35 | AC_SUBST([MOD_ABI_VERSION]) 36 | AC_SUBST([MODADV_ABI_VERSION]) 37 | 38 | AC_DEFINE_UNQUOTED([HOST_PLATFORM], ["$host"], 39 | [Define to the host platform name.]) 40 | 41 | # Checks for programs. 42 | AC_PROG_CC 43 | AS_IF([test "x$ac_cv_prog_cc_c99" = xno], 44 | AC_MSG_ERROR([C99 compiler is not found.])) 45 | 46 | AC_PROG_CXX 47 | AX_CXX_COMPILE_STDCXX([14], [ext], [mandatory]) 48 | 49 | AM_PROG_AR 50 | 51 | AS_IF([test "x$target_alias" = x], 52 | [target_alias=$target]) 53 | AC_CHECK_TARGET_TOOL([WINDRES], [windres], [no]) 54 | AS_IF([test "x$WINDRES" = xno], 55 | AC_MSG_ERROR([windres is not found.])) 56 | 57 | AM_PATH_LISPDIR 58 | AC_ARG_WITH([pkglispdir], 59 | AS_HELP_STRING([--with-pkglispdir=DIR], 60 | [where to install emacs lisp files (default lispdir/PACKAGE)]), 61 | [pkglispdir=${withval}], [pkglispdir='${lispdir}/${PACKAGE}']) 62 | AC_SUBST([pkglispdir]) 63 | AC_MSG_NOTICE([where to install emacs lisp files is ${pkglispdir}]) 64 | 65 | AC_ARG_WITH([pkgmoduledir], 66 | AS_HELP_STRING([--with-pkgmoduledir=DIR], 67 | [where to install emacs dynamic modules (default lispdir/PACKAGE)]), 68 | [pkgmoduleexecdir=${withval}], [pkgmoduleexecdir='${lispdir}/${PACKAGE}']) 69 | AC_SUBST([pkgmoduleexecdir]) 70 | AC_MSG_NOTICE([where to install emacs dynamic modules is ${pkgmoduleexecdir}]) 71 | 72 | # Checks for libraries. 73 | LT_INIT([disable-static shared win32-dll]) 74 | LT_LANG([Windows Resource]) 75 | SHREXT=${shrext_cmds} 76 | AC_SUBST([SHREXT]) 77 | 78 | AC_SUBST([objdir]) 79 | 80 | # Checks for header files. 81 | AC_ARG_WITH([emacs-module-hdir], 82 | AS_HELP_STRING([--with-emacs-module-hdir=DIR], 83 | [directory of emacs-module.h (default: ${srcdir}/src/emacs-27.1)]), 84 | [CPPFLAGS="${CPPFLAGS} -I ${withval}"], 85 | [CPPFLAGS="${CPPFLAGS} -I ${PWD}/${srcdir}/src/emacs-27.1"]) 86 | AC_CHECK_HEADERS([emacs-module.h],, 87 | AC_MSG_ERROR([emacs-module.h is not found.])) 88 | 89 | AC_CHECK_HEADERS([windows.h],, 90 | AC_MSG_ERROR([windows.h is not found.])) 91 | 92 | AC_CHECK_HEADERS([imm.h],, 93 | AC_MSG_ERROR([imm.h is not found.]), 94 | [#include ]) 95 | 96 | # Checks for typedefs, structures, and compiler characteristics. 97 | AC_CHECK_TYPES([ptrdiff_t]) 98 | 99 | AC_LANG_PUSH([C++]) 100 | AC_MSG_CHECKING([whether the C++ compiler has __PRETTY_FUNCTION__]) 101 | AC_COMPILE_IFELSE( 102 | [AC_LANG_PROGRAM([[]],[[ const char* foo = __PRETTY_FUNCTION__; ]])], 103 | [AC_MSG_RESULT([yes]) 104 | AC_DEFINE([HAVE_CXX_PRETTY_FUNCTION], [1], 105 | [Define if C++ compiler has __PRETTY_FUNCTION__])], 106 | [AC_MSG_RESULT([no])]) 107 | AC_LANG_POP([C++]) 108 | 109 | # Checks for library functions. 110 | 111 | AC_CONFIG_FILES([Makefile 112 | lisp/Makefile 113 | src/Makefile]) 114 | AC_OUTPUT 115 | -------------------------------------------------------------------------------- /lisp/Makefile.am: -------------------------------------------------------------------------------- 1 | # 2 | # Targets 3 | # 4 | 5 | pkglisp_LISP = tr-ime.el \ 6 | tr-ime-openstatus.el \ 7 | tr-ime-hook.el \ 8 | tr-ime-workaround-prefix-key.el \ 9 | tr-ime-workaround-inconsistent.el \ 10 | tr-ime-subclassify.el \ 11 | tr-ime-thread-message.el \ 12 | tr-ime-recv-notify.el \ 13 | tr-ime-font.el \ 14 | tr-ime-isearch.el \ 15 | tr-ime-workaround-isearch.el \ 16 | tr-ime-prefix-key.el \ 17 | tr-ime-sync.el \ 18 | tr-ime-reconversion.el \ 19 | tr-ime-documentfeed.el \ 20 | tr-ime-debug.el \ 21 | tr-ime-download.el 22 | EXTRA_DIST = tr-ime.el \ 23 | tr-ime-openstatus.el \ 24 | tr-ime-hook.el \ 25 | tr-ime-workaround-prefix-key.el \ 26 | tr-ime-workaround-inconsistent.el \ 27 | tr-ime-subclassify.el \ 28 | tr-ime-thread-message.el \ 29 | tr-ime-recv-notify.el \ 30 | tr-ime-font.el \ 31 | tr-ime-isearch.el \ 32 | tr-ime-workaround-isearch.el \ 33 | tr-ime-prefix-key.el \ 34 | tr-ime-sync.el \ 35 | tr-ime-reconversion.el \ 36 | tr-ime-documentfeed.el \ 37 | tr-ime-debug.el \ 38 | tr-ime-download.el 39 | -------------------------------------------------------------------------------- /lisp/tr-ime-debug.el: -------------------------------------------------------------------------------- 1 | ;;; tr-ime-debug.el --- Debug settings -*- lexical-binding: t -*- 2 | 3 | ;; Copyright (C) 2020, 2022 Masamichi Hosoda 4 | 5 | ;; Author: Masamichi Hosoda 6 | ;; URL: https://github.com/trueroad/tr-emacs-ime-module 7 | 8 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 9 | ;; is free software: you can redistribute it and/or modify 10 | ;; it under the terms of the GNU General Public License as published by 11 | ;; the Free Software Foundation, either version 3 of the License, or 12 | ;; (at your option) any later version. 13 | ;; 14 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 15 | ;; is distributed in the hope that it will be useful, 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | ;; GNU General Public License for more details. 19 | ;; 20 | ;; You should have received a copy of the GNU General Public License 21 | ;; along with tr-ime. 22 | ;; If not, see . 23 | 24 | ;;; Commentary: 25 | 26 | ;; This file is part of 27 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime). 28 | ;; See tr-ime.el 29 | 30 | ;;; Code: 31 | 32 | ;; 33 | ;; ユーザ設定用 34 | ;; 35 | 36 | (defgroup tr-ime-debug nil 37 | "デバッグ設定 (advanced)." 38 | :group 'tr-ime) 39 | 40 | ;; 41 | ;; デバッグ出力レベル 42 | ;; 43 | 44 | (declare-function tr-ime-modadv--set-verbose-level "tr-ime-modadv" 45 | (arg1)) 46 | 47 | (defun tr-ime-debug--verbose-level-set (symb level) 48 | "デバッグ出力レベルを設定する. 49 | 50 | SYMB には tr-ime-debug-verbose-level をしている。 51 | LEVEL はデバッグ出力レベルを 0 (none) から 6 (trace) の整数で指定するか、 52 | nil を指定した場合は設定(変更)しない。" 53 | (when level 54 | (tr-ime-modadv--set-verbose-level level)) 55 | (set-default symb level)) 56 | 57 | (defcustom tr-ime-debug-verbose-level nil 58 | "デバッグ出力レベル. 59 | 60 | この設定を変更する場合には \"custom-set-variables\" を使うこと。 61 | 62 | Win32 API の OutputDebugString を使った、 63 | デバッグメッセージの出力レベルを 0 (none) から 6 (trace) の整数で指定するか、 64 | nil を指定した場合は設定(変更)しない。" 65 | :type '(choice (const :tag "none" 0) 66 | (const :tag "fatal" 1) 67 | (const :tag "error" 2) 68 | (const :tag "warn" 3) 69 | (const :tag "info" 4) 70 | (const :tag "debug" 5) 71 | (const :tag "trace" 6) 72 | (const :tag "no set" nil)) 73 | :set #'tr-ime-debug--verbose-level-set 74 | :group 'tr-ime-debug) 75 | 76 | ;; 77 | ;; provide 78 | ;; 79 | 80 | (provide 'tr-ime-debug) 81 | 82 | ;; Local Variables: 83 | ;; coding: utf-8 84 | ;; End: 85 | 86 | ;;; tr-ime-debug.el ends here 87 | -------------------------------------------------------------------------------- /lisp/tr-ime-documentfeed.el: -------------------------------------------------------------------------------- 1 | ;;; tr-ime-documentfeed.el --- Documentfeed -*- lexical-binding: t -*- 2 | 3 | ;; Copyright (C) 2020, 2022 Masamichi Hosoda 4 | 5 | ;; Author: Masamichi Hosoda 6 | ;; URL: https://github.com/trueroad/tr-emacs-ime-module 7 | 8 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 9 | ;; is free software: you can redistribute it and/or modify 10 | ;; it under the terms of the GNU General Public License as published by 11 | ;; the Free Software Foundation, either version 3 of the License, or 12 | ;; (at your option) any later version. 13 | ;; 14 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 15 | ;; is distributed in the hope that it will be useful, 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | ;; GNU General Public License for more details. 19 | ;; 20 | ;; You should have received a copy of the GNU General Public License 21 | ;; along with tr-ime. 22 | ;; If not, see . 23 | 24 | ;;; Commentary: 25 | 26 | ;; This file is part of 27 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime). 28 | ;; See tr-ime.el 29 | 30 | ;;; Code: 31 | 32 | ;; 33 | ;; require 34 | ;; 35 | 36 | (require 'tr-ime-reconversion) 37 | 38 | ;; 39 | ;; ユーザ設定用 40 | ;; 41 | 42 | (defgroup tr-ime-documentfeed nil 43 | "前後の確定済文字列を参照した変換 (advanced)." 44 | :group 'tr-ime) 45 | 46 | ;; 47 | ;; 前後の確定済文字列を参照した変換 (DOCUMENTFEED) 48 | ;; 49 | 50 | (declare-function tr-ime-modadv--set-documentfeed "tr-ime-modadv" 51 | (arg1 arg2)) 52 | 53 | (defun tr-ime-documentfeed--set (symb bool) 54 | "前後の確定済文字列を参照した変換 (DOCUMENTFEED) 動作を行うか否か設定する. 55 | 56 | SYMB には tr-ime-documentfeed-p を指定する。 57 | BOOL が non-nil なら DOCUMENTFEED 動作を行う。 58 | それ以外なら行わない。" 59 | (if bool 60 | (when (and (boundp 'tr-ime-enabled-features) 61 | (eq tr-ime-enabled-features 'advanced)) 62 | (add-hook 'tr-ime-modadv--documentfeed-hook 63 | #'tr-ime-reconversion--notify-reconvert-string) 64 | (tr-ime-modadv--set-documentfeed 65 | (string-to-number (frame-parameter nil 'window-id)) t)) 66 | (when (fboundp 'tr-ime-modadv--set-documentfeed) 67 | (tr-ime-modadv--set-documentfeed 68 | (string-to-number (frame-parameter nil 'window-id)) nil)) 69 | (remove-hook 'tr-ime-modadv--documentfeed-hook 70 | #'tr-ime-reconversion--notify-reconvert-string)) 71 | (set-default symb bool)) 72 | 73 | (defcustom tr-ime-documentfeed-p t 74 | "前後の確定済文字列を参照した変換 (DOCUMENTFEED) 動作を行うか否か. 75 | 76 | この設定を変更する場合には \"custom-set-variables\" を使うこと。 77 | 78 | 確定済文字列のあるところにカーソルを置いて文字を入力・変換すると、 79 | カーソルのあった場所の確定済文字列によって変換候補が変わる機能。" 80 | :type '(choice (const :tag "Enable" t) 81 | (const :tag "Disable" nil)) 82 | :set #'tr-ime-documentfeed--set 83 | :group 'tr-ime-documentfeed) 84 | 85 | (defun tr-ime-documentfeed-unload-function () 86 | "アンロードするため DOCUMENTFEED を無効にする." 87 | (let (_dummy) 88 | (tr-ime-documentfeed--set '_dummy nil))) 89 | 90 | ;; 91 | ;; provide 92 | ;; 93 | 94 | (provide 'tr-ime-documentfeed) 95 | 96 | ;; Local Variables: 97 | ;; coding: utf-8 98 | ;; End: 99 | 100 | ;;; tr-ime-documentfeed.el ends here 101 | -------------------------------------------------------------------------------- /lisp/tr-ime-download.el: -------------------------------------------------------------------------------- 1 | ;;; tr-ime-download.el --- Download files -*- lexical-binding: t -*- 2 | 3 | ;; Copyright (C) 2020, 2022 Masamichi Hosoda 4 | 5 | ;; Author: Masamichi Hosoda 6 | ;; URL: https://github.com/trueroad/tr-emacs-ime-module 7 | 8 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 9 | ;; is free software: you can redistribute it and/or modify 10 | ;; it under the terms of the GNU General Public License as published by 11 | ;; the Free Software Foundation, either version 3 of the License, or 12 | ;; (at your option) any later version. 13 | ;; 14 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 15 | ;; is distributed in the hope that it will be useful, 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | ;; GNU General Public License for more details. 19 | ;; 20 | ;; You should have received a copy of the GNU General Public License 21 | ;; along with tr-ime. 22 | ;; If not, see . 23 | 24 | ;;; Commentary: 25 | 26 | ;; This file is part of 27 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime). 28 | ;; See tr-ime.el 29 | 30 | ;;; Code: 31 | 32 | ;; 33 | ;; モジュール DLL のダウンロード 34 | ;; 35 | 36 | (defconst tr-ime-download--url-prefix 37 | "https://github.com/trueroad/tr-ime-dist/raw/v0.5.0/" 38 | "ダウンロード先 URL のプレフィックス.") 39 | 40 | (defconst tr-ime-download--url-suffix ".gz" 41 | "ダウンロード先 URL のサフィックス.") 42 | 43 | (defconst tr-ime-download--file-sum-alist 44 | '(("tr-ime-mod-1-i686-pc-cygwin.dll" . 45 | "68c734d8b1c56abb089b05f0ece0fe1b2c47ed818ea118be1cadd678d7a2ceb1") 46 | ("tr-ime-mod-1-i686-w64-mingw32.dll" . 47 | "ba162d3f927d779fa42f6906b3c8ac1252dd3f7332938b28c41b0b1cfee646dd") 48 | ("tr-ime-mod-1-x86_64-pc-cygwin.dll" . 49 | "f8362c23faa9835c6071de62967125a3683304718703f39296baec70bbdb0981") 50 | ("tr-ime-mod-1-x86_64-w64-mingw32.dll" . 51 | "92159ebcf946ec6d5a498d9bc473ec3788aaee0caea51f34435da3535f70f2bf") 52 | ("tr-ime-modadv-2-i686-pc-cygwin.dll" . 53 | "3a1dd0e3b114ee3ae1d9bc24f0723a11f4ac57dceaf0de6967262c611e80fe9f") 54 | ("tr-ime-modadv-2-i686-w64-mingw32.dll" . 55 | "9fc539e63601763f7e94fd82523c8b98ac5f2e49fb5ecc7040454488a1e77152") 56 | ("tr-ime-modadv-2-x86_64-pc-cygwin.dll" . 57 | "c3f6ec346293800268af2004053bf6ebde1fe513554e9755d1fa3b6662bd619b") 58 | ("tr-ime-modadv-2-x86_64-w64-mingw32.dll" . 59 | "d3492a55d6342351f38c3cb7c1c3afdc6cba36c58934786e7d2bc7ac999bc0c5")) 60 | "ダウンロードする DLL の sha256sum.") 61 | 62 | (defconst tr-ime-download--dir (file-name-directory load-file-name) 63 | "モジュール DLL のダウンロード先ディレクトリ.") 64 | 65 | (defun tr-ime-download--download-and-unzip (url filename) 66 | "モジュール DLL をダウンロードして解凍する. 67 | 68 | URL からダウンロードして解凍したファイルを、 69 | ディレクトリ DIR のファイル名 FILENAME に置く。" 70 | (let ((tmpfilename (make-temp-file (concat tr-ime-download--dir "tmp")))) 71 | (url-copy-file url tmpfilename t) 72 | (with-temp-file (concat tr-ime-download--dir filename) 73 | (set-buffer-multibyte nil) 74 | (insert-file-contents-literally tmpfilename) 75 | (delete-file tmpfilename) 76 | (zlib-decompress-region (point-min) (point-max))))) 77 | 78 | (defun tr-ime-download--good-file-p (filename) 79 | "ファイルのハッシュを確認する. 80 | 81 | ディレクトリ DIR のファイル名 FILENAME について sha256sum を確認する。 82 | 一致すれば non-nil を返す。そうでなければ nil を返す。" 83 | (let ((sum (cdr (assoc filename tr-ime-download--file-sum-alist))) 84 | (path (concat tr-ime-download--dir filename))) 85 | (if (file-exists-p path) 86 | (with-temp-buffer 87 | (set-buffer-multibyte nil) 88 | (insert-file-contents-literally path) 89 | (string= (secure-hash 'sha256 (current-buffer)) sum)) 90 | nil))) 91 | 92 | (defun tr-ime-download--request-file (filename) 93 | "モジュール DLL をダウンロードしてロードする. 94 | 95 | FILENAME のモジュール DLL をダウンロードしてロードする。" 96 | (tr-ime-download--download-and-unzip 97 | (concat tr-ime-download--url-prefix 98 | filename 99 | tr-ime-download--url-suffix) 100 | filename) 101 | (if (tr-ime-download--good-file-p filename) 102 | (progn 103 | (set-file-modes (concat tr-ime-download--dir filename) #o755) 104 | (load filename)) 105 | (delete-file (concat tr-ime-download--dir filename)) 106 | (error "Download failed: %s" filename))) 107 | 108 | (defun tr-ime-download-mod-file (name &optional no-confirm) 109 | "モジュール DLL をダウンロードするか否か確認してダウンロードする. 110 | 111 | NAME にモジュール DLL のファイル名拡張子なしを指定する。 112 | NO-CONFIRM が non-nil なら確認せずにダウンロードする。" 113 | (if (or no-confirm 114 | (y-or-n-p (format "Download %s.dll? " name))) 115 | (tr-ime-download--request-file (concat name ".dll")) 116 | (error "%s.dll is not found. 117 | 118 | Download or build it and put it in the directory specified in \"load-path.\" 119 | See https://github.com/trueroad/tr-emacs-ime-module" name))) 120 | 121 | ;; 122 | ;; provide 123 | ;; 124 | 125 | (provide 'tr-ime-download) 126 | 127 | ;; Local Variables: 128 | ;; coding: utf-8 129 | ;; End: 130 | 131 | ;;; tr-ime-download.el ends here 132 | -------------------------------------------------------------------------------- /lisp/tr-ime-font.el: -------------------------------------------------------------------------------- 1 | ;;; tr-ime-font.el --- Font handling -*- lexical-binding: t -*- 2 | 3 | ;; Copyright (C) 2020, 2022 Masamichi Hosoda 4 | 5 | ;; Author: Masamichi Hosoda 6 | ;; URL: https://github.com/trueroad/tr-emacs-ime-module 7 | 8 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 9 | ;; is free software: you can redistribute it and/or modify 10 | ;; it under the terms of the GNU General Public License as published by 11 | ;; the Free Software Foundation, either version 3 of the License, or 12 | ;; (at your option) any later version. 13 | ;; 14 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 15 | ;; is distributed in the hope that it will be useful, 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | ;; GNU General Public License for more details. 19 | ;; 20 | ;; You should have received a copy of the GNU General Public License 21 | ;; along with tr-ime. 22 | ;; If not, see . 23 | 24 | ;;; Commentary: 25 | 26 | ;; This file is part of 27 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime). 28 | ;; See tr-ime.el 29 | 30 | ;;; Code: 31 | 32 | ;; 33 | ;; require 34 | ;; 35 | 36 | (require 'seq) 37 | 38 | ;; 39 | ;; ユーザ設定用 40 | ;; 41 | 42 | (defgroup tr-ime-font nil 43 | "IME フォント(未確定文字列フォント)設定 (advanced)." 44 | :group 'tr-ime) 45 | 46 | ;; 47 | ;; 属性変換 48 | ;; 49 | 50 | (defun tr-ime-font--encode-weight (symb) 51 | "フェイス属性の weight から LOGFONT 構造体の lfWeight へ変換する. 52 | 53 | SYMB に weight を指定する。返り値は lfWeight。" 54 | (let* ((result 55 | (seq-drop-while 56 | (lambda (x) 57 | (eq (seq-drop-while (lambda (y) (not (eq y symb))) x) [])) 58 | font-weight-table)) 59 | (weight 60 | (if (eq result []) 100 (aref (aref result 0) 0)))) 61 | (cond ((>= weight 210) 900) ; FW_HEAVY 62 | ((>= weight 205) 800) ; FW_EXTRABOLD 63 | ((>= weight 200) 700) ; FW_BOLD 64 | ((>= weight 180) 600) ; FW_SEMIBOLD 65 | ((>= weight 100) 400) ; FW_NORMAL 66 | ((>= weight 50) 300) ; FW_LIGHT 67 | ((>= weight 40) 200) ; FW_EXTRALIGHT 68 | ((>= weight 20) 100) ; FW_THIN 69 | (t 0)))) 70 | 71 | (defun tr-ime-font--encode-slant (symb) 72 | "フェイス属性の slant から LOGFONT 構造体の lfItalic へ変換する. 73 | 74 | SYMB に slant を指定する。返り値は lfItalic。" 75 | (let* ((result 76 | (seq-drop-while 77 | (lambda (x) 78 | (eq (seq-drop-while (lambda (y) (not (eq y symb))) x) [])) 79 | font-slant-table)) 80 | (slant 81 | (if (eq result []) 100 (aref (aref result 0) 0)))) 82 | (> slant 150))) 83 | 84 | ;; 85 | ;; フレームの ime-font 設定を反映 86 | ;; 87 | 88 | (declare-function tr-ime-modadv--set-font "tr-ime-modadv" 89 | (arg1 arg2 arg3 arg4 arg5 arg6 arg7 arg8 90 | arg9 arg10 arg11 arg12 arg13 arg14 arg15)) 91 | (declare-function tr-ime-modadv--get-dpi "tr-ime-modadv") 92 | 93 | (defun tr-ime-font-reflect-frame-parameter (&optional frame) 94 | "フレームの ime-font 設定を反映する. 95 | 96 | FRAME の フレームパラーメータから ime-font 設定を読み取り、 97 | モジュールで C++ 実装されている低レベルフォント設定関数 98 | tr-ime-modadv--set-font を使って未確定文字列のフォントを設定する。 99 | FRAME が nil または省略された場合は選択されているフレームが対象となる。 100 | family に generic family を指定することはできない。 101 | 102 | IME パッチではフレームの ime-font 設定を変更すると即座に反映されるが、 103 | tr-ime 環境では、フレームの ime-font 設定と、 104 | モジュール内部の未確定文字列フォント設定は独立であり、 105 | フレームの ime-font 設定を変更しても、本関数を呼ぶまで反映されない。 106 | よって、設定後に必ず本関数を呼ぶようにするか、何らかのフックなどで 107 | フレームの ime-font 設定変更を検出して本関数を呼ぶようなどすれば、 108 | IME パッチと同様の設定で使うことができる。 109 | 110 | なお、低レベルフォント設定関数 tr-ime-modadv--set-font で設定される、 111 | モジュール内部の設定はスレッド毎の設定となっており、 112 | 一度設定すると他のフレームでも同じ設定が使われる。 113 | そのため、全フレームで同一の設定にしたい場合は、 114 | 115 | (modify-all-frames-parameters '((ime-font . \"原ノ味明朝-24\"))) 116 | (w32-tr-ime-reflect-frame-parameter-ime-font) 117 | 118 | のようにすることによって、全フレームおよび \"default-frame-alist\" の 119 | ime-font 設定が変更された上で、モジュール内部の設定にも反映される。 120 | 121 | 逆にフレーム毎の設定をしたい場合は、 122 | 各フレームの ime-font 設定を別々に設定しておき、 123 | \"focus-in-hook\" などで ime-font 設定が変わったことを検出して 124 | 本関数を呼び出すなどすれば、フレームが切り替わった際に、 125 | そのフレームの ime-font 設定を反映させることもできる。" 126 | (interactive) 127 | (let ((ime-font (frame-parameter frame 'ime-font))) 128 | (when ime-font 129 | (let* ((attributes (font-face-attributes ime-font)) 130 | (family (plist-get attributes :family)) 131 | (height (plist-get attributes :height))) 132 | (when (and family height) 133 | (let ((h (round (/ (* height 134 | (cdr (tr-ime-modadv--get-dpi))) 135 | -720.0)))) 136 | (tr-ime-modadv--set-font 137 | (string-to-number 138 | (frame-parameter frame 'window-id)) 139 | h 0 0 0 140 | (tr-ime-font--encode-weight (plist-get attributes :weight)) 141 | (tr-ime-font--encode-slant (plist-get attributes :slant)) 142 | nil nil 1 0 0 0 0 family))))))) 143 | 144 | ;; 145 | ;; 未確定文字列フォント変更検出 146 | ;; 147 | 148 | (defvar tr-ime-font--last-ime-font nil 149 | "未確定文字列フォント変更検出用.") 150 | 151 | (defun tr-ime-font-check () 152 | "フレームパラメータ ime-font が変更されていたら反映する. 153 | 154 | Emacs の標準的なフックである \"post-command-hook\" に登録するか、 155 | \"after-focus-change-function\" 経由で呼び出す。 156 | 157 | IME パッチは、フレームパラメータの ime-font を設定すると、 158 | 即座に未確定文字列フォントに反映されるが、モジュール環境では反映できない。 159 | 本関数は ime-font が変更されているか確認し、変更されていたら 160 | 変更を反映する tr-ime-font-reflect-frame-parameter 161 | 関数を呼び出すことによって未確定文字列フォントを設定する。 162 | 163 | \"after-focus-change-function\" 経由で呼び出した場合は、 164 | フレームを変更した際に呼ばれ、 165 | フレームへ設定されたパラメータに応じて未確定文字列フォントが 166 | 設定されるようになる。 167 | 168 | \"post-command-hook\" に登録した場合は、ほとんどのコマンドの動作後に呼ばれ、 169 | フレームパラメータの変更後すぐに未確定文字列フォントが 170 | 設定されるようになる。" 171 | (let ((parameter (frame-parameter nil 'ime-font))) 172 | (unless (string= parameter tr-ime-font--last-ime-font) 173 | (tr-ime-font-reflect-frame-parameter) 174 | (setq tr-ime-font--last-ime-font parameter)))) 175 | 176 | ;; 177 | ;; フォーカス変更(フレーム変更)時 178 | ;; 179 | 180 | (defun tr-ime-font--after-focus-change-function () 181 | "フォーカス変更を確認して ime-font 設定を反映する. 182 | 183 | \"after-focus-change-function\" は呼び出された時点では 184 | まだ \"selected-frame\" が変わっていないことがあるので、 185 | 全フレームに対して \"frame-focus-state\" でフォーカスを得ているか否か判定し、 186 | フォーカスを得ていたフレームで w32-tr-ime-font-check 187 | を呼び出して未確定文字列フォントを設定する。 188 | 189 | \"after-focus-change-function\" に登録して使う。" 190 | (dolist (f (frame-list)) 191 | (when (frame-focus-state f) 192 | (with-selected-frame f (tr-ime-font-check))))) 193 | 194 | (defun tr-ime-font--focus-set (symb bool) 195 | "フォーカス変更時に ime-font 設定を反映するか否か設定する. 196 | 197 | SYMB は tr-ime-font-focus-p を指定する。 198 | BOOL が non-nil ならフォーカス変更時に ime-font 設定を反映する。 199 | そうでなければフォーカス変更時に ime-font 設定を反映しない。" 200 | (if bool 201 | (add-function :before 202 | after-focus-change-function 203 | #'tr-ime-font--after-focus-change-function) 204 | (remove-function 205 | after-focus-change-function 206 | #'tr-ime-font--after-focus-change-function)) 207 | (set-default symb bool)) 208 | 209 | (defcustom tr-ime-font-focus-p t 210 | "フォーカス変更時に ime-font 設定を反映するか否か. 211 | 212 | この設定を変更する場合には \"custom-set-variables\" を使うこと。 213 | 214 | 本設定を non-nil (Enable) にすると、フォーカス変更(フレーム変更)時に 215 | フレームパラメータの ime-font 設定が、 216 | モジュールの未確定文字列フォントに反映される。" 217 | :type '(choice (const :tag "Enable" t) 218 | (const :tag "Disable" nil)) 219 | :set #'tr-ime-font--focus-set 220 | :group 'tr-ime-font) 221 | 222 | ;; 223 | ;; コマンド実行後 224 | ;; 225 | 226 | (defun tr-ime-font--post-command-set (symb bool) 227 | "コマンド実行後に ime-font 設定を反映するか否か設定する. 228 | 229 | SYMB は tr-ime-font-post-command-p を指定する。 230 | BOOL が non-nil ならコマンド実行後に設定を反映する。 231 | そうでなければコマンド実行後に設定を反映しない。" 232 | (if bool 233 | (add-hook 'post-command-hook 234 | #'tr-ime-font-check) 235 | (remove-hook 'post-command-hook 236 | #'tr-ime-font-check)) 237 | (set-default symb bool)) 238 | 239 | (defcustom tr-ime-font-post-command-p nil 240 | "コマンド実行後に ime-font 設定を反映するか否か. 241 | 242 | この設定を変更する場合には \"custom-set-variables\" を使うこと。 243 | 244 | 本設定を non-nil (Enable) にすると、ほとんどのコマンド実行後に 245 | フレームパラメータの ime-font 設定が、 246 | モジュールの未確定文字列フォントに反映される。 247 | つまり、ime-font 設定を変更することで IME パッチ環境と同様、 248 | ほぼ即座に未確定文字列フォントが設定できる。" 249 | :type '(choice (const :tag "Enable" t) 250 | (const :tag "Disable" nil)) 251 | :set #'tr-ime-font--post-command-set 252 | :group 'tr-ime-font) 253 | 254 | ;; 255 | ;; アンロード 256 | ;; 257 | 258 | (defun tr-ime-font-unload-function () 259 | "アンロードするため IME フォント(未確定文字列フォント)設定を無効にする." 260 | (let (_dummy) 261 | (tr-ime-font--focus-set '_dummy nil) 262 | (tr-ime-font--post-command-set '_dummy nil))) 263 | 264 | ;; 265 | ;; provide 266 | ;; 267 | 268 | (provide 'tr-ime-font) 269 | 270 | ;; Local Variables: 271 | ;; coding: utf-8 272 | ;; End: 273 | 274 | ;;; tr-ime-font.el ends here 275 | -------------------------------------------------------------------------------- /lisp/tr-ime-hook.el: -------------------------------------------------------------------------------- 1 | ;;; tr-ime-hook.el --- Hook emulation of IME patch -*- lexical-binding: t -*- 2 | 3 | ;; Copyright (C) 2020-2022 Masamichi Hosoda 4 | 5 | ;; Author: Masamichi Hosoda 6 | ;; URL: https://github.com/trueroad/tr-emacs-ime-module 7 | 8 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 9 | ;; is free software: you can redistribute it and/or modify 10 | ;; it under the terms of the GNU General Public License as published by 11 | ;; the Free Software Foundation, either version 3 of the License, or 12 | ;; (at your option) any later version. 13 | ;; 14 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 15 | ;; is distributed in the hope that it will be useful, 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | ;; GNU General Public License for more details. 19 | ;; 20 | ;; You should have received a copy of the GNU General Public License 21 | ;; along with tr-ime. 22 | ;; If not, see . 23 | 24 | ;;; Commentary: 25 | 26 | ;; This file is part of 27 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime). 28 | ;; See tr-ime.el 29 | 30 | ;;; Code: 31 | 32 | ;; 33 | ;; ユーザ設定用 34 | ;; 35 | 36 | (defgroup tr-ime-core nil 37 | "コア機能設定. 38 | 39 | コア機能の設定です。通常は設定変更しないでください。" 40 | :group 'tr-ime) 41 | 42 | (defgroup tr-ime-hook nil 43 | "IME パッチ特有のアブノーマルフック." 44 | :group 'tr-ime-core) 45 | 46 | ;; 47 | ;; Hook 48 | ;; 49 | 50 | ;; IME パッチ適用 Emacs ではコンフリクトを未然に防ぐため 51 | ;; 明示的にエラーを出して動作を停止させる 52 | (require 'tr-ime) 53 | (when (tr-ime-detect-ime-patch-p) 54 | (error "%s" (concat "Emacs seems to have an IME patch applied. " 55 | "tr-ime cannot work on it."))) 56 | 57 | ;; IME パッチ適用 Emacs だと変数 select-window-functions が 58 | ;; C 実装なのでエイリアスにしようとするとエラーが発生する 59 | (define-obsolete-variable-alias 'select-window-functions 60 | 'tr-ime-hook-select-window-functions "2020") 61 | (defvar tr-ime-hook-select-window-functions nil 62 | "選択されたウィンドウが変更されると呼ばれるアブノーマルフック. 63 | 64 | IME パッチ特有のフックで、 IME パッチでは C 実装されているが、 65 | Lisp でエミュレーションする。") 66 | 67 | ;; IME パッチ適用 Emacs だと変数 set-selected-window-buffer-functions が 68 | ;; C 実装なのでエイリアスにしようとするとエラーが発生する 69 | (define-obsolete-variable-alias 'set-selected-window-buffer-functions 70 | 'tr-ime-hook-set-selected-window-buffer-functions "2020") 71 | (defvar tr-ime-hook-set-selected-window-buffer-functions nil 72 | "選択ウィンドウに紐づいたバッファが変更されると呼ばれるアブノーマルフック. 73 | 74 | IME パッチ特有のフックで、 IME パッチでは C 実装されているが、 75 | Lisp でエミュレーションする。") 76 | 77 | ;; 78 | ;; 選択ウィンドウに紐づいたバッファの変更を検出する 79 | ;; 80 | 81 | (defvar tr-ime-hook--last-selected-window-buffer nil 82 | "選択ウィンドウに紐づいたバッファの変更検出用変数.") 83 | 84 | (defun tr-ime-hook-check-selected-window-buffer (_frame) 85 | "選択ウィンドウに紐づいたバッファが変更されていたらフックを呼ぶ." 86 | (let* ((window (selected-window)) 87 | (buffer (window-buffer window))) 88 | (unless (eq buffer tr-ime-hook--last-selected-window-buffer) 89 | (run-hook-with-args 'tr-ime-hook-set-selected-window-buffer-functions 90 | tr-ime-hook--last-selected-window-buffer 91 | window 92 | buffer) 93 | (setq tr-ime-hook--last-selected-window-buffer buffer)))) 94 | 95 | ;; 96 | ;; 選択ウィンドウの変更を検出する 97 | ;; 98 | 99 | (defvar tr-ime-hook--last-selected-window nil 100 | "選択ウィンドウの変更検出用変数.") 101 | 102 | (defun tr-ime-hook-check-selected-window (_frame) 103 | "選択ウィンドウが変更されていたらフックを呼ぶ." 104 | (let* ((window (selected-window)) 105 | (buffer (window-buffer window))) 106 | (unless (eq window tr-ime-hook--last-selected-window) 107 | (run-hook-with-args 'tr-ime-hook-select-window-functions 108 | tr-ime-hook--last-selected-window 109 | window) 110 | (setq tr-ime-hook--last-selected-window window) 111 | (setq tr-ime-hook--last-selected-window-buffer buffer)))) 112 | 113 | ;; 114 | ;; 選択ウィンドウとバッファの両方の変更を検出する 115 | ;; 116 | 117 | (defun tr-ime-hook-check () 118 | "選択ウィンドウとバッファの両方を確認してフックを呼ぶ." 119 | (let ((frame (selected-frame))) 120 | (tr-ime-hook-check-selected-window frame) 121 | (tr-ime-hook-check-selected-window-buffer frame))) 122 | 123 | ;; 124 | ;; 設定用 125 | ;; 126 | 127 | (defun tr-ime-hook--set (symb bool) 128 | "IME パッチ特有のアブノーマルフックをエミュレーションするか否か設定する. 129 | 130 | SYMB は tr-ime-hook-p を指定すること。 131 | BOOL が non-nil ならエミュレーション有効でフックが呼ばれる。 132 | そうでなければエミュレーション無効でフックは呼ばれない。" 133 | (if bool 134 | (progn 135 | (add-hook 'window-selection-change-functions 136 | #'tr-ime-hook-check-selected-window) 137 | (add-hook 'window-buffer-change-functions 138 | #'tr-ime-hook-check-selected-window-buffer)) 139 | (remove-hook 'window-selection-change-functions 140 | #'tr-ime-hook-check-selected-window) 141 | (remove-hook 'window-buffer-change-functions 142 | #'tr-ime-hook-check-selected-window-buffer)) 143 | (set-default symb bool)) 144 | 145 | (defcustom tr-ime-hook-p t 146 | "IME パッチ特有のアブノーマルフックをエミュレーションするか否か. 147 | 148 | この設定を変更する場合には \"custom-set-variables\" を使うこと。 149 | 150 | 注意:w32-ime.el はこれらのアブノーマルフックを使って 151 | ウィンドウやバッファの切り替えを認識して 152 | IME/IM の同期や切り替えなどを行っている。 153 | 本設定を無効にすると、ウィンドウやバッファ切り替え時に 154 | IME/IM が同期しなくなるなどの問題が発生する。 155 | 特別な目的が無い限りは non-nil (Enable) にしておくこと。" 156 | :type '(choice (const :tag "Enable" t) 157 | (const :tag "Disable" nil)) 158 | :set #'tr-ime-hook--set 159 | :group 'tr-ime-hook) 160 | 161 | (defun tr-ime-hook-unload-function () 162 | "アンロードするため IME パッチ特有のアブノーマルフックを無効にする." 163 | (let (_dummy) 164 | (tr-ime-hook--set '_dummy nil))) 165 | 166 | ;; 167 | ;; provide 168 | ;; 169 | 170 | (provide 'tr-ime-hook) 171 | 172 | ;; Local Variables: 173 | ;; coding: utf-8 174 | ;; End: 175 | 176 | ;;; tr-ime-hook.el ends here 177 | -------------------------------------------------------------------------------- /lisp/tr-ime-isearch.el: -------------------------------------------------------------------------------- 1 | ;;; tr-ime-isearch.el --- Handle isearch-mode -*- lexical-binding: t -*- 2 | 3 | ;; Copyright (C) 2020-2022 Masamichi Hosoda 4 | 5 | ;; Author: Masamichi Hosoda 6 | ;; URL: https://github.com/trueroad/tr-emacs-ime-module 7 | 8 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 9 | ;; is free software: you can redistribute it and/or modify 10 | ;; it under the terms of the GNU General Public License as published by 11 | ;; the Free Software Foundation, either version 3 of the License, or 12 | ;; (at your option) any later version. 13 | ;; 14 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 15 | ;; is distributed in the hope that it will be useful, 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | ;; GNU General Public License for more details. 19 | ;; 20 | ;; You should have received a copy of the GNU General Public License 21 | ;; along with tr-ime. 22 | ;; If not, see . 23 | 24 | ;;; Commentary: 25 | 26 | ;; This file is part of 27 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime). 28 | ;; See tr-ime.el 29 | 30 | ;;; Code: 31 | 32 | ;; 33 | ;; ユーザ設定用 34 | ;; 35 | 36 | (defgroup tr-ime-isearch nil 37 | "\"isearch-mode\" 設定 (advanced)." 38 | :group 'tr-ime) 39 | 40 | ;; 41 | ;; エコーエリア検出 42 | ;; 43 | 44 | (defvar tr-ime-isearch--last-echo-area-0-point nil 45 | "エコーエリア 0 の point 移動検出用.") 46 | 47 | (defvar tr-ime-isearch--last-echo-area-1-point nil 48 | "エコーエリア 1 の point 移動検出用.") 49 | 50 | (defvar tr-ime-isearch--last-echo-area-buffer nil 51 | "最後に使用されたエコーエリアバッファ.") 52 | 53 | (defun tr-ime-isearch--start () 54 | "エコーエリアのバッファのうちどちらが使われているか検出を開始する. 55 | 56 | \"isearch-mode-hook\" に登録することにより、\"isearch-mode\" 中に 57 | どのエコーエリアが使われているか検出できるようにする。" 58 | (setq tr-ime-isearch--last-echo-area-0-point 59 | (with-current-buffer " *Echo Area 0*" 60 | (point))) 61 | (setq tr-ime-isearch--last-echo-area-1-point 62 | (with-current-buffer " *Echo Area 1*" 63 | (point)))) 64 | 65 | (defun tr-ime-isearch--detect-echo-area-buffer () 66 | "使用中のエコーエリアバッファを検出して返す. 67 | 68 | \"isearch-mode\" 中に使用しているエコーエリアバッファを返す。" 69 | (let* ((point0 (with-current-buffer " *Echo Area 0*" 70 | (point))) 71 | (point1 (with-current-buffer " *Echo Area 1*" 72 | (point))) 73 | (buff (cond ((and tr-ime-isearch--last-echo-area-0-point 74 | (/= point0 75 | tr-ime-isearch--last-echo-area-0-point)) 76 | (get-buffer " *Echo Area 0*")) 77 | ((and tr-ime-isearch--last-echo-area-1-point 78 | (/= point1 79 | tr-ime-isearch--last-echo-area-1-point)) 80 | (get-buffer " *Echo Area 1*")) 81 | (tr-ime-isearch--last-echo-area-buffer 82 | tr-ime-isearch--last-echo-area-buffer) 83 | (t 84 | (get-buffer " *Echo Area 0*"))))) 85 | ;; (tr-ime-modadv--debug-output 86 | ;; (format-message "last point0 %s, point1 %s, buff %s" 87 | ;; tr-ime-isearch--last-echo-area-0-point 88 | ;; tr-ime-isearch--last-echo-area-1-point 89 | ;; tr-ime-isearch--last-echo-area-buffer)) 90 | ;; (tr-ime-modadv--debug-output 91 | ;; (format-message " now point0 %s, point1 %s, buff %s" 92 | ;; point0 point1 buff)) 93 | (setq tr-ime-isearch--last-echo-area-0-point point0) 94 | (setq tr-ime-isearch--last-echo-area-1-point point1) 95 | (setq tr-ime-isearch--last-echo-area-buffer buff))) 96 | 97 | ;; 98 | ;; 未確定文字列の表示位置 99 | ;; 100 | 101 | (declare-function tr-ime-modadv--set-composition-window "tr-ime-modadv" 102 | (arg1 arg2 arg3 arg4 arg5 arg6 arg7 arg8)) 103 | 104 | (defun tr-ime-isearch--update () 105 | "未確定文字列の表示位置を更新・設定する. 106 | 107 | \"isearch-update-post-hook\" に登録することにより、 108 | \"isearch-mode\" 中の未確定文字列の表示位置を 109 | ミニバッファ上の文字入力位置を更新・設定する。" 110 | (with-current-buffer (tr-ime-isearch--detect-echo-area-buffer) 111 | (let* ((sw 112 | (string-width 113 | (buffer-substring-no-properties (point-min) (point)))) 114 | (wc (window-width (minibuffer-window))) 115 | (x (* (% sw wc) (frame-char-width))) 116 | (y (* (/ sw wc) (with-selected-window (minibuffer-window) 117 | (line-pixel-height)))) 118 | (edges (window-inside-pixel-edges (minibuffer-window))) 119 | (left (nth 0 edges)) 120 | (top (nth 1 edges)) 121 | (right (nth 2 edges)) 122 | (bottom (nth 3 edges)) 123 | (px (+ x left)) 124 | (py (+ y top))) 125 | ;; (tr-ime-modadv--debug-output 126 | ;; (format-message 127 | ;; "sw %s, wc %s, x %s, y %s, edges %s" 128 | ;; sw wc x y edges)) 129 | ;; (tr-ime-modadv--debug-output 130 | ;; (format-message 131 | ;; "left %s, top %s, right %s, bottom %s, px %s, py %s" 132 | ;; left top right bottom px py)) 133 | (tr-ime-modadv--set-composition-window 134 | (string-to-number (frame-parameter nil 'window-id)) 135 | 1 px py left top right bottom)))) 136 | 137 | (defun tr-ime-isearch--end () 138 | "未確定文字列の表示位置を元に戻す. 139 | 140 | \"isearch-mode-end-hook\" に登録することにより、\"isearch-mode\" 終了後に 141 | 未確定文字列の表示位置を通常のバッファ内のカーソル位置に戻す。" 142 | (tr-ime-modadv--set-composition-window 143 | (string-to-number (frame-parameter nil 'window-id)) 144 | 0 0 0 0 0 0 0)) 145 | 146 | ;; 147 | ;; 未確定文字列表示位置を文字入力位置にするか否か設定 148 | ;; 149 | 150 | (defun tr-ime-isearch--set (symb bool) 151 | "未確定文字列表示位置を文字入力位置にするか否か設定する. 152 | 153 | SYMB には tr-ime-isearch-p を指定する。 154 | BOOL が non-nil なら \"isearch-mode\" 中の 155 | 未確定文字列表示位置を文字入力位置に設定する。 156 | そうでなければ設定しない。" 157 | (if bool 158 | (progn 159 | (add-hook 'isearch-mode-hook #'tr-ime-isearch--start) 160 | (add-hook 'isearch-update-post-hook #'tr-ime-isearch--update) 161 | (add-hook 'isearch-mode-end-hook #'tr-ime-isearch--end)) 162 | (remove-hook 'isearch-mode-hook #'tr-ime-isearch--start) 163 | (remove-hook 'isearch-update-post-hook #'tr-ime-isearch--update) 164 | (remove-hook 'isearch-mode-end-hook #'tr-ime-isearch--end)) 165 | (set-default symb bool)) 166 | 167 | (defcustom tr-ime-isearch-p t 168 | "未確定文字列表示位置を文字入力位置にするか否か. 169 | 170 | この設定を変更する場合には \"custom-set-variables\" を使うこと。 171 | 172 | \"isearch-mode\" 中に未確定文字列をエコーエリア(ミニバッファ) 173 | に表示する機能。本機能が無効の場合、 174 | 未確定文字列は \"isearch-mode\" に入る前の入力位置に表示される。" 175 | :type '(choice (const :tag "Enable" t) 176 | (const :tag "Disable" nil)) 177 | :set #'tr-ime-isearch--set 178 | :group 'tr-ime-isearch) 179 | 180 | ;; 181 | ;; WM_IME_STARTCOMPOSITION で常に DefSubclassProc を呼ぶか 182 | ;; 183 | 184 | (declare-function tr-ime-modadv--set-startcomposition-defsubclassproc 185 | "tr-ime-modadv" 186 | (arg1 arg2)) 187 | 188 | (defun tr-ime-isearch--defsubclassproc-set (symb bool) 189 | "WM_IME_STARTCOMPOSITION で常に DefSubclassProc を呼ぶか否か設定する. 190 | 191 | SYMB には tr-ime-isearch-defsubclassproc-p を指定する。 192 | BOOL が non-nil なら常に呼ぶようになる。 193 | そうでなければ未確定文字列ウィンドウの位置設定中は呼ばなくなる。" 194 | (tr-ime-modadv--set-startcomposition-defsubclassproc 195 | (string-to-number (frame-parameter nil 'window-id)) bool) 196 | (set-default symb bool)) 197 | 198 | (defcustom tr-ime-isearch-defsubclassproc-p nil 199 | "WM_IME_STARTCOMPOSITION で常に DefSubclassProc を呼ぶか否か. 200 | 201 | この設定を変更する場合には \"custom-set-variables\" を使うこと。 202 | 203 | WM_IME_STARTCOMPOSITION ハンドラにおいて、 204 | \"isearch-mode\" 中(未確定文字列ウィンドウの位置設定中)は 205 | DefSubcalssProc を呼ばず Emacs のメッセージ処理をスキップしている。 206 | これは Emacs で未確定文字列ウィンドウの位置を \"isearch-mode\" 207 | に入る前の文字入力位置に設定してしまうからで、 208 | この設定後に位置を上書きしても未確定文字列ウィンドウがチラつくからである。 209 | しかし、何らかの理由で元の Emacs の処理に戻さなければならない時は、 210 | 本設定を non-nil (Enable) にすることで \"isearch-mode\" 中であっても、 211 | DefSubcalssProc により Emacs のメッセージ処理が必ず呼ばれるようになる。" 212 | :type '(choice (const :tag "Enable" t) 213 | (const :tag "Disable" nil)) 214 | :set #'tr-ime-isearch--defsubclassproc-set 215 | :group 'tr-ime-isearch-mode) 216 | 217 | ;; 218 | ;; アンロード 219 | ;; 220 | 221 | (defun tr-ime-isearch-unload-function () 222 | "アンロードするため \"isearch-mode\" 設定を無効にする." 223 | (let (_dummy) 224 | (tr-ime-isearch--set '_dummy nil) 225 | (tr-ime-isearch--defsubclassproc-set '_dummy nil))) 226 | 227 | ;; 228 | ;; provide 229 | ;; 230 | 231 | (provide 'tr-ime-isearch) 232 | 233 | ;; Local Variables: 234 | ;; coding: utf-8 235 | ;; End: 236 | 237 | ;;; tr-ime-isearch.el ends here 238 | -------------------------------------------------------------------------------- /lisp/tr-ime-openstatus.el: -------------------------------------------------------------------------------- 1 | ;;; tr-ime-openstatus.el --- IME openstatus functions -*- lexical-binding: t -*- 2 | 3 | ;; Copyright (C) 2020-2022 Masamichi Hosoda 4 | 5 | ;; Author: Masamichi Hosoda 6 | ;; URL: https://github.com/trueroad/tr-emacs-ime-module 7 | 8 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 9 | ;; is free software: you can redistribute it and/or modify 10 | ;; it under the terms of the GNU General Public License as published by 11 | ;; the Free Software Foundation, either version 3 of the License, or 12 | ;; (at your option) any later version. 13 | ;; 14 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 15 | ;; is distributed in the hope that it will be useful, 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | ;; GNU General Public License for more details. 19 | ;; 20 | ;; You should have received a copy of the GNU General Public License 21 | ;; along with tr-ime. 22 | ;; If not, see . 23 | 24 | ;;; Commentary: 25 | 26 | ;; This file is part of 27 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime). 28 | ;; See tr-ime.el 29 | 30 | ;;; Code: 31 | 32 | ;; 33 | ;; ユーザ設定用 34 | ;; 35 | 36 | (defgroup tr-ime-core nil 37 | "コア機能設定. 38 | 39 | コア機能の設定です。通常は設定変更しないでください。" 40 | :group 'tr-ime) 41 | 42 | (defgroup tr-ime-openstatus nil 43 | "IME 状態変更・状態取得." 44 | :group 'tr-ime-core) 45 | 46 | ;; 47 | ;; Emacs 28 standard 48 | ;; 49 | 50 | (defcustom tr-ime-openstatus-emacs28-open-check-counter 10 51 | "GNU Emacs 28 の IME 状態変更関数使用後の状態確認回数上限 (standard). 52 | 53 | GNU Emacs 28 で standard の場合は 54 | IME 状態変更関数 \"w32-set-ime-open-status\" を使うが、 55 | これを呼んだ直後に IME 状態確認関数 \"w32-get-ime-open-status\" を呼んでも、 56 | 状態変更前を示す返り値が得られることがある。 57 | そこで、ここで設定した回数を上限として状態変更が完了するまで確認する。 58 | 例えば 3 に設定すると最大で 3 回確認するが、 59 | 1 回目や 2 回目で完了していたらそこで打ち切る。 60 | 0 を設定した場合は一切完了確認しない。" 61 | :type 'integer 62 | :group 'tr-ime-openstatus) 63 | 64 | (declare-function w32-set-ime-open-status "w32fns.c" (status)) ; Emacs 28 65 | (declare-function w32-get-ime-open-status "w32fns.c") ; Emacs 28 66 | 67 | (defun tr-ime-openstatus--get-mode-emacs28 () 68 | "GNU Emacs 28 standard 向け ime-get-mode 実装. 69 | 70 | GNU Emacs 28 の \"w32-get-ime-open-status\" で 71 | IME パッチの ime-force-on をエミュレーションする。 72 | 選択されたフレームが w32 のときは、 73 | IME が OFF なら nil を、ON ならそれ以外を返す。 74 | 非 w32 のときは常に nil を返す。" 75 | (if (eq (framep (selected-frame)) 'w32) 76 | (w32-get-ime-open-status) 77 | nil)) 78 | 79 | (defun tr-ime-openstatus--force-on-emacs28 (&optional _dummy) 80 | "GNU Emacs 28 standard 向け ime-force-on 実装. 81 | 82 | GNU Emacs 28 の \"w32-set-ime-open-status\" で 83 | IME パッチの ime-force-on をエミュレーションする。 84 | 選択されたフレームが w32 のときは IME が on になる。 85 | 非 w32 のときは何もしない。" 86 | (when (eq (framep (selected-frame)) 'w32) 87 | (w32-set-ime-open-status t) 88 | (let ((counter 0)) 89 | (while (and (< counter tr-ime-openstatus-emacs28-open-check-counter) 90 | (not (w32-get-ime-open-status))) 91 | (thread-yield) 92 | (setq counter (1+ counter)))))) 93 | 94 | (defun tr-ime-openstatus--force-off-emacs28 (&optional _dummy) 95 | "GNU Emacs 28 standard 向け ime-force-off 実装. 96 | 97 | GNU Emacs 28 の \"w32-set-ime-open-status\" で 98 | IME パッチの ime-force-off をエミュレーションする。 99 | 選択されたフレームが w32 のときは IME が off になる。 100 | 非 w32 のときは何もしない。" 101 | (when (eq (framep (selected-frame)) 'w32) 102 | (w32-set-ime-open-status nil) 103 | (let ((counter 0)) 104 | (while (and (< counter tr-ime-openstatus-emacs28-open-check-counter) 105 | (w32-get-ime-open-status)) 106 | (thread-yield) 107 | (setq counter (1+ counter)))))) 108 | 109 | ;; 110 | ;; Emacs 27 standard 111 | ;; 112 | 113 | (declare-function tr-ime-mod--setopenstatus "tr-ime-mod" 114 | (arg1 arg2)) 115 | (declare-function tr-ime-mod--getopenstatus "tr-ime-mod" 116 | (arg1)) 117 | 118 | (defun tr-ime-openstatus--get-mode-emacs27 () 119 | "GNU Emacs 27 standard 向け ime-get-mode 実装. 120 | 121 | C 実装モジュールで IME パッチの ime-get-mode をエミュレーションする。 122 | 選択されたフレームに window-id パラメータがある(w32 フレーム)ときは、 123 | IME が OFF なら nil を、ON ならそれ以外を返す。 124 | 無いときは常に nil を返す。" 125 | (let ((win-id (frame-parameter nil 'window-id))) 126 | (if win-id 127 | (tr-ime-mod--getopenstatus (string-to-number win-id)) 128 | nil))) 129 | 130 | (defun tr-ime-openstatus--force-on-emacs27 (&optional _dummy) 131 | "GNU Emacs 27 standard 向け ime-force-on 実装. 132 | 133 | C 実装モジュールで IME パッチの ime-force-on をエミュレーションする。 134 | 選択されたフレームに window-id パラメータがある(w32 フレーム)ときは、 135 | IME が on になる。無いときは何もしない。" 136 | (let ((win-id (frame-parameter nil 'window-id))) 137 | (when win-id 138 | (tr-ime-mod--setopenstatus (string-to-number win-id) t)))) 139 | 140 | (defun tr-ime-openstatus--force-off-emacs27 (&optional _dummy) 141 | "GNU Emacs 27 standard 向け ime-force-off 実装. 142 | 143 | C 実装モジュールで IME パッチの ime-force-off をエミュレーションする。 144 | 選択されたフレームに window-id パラメータがある(w32 フレーム)ときは、 145 | IME が off になる。無いときは何もしない。" 146 | (let ((win-id (frame-parameter nil 'window-id))) 147 | (when win-id 148 | (tr-ime-mod--setopenstatus (string-to-number win-id) nil)))) 149 | 150 | ;; 151 | ;; advanced 152 | ;; 153 | 154 | (declare-function tr-ime-modadv--setopenstatus "tr-ime-modadv" 155 | (arg1 arg2)) 156 | (declare-function tr-ime-modadv--getopenstatus "tr-ime-modadv" 157 | (arg1)) 158 | 159 | (defun tr-ime-openstatus--get-mode-advanced () 160 | "Advanced 向け ime-get-mode 実装. 161 | 162 | C++ 実装モジュールで IME パッチの ime-get-mode をエミュレーションする。 163 | 選択されたフレームに window-id パラメータがある(w32 フレーム)ときは、 164 | IME が OFF なら nil を、ON ならそれ以外を返す。 165 | 無いときは常に nil を返す。 166 | メッセージフックおよびサブクラス化が有効である必要がある。" 167 | (let ((win-id (frame-parameter nil 'window-id))) 168 | (if win-id 169 | (tr-ime-modadv--getopenstatus (string-to-number win-id)) 170 | nil))) 171 | 172 | (defun tr-ime-openstatus--force-on-advanced (&optional _dummy) 173 | "Advanced 向け ime-force-on 実装. 174 | 175 | C++ 実装モジュールで IME パッチの ime-force-on をエミュレーションする。 176 | 選択されたフレームに window-id パラメータがある(w32 フレーム)ときは、 177 | IME が on になる。無いときは何もしない。 178 | メッセージフックおよびサブクラス化が有効である必要がある。" 179 | (let ((win-id (frame-parameter nil 'window-id))) 180 | (when win-id 181 | (tr-ime-modadv--setopenstatus (string-to-number win-id) t)))) 182 | 183 | (defun tr-ime-openstatus--force-off-advanced (&optional _dummy) 184 | "Advanced 向け ime-force-off 実装. 185 | 186 | C++ 実装モジュールで IME パッチの ime-force-off をエミュレーションする。 187 | 選択されたフレームに window-id パラメータがある(w32 フレーム)ときは、 188 | IME が off になる。無いときは何もしない。 189 | メッセージフックおよびサブクラス化が有効である必要がある。" 190 | (let ((win-id (frame-parameter nil 'window-id))) 191 | (when win-id 192 | (tr-ime-modadv--setopenstatus (string-to-number win-id) nil)))) 193 | 194 | ;; 195 | ;; define aliases 196 | ;; 197 | 198 | (defalias 'tr-ime-openstatus-get-mode 199 | (cond 200 | ((and (boundp 'tr-ime-enabled-features) 201 | (eq tr-ime-enabled-features 'advanced)) 202 | #'tr-ime-openstatus--get-mode-advanced) 203 | ((fboundp #'w32-get-ime-open-status) 204 | #'tr-ime-openstatus--get-mode-emacs28) 205 | (t 206 | #'tr-ime-openstatus--get-mode-emacs27)) 207 | "IME 状態を返す関数 208 | 209 | IME パッチの ime-get-mode 互換。 210 | IME が OFF なら nil を、ON ならそれ以外を返す。") 211 | 212 | (defalias 'tr-ime-openstatus-force-on 213 | (cond 214 | ((and (boundp 'tr-ime-enabled-features) 215 | (eq tr-ime-enabled-features 'advanced)) 216 | #'tr-ime-openstatus--force-on-advanced) 217 | ((fboundp #'w32-set-ime-open-status) 218 | #'tr-ime-openstatus--force-on-emacs28) 219 | (t 220 | #'tr-ime-openstatus--force-on-emacs27)) 221 | "IME を on にする関数 222 | 223 | IME パッチの ime-force-on 互換。") 224 | 225 | (defalias 'tr-ime-openstatus-force-off 226 | (cond 227 | ((and (boundp 'tr-ime-enabled-features) 228 | (eq tr-ime-enabled-features 'advanced)) 229 | #'tr-ime-openstatus--force-off-advanced) 230 | ((fboundp #'w32-set-ime-open-status) 231 | #'tr-ime-openstatus--force-off-emacs28) 232 | (t 233 | #'tr-ime-openstatus--force-off-emacs27)) 234 | "IME を off にする関数 235 | 236 | IME パッチの ime-force-on 互換。") 237 | 238 | ;; 239 | ;; define obsolete functions 240 | ;; 241 | 242 | (define-obsolete-function-alias 'ime-get-mode 243 | #'tr-ime-openstatus-get-mode "2020") 244 | 245 | (define-obsolete-function-alias 'ime-force-on 246 | #'tr-ime-openstatus-force-on "2020") 247 | 248 | (define-obsolete-function-alias 'ime-force-off 249 | #'tr-ime-openstatus-force-off "2020") 250 | 251 | ;; 252 | ;; provide 253 | ;; 254 | 255 | (provide 'tr-ime-openstatus) 256 | 257 | ;; Local Variables: 258 | ;; coding: utf-8 259 | ;; End: 260 | 261 | ;;; tr-ime-openstatus.el ends here 262 | -------------------------------------------------------------------------------- /lisp/tr-ime-prefix-key.el: -------------------------------------------------------------------------------- 1 | ;;; tr-ime-prefix-key.el --- Handle prefix key -*- lexical-binding: t -*- 2 | 3 | ;; Copyright (C) 2020, 2022 Masamichi Hosoda 4 | 5 | ;; Author: Masamichi Hosoda 6 | ;; URL: https://github.com/trueroad/tr-emacs-ime-module 7 | 8 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 9 | ;; is free software: you can redistribute it and/or modify 10 | ;; it under the terms of the GNU General Public License as published by 11 | ;; the Free Software Foundation, either version 3 of the License, or 12 | ;; (at your option) any later version. 13 | ;; 14 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 15 | ;; is distributed in the hope that it will be useful, 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | ;; GNU General Public License for more details. 19 | ;; 20 | ;; You should have received a copy of the GNU General Public License 21 | ;; along with tr-ime. 22 | ;; If not, see . 23 | 24 | ;;; Commentary: 25 | 26 | ;; This file is part of 27 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime). 28 | ;; See tr-ime.el 29 | 30 | ;;; Code: 31 | 32 | ;; 33 | ;; ユーザ設定用 34 | ;; 35 | 36 | (defgroup tr-ime-prefix-key nil 37 | "プレフィックスキー検出 (advanced)." 38 | :group 'tr-ime) 39 | 40 | ;; 41 | ;; 検出対象リスト 42 | ;; 43 | 44 | (declare-function tr-ime-modadv--set-prefix-keys "tr-ime-modadv" 45 | (arg1 arg2)) 46 | 47 | (defvar tr-ime-prefix-key-p t) 48 | 49 | (defun tr-ime-prefix-key--list-set (symb settings) 50 | "プレフィックスキー検出対象リストを設定する. 51 | 52 | SYMB は tr-ime-prefix-key-list を指定する。 53 | SETTINGS はプレフィックスキーとして検出したいコードのリスト。" 54 | (set-default symb settings) 55 | (when tr-ime-prefix-key-p 56 | (tr-ime-modadv--set-prefix-keys 57 | (string-to-number (frame-parameter nil 'window-id)) 58 | settings))) 59 | 60 | (defcustom tr-ime-prefix-key-list '(#x20058 #x20048 #x20043 #x1b) 61 | "プレフィックスキー検出対象リスト. 62 | 63 | この設定を変更する場合には \"custom-set-variables\" を使うこと。 64 | 65 | プレフィックスキーとして検出したいコードのリスト。 66 | コードは上位 16 bit が修飾キー、下位 16 bit が修飾されるキーの 67 | バーチャルキーコードを指定する。 68 | 修飾キーは Shift (#x10000), Ctrl (#x20000), Alt (#x40000) の 69 | ビット論理和で指定する。バーチャルキーコードは Windows のものを指定する。 70 | 71 | 例えば Ctrl-x は Ctrl の修飾キー #x20000 と、 72 | X キーのバーチャルキーコード #x58 のビット論理和なので #x20058 を指定する。 73 | Ctrl-Alt-x であれば、さらに Alt の修飾キーを含めて #x60058 を指定する。" 74 | :type '(repeat integer) 75 | :set #'tr-ime-prefix-key--list-set 76 | :group 'tr-ime-prefix-key) 77 | 78 | ;; 79 | ;; プレフィックスキー(C-x など)を検出して自動的に IME off する 80 | ;; 81 | 82 | (declare-function tr-ime-modadv--resume-prefix-key "tr-ime-modadv") 83 | 84 | (defun tr-ime-prefix-key--set (symb bool) 85 | "プレフィックスキーを検出して自動的に IME off するか否か設定する. 86 | 87 | SYMB には tr-ime-prefix-key-p を指定する。 88 | BOOL が non-nil ならプレフィックスキーを検出して IME off する。 89 | あわせて standard で同様な機能を持つワークアラウンドを無効にする。 90 | BOOL が nil なら停止する。" 91 | (if bool 92 | (when (and (boundp 'tr-ime-enabled-features) 93 | (eq tr-ime-enabled-features 'advanced)) 94 | ;; ここで custom-set-variables を使うと init.el に 95 | ;; 設定が書き込まれてしまうので直接 setter を使って無効に設定する 96 | (when (fboundp 'tr-ime-workaround-prefix-key--set) 97 | (let (_dummy) 98 | (tr-ime-workaround-prefix-key--set '_dummy nil))) 99 | (tr-ime-modadv--set-prefix-keys 100 | (string-to-number (frame-parameter nil 'window-id)) 101 | tr-ime-prefix-key-list) 102 | (add-hook 'pre-command-hook #'tr-ime-modadv--resume-prefix-key)) 103 | (when (fboundp 'tr-ime-modadv--set-prefix-keys) 104 | (tr-ime-modadv--set-prefix-keys 105 | (string-to-number (frame-parameter nil 'window-id)) nil)) 106 | (remove-hook 'pre-command-hook #'tr-ime-modadv--resume-prefix-key)) 107 | (set-default symb bool)) 108 | 109 | (defcustom tr-ime-prefix-key-p t 110 | "プレフィックスキーを検出して自動的に IME off するか否か. 111 | 112 | この設定を変更する場合には \"custom-set-variables\" を使うこと。 113 | 114 | コマンドのキーシーケンスになる最初のキーである 115 | プレフィックスキーを検出すると、 116 | 自動的に IME off にして、コマンド終了後に IME 状態を戻す機能。 117 | 118 | 本機能を有効にすると standard 用の 119 | プレフィックスキー検出ワークアラウンドが無効になる。" 120 | :type '(choice (const :tag "Enable" t) 121 | (const :tag "Disable" nil)) 122 | :set #'tr-ime-prefix-key--set 123 | :group 'tr-ime-prefix-key) 124 | 125 | (defun tr-ime-prefix-key-unload-function () 126 | "アンロードするためプレフィックスキー検出を無効にする." 127 | (let (_dummy) 128 | (tr-ime-prefix-key--set '_dummy nil))) 129 | 130 | ;; 131 | ;; provide 132 | ;; 133 | 134 | (provide 'tr-ime-prefix-key) 135 | 136 | ;; Local Variables: 137 | ;; coding: utf-8 138 | ;; End: 139 | 140 | ;;; tr-ime-prefix-key.el ends here 141 | -------------------------------------------------------------------------------- /lisp/tr-ime-reconversion.el: -------------------------------------------------------------------------------- 1 | ;;; tr-ime-reconversion.el --- Reconversion -*- lexical-binding: t -*- 2 | 3 | ;; Copyright (C) 2020, 2022 Masamichi Hosoda 4 | 5 | ;; Author: Masamichi Hosoda 6 | ;; URL: https://github.com/trueroad/tr-emacs-ime-module 7 | 8 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 9 | ;; is free software: you can redistribute it and/or modify 10 | ;; it under the terms of the GNU General Public License as published by 11 | ;; the Free Software Foundation, either version 3 of the License, or 12 | ;; (at your option) any later version. 13 | ;; 14 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 15 | ;; is distributed in the hope that it will be useful, 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | ;; GNU General Public License for more details. 19 | ;; 20 | ;; You should have received a copy of the GNU General Public License 21 | ;; along with tr-ime. 22 | ;; If not, see . 23 | 24 | ;;; Commentary: 25 | 26 | ;; This file is part of 27 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime). 28 | ;; See tr-ime.el 29 | 30 | ;;; Code: 31 | 32 | ;; 33 | ;; ユーザ設定用 34 | ;; 35 | 36 | (defgroup tr-ime-reconversion nil 37 | "再変換 (advanced)." 38 | :group 'tr-ime) 39 | 40 | ;; 41 | ;; 再変換 (RECONVERSION) 42 | ;; 43 | 44 | (declare-function tr-ime-modadv--notify-reconvert-string "tr-ime-modadv" 45 | (arg1 arg2 arg3)) 46 | 47 | (defun tr-ime-reconversion--notify-reconvert-string () 48 | "RECONVERTSTRING 構造体用の材料を収集して UI スレッドへ通知する. 49 | 50 | point のある行全体の文字列と、文字列中の point 位置を収集し、 51 | advanced の C++ 実装である tr-ime-modadv--notify-reconvert-string 関数を呼び、 52 | UI スレッドへ通知する。 53 | ノーマルフック tr-ime-modadv--reconvertstring-hook および 54 | tr-ime-modadv--documentfeed-hook に登録して使う。" 55 | (tr-ime-modadv--notify-reconvert-string 56 | (string-to-number (frame-parameter nil 'window-id)) 57 | (buffer-substring-no-properties 58 | (line-beginning-position) (line-end-position)) 59 | (- (point) (line-beginning-position)))) 60 | 61 | ;; 62 | ;; 設定用 63 | ;; 64 | 65 | (declare-function tr-ime-modadv--set-reconversion "tr-ime-modadv" 66 | (arg1 arg2)) 67 | 68 | (defun tr-ime-reconversion--set (symb bool) 69 | "再変換 (RECONVERSION) 動作を行うか否か設定する. 70 | 71 | SYMB には tr-ime-reconversion-p を指定する。 72 | BOOL が non-nil なら再変換動作を行う。 73 | そうでなければ行わない。" 74 | (if bool 75 | (when (and (boundp 'tr-ime-enabled-features) 76 | (eq tr-ime-enabled-features 'advanced)) 77 | (add-hook 'tr-ime-modadv--reconvertstring-hook 78 | #'tr-ime-reconversion--notify-reconvert-string) 79 | (tr-ime-modadv--set-reconversion 80 | (string-to-number (frame-parameter nil 'window-id)) t)) 81 | (when (fboundp 'tr-ime-modadv--set-reconversion) 82 | (tr-ime-modadv--set-reconversion 83 | (string-to-number (frame-parameter nil 'window-id)) nil)) 84 | (remove-hook 'tr-ime-modadv--reconvertstring-hook 85 | #'tr-ime-reconversion--notify-reconvert-string)) 86 | (set-default symb bool)) 87 | 88 | (defcustom tr-ime-reconversion-p t 89 | "再変換 (RECONVERSION) 動作を行うか否か. 90 | 91 | この設定を変更する場合には \"custom-set-variables\" を使うこと。 92 | 93 | 確定済文字列にカーソルを置いて変換キーを押すと、 94 | カーソルのあった場所の確定済文字列が未確定文字列になって、 95 | 再変換できるようになる機能。" 96 | :type '(choice (const :tag "Enable" t) 97 | (const :tag "Disable" nil)) 98 | :set #'tr-ime-reconversion--set 99 | :group 'tr-ime-reconversion) 100 | 101 | (defun tr-ime-reconversion-unload-function () 102 | "アンロードするため再変換 (RECONVERSION) を無効にする." 103 | (let (_dummy) 104 | (tr-ime-reconversion--set '_dummy nil))) 105 | 106 | ;; 107 | ;; provide 108 | ;; 109 | 110 | (provide 'tr-ime-reconversion) 111 | 112 | ;; Local Variables: 113 | ;; coding: utf-8 114 | ;; End: 115 | 116 | ;;; tr-ime-reconversion.el ends here 117 | -------------------------------------------------------------------------------- /lisp/tr-ime-recv-notify.el: -------------------------------------------------------------------------------- 1 | ;;; tr-ime-recv-notify.el --- Receive notify -*- lexical-binding: t -*- 2 | 3 | ;; Copyright (C) 2020, 2022 Masamichi Hosoda 4 | 5 | ;; Author: Masamichi Hosoda 6 | ;; URL: https://github.com/trueroad/tr-emacs-ime-module 7 | 8 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 9 | ;; is free software: you can redistribute it and/or modify 10 | ;; it under the terms of the GNU General Public License as published by 11 | ;; the Free Software Foundation, either version 3 of the License, or 12 | ;; (at your option) any later version. 13 | ;; 14 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 15 | ;; is distributed in the hope that it will be useful, 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | ;; GNU General Public License for more details. 19 | ;; 20 | ;; You should have received a copy of the GNU General Public License 21 | ;; along with tr-ime. 22 | ;; If not, see . 23 | 24 | ;;; Commentary: 25 | 26 | ;; This file is part of 27 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime). 28 | ;; See tr-ime.el 29 | 30 | ;;; Code: 31 | 32 | ;; 33 | ;; ユーザ設定用 34 | ;; 35 | 36 | (defgroup tr-ime-core nil 37 | "コア機能設定. 38 | 39 | コア機能の設定です。通常は設定変更しないでください。" 40 | :group 'tr-ime) 41 | 42 | (defgroup tr-ime-recv-notify nil 43 | "UI スレッドからの通知 (advanced)." 44 | :group 'tr-ime-core) 45 | 46 | ;; 47 | ;; UI スレッドからの通知を Lisp で受け取る 48 | ;; 49 | 50 | (declare-function tr-ime-modadv--language-change-handler "tr-ime-modadv") 51 | 52 | (defun tr-ime-recv-notify--set (symb bool) 53 | "UI スレッドからの通知を Lisp で受け取るか否か設定する. 54 | 55 | SYMB は tr-ime-recv-notify-p を指定する。 56 | BOOL が non-nil なら UI スレッドからの通知を Lisp で受け取る。 57 | そうでなければ受け取らない。" 58 | (if bool 59 | (define-key special-event-map [language-change] 60 | (lambda () 61 | (interactive) 62 | (tr-ime-modadv--language-change-handler))) 63 | (define-key special-event-map [language-change] 'ignore)) 64 | (set-default symb bool)) 65 | 66 | (defcustom tr-ime-recv-notify-p t 67 | "UI スレッドからの通知を Lisp で受け取るか否か. 68 | 69 | この設定を変更する場合には \"custom-set-variables\" を使うこと。 70 | 71 | 注意:advanced の一部の機能は 72 | UI スレッドからの通知を Lisp で受け取り、 73 | Lisp での処理結果が UI スレッドへ通知されるまで待つものがある。 74 | これらの機能が有効なまま本設定を無効にしてしまうと 75 | Lisp が通知を受け取れなくなり処理もされず、 76 | UI スレッドは返ってこない通知を待つため(一時的に) 77 | ロックしてしまうことがある。 78 | 特別な目的が無い限りは non-nil (Enable) にしておくこと。" 79 | :type '(choice (const :tag "Enable" t) 80 | (const :tag "Disable" nil)) 81 | :set #'tr-ime-recv-notify--set 82 | :group 'tr-ime-recv-notify) 83 | 84 | (defun tr-ime-recv-notify-unload-function () 85 | "アンロードするため UI スレッドからの通知を無効にする." 86 | (let (_dummy) 87 | (tr-ime-recv-notify--set '_dummy nil))) 88 | 89 | ;; 90 | ;; provide 91 | ;; 92 | 93 | (provide 'tr-ime-recv-notify) 94 | 95 | ;; Local Variables: 96 | ;; coding: utf-8 97 | ;; End: 98 | 99 | ;;; tr-ime-recv-notify.el ends here 100 | -------------------------------------------------------------------------------- /lisp/tr-ime-subclassify.el: -------------------------------------------------------------------------------- 1 | ;;; tr-ime-subclassify.el --- Subclassify frame -*- lexical-binding: t -*- 2 | 3 | ;; Copyright (C) 2020, 2022 Masamichi Hosoda 4 | 5 | ;; Author: Masamichi Hosoda 6 | ;; URL: https://github.com/trueroad/tr-emacs-ime-module 7 | 8 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 9 | ;; is free software: you can redistribute it and/or modify 10 | ;; it under the terms of the GNU General Public License as published by 11 | ;; the Free Software Foundation, either version 3 of the License, or 12 | ;; (at your option) any later version. 13 | ;; 14 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 15 | ;; is distributed in the hope that it will be useful, 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | ;; GNU General Public License for more details. 19 | ;; 20 | ;; You should have received a copy of the GNU General Public License 21 | ;; along with tr-ime. 22 | ;; If not, see . 23 | 24 | ;;; Commentary: 25 | 26 | ;; This file is part of 27 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime). 28 | ;; See tr-ime.el 29 | 30 | ;;; Code: 31 | 32 | ;; 33 | ;; ユーザ設定用 34 | ;; 35 | 36 | (defgroup tr-ime-core nil 37 | "コア機能設定. 38 | 39 | コア機能の設定です。通常は設定変更しないでください。" 40 | :group 'tr-ime) 41 | 42 | (defgroup tr-ime-subclassify nil 43 | "メッセージフックとサブクラス化 (advanced)." 44 | :group 'tr-ime-core) 45 | 46 | ;; 47 | ;; メッセージフックとサブクラス化 48 | ;; 49 | 50 | (declare-function tr-ime-modadv--install-message-hook-hwnd "tr-ime-modadv" 51 | (arg1)) 52 | (declare-function tr-ime-modadv--uninstall-message-hook-hwnd "tr-ime-modadv" 53 | (arg1)) 54 | (declare-function tr-ime-modadv--subclassify-hwnd "tr-ime-modadv" 55 | (arg1 &optional arg2)) 56 | (declare-function tr-ime-modadv--unsubclassify-hwnd "tr-ime-modadv" 57 | (&optional arg1 arg2)) 58 | (declare-function tr-ime-modadv--exists-subclassified "tr-ime-modadv") 59 | 60 | (defun tr-ime-subclassify--set (symb bool) 61 | "IME 制御のためメッセージフックしてサブクラス化するか否か設定する. 62 | 63 | SYMB は tr-ime-subclassify-p を指定する。 64 | BOOL が non-nil ならメッセージフックしてサブクラス化する。 65 | そうでなければサブクラス解除してメッセージフックを停止する。 66 | 67 | 注意:advanced のほとんどの機能は 68 | メッセージフックとサブクラス化を前提としており、 69 | これらが有効でなければ機能しないだけではなく、 70 | 設定変更すらできないものも存在する。" 71 | (if bool 72 | (progn 73 | (tr-ime-modadv--install-message-hook-hwnd 74 | (string-to-number (frame-parameter nil 'window-id))) 75 | (tr-ime-modadv--subclassify-hwnd 76 | (string-to-number (frame-parameter nil 'window-id)) nil)) 77 | (tr-ime-modadv--unsubclassify-hwnd 78 | (string-to-number (frame-parameter nil 'window-id)) nil) 79 | ;; サブクラス解除は非同期に実施されるが、 80 | ;; 解除前にメッセージフック停止すると解除できなくなるので 81 | ;; 存在確認し待機する。 82 | (let ((counter 0)) 83 | (while (and (< counter 10) 84 | (tr-ime-modadv--exists-subclassified)) 85 | (thread-yield) 86 | (setq counter (1+ counter)))) 87 | (tr-ime-modadv--uninstall-message-hook-hwnd 88 | (string-to-number (frame-parameter nil 'window-id)))) 89 | (set-default symb bool)) 90 | 91 | (defcustom tr-ime-subclassify-p t 92 | "IME 制御のためメッセージフックしてサブクラス化するか否か. 93 | 94 | この設定を変更する場合には \"custom-set-variables\" を使うこと。 95 | 96 | 注意:advanced のほとんどの機能は 97 | メッセージフックとサブクラス化を前提としており、 98 | これらが有効でなければ機能しないだけではなく、 99 | 設定変更すらできないものが存在する。 100 | 特別な目的が無い限りは non-nil (Enable) にしておくこと。" 101 | :type '(choice (const :tag "Enable" t) 102 | (const :tag "Disable" nil)) 103 | :set #'tr-ime-subclassify--set 104 | :group 'tr-ime-subclassify) 105 | 106 | (defun tr-ime-subclassify-unload-function () 107 | "アンロードするためメッセージフックとサブクラス化を無効にする." 108 | (let (_dummy) 109 | (tr-ime-subclassify--set '_dummy nil))) 110 | 111 | ;; 112 | ;; provide 113 | ;; 114 | 115 | (provide 'tr-ime-subclassify) 116 | 117 | ;; Local Variables: 118 | ;; coding: utf-8 119 | ;; End: 120 | 121 | ;;; tr-ime-subclassify.el ends here 122 | -------------------------------------------------------------------------------- /lisp/tr-ime-sync.el: -------------------------------------------------------------------------------- 1 | ;;; tr-ime-sync.el --- Sync IME openstatus -*- lexical-binding: t -*- 2 | 3 | ;; Copyright (C) 2020, 2022 Masamichi Hosoda 4 | 5 | ;; Author: Masamichi Hosoda 6 | ;; URL: https://github.com/trueroad/tr-emacs-ime-module 7 | 8 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 9 | ;; is free software: you can redistribute it and/or modify 10 | ;; it under the terms of the GNU General Public License as published by 11 | ;; the Free Software Foundation, either version 3 of the License, or 12 | ;; (at your option) any later version. 13 | ;; 14 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 15 | ;; is distributed in the hope that it will be useful, 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | ;; GNU General Public License for more details. 19 | ;; 20 | ;; You should have received a copy of the GNU General Public License 21 | ;; along with tr-ime. 22 | ;; If not, see . 23 | 24 | ;;; Commentary: 25 | 26 | ;; This file is part of 27 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime). 28 | ;; See tr-ime.el 29 | 30 | ;;; Code: 31 | 32 | ;; 33 | ;; requires 34 | ;; 35 | 36 | (require 'tr-ime-hook) 37 | (require 'tr-ime-openstatus) 38 | 39 | ;; 40 | ;; ユーザ設定用 41 | ;; 42 | 43 | (defgroup tr-ime-sync nil 44 | "IME 状態変更通知による IME/IM 状態同期 (advanced)." 45 | :group 'tr-ime) 46 | 47 | ;; 48 | ;; 状態同期 49 | ;; 50 | 51 | (defun tr-ime-sync--setopenstatus () 52 | "IME 状態変更通知時に呼ばれる関数. 53 | 54 | まずフックエミュレーション関数を呼び、 55 | これによってウィンドウやバッファの切り替え未検出があったら、 56 | アブノーマルフックが呼ばれて、IME/IM 状態が整える。 57 | 58 | その上で IME 状態と IM 状態が食い違ったら IM 状態を反転して一致させる。 59 | これにより、IME 側トリガの状態変更を IM に反映させる。" 60 | (tr-ime-hook-check) 61 | (let ((ime-status (tr-ime-openstatus-get-mode))) 62 | (cond ((and ime-status 63 | (not current-input-method)) 64 | (activate-input-method "W32-IME")) 65 | ((and (not ime-status) 66 | current-input-method) 67 | (deactivate-input-method))))) 68 | 69 | ;; 70 | ;; 設定用 71 | ;; 72 | 73 | (defun tr-ime-sync--set (symb bool) 74 | "IME 状態変更通知による IM 状態同期をするか否か設定する. 75 | 76 | SYMB には tr-ime-sync-p を指定する。 77 | BOOL が non-nil なら IME 状態変更通知による IM 状態同期をする。 78 | そうでなければ同期しない。" 79 | (if bool 80 | (progn 81 | ;; ここで custom-set-variables を使うと init.el に 82 | ;; 設定が書き込まれてしまうので直接 setter を使って無効に設定する 83 | (when (fboundp 'tr-ime-workaround-inconsistent--set) 84 | (let (_dummy) 85 | (tr-ime-workaround-inconsistent--set '_dummy nil))) 86 | (add-hook 'tr-ime-modadv--setopenstatus-hook 87 | #'tr-ime-sync--setopenstatus)) 88 | (remove-hook 'tr-ime-modadv--setopenstatus-hook 89 | #'tr-ime-sync--setopenstatus)) 90 | (set-default symb bool)) 91 | 92 | (defcustom tr-ime-sync-p t 93 | "IME 状態変更通知による IM 状態同期をするか否か. 94 | 95 | この設定を変更する場合には \"custom-set-variables\" を使うこと。 96 | 97 | Emacs 側トリガ(C-\\ やウィンドウ・バッファの切り替えなど)だけでなく、 98 | IME 側トリガ(半角/全角キーやマウスでの切り替えなど)も含め、 99 | IME 状態変更通知がきた時に、IME/IM 状態同期をする機能。 100 | 101 | 本機能を有効にすると standard 用の 102 | IME 状態食い違い検出ワークアラウンドが無効になる。" 103 | :type '(choice (const :tag "Enable" t) 104 | (const :tag "Disable" nil)) 105 | :set #'tr-ime-sync--set 106 | :group 'tr-ime-sync) 107 | 108 | (defun tr-ime-sync-unload-function () 109 | "アンロードするため IME 状態変更通知による IM 状態同期を無効にする." 110 | (let (_dummy) 111 | (tr-ime-sync--set '_dummy nil))) 112 | 113 | ;; 114 | ;; provide 115 | ;; 116 | 117 | (provide 'tr-ime-sync) 118 | 119 | ;; Local Variables: 120 | ;; coding: utf-8 121 | ;; End: 122 | 123 | ;;; tr-ime-sync.el ends here 124 | -------------------------------------------------------------------------------- /lisp/tr-ime-thread-message.el: -------------------------------------------------------------------------------- 1 | ;;; tr-ime-thread-message.el --- Thread message -*- lexical-binding: t -*- 2 | 3 | ;; Copyright (C) 2020, 2022 Masamichi Hosoda 4 | 5 | ;; Author: Masamichi Hosoda 6 | ;; URL: https://github.com/trueroad/tr-emacs-ime-module 7 | 8 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 9 | ;; is free software: you can redistribute it and/or modify 10 | ;; it under the terms of the GNU General Public License as published by 11 | ;; the Free Software Foundation, either version 3 of the License, or 12 | ;; (at your option) any later version. 13 | ;; 14 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 15 | ;; is distributed in the hope that it will be useful, 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | ;; GNU General Public License for more details. 19 | ;; 20 | ;; You should have received a copy of the GNU General Public License 21 | ;; along with tr-ime. 22 | ;; If not, see . 23 | 24 | ;;; Commentary: 25 | 26 | ;; This file is part of 27 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime). 28 | ;; See tr-ime.el 29 | 30 | ;;; Code: 31 | 32 | ;; 33 | ;; ユーザ設定用 34 | ;; 35 | 36 | (defgroup tr-ime-core nil 37 | "コア機能設定. 38 | 39 | コア機能の設定です。通常は設定変更しないでください。" 40 | :group 'tr-ime) 41 | 42 | (defgroup tr-ime-thread-message nil 43 | "スレッドメッセージ (advanced)." 44 | :group 'tr-ime-core) 45 | 46 | ;; 47 | ;; スレッドメッセージのディスパッチ 48 | ;; 49 | 50 | (declare-function tr-ime-modadv--set-dispatch-thread-message "tr-ime-modadv" 51 | (arg1)) 52 | (declare-function tr-ime-modadv--set-dispatch-thread-wm-timer "tr-ime-modadv" 53 | (arg1)) 54 | (defvar tr-ime-thread-message-dispatch-p) 55 | (defvar tr-ime-thread-message-dispatch-wm-timer-p) 56 | 57 | (defun tr-ime-thread-message--dispatch-set (symb bool) 58 | "すべてのスレッドメッセージをディスパッチするか否か設定する. 59 | 60 | SYMB は tr-ime-thread-message-dispatch-p を設定する。 61 | BOOL が non-nil ならすべてのスレッドメッセージをディスパッチする。 62 | そうでなければディスパッチしない。 63 | 64 | 本関数の設定より 65 | tr-ime-thread-message--dispatch-wm-timer-set 関数の設定が優先される。 66 | 本関数による設定を有効にしたい場合は 67 | tr-ime-thread-message--dispatch-wm-timer-set の BOOL を 68 | nil にする必要がある。 69 | 70 | GNU Emacs 27 や 28 の UI スレッドは、 71 | スレッドメッセージをディスパッチしないため IME の動作に不具合が発生する 72 | (タスクトレイの IME 状態表示アイコンが変わらない等)。 73 | そこで、本設定によって Emacs の代わりにメッセージフックが 74 | スレッドメッセージをディスパッチするようにできる。 75 | 76 | 大抵の場合はすべてのスレッドメッセージではなく 77 | WM_TIMER だけをディスパッチすればよいので、本関数ではなく 78 | tr-ime-thread-message--dispatch-wm-timer-set を使った方が良い。 79 | WM_TIMER だけではうまくいかないときに本関数を使う。 80 | 81 | ただし、将来の Emacs でスレッドメッセージをディスパッチするように修正されたら 82 | 本設定を nil にすること。 83 | さもなければひとつのスレッドメッセージを 84 | 二重にディスパッチしてしまうことになり、 85 | Emacs の動作がおかしくなってしまう。" 86 | (if (and (boundp 'tr-ime-thread-message-dispatch-wm-timer-p) 87 | (not tr-ime-thread-message-dispatch-wm-timer-p)) 88 | (tr-ime-modadv--set-dispatch-thread-message bool) 89 | (tr-ime-modadv--set-dispatch-thread-message nil)) 90 | (set-default symb bool)) 91 | 92 | (defun tr-ime-thread-message--dispatch-wm-timer-set (symb bool) 93 | "スレッドメッセージ WM_TIMER をディスパッチするか否か設定する. 94 | 95 | SYMB は tr-ime-thread-message-dispatch-wm-timer-p を設定する。 96 | BOOL が non-nil ならスレッドメッセージ WM_TIMER をディスパッチして 97 | WM_NULL にすり替えて握りつぶす。そうでなければしない。 98 | 99 | 本関数の設定は tr-ime-thread-message--dispatch-set よりも優先する。 100 | tr-ime-thread-message--dispatch-set 関数による設定を有効にしたい場合は 101 | 本関数の BOOL を nil にする必要がある。 102 | 103 | GNU Emacs 27 や 28 の UI スレッドは、 104 | スレッドメッセージをディスパッチしないため IME の動作に不具合が発生する 105 | (タスクトレイの IME 状態表示アイコンが変わらない等)。 106 | そこで、本設定によって Emacs の代わりにメッセージフックが 107 | スレッドメッセージ WM_TIMER をディスパッチするようにできる。 108 | 109 | 大抵の場合はすべてのスレッドメッセージではなく 110 | WM_TIMER だけをディスパッチすればよい。 111 | また、WM_NULL にすり替えて握りつぶすことにより 112 | 将来の Emacs でスレッドメッセージをディスパッチするように 113 | 修正されても二重ディスパッチにならないようにしている。 114 | 115 | WM_TIMER だけではうまくいかない時には本関数の BOOL を nil にして 116 | tr-ime-thread-message--dispatch-set を使って 117 | すべてのスレッドメッセージをディスパッチするとよいかもしれない。" 118 | (let (_dummy) 119 | (if bool 120 | (tr-ime-thread-message--dispatch-set '_dummy nil) 121 | (if (boundp 'tr-ime-thread-message-dispatch-p) 122 | (tr-ime-thread-message--dispatch-set 123 | '_dummy tr-ime-thread-message-dispatch-p)))) 124 | (tr-ime-modadv--set-dispatch-thread-wm-timer bool) 125 | (set-default symb bool)) 126 | 127 | (defcustom tr-ime-thread-message-dispatch-p nil 128 | "すべてのスレッドメッセージをディスパッチするか否か. 129 | 130 | この設定を変更する場合には \"custom-set-variables\" を使うこと。 131 | 132 | 本設定より 133 | tr-ime-thread-message--dispatch-wm-timer-p 設定が優先される。 134 | 本設定を有効にしたい場合は 135 | tr-ime-thread-message--dispatch-wm-timer-p を nil にする必要がある。 136 | 137 | GNU Emacs 27 や 28 の UI スレッドは、 138 | スレッドメッセージがディスパッチされない。 139 | これによって IME の動作に不具合が発生する 140 | (タスクトレイの IME 状態表示アイコンが変わらない等)。 141 | そこで、本設定によってメッセージフックが 142 | スレッドメッセージをディスパッチするようにできる。 143 | 144 | 大抵の場合はすべてのスレッドメッセージではなく 145 | WM_TIMER だけをディスパッチすればよいので、本設定ではなく 146 | tr-ime-thread-message-dispatch-wm-timer-p を使った方が良い。 147 | WM_TIMER だけではうまくいかないときに本設定を使う。 148 | 149 | ただし、将来の Emacs で 150 | スレッドメッセージをディスパッチするようになったら 151 | 本設定を nil (Disable) にすること。 152 | さもなければひとつのスレッドメッセージを 153 | 二重にディスパッチしてしまうことになり、 154 | Emacs の動作がおかしくなってしまう。" 155 | :type '(choice (const :tag "Enable" t) 156 | (const :tag "Disable" nil)) 157 | :set #'tr-ime-thread-message--dispatch-set 158 | :group 'tr-ime-thread-message) 159 | 160 | (defcustom tr-ime-thread-message-dispatch-wm-timer-p t 161 | "スレッドメッセージ WM_TIMER をディスパッチするか否か. 162 | 163 | この設定を変更する場合には \"custom-set-variables\" を使うこと。 164 | 165 | 本設定は tr-ime-thread-message--dispatch-p よりも優先する。 166 | tr-ime-thread-message--dispatch-p の設定を有効にしたい場合は 167 | 本設定 を nil にする必要がある。 168 | 169 | GNU Emacs 27 や 28 の UI スレッドは、 170 | スレッドメッセージがディスパッチされない。 171 | これによって IME の動作に不具合が発生する 172 | (タスクトレイの IME 状態表示アイコンが変わらない等)。 173 | そこで、本設定によってメッセージフックが 174 | スレッドメッセージ WM_TIMER をディスパッチするようにできる。 175 | 176 | 大抵の場合はすべてのスレッドメッセージではなく 177 | WM_TIMER だけをディスパッチすればよい。 178 | また、WM_NULL にすり替えて握りつぶすことにより 179 | 将来の Emacs でスレッドメッセージをディスパッチするように 180 | 修正されても二重ディスパッチにならないようにしている。 181 | 182 | WM_TIMER だけではうまくいかない時には本設定を nil にして 183 | tr-ime-thread-message-dispatch-p を使って 184 | すべてのスレッドメッセージをディスパッチするとよいかもしれない。" 185 | :type '(choice (const :tag "Enable" t) 186 | (const :tag "Disable" nil)) 187 | :set #'tr-ime-thread-message--dispatch-wm-timer-set 188 | :group 'tr-ime-thread-message) 189 | 190 | (defun tr-ime-thread-message-unload-function () 191 | "アンロードするためスレッドメッセージのディスパッチを無効にする." 192 | (let (_dummy) 193 | (tr-ime-thread-message--dispatch-set '_dummy nil) 194 | (tr-ime-thread-message--dispatch-wm-timer-set '_dummy nil))) 195 | 196 | ;; 197 | ;; provide 198 | ;; 199 | 200 | (provide 'tr-ime-thread-message) 201 | 202 | ;; Local Variables: 203 | ;; coding: utf-8 204 | ;; End: 205 | 206 | ;;; tr-ime-thread-message.el ends here 207 | -------------------------------------------------------------------------------- /lisp/tr-ime-workaround-inconsistent.el: -------------------------------------------------------------------------------- 1 | ;;; tr-ime-workaround-inconsistent.el --- Fix inconsistent workaround -*- lexical-binding: t -*- 2 | 3 | ;; Copyright (C) 2020, 2022 Masamichi Hosoda 4 | 5 | ;; Author: Masamichi Hosoda 6 | ;; URL: https://github.com/trueroad/tr-emacs-ime-module 7 | 8 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 9 | ;; is free software: you can redistribute it and/or modify 10 | ;; it under the terms of the GNU General Public License as published by 11 | ;; the Free Software Foundation, either version 3 of the License, or 12 | ;; (at your option) any later version. 13 | ;; 14 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 15 | ;; is distributed in the hope that it will be useful, 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | ;; GNU General Public License for more details. 19 | ;; 20 | ;; You should have received a copy of the GNU General Public License 21 | ;; along with tr-ime. 22 | ;; If not, see . 23 | 24 | ;;; Commentary: 25 | 26 | ;; This file is part of 27 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime). 28 | ;; See tr-ime.el 29 | 30 | ;;; Code: 31 | 32 | ;; 33 | ;; requires 34 | ;; 35 | 36 | (require 'tr-ime-openstatus) 37 | (require 'tr-ime-hook) 38 | 39 | ;; 40 | ;; ユーザ設定用 41 | ;; 42 | 43 | (defgroup tr-ime-workaround nil 44 | "ワークアラウンド設定." 45 | :group 'tr-ime) 46 | 47 | (defgroup tr-ime-workaround-inconsistent nil 48 | "IME 状態食い違い検出 (standard) 49 | 50 | advanced では、このワークアラウンドではなく、 51 | advanced の IME 状態変更通知による IM 状態同期を使うこと。" 52 | :group 'tr-ime-workaround) 53 | 54 | ;; 55 | ;; IME 状態の食い違いを検出して修正するワークアラウンド 56 | ;; 57 | 58 | (defcustom tr-ime-workaround-inconsistentent-polling-time 1.0 59 | "IME 状態食い違い検出修正ワークアラウンド用ポーリング時間(秒)." 60 | :type 'float 61 | :group 'tr-ime-workaround-inconsistent) 62 | 63 | (defvar tr-ime-workaround-inconsistent--timer nil 64 | "IME 状態食い違い検出修正ワークアラウンド用タイマ.") 65 | 66 | (defun tr-ime-workaround-inconsistent--polling-handler () 67 | "IME 状態食い違い検出修正ワークアラウンドのためのポーリングで呼ばれる関数. 68 | 69 | まずフックエミュレーション関数を呼ぶ。 70 | これによってウィンドウやバッファの切り替え未検出があったら、 71 | アブノーマルフックが呼ばれて、IME/IM 状態が整えられる。 72 | 73 | その上で IME 状態と IM 状態が食い違ったら IM 状態を反転して一致させる。 74 | これにより、IME 側トリガの状態変更を IM に反映させる。" 75 | (tr-ime-hook-check) 76 | (let ((ime-status (tr-ime-openstatus-get-mode))) 77 | (cond ((and ime-status 78 | (not current-input-method)) 79 | (activate-input-method "W32-IME")) 80 | ((and (not ime-status) 81 | current-input-method) 82 | (deactivate-input-method))))) 83 | 84 | ;; 85 | ;; 設定用 86 | ;; 87 | 88 | (defun tr-ime-workaround-inconsistent--set (symb bool) 89 | "IME 状態食い違い検出修正ワークアラウンドを動作させるか否か設定する. 90 | 91 | SYMB は tr-ime-workaround-inconsistent-p を指定すること。 92 | BOOL が non-nil ならワークアラウンド有効で動作する。 93 | そうでなければワークアラウンド無効で動作しない。" 94 | (when tr-ime-workaround-inconsistent--timer 95 | (cancel-timer tr-ime-workaround-inconsistent--timer) 96 | (setq tr-ime-workaround-inconsistent--timer nil)) 97 | (when (and bool 98 | (boundp 'tr-ime-enabled-features) 99 | (eq tr-ime-enabled-features 'standard)) 100 | (setq tr-ime-workaround-inconsistent--timer 101 | (run-at-time 102 | t tr-ime-workaround-inconsistentent-polling-time 103 | #'tr-ime-workaround-inconsistent--polling-handler))) 104 | (set-default symb bool)) 105 | 106 | (defcustom tr-ime-workaround-inconsistent-p t 107 | "IME 状態食い違い検出修正ワークアラウンドを動作させるか否か. 108 | 109 | この設定を変更する場合には \"custom-set-variables\" を使うこと。 110 | 111 | IME 側トリガの状態変更(半角/全角キーやマウスでの切り替え)を 112 | 定期的なタイマによるポーリングで検出して IM 側を同期させるための機構。" 113 | :type '(choice (const :tag "Enable" t) 114 | (const :tag "Disable" nil)) 115 | :set #'tr-ime-workaround-inconsistent--set 116 | :group 'tr-ime-workaround-inconsistent) 117 | 118 | (defun tr-ime-workaround-inconsistent-unload-function () 119 | "アンロードするため IME 状態食い違い検出修正ワークアラウンドを無効にする." 120 | (let (_dummy) 121 | (tr-ime-workaround-inconsistent--set '_dummy nil))) 122 | 123 | ;; 124 | ;; provide 125 | ;; 126 | 127 | (provide 'tr-ime-workaround-inconsistent) 128 | 129 | ;; Local Variables: 130 | ;; coding: utf-8 131 | ;; End: 132 | 133 | ;;; tr-ime-workaround-inconsistent.el ends here 134 | -------------------------------------------------------------------------------- /lisp/tr-ime-workaround-isearch.el: -------------------------------------------------------------------------------- 1 | ;;; tr-ime-workaround-isearch.el --- Workaround isearch-mode -*- lexical-binding: t -*- 2 | 3 | ;; Copyright (C) 2020, 2022 Masamichi Hosoda 4 | 5 | ;; Author: Masamichi Hosoda 6 | ;; URL: https://github.com/trueroad/tr-emacs-ime-module 7 | 8 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 9 | ;; is free software: you can redistribute it and/or modify 10 | ;; it under the terms of the GNU General Public License as published by 11 | ;; the Free Software Foundation, either version 3 of the License, or 12 | ;; (at your option) any later version. 13 | ;; 14 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 15 | ;; is distributed in the hope that it will be useful, 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | ;; GNU General Public License for more details. 19 | ;; 20 | ;; You should have received a copy of the GNU General Public License 21 | ;; along with tr-ime. 22 | ;; If not, see . 23 | 24 | ;;; Commentary: 25 | 26 | ;; This file is part of 27 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime). 28 | ;; See tr-ime.el 29 | 30 | ;;; Code: 31 | 32 | ;; 33 | ;; ユーザ設定用 34 | ;; 35 | 36 | (defgroup tr-ime-workaround nil 37 | "ワークアラウンド設定." 38 | :group 'tr-ime) 39 | 40 | (defgroup tr-ime-workaround-isearch nil 41 | "\"isearch-mode\" (advanced)." 42 | :group 'tr-ime-workaround) 43 | 44 | ;; 45 | ;; isearch-mode 時の Alt + 半角/全角ワークアラウンド 46 | ;; 47 | 48 | (defcustom tr-ime-workaround-isearch-delayed-update-time 0.0001 49 | "Alt + 半角/全角ワークアラウンドで使うタイマの待ち時間(秒)." 50 | :type 'float 51 | :group 'tr-ime-workaround-isearch) 52 | 53 | (defun tr-ime-workaround-isearch--delayed-update () 54 | "アイドル状態になったら \"isearch-mode\" のエコーエリアを再表示する. 55 | 56 | advanced で \"isearch-mode\" 時に Alt + 半角/全角キー操作をすると、 57 | なぜかエコーエリアが消えてしまう。 58 | キー操作時に再表示させても効果が無い 59 | (恐らくキー操作後にくるイベントか何かで消されている)ので、 60 | Emacs がアイドル状態になったら動作するタイマで再表示させる。" 61 | (interactive) 62 | (run-with-idle-timer tr-ime-workaround-isearch-delayed-update-time 63 | nil #'isearch-update)) 64 | 65 | (defun tr-ime-workaround-isearch--delayed-update-set (symb bool) 66 | "Alt + 半角/全角ワークアラウンドを動作させるか否か設定. 67 | 68 | advanced で \"isearch-mode\" 時に Alt + 半角/全角キー操作をすると、 69 | なぜかエコーエリアが消えてしまう対策のワークアラウンドを動作させるか否か 70 | 設定する。 71 | 72 | SYMB には tr-ime-workaround-isearch-delayed-update-p を指定する。 73 | BOOL が non-nil なら動作させる。それ以外なら停止させる。" 74 | (if bool 75 | (define-key isearch-mode-map [M-kanji] 76 | 'tr-ime-workaround-isearch--delayed-update) 77 | (define-key isearch-mode-map [M-kanji] 'ignore)) 78 | (set-default symb bool)) 79 | 80 | (defcustom tr-ime-workaround-isearch-delayed-update-p t 81 | "Alt + 半角/全角ワークアラウンドを動作させるか否か. 82 | 83 | この設定を変更する場合には \"custom-set-variables\" を使うこと。 84 | 85 | advanced で \"isearch-mode\" 時に Alt + 半角/全角キー操作をすると、 86 | なぜかエコーエリアが消えてしまう。 87 | キー操作時に再表示させても効果が無い 88 | (恐らくキー操作後にくるイベントか何かで消されている)ので、 89 | Emacs がアイドル状態になったら動作するタイマで再表示させるワークアラウンド。" 90 | :type '(choice (const :tag "Enable" t) 91 | (const :tag "Disable" nil)) 92 | :set #'tr-ime-workaround-isearch--delayed-update-set 93 | :group 'tr-ime-workaround-isearch) 94 | 95 | (defun tr-ime-workaround-isearch-unload-function () 96 | "アンロードするため \"isearch-mode\" ワークアラウンドを無効にする." 97 | (let (_dummy) 98 | (tr-ime-workaround-isearch--delayed-update-set '_dummy nil))) 99 | 100 | ;; 101 | ;; provide 102 | ;; 103 | 104 | (provide 'tr-ime-workaround-isearch) 105 | 106 | ;; Local Variables: 107 | ;; coding: utf-8 108 | ;; End: 109 | 110 | ;;; tr-ime-workaround-isearch.el ends here 111 | -------------------------------------------------------------------------------- /lisp/tr-ime-workaround-prefix-key.el: -------------------------------------------------------------------------------- 1 | ;;; tr-ime-workaround-prefix-key.el --- Prefix key workaround -*- lexical-binding: t -*- 2 | 3 | ;; Copyright (C) 2020, 2022 Masamichi Hosoda 4 | 5 | ;; Author: Masamichi Hosoda 6 | ;; URL: https://github.com/trueroad/tr-emacs-ime-module 7 | 8 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 9 | ;; is free software: you can redistribute it and/or modify 10 | ;; it under the terms of the GNU General Public License as published by 11 | ;; the Free Software Foundation, either version 3 of the License, or 12 | ;; (at your option) any later version. 13 | ;; 14 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 15 | ;; is distributed in the hope that it will be useful, 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | ;; GNU General Public License for more details. 19 | ;; 20 | ;; You should have received a copy of the GNU General Public License 21 | ;; along with tr-ime. 22 | ;; If not, see . 23 | 24 | ;;; Commentary: 25 | 26 | ;; This file is part of 27 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime). 28 | ;; See tr-ime.el 29 | 30 | ;;; Code: 31 | 32 | ;; 33 | ;; require 34 | ;; 35 | 36 | (require 'tr-ime-openstatus) 37 | 38 | ;; 39 | ;; ユーザ設定用 40 | ;; 41 | 42 | (defgroup tr-ime-workaround nil 43 | "ワークアラウンド設定." 44 | :group 'tr-ime) 45 | 46 | (defgroup tr-ime-workaround-prefix-key nil 47 | "プレフィックスキー検出 (standard) 48 | 49 | advanced では、このワークアラウンドではなく、 50 | advanced のプレフィックスキー検出を使うこと。" 51 | :group 'tr-ime-workaround) 52 | 53 | ;; 54 | ;; プレフィックスキー(C-x など)を検出して IME OFF するワークアラウンド 55 | ;; 56 | 57 | (defcustom tr-ime-workaround-prefix-key-polling-time 0.1 58 | "ポーリング時間(秒)." 59 | :type 'float 60 | :group 'tr-ime-workaround-prefix-key) 61 | 62 | (defcustom tr-ime-workaround-prefix-key-list '(?\C-x ?\C-h ?\C-c ?\e) 63 | "検出対象リスト. 64 | 65 | プレフィックスキーとして検出したいキーのリスト。" 66 | :type '(repeat integer) 67 | :group 'tr-ime-workaround-prefix-key) 68 | 69 | (defvar tr-ime-workaround-prefix-key--detected-p nil 70 | "プレフィックスキー検出フラグ.") 71 | (defvar tr-ime-workaround-prefix-key--before-ime-mode-p nil 72 | "プレフィックスキー検出時の IME 状態保存用.") 73 | (defvar tr-ime-workaround-prefix-key--timer nil 74 | "プレフィックスキー検出用タイマ.") 75 | 76 | (defun tr-ime-workaround-prefix-key--polling-handler () 77 | "プレフィックスキー検出のためのポーリングで呼ばれる関数. 78 | 79 | 未検出かつ最後に押されたキーが検出対象リストのいずれかだったら、 80 | IME 状態を保存してから IME off にし、フラグを検出済にする。" 81 | (unless tr-ime-workaround-prefix-key--detected-p 82 | (let ((keys (this-single-command-keys))) 83 | (when (and (not (equal [] keys)) 84 | (member (aref keys 0) tr-ime-workaround-prefix-key-list)) 85 | (setq tr-ime-workaround-prefix-key--before-ime-mode-p 86 | (tr-ime-openstatus-get-mode)) 87 | (tr-ime-openstatus-force-off) 88 | (setq tr-ime-workaround-prefix-key--detected-p t))))) 89 | 90 | (defun tr-ime-workaround-prefix-key--restore-ime-mode () 91 | "自動 IME off から IME 状態を復帰させる関数. 92 | 93 | Emacs の標準的なフックの一つ \"pre-command-hook\" に登録する。 94 | \"pre-command-hook\" によって、ほとんどのコマンドの動作後に呼ばれる。 95 | 96 | この関数の動作は、 97 | プレフィックスキー検出済であったら未検出に変え、 98 | 検出時の IME 状態が on であれば IME on に復帰する。 99 | 未検出であったら何もしない。" 100 | (when tr-ime-workaround-prefix-key--detected-p 101 | (setq tr-ime-workaround-prefix-key--detected-p nil) 102 | (when tr-ime-workaround-prefix-key--before-ime-mode-p 103 | (tr-ime-openstatus-force-on)))) 104 | 105 | ;; 106 | ;; 設定用 107 | ;; 108 | 109 | (defun tr-ime-workaround-prefix-key--set (symb bool) 110 | "プレフィックスキー検出ワークアラウンドを動作させるか否か設定する. 111 | 112 | SYMB は tr-ime-workaround-prefix-key-p を指定すること。 113 | BOOL が non-nil ならワークアラウンド有効で動作する。 114 | そうでなければワークアラウンド無効で動作しない。" 115 | (if bool 116 | (when (and (boundp 'tr-ime-enabled-features) 117 | (eq tr-ime-enabled-features 'standard)) 118 | (setq tr-ime-workaround-prefix-key--detected-p nil) 119 | (add-hook 'pre-command-hook 120 | #'tr-ime-workaround-prefix-key--restore-ime-mode) 121 | (when tr-ime-workaround-prefix-key--timer 122 | (cancel-timer tr-ime-workaround-prefix-key--timer)) 123 | (setq tr-ime-workaround-prefix-key--timer 124 | (run-with-idle-timer 125 | tr-ime-workaround-prefix-key-polling-time t 126 | #'tr-ime-workaround-prefix-key--polling-handler))) 127 | (remove-hook 'pre-command-hook 128 | #'tr-ime-workaround-prefix-key--restore-ime-mode) 129 | (when tr-ime-workaround-prefix-key--timer 130 | (cancel-timer tr-ime-workaround-prefix-key--timer)) 131 | (setq tr-ime-workaround-prefix-key--timer nil)) 132 | (set-default symb bool)) 133 | 134 | (defcustom tr-ime-workaround-prefix-key-p t 135 | "プレフィックスキー検出ワークアラウンドを動作させるか否か. 136 | 137 | この設定を変更する場合には \"custom-set-variables\" を使うこと。 138 | 139 | コマンドのキーシーケンスになる最初のキーである 140 | プレフィックスキーをタイマによるポーリングで検出すると、 141 | 自動的に IME off にして、コマンド開始前に IME 状態を戻す機能。" 142 | :type '(choice (const :tag "Enable" t) 143 | (const :tag "Disable" nil)) 144 | :set #'tr-ime-workaround-prefix-key--set 145 | :group 'tr-ime-workaround-prefix-key) 146 | 147 | (defun tr-ime-workaround-prefix-key-unload-function () 148 | "アンロードするためプレフィックスキー検出ワークアラウンドを無効にする." 149 | (let (_dummy) 150 | (tr-ime-workaround-prefix-key--set '_dummy nil))) 151 | 152 | ;; 153 | ;; provide 154 | ;; 155 | 156 | (provide 'tr-ime-workaround-prefix-key) 157 | 158 | ;; Local Variables: 159 | ;; coding: utf-8 160 | ;; End: 161 | 162 | ;;; tr-ime-workaround-prefix-key.el ends here 163 | -------------------------------------------------------------------------------- /lisp/tr-ime.el: -------------------------------------------------------------------------------- 1 | ;;; tr-ime.el --- Emulator of IME patch for Windows -*- lexical-binding: t -*- 2 | 3 | ;; Copyright (C) 2020-2022 Masamichi Hosoda 4 | 5 | ;; Author: Masamichi Hosoda 6 | ;; URL: https://github.com/trueroad/tr-emacs-ime-module 7 | ;; Version: 0.5.0 8 | ;; Package-Requires: ((emacs "27.1") (w32-ime "0.0.1")) 9 | 10 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 11 | ;; is free software: you can redistribute it and/or modify 12 | ;; it under the terms of the GNU General Public License as published by 13 | ;; the Free Software Foundation, either version 3 of the License, or 14 | ;; (at your option) any later version. 15 | ;; 16 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) 17 | ;; is distributed in the hope that it will be useful, 18 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | ;; GNU General Public License for more details. 21 | ;; 22 | ;; You should have received a copy of the GNU General Public License 23 | ;; along with tr-ime. 24 | ;; If not, see . 25 | 26 | ;;; Commentary: 27 | 28 | ;; Emulator of GNU Emacs IME patch for Windows (tr-ime) emulates the C 29 | ;; implementation part of an IME patch for GNU Emacs that allows to input 30 | ;; Japanese using the Windows IME (Input Method Editor). On Emacs 26.2 or 31 | ;; later, Japanese input using the IME is now possible even without the IME 32 | ;; patch. However, some of the features of the IME patch are not implemented 33 | ;; in current Emacs, so it is possible to type Japanese on Emacs without the 34 | ;; IME patch, but it is not convenient. 35 | ;; 36 | ;; w32-ime.el in the w32-ime package manages the upper layer of the IME 37 | ;; patch and provides the convenient features but it could not be used on 38 | ;; emacs.exe without the IME patch applied. tr-ime emulates the lower 39 | ;; layers of the IME patches and can interact with w32-ime.el. So, using 40 | ;; tr-ime, w32-ime.el can be used on emacs.exe without the IME patch applied. 41 | ;; 42 | ;; By using tr-ime and w32-ime.el together, emacs.exe without the IME patch 43 | ;; can use the same convenient features as the IME patched emacs.exe. They 44 | ;; can display the on/off state of the IME in the mode line as UI/UX features. 45 | ;; They also have hooks to call when the IME state is changed. With these 46 | ;; hooks, you can change the color and shape of the cursor depending on the 47 | ;; IME on/off status to be visually known to the IME state. 48 | 49 | ;; To use standard features (stable but less functionality) of the tr-ime 50 | ;; package, add the following code to your init.el or .emacs 51 | ;; It loads the tr-ime-mod DLL module if you use Emacs 27. 52 | ;; 53 | ;; (tr-ime-standard-install) 54 | ;; (setq default-input-method "W32-IME") 55 | ;; (w32-ime-initialize) 56 | ;; 57 | ;; To use advanced features (experimental but more functionality) of the 58 | ;; tr-ime package, add the following code to your init.el or .emacs 59 | ;; It loads the tr-ime-modadv DLL module. 60 | ;; 61 | ;; (tr-ime-advanced-install) 62 | ;; (setq default-input-method "W32-IME") 63 | ;; (w32-ime-initialize) 64 | 65 | ;;; Code: 66 | 67 | (defgroup tr-ime nil 68 | "Emulator of GNU Emacs IME patch for Windows (tr-ime)." 69 | :group 'emacs) 70 | 71 | (defconst tr-ime--mod-abi-version 1 72 | "ABI version number of tr-ime-mod DLL.") 73 | (defconst tr-ime--mod-name (concat "tr-ime-mod-" 74 | (int-to-string tr-ime--mod-abi-version) 75 | "-" 76 | system-configuration) 77 | "Module name of tr-ime-mod (standard).") 78 | 79 | (defconst tr-ime--modadv-abi-version 2 80 | "ABI version number of tr-ime-modadv DLL.") 81 | (defconst tr-ime--modadv-name (concat 82 | "tr-ime-modadv-" 83 | (int-to-string tr-ime--modadv-abi-version) 84 | "-" 85 | system-configuration) 86 | "Module name of tr-imeadv-mod (advanced).") 87 | 88 | (defvar tr-ime-enabled-features nil 89 | "Enabled features in tr-ime (standard/advanced). 90 | 91 | If the standard features are enabled, it is set to 'standard. 92 | If the advanced features are enabled, it is set to 'advanced. 93 | If any features are not enabled, it is set to nil.") 94 | 95 | (declare-function tr-ime-download-mod-file "tr-ime-download" 96 | (name &optional no-confirm)) 97 | 98 | (defun tr-ime--c-function-p (symb) 99 | "Return non-nil if SYMB is a function that is defined in a C source." 100 | (and (fboundp symb) 101 | (subrp (symbol-function symb)))) 102 | 103 | (defun tr-ime--c-variable-p (symb) 104 | "Return non-nil if SYMB is a variable that is defined in a C source." 105 | (and (boundp symb) 106 | (not (symbol-file symb 'defvar)))) 107 | 108 | ;;;###autoload 109 | (defun tr-ime-detect-ime-patch-p () 110 | "Return non-nil if an IME patch seems to be applied to Emacs." 111 | (or (tr-ime--c-function-p 'ime-get-mode) 112 | (tr-ime--c-function-p 'ime-force-on) 113 | (tr-ime--c-function-p 'ime-force-off) 114 | (tr-ime--c-variable-p 'set-selected-window-buffer-functions) 115 | (tr-ime--c-variable-p 'select-window-functions))) 116 | 117 | ;;;###autoload 118 | (defun tr-ime-standard-install (&optional no-confirm) 119 | "Install tr-ime standard (stable but less functionality) DLL. 120 | 121 | If NO-CONFIRM is non-nil, download the necessary module DLL without 122 | confirming the user." 123 | (tr-ime-uninitialize) 124 | (cond 125 | ((not (eq window-system 'w32)) 126 | (display-warning 'tr-ime 127 | (concat 128 | "window-system is not w32. " 129 | "tr-ime cannot install standard DLL on it.") 130 | :warning)) 131 | ((tr-ime-detect-ime-patch-p) 132 | (display-warning 'tr-ime 133 | (concat 134 | "Emacs seems to have an IME patch applied. " 135 | "tr-ime cannot work on it.") 136 | :warning)) 137 | ((fboundp 'w32-get-ime-open-status) 138 | (display-warning 'tr-ime 139 | (concat 140 | "Function w32-get-ime-open-status exists. " 141 | "tr-ime standard DLL is not necessary.") 142 | :debug)) 143 | ((not (string= module-file-suffix ".dll")) 144 | (display-warning 'tr-ime 145 | (concat 146 | "module-file-suffix is not \".dll\". " 147 | "Emacs cannot load tr-ime module DLLs.") 148 | :warning)) 149 | ((locate-library tr-ime--mod-name) 150 | (display-warning 'tr-ime 151 | "tr-ime standard DLL already exists." 152 | :debug)) 153 | (t 154 | (require 'tr-ime-download) 155 | (tr-ime-download-mod-file tr-ime--mod-name no-confirm))) 156 | (tr-ime-standard-initialize)) 157 | 158 | ;;;###autoload 159 | (defun tr-ime-standard-initialize () 160 | "Initialize tr-ime standard (stable but less functionality) features." 161 | (cond 162 | ((not (eq window-system 'w32)) 163 | (display-warning 'tr-ime 164 | (concat 165 | "window-system is not w32. " 166 | "tr-ime cannot initialize on it.") 167 | :warning)) 168 | ((tr-ime-detect-ime-patch-p) 169 | (display-warning 'tr-ime 170 | (concat 171 | "Emacs seems to have an IME patch applied. " 172 | "tr-ime cannot work on it.") 173 | :warning)) 174 | ((and (not (fboundp 'w32-get-ime-open-status)) 175 | (not (string= module-file-suffix ".dll"))) 176 | (display-warning 'tr-ime 177 | (concat 178 | "module-file-suffix is not \".dll\". " 179 | "Emacs cannot load tr-ime module DLLs.") 180 | :warning)) 181 | (t 182 | (setq tr-ime-enabled-features 'standard) 183 | (unless (fboundp 'w32-get-ime-open-status) 184 | (require 'tr-ime-mod tr-ime--mod-name)) 185 | (require 'tr-ime-openstatus) 186 | (require 'tr-ime-hook) 187 | (require 'tr-ime-workaround-prefix-key) 188 | (require 'tr-ime-workaround-inconsistent) 189 | (define-key global-map [M-kanji] 'toggle-input-method) 190 | (define-key isearch-mode-map [M-kanji] 'isearch-toggle-input-method) 191 | (require 'w32-ime)))) 192 | 193 | ;;;###autoload 194 | (defun tr-ime-advanced-install (&optional no-confirm) 195 | "Install tr-ime advanced (experimental but more functionality) DLL. 196 | 197 | If NO-CONFIRM is non-nil, download the necessary module DLL without 198 | confirming the user." 199 | (tr-ime-uninitialize) 200 | (cond 201 | ((not (eq window-system 'w32)) 202 | (display-warning 'tr-ime 203 | (concat 204 | "window-system is not w32. " 205 | "tr-ime cannot install advanced DLL on it.") 206 | :warning)) 207 | ((tr-ime-detect-ime-patch-p) 208 | (display-warning 'tr-ime 209 | (concat 210 | "Emacs seems to have an IME patch applied. " 211 | "tr-ime cannot work on it.") 212 | :warning)) 213 | ((not (string= module-file-suffix ".dll")) 214 | (display-warning 'tr-ime 215 | (concat 216 | "module-file-suffix is not \".dll\". " 217 | "Emacs cannot load tr-ime module DLLs.") 218 | :warning)) 219 | ((locate-library tr-ime--modadv-name) 220 | (display-warning 'tr-ime 221 | "tr-ime advanced DLL already exists." 222 | :debug)) 223 | (t 224 | (require 'tr-ime-download) 225 | (tr-ime-download-mod-file tr-ime--modadv-name no-confirm))) 226 | (tr-ime-advanced-initialize)) 227 | 228 | ;;;###autoload 229 | (defun tr-ime-advanced-initialize () 230 | "Initialize tr-ime advanced (experimental but more functionality) features." 231 | (cond 232 | ((not (eq window-system 'w32)) 233 | (display-warning 'tr-ime 234 | (concat 235 | "window-system is not w32. " 236 | "tr-ime cannot initialize on it.") 237 | :warning)) 238 | ((tr-ime-detect-ime-patch-p) 239 | (display-warning 'tr-ime 240 | (concat 241 | "Emacs seems to have an IME patch applied. " 242 | "tr-ime cannot work on it.") 243 | :warning)) 244 | ((not (string= module-file-suffix ".dll")) 245 | (display-warning 'tr-ime 246 | (concat 247 | "module-file-suffix is not \".dll\". " 248 | "Emacs cannot load tr-ime module DLLs.") 249 | :warning)) 250 | (t 251 | (setq tr-ime-enabled-features 'advanced) 252 | (require 'tr-ime-modadv tr-ime--modadv-name) 253 | (require 'tr-ime-openstatus) 254 | (require 'tr-ime-hook) 255 | (require 'tr-ime-subclassify) 256 | (require 'tr-ime-thread-message) 257 | (require 'tr-ime-recv-notify) 258 | (require 'tr-ime-font) 259 | (require 'tr-ime-isearch) 260 | (require 'tr-ime-workaround-isearch) 261 | (require 'tr-ime-prefix-key) 262 | (require 'tr-ime-sync) 263 | (require 'tr-ime-reconversion) 264 | (require 'tr-ime-documentfeed) 265 | (require 'tr-ime-debug) 266 | (define-key global-map [M-kanji] 'ignore) 267 | (require 'w32-ime)))) 268 | 269 | ;;;###autoload 270 | (defun tr-ime-uninitialize () 271 | "Uninitialize tr-ime features." 272 | (when (eq tr-ime-enabled-features 'standard) 273 | (define-key global-map [M-kanji] 'ignore) 274 | (define-key isearch-mode-map [M-kanji] 'ignore)) 275 | (when (featurep 'tr-ime-debug) 276 | (unload-feature 'tr-ime-debug t)) 277 | (when (featurep 'tr-ime-documentfeed) 278 | (unload-feature 'tr-ime-documentfeed t)) 279 | (when (featurep 'tr-ime-reconversion) 280 | (unload-feature 'tr-ime-reconversion t)) 281 | (when (featurep 'tr-ime-sync) 282 | (unload-feature 'tr-ime-sync t)) 283 | (when (featurep 'tr-ime-prefix-key) 284 | (unload-feature 'tr-ime-prefix-key t)) 285 | (when (featurep 'tr-ime-workaround-isearch) 286 | (unload-feature 'tr-ime-workaround-isearch t)) 287 | (when (featurep 'tr-ime-isearch) 288 | (unload-feature 'tr-ime-isearch t)) 289 | (when (featurep 'tr-ime-font) 290 | (unload-feature 'tr-ime-font t)) 291 | (when (featurep 'tr-ime-recv-notify) 292 | (unload-feature 'tr-ime-recv-notify t)) 293 | (when (featurep 'tr-ime-thread-message) 294 | (unload-feature 'tr-ime-thread-message t)) 295 | (when (featurep 'tr-ime-subclassify) 296 | (unload-feature 'tr-ime-subclassify t)) 297 | (when (featurep 'tr-ime-workaround-inconsistent) 298 | (unload-feature 'tr-ime-workaround-inconsistent t)) 299 | (when (featurep 'tr-ime-workaround-prefix-key) 300 | (unload-feature 'tr-ime-workaround-prefix-key t)) 301 | (when (featurep 'tr-ime-hook) 302 | (unload-feature 'tr-ime-hook t)) 303 | (when (featurep 'tr-ime-openstatus) 304 | (unload-feature 'tr-ime-openstatus t)) 305 | (when (featurep 'tr-ime-modadv) 306 | (unload-feature 'tr-ime-modadv t)) 307 | (when (featurep 'tr-ime-mod) 308 | (unload-feature 'tr-ime-mod t)) 309 | (setq tr-ime-enabled-features nil)) 310 | 311 | (defun tr-ime-unload-feature () 312 | "Prepare unloading tr-ime features." 313 | (tr-ime-uninitialize)) 314 | 315 | (provide 'tr-ime) 316 | 317 | ;; Local Variables: 318 | ;; coding: utf-8 319 | ;; End: 320 | 321 | ;;; tr-ime.el ends here 322 | -------------------------------------------------------------------------------- /m4/.gitignore: -------------------------------------------------------------------------------- 1 | libtool.m4 2 | lt~obsolete.m4 3 | ltoptions.m4 4 | ltsugar.m4 5 | ltversion.m4 6 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | # 2 | # Targets 3 | # 4 | 5 | noinst_LTLIBRARIES = tr-ime-mod.la 6 | pkgmoduleexec_SCRIPTS = tr-ime-mod-$(MOD_ABI_VERSION)-$(host)$(SHREXT) 7 | CLEANFILES = tr-ime-mod-$(MOD_ABI_VERSION)-$(host)$(SHREXT) 8 | 9 | noinst_LTLIBRARIES += tr-ime-modadv.la 10 | pkgmoduleexec_SCRIPTS += tr-ime-modadv-$(MODADV_ABI_VERSION)-$(host)$(SHREXT) 11 | CLEANFILES += tr-ime-modadv-$(MODADV_ABI_VERSION)-$(host)$(SHREXT) 12 | 13 | # 14 | # Workaround for install-strip modules 15 | # 16 | 17 | INSTALL_SCRIPT = $(INSTALL_PROGRAM) 18 | 19 | # 20 | # For tr-ime-mod 21 | # 22 | 23 | tr_ime_mod_la_SOURCES = tr-ime-mod.c tr-ime-mod-resource.rc 24 | 25 | tr_ime_mod_la_LIBADD = -limm32 26 | 27 | tr_ime_mod_la_LDFLAGS = -no-undefined 28 | tr_ime_mod_la_LDFLAGS += -module 29 | tr_ime_mod_la_LDFLAGS += -avoid-version 30 | tr_ime_mod_la_LDFLAGS += -rpath $(pkgmoduleexecdir) 31 | 32 | $(objdir)/tr-ime-mod$(SHREXT): tr-ime-mod.la 33 | 34 | tr-ime-mod-$(MOD_ABI_VERSION)-$(host)$(SHREXT): \ 35 | $(objdir)/tr-ime-mod$(SHREXT) 36 | cp -p $< $@ 37 | 38 | # 39 | # For tr-ime-modadv 40 | # 41 | 42 | tr_ime_modadv_la_SOURCES = tr-ime-modadv.cc tr-ime-modadv-resource.rc \ 43 | debug-message.cc debug-message.hh lisp-in-cc.cc lisp-in-cc.hh \ 44 | get_msg_hook.cc get_msg_hook.hh get_msg_proc.cc get_msg_proc.hh \ 45 | message.cc message.hh subclass_proc.cc subclass_proc.hh \ 46 | queue.cc queue.hh 47 | 48 | tr_ime_modadv_la_LIBADD = -lgdi32 -lcomctl32 -limm32 49 | 50 | tr_ime_modadv_la_LDFLAGS = -no-undefined 51 | tr_ime_modadv_la_LDFLAGS += -module 52 | tr_ime_modadv_la_LDFLAGS += -avoid-version 53 | tr_ime_modadv_la_LDFLAGS += -rpath $(pkgmoduleexecdir) 54 | 55 | $(objdir)/tr-ime-modadv$(SHREXT): tr-ime-modadv.la 56 | 57 | tr-ime-modadv-$(MODADV_ABI_VERSION)-$(host)$(SHREXT): \ 58 | $(objdir)/tr-ime-modadv$(SHREXT) 59 | cp -p $< $@ 60 | 61 | # 62 | # For Windows Resource Script (.rc) 63 | # 64 | 65 | WINDRESFLAGS = $(DEFAULT_INCLUDES) 66 | 67 | .rc.lo: 68 | $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ 69 | --tag=RC --mode=compile \ 70 | $(WINDRES) $(WINDRESFLAGS) -i $< -o $@ 71 | 72 | # 73 | # emacs-module.h 74 | # 75 | 76 | EXTRA_DIST = emacs-27.1/emacs-module.h 77 | -------------------------------------------------------------------------------- /src/debug-message.cc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; coding: utf-8 -*- 2 | 3 | // This file is part of 4 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 5 | // https://github.com/trueroad/tr-emacs-ime-module 6 | // 7 | // Copyright (C) 2020 Masamichi Hosoda 8 | // 9 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 10 | // is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 16 | // is distributed in the hope that it will be useful, 17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | // GNU General Public License for more details. 20 | // 21 | // You should have received a copy of the GNU General Public License 22 | // along with tr-ime. 23 | // If not, see . 24 | 25 | #include "debug-message.hh" 26 | 27 | #ifdef HAVE_CONFIG_H 28 | #include "config.h" 29 | #endif 30 | 31 | #include 32 | #include 33 | 34 | #include 35 | 36 | // verbose level 37 | // 0: none 38 | // 1: fatal 39 | // 2: error 40 | // 3: warn 41 | // 4: info 42 | // 5: debug 43 | // 6: trace 44 | 45 | #ifndef NDEBUG 46 | int verbose_level = 5; 47 | #else 48 | int verbose_level = 3; 49 | #endif 50 | 51 | std::string 52 | get_format_message (DWORD dwMessageId) 53 | { 54 | LPSTR lpbuff; 55 | 56 | if (!FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER | 57 | FORMAT_MESSAGE_FROM_SYSTEM | 58 | FORMAT_MESSAGE_IGNORE_INSERTS, 59 | nullptr, 60 | dwMessageId, 61 | MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), 62 | reinterpret_cast (&lpbuff), 63 | 0, 64 | nullptr)) 65 | return "error"; 66 | 67 | std::string ret {lpbuff}; 68 | LocalFree (lpbuff); 69 | 70 | return ret; 71 | } 72 | 73 | void 74 | debug_output_reconvert_string (RECONVERTSTRING *rs) 75 | { 76 | std::stringstream ss; 77 | 78 | ss << "---RECONVERTSTRING---" << std::endl 79 | << " dwSize : " << rs->dwSize << std::endl 80 | << " dwVersion : " << rs->dwVersion << std::endl 81 | << " dwStrLen : " << rs->dwStrLen << std::endl 82 | << " dwStrOffset : " << rs->dwStrOffset << std::endl 83 | << " dwCompStrLen : " << rs->dwCompStrLen << std::endl 84 | << " dwCompStrOffset : " << rs->dwCompStrOffset << std::endl 85 | << " dwTargetStrLen : " << rs->dwTargetStrLen << std::endl 86 | << " dwTargetStrOffset: " << rs->dwTargetStrOffset << std::endl; 87 | DEBUG_MESSAGE_STATIC (ss.str ().c_str ()); 88 | 89 | auto *buff = reinterpret_cast 90 | (reinterpret_cast (rs) + sizeof (RECONVERTSTRING)); 91 | std::basic_string str (buff, rs->dwStrLen); 92 | TRACE_MESSAGE_W (L" buff = \"" << str << L"\"\n"); 93 | } 94 | -------------------------------------------------------------------------------- /src/debug-message.hh: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; coding: utf-8 -*- 2 | 3 | // This file is part of 4 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 5 | // https://github.com/trueroad/tr-emacs-ime-module 6 | // 7 | // Copyright (C) 2020 Masamichi Hosoda 8 | // 9 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 10 | // is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 16 | // is distributed in the hope that it will be useful, 17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | // GNU General Public License for more details. 20 | // 21 | // You should have received a copy of the GNU General Public License 22 | // along with tr-ime. 23 | // If not, see . 24 | 25 | #ifndef INCLUDE_GUARD_DEBUG_MESSAGE_HH 26 | #define INCLUDE_GUARD_DEBUG_MESSAGE_HH 27 | 28 | #ifdef HAVE_CONFIG_H 29 | #include "config.h" 30 | #endif 31 | 32 | #include 33 | #include 34 | 35 | #include 36 | 37 | #ifdef HAVE_CXX_PRETTY_FUNCTION 38 | 39 | #ifdef NDEBUG 40 | #define DEBUG_MESSAGE(x) 41 | #else 42 | #define DEBUG_MESSAGE(x) \ 43 | do \ 44 | { \ 45 | if (verbose_level >= 5) \ 46 | { \ 47 | std::stringstream ss; \ 48 | ss << "debug: " << __PRETTY_FUNCTION__ << ": " << x; \ 49 | OutputDebugStringA (ss.str ().c_str ()); \ 50 | } \ 51 | } \ 52 | while (false) 53 | #endif 54 | 55 | #define WARNING_MESSAGE(x) \ 56 | do \ 57 | { \ 58 | if (verbose_level >= 3) \ 59 | { \ 60 | std::stringstream ss; \ 61 | ss << "warning: " << __PRETTY_FUNCTION__ << ": " << x; \ 62 | OutputDebugStringA (ss.str ().c_str ()); \ 63 | } \ 64 | } \ 65 | while (false) 66 | 67 | #else // HAVE_PRETTY_FUNCTION 68 | 69 | #ifdef NDEBUG 70 | #define DEBUG_MESSAGE(x) 71 | #else 72 | #define DEBUG_MESSAGE(x) \ 73 | do \ 74 | { \ 75 | if (verbose_level >= 5) \ 76 | { \ 77 | std::stringstream ss; \ 78 | ss << "debug: " << __func__ << ": " << x; \ 79 | OutputDebugStringA (ss.str ().c_str ()); \ 80 | } \ 81 | } \ 82 | while (false) 83 | #endif 84 | 85 | #define WARNING_MESSAGE(x) \ 86 | do \ 87 | { \ 88 | if (verbose_level >= 3) \ 89 | { \ 90 | std::stringstream ss; \ 91 | ss << "warning: " << __func__ << ": " << x; \ 92 | OutputDebugStringA (ss.str ().c_str ()); \ 93 | } \ 94 | } \ 95 | while (false) 96 | 97 | #endif // HAVE_PRETTY_FUNCTION 98 | 99 | #ifdef NDEBUG 100 | #define DEBUG_MESSAGE_A(x) 101 | #define DEBUG_MESSAGE_W(x) 102 | #define DEBUG_MESSAGE_STATIC(x) 103 | #define DEBUG_MESSAGE_RECONVERTSTRING(x) 104 | #define TRACE_MESSAGE_A(x) 105 | #define TRACE_MESSAGE_W(x) 106 | #define TRACE_MESSAGE_STATIC(x) 107 | #else 108 | #define DEBUG_MESSAGE_A(x) \ 109 | do \ 110 | { \ 111 | if (verbose_level >= 5) \ 112 | { \ 113 | std::stringstream ss; \ 114 | ss << x; \ 115 | OutputDebugStringA (ss.str ().c_str ()); \ 116 | } \ 117 | } \ 118 | while (false) 119 | #define DEBUG_MESSAGE_W(x) \ 120 | do \ 121 | { \ 122 | if (verbose_level >= 5) \ 123 | { \ 124 | std::basic_stringstream ss; \ 125 | ss << x; \ 126 | OutputDebugStringW (ss.str ().c_str ()); \ 127 | } \ 128 | } \ 129 | while (false) 130 | #define DEBUG_MESSAGE_STATIC(x) \ 131 | do \ 132 | { \ 133 | if (verbose_level >= 5) \ 134 | OutputDebugStringA ((x)); \ 135 | } \ 136 | while (false) 137 | #define DEBUG_MESSAGE_RECONVERTSTRING(x) \ 138 | do \ 139 | { \ 140 | if (verbose_level >= 5) \ 141 | debug_output_reconvert_string ((x)); \ 142 | } \ 143 | while (false) 144 | #define TRACE_MESSAGE_A(x) \ 145 | do \ 146 | { \ 147 | if (verbose_level >= 6) \ 148 | { \ 149 | std::stringstream ss; \ 150 | ss << x; \ 151 | OutputDebugStringA (ss.str ().c_str ()); \ 152 | } \ 153 | } \ 154 | while (false) 155 | #define TRACE_MESSAGE_W(x) \ 156 | do \ 157 | { \ 158 | if (verbose_level >= 6) \ 159 | { \ 160 | std::basic_stringstream ss; \ 161 | ss << x; \ 162 | OutputDebugStringW (ss.str ().c_str ()); \ 163 | } \ 164 | } \ 165 | while (false) 166 | #define TRACE_MESSAGE_STATIC(x) \ 167 | do \ 168 | { \ 169 | if (verbose_level >= 6) \ 170 | OutputDebugStringA ((x)); \ 171 | } \ 172 | while (false) 173 | #endif 174 | 175 | #define WARNING_MESSAGE_A(x) \ 176 | do \ 177 | { \ 178 | if (verbose_level >= 3) \ 179 | { \ 180 | std::stringstream ss; \ 181 | ss << x; \ 182 | OutputDebugStringA (ss.str ().c_str ()); \ 183 | } \ 184 | } \ 185 | while (false) 186 | #define WARNING_MESSAGE_W(x) \ 187 | do \ 188 | { \ 189 | if (verbose_level >= 3) \ 190 | { \ 191 | std::basic_stringstream ss; \ 192 | ss << x; \ 193 | OutputDebugStringW (ss.str ().c_str ()); \ 194 | } \ 195 | } \ 196 | while (false) 197 | #define WARNING_MESSAGE_STATIC(x) \ 198 | do \ 199 | { \ 200 | if (verbose_level >= 3) \ 201 | OutputDebugStringA ((x)); \ 202 | } \ 203 | while (false) 204 | 205 | std::string get_format_message (DWORD dwMessageId); 206 | void debug_output_reconvert_string (RECONVERTSTRING *rs); 207 | 208 | extern int verbose_level; 209 | 210 | #endif // INCLUDE_GUARD_DEBUG_MESSAGE_HH 211 | -------------------------------------------------------------------------------- /src/emacs-27.1/emacs-module.h: -------------------------------------------------------------------------------- 1 | /* emacs-module.h - GNU Emacs module API. 2 | 3 | Copyright (C) 2015-2020 Free Software Foundation, Inc. 4 | 5 | This file is part of GNU Emacs. 6 | 7 | GNU Emacs is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or (at 10 | your option) any later version. 11 | 12 | GNU Emacs is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with GNU Emacs. If not, see . */ 19 | 20 | /* 21 | This file defines the Emacs module API. Please see the chapter 22 | `Dynamic Modules' in the GNU Emacs Lisp Reference Manual for 23 | information how to write modules and use this header file. 24 | */ 25 | 26 | #ifndef EMACS_MODULE_H 27 | #define EMACS_MODULE_H 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | #ifndef __cplusplus 34 | #include 35 | #endif 36 | 37 | #define EMACS_MAJOR_VERSION 27 38 | 39 | #if defined __cplusplus && __cplusplus >= 201103L 40 | # define EMACS_NOEXCEPT noexcept 41 | #else 42 | # define EMACS_NOEXCEPT 43 | #endif 44 | 45 | #ifdef __has_attribute 46 | #if __has_attribute(__nonnull__) 47 | # define EMACS_ATTRIBUTE_NONNULL(...) __attribute__((__nonnull__(__VA_ARGS__))) 48 | #endif 49 | #endif 50 | #ifndef EMACS_ATTRIBUTE_NONNULL 51 | # define EMACS_ATTRIBUTE_NONNULL(...) 52 | #endif 53 | 54 | #ifdef __cplusplus 55 | extern "C" { 56 | #endif 57 | 58 | /* Current environment. */ 59 | typedef struct emacs_env_27 emacs_env; 60 | 61 | /* Opaque pointer representing an Emacs Lisp value. 62 | BEWARE: Do not assume NULL is a valid value! */ 63 | typedef struct emacs_value_tag *emacs_value; 64 | 65 | enum { emacs_variadic_function = -2 }; 66 | 67 | /* Struct passed to a module init function (emacs_module_init). */ 68 | struct emacs_runtime 69 | { 70 | /* Structure size (for version checking). */ 71 | ptrdiff_t size; 72 | 73 | /* Private data; users should not touch this. */ 74 | struct emacs_runtime_private *private_members; 75 | 76 | /* Return an environment pointer. */ 77 | emacs_env *(*get_environment) (struct emacs_runtime *ert) 78 | EMACS_ATTRIBUTE_NONNULL(1); 79 | }; 80 | 81 | 82 | /* Possible Emacs function call outcomes. */ 83 | enum emacs_funcall_exit 84 | { 85 | /* Function has returned normally. */ 86 | emacs_funcall_exit_return = 0, 87 | 88 | /* Function has signaled an error using `signal'. */ 89 | emacs_funcall_exit_signal = 1, 90 | 91 | /* Function has exit using `throw'. */ 92 | emacs_funcall_exit_throw = 2 93 | }; 94 | 95 | /* Possible return values for emacs_env.process_input. */ 96 | enum emacs_process_input_result 97 | { 98 | /* Module code may continue */ 99 | emacs_process_input_continue = 0, 100 | 101 | /* Module code should return control to Emacs as soon as possible. */ 102 | emacs_process_input_quit = 1 103 | }; 104 | 105 | /* Define emacs_limb_t so that it is likely to match GMP's mp_limb_t. 106 | This micro-optimization can help modules that use mpz_export and 107 | mpz_import, which operate more efficiently on mp_limb_t. It's OK 108 | (if perhaps a bit slower) if the two types do not match, and 109 | modules shouldn't rely on the two types matching. */ 110 | typedef size_t emacs_limb_t; 111 | #define EMACS_LIMB_MAX SIZE_MAX 112 | 113 | struct emacs_env_25 114 | { 115 | /* Structure size (for version checking). */ 116 | ptrdiff_t size; 117 | 118 | /* Private data; users should not touch this. */ 119 | struct emacs_env_private *private_members; 120 | 121 | /* Memory management. */ 122 | 123 | emacs_value (*make_global_ref) (emacs_env *env, 124 | emacs_value any_reference) 125 | EMACS_ATTRIBUTE_NONNULL(1); 126 | 127 | void (*free_global_ref) (emacs_env *env, 128 | emacs_value global_reference) 129 | EMACS_ATTRIBUTE_NONNULL(1); 130 | 131 | /* Non-local exit handling. */ 132 | 133 | enum emacs_funcall_exit (*non_local_exit_check) (emacs_env *env) 134 | EMACS_ATTRIBUTE_NONNULL(1); 135 | 136 | void (*non_local_exit_clear) (emacs_env *env) 137 | EMACS_ATTRIBUTE_NONNULL(1); 138 | 139 | enum emacs_funcall_exit (*non_local_exit_get) 140 | (emacs_env *env, 141 | emacs_value *non_local_exit_symbol_out, 142 | emacs_value *non_local_exit_data_out) 143 | EMACS_ATTRIBUTE_NONNULL(1, 2, 3); 144 | 145 | void (*non_local_exit_signal) (emacs_env *env, 146 | emacs_value non_local_exit_symbol, 147 | emacs_value non_local_exit_data) 148 | EMACS_ATTRIBUTE_NONNULL(1); 149 | 150 | void (*non_local_exit_throw) (emacs_env *env, 151 | emacs_value tag, 152 | emacs_value value) 153 | EMACS_ATTRIBUTE_NONNULL(1); 154 | 155 | /* Function registration. */ 156 | 157 | emacs_value (*make_function) (emacs_env *env, 158 | ptrdiff_t min_arity, 159 | ptrdiff_t max_arity, 160 | emacs_value (*function) (emacs_env *env, 161 | ptrdiff_t nargs, 162 | emacs_value args[], 163 | void *) 164 | EMACS_NOEXCEPT 165 | EMACS_ATTRIBUTE_NONNULL(1), 166 | const char *documentation, 167 | void *data) 168 | EMACS_ATTRIBUTE_NONNULL(1, 4); 169 | 170 | emacs_value (*funcall) (emacs_env *env, 171 | emacs_value function, 172 | ptrdiff_t nargs, 173 | emacs_value args[]) 174 | EMACS_ATTRIBUTE_NONNULL(1); 175 | 176 | emacs_value (*intern) (emacs_env *env, 177 | const char *symbol_name) 178 | EMACS_ATTRIBUTE_NONNULL(1, 2); 179 | 180 | /* Type conversion. */ 181 | 182 | emacs_value (*type_of) (emacs_env *env, 183 | emacs_value value) 184 | EMACS_ATTRIBUTE_NONNULL(1); 185 | 186 | bool (*is_not_nil) (emacs_env *env, emacs_value value) 187 | EMACS_ATTRIBUTE_NONNULL(1); 188 | 189 | bool (*eq) (emacs_env *env, emacs_value a, emacs_value b) 190 | EMACS_ATTRIBUTE_NONNULL(1); 191 | 192 | intmax_t (*extract_integer) (emacs_env *env, emacs_value value) 193 | EMACS_ATTRIBUTE_NONNULL(1); 194 | 195 | emacs_value (*make_integer) (emacs_env *env, intmax_t value) 196 | EMACS_ATTRIBUTE_NONNULL(1); 197 | 198 | double (*extract_float) (emacs_env *env, emacs_value value) 199 | EMACS_ATTRIBUTE_NONNULL(1); 200 | 201 | emacs_value (*make_float) (emacs_env *env, double value) 202 | EMACS_ATTRIBUTE_NONNULL(1); 203 | 204 | /* Copy the content of the Lisp string VALUE to BUFFER as an utf8 205 | NUL-terminated string. 206 | 207 | SIZE must point to the total size of the buffer. If BUFFER is 208 | NULL or if SIZE is not big enough, write the required buffer size 209 | to SIZE and return true. 210 | 211 | Note that SIZE must include the last NUL byte (e.g. "abc" needs 212 | a buffer of size 4). 213 | 214 | Return true if the string was successfully copied. */ 215 | 216 | bool (*copy_string_contents) (emacs_env *env, 217 | emacs_value value, 218 | char *buffer, 219 | ptrdiff_t *size_inout) 220 | EMACS_ATTRIBUTE_NONNULL(1, 4); 221 | 222 | /* Create a Lisp string from a utf8 encoded string. */ 223 | emacs_value (*make_string) (emacs_env *env, 224 | const char *contents, ptrdiff_t length) 225 | EMACS_ATTRIBUTE_NONNULL(1, 2); 226 | 227 | /* Embedded pointer type. */ 228 | emacs_value (*make_user_ptr) (emacs_env *env, 229 | void (*fin) (void *) EMACS_NOEXCEPT, 230 | void *ptr) 231 | EMACS_ATTRIBUTE_NONNULL(1); 232 | 233 | void *(*get_user_ptr) (emacs_env *env, emacs_value uptr) 234 | EMACS_ATTRIBUTE_NONNULL(1); 235 | void (*set_user_ptr) (emacs_env *env, emacs_value uptr, void *ptr) 236 | EMACS_ATTRIBUTE_NONNULL(1); 237 | 238 | void (*(*get_user_finalizer) (emacs_env *env, emacs_value uptr)) 239 | (void *) EMACS_NOEXCEPT EMACS_ATTRIBUTE_NONNULL(1); 240 | void (*set_user_finalizer) (emacs_env *env, 241 | emacs_value uptr, 242 | void (*fin) (void *) EMACS_NOEXCEPT) 243 | EMACS_ATTRIBUTE_NONNULL(1); 244 | 245 | /* Vector functions. */ 246 | emacs_value (*vec_get) (emacs_env *env, emacs_value vec, ptrdiff_t i) 247 | EMACS_ATTRIBUTE_NONNULL(1); 248 | 249 | void (*vec_set) (emacs_env *env, emacs_value vec, ptrdiff_t i, 250 | emacs_value val) 251 | EMACS_ATTRIBUTE_NONNULL(1); 252 | 253 | ptrdiff_t (*vec_size) (emacs_env *env, emacs_value vec) 254 | EMACS_ATTRIBUTE_NONNULL(1); 255 | }; 256 | 257 | struct emacs_env_26 258 | { 259 | /* Structure size (for version checking). */ 260 | ptrdiff_t size; 261 | 262 | /* Private data; users should not touch this. */ 263 | struct emacs_env_private *private_members; 264 | 265 | /* Memory management. */ 266 | 267 | emacs_value (*make_global_ref) (emacs_env *env, 268 | emacs_value any_reference) 269 | EMACS_ATTRIBUTE_NONNULL(1); 270 | 271 | void (*free_global_ref) (emacs_env *env, 272 | emacs_value global_reference) 273 | EMACS_ATTRIBUTE_NONNULL(1); 274 | 275 | /* Non-local exit handling. */ 276 | 277 | enum emacs_funcall_exit (*non_local_exit_check) (emacs_env *env) 278 | EMACS_ATTRIBUTE_NONNULL(1); 279 | 280 | void (*non_local_exit_clear) (emacs_env *env) 281 | EMACS_ATTRIBUTE_NONNULL(1); 282 | 283 | enum emacs_funcall_exit (*non_local_exit_get) 284 | (emacs_env *env, 285 | emacs_value *non_local_exit_symbol_out, 286 | emacs_value *non_local_exit_data_out) 287 | EMACS_ATTRIBUTE_NONNULL(1, 2, 3); 288 | 289 | void (*non_local_exit_signal) (emacs_env *env, 290 | emacs_value non_local_exit_symbol, 291 | emacs_value non_local_exit_data) 292 | EMACS_ATTRIBUTE_NONNULL(1); 293 | 294 | void (*non_local_exit_throw) (emacs_env *env, 295 | emacs_value tag, 296 | emacs_value value) 297 | EMACS_ATTRIBUTE_NONNULL(1); 298 | 299 | /* Function registration. */ 300 | 301 | emacs_value (*make_function) (emacs_env *env, 302 | ptrdiff_t min_arity, 303 | ptrdiff_t max_arity, 304 | emacs_value (*function) (emacs_env *env, 305 | ptrdiff_t nargs, 306 | emacs_value args[], 307 | void *) 308 | EMACS_NOEXCEPT 309 | EMACS_ATTRIBUTE_NONNULL(1), 310 | const char *documentation, 311 | void *data) 312 | EMACS_ATTRIBUTE_NONNULL(1, 4); 313 | 314 | emacs_value (*funcall) (emacs_env *env, 315 | emacs_value function, 316 | ptrdiff_t nargs, 317 | emacs_value args[]) 318 | EMACS_ATTRIBUTE_NONNULL(1); 319 | 320 | emacs_value (*intern) (emacs_env *env, 321 | const char *symbol_name) 322 | EMACS_ATTRIBUTE_NONNULL(1, 2); 323 | 324 | /* Type conversion. */ 325 | 326 | emacs_value (*type_of) (emacs_env *env, 327 | emacs_value value) 328 | EMACS_ATTRIBUTE_NONNULL(1); 329 | 330 | bool (*is_not_nil) (emacs_env *env, emacs_value value) 331 | EMACS_ATTRIBUTE_NONNULL(1); 332 | 333 | bool (*eq) (emacs_env *env, emacs_value a, emacs_value b) 334 | EMACS_ATTRIBUTE_NONNULL(1); 335 | 336 | intmax_t (*extract_integer) (emacs_env *env, emacs_value value) 337 | EMACS_ATTRIBUTE_NONNULL(1); 338 | 339 | emacs_value (*make_integer) (emacs_env *env, intmax_t value) 340 | EMACS_ATTRIBUTE_NONNULL(1); 341 | 342 | double (*extract_float) (emacs_env *env, emacs_value value) 343 | EMACS_ATTRIBUTE_NONNULL(1); 344 | 345 | emacs_value (*make_float) (emacs_env *env, double value) 346 | EMACS_ATTRIBUTE_NONNULL(1); 347 | 348 | /* Copy the content of the Lisp string VALUE to BUFFER as an utf8 349 | NUL-terminated string. 350 | 351 | SIZE must point to the total size of the buffer. If BUFFER is 352 | NULL or if SIZE is not big enough, write the required buffer size 353 | to SIZE and return true. 354 | 355 | Note that SIZE must include the last NUL byte (e.g. "abc" needs 356 | a buffer of size 4). 357 | 358 | Return true if the string was successfully copied. */ 359 | 360 | bool (*copy_string_contents) (emacs_env *env, 361 | emacs_value value, 362 | char *buffer, 363 | ptrdiff_t *size_inout) 364 | EMACS_ATTRIBUTE_NONNULL(1, 4); 365 | 366 | /* Create a Lisp string from a utf8 encoded string. */ 367 | emacs_value (*make_string) (emacs_env *env, 368 | const char *contents, ptrdiff_t length) 369 | EMACS_ATTRIBUTE_NONNULL(1, 2); 370 | 371 | /* Embedded pointer type. */ 372 | emacs_value (*make_user_ptr) (emacs_env *env, 373 | void (*fin) (void *) EMACS_NOEXCEPT, 374 | void *ptr) 375 | EMACS_ATTRIBUTE_NONNULL(1); 376 | 377 | void *(*get_user_ptr) (emacs_env *env, emacs_value uptr) 378 | EMACS_ATTRIBUTE_NONNULL(1); 379 | void (*set_user_ptr) (emacs_env *env, emacs_value uptr, void *ptr) 380 | EMACS_ATTRIBUTE_NONNULL(1); 381 | 382 | void (*(*get_user_finalizer) (emacs_env *env, emacs_value uptr)) 383 | (void *) EMACS_NOEXCEPT EMACS_ATTRIBUTE_NONNULL(1); 384 | void (*set_user_finalizer) (emacs_env *env, 385 | emacs_value uptr, 386 | void (*fin) (void *) EMACS_NOEXCEPT) 387 | EMACS_ATTRIBUTE_NONNULL(1); 388 | 389 | /* Vector functions. */ 390 | emacs_value (*vec_get) (emacs_env *env, emacs_value vec, ptrdiff_t i) 391 | EMACS_ATTRIBUTE_NONNULL(1); 392 | 393 | void (*vec_set) (emacs_env *env, emacs_value vec, ptrdiff_t i, 394 | emacs_value val) 395 | EMACS_ATTRIBUTE_NONNULL(1); 396 | 397 | ptrdiff_t (*vec_size) (emacs_env *env, emacs_value vec) 398 | EMACS_ATTRIBUTE_NONNULL(1); 399 | 400 | /* Returns whether a quit is pending. */ 401 | bool (*should_quit) (emacs_env *env) 402 | EMACS_ATTRIBUTE_NONNULL(1); 403 | }; 404 | 405 | struct emacs_env_27 406 | { 407 | /* Structure size (for version checking). */ 408 | ptrdiff_t size; 409 | 410 | /* Private data; users should not touch this. */ 411 | struct emacs_env_private *private_members; 412 | 413 | /* Memory management. */ 414 | 415 | emacs_value (*make_global_ref) (emacs_env *env, 416 | emacs_value any_reference) 417 | EMACS_ATTRIBUTE_NONNULL(1); 418 | 419 | void (*free_global_ref) (emacs_env *env, 420 | emacs_value global_reference) 421 | EMACS_ATTRIBUTE_NONNULL(1); 422 | 423 | /* Non-local exit handling. */ 424 | 425 | enum emacs_funcall_exit (*non_local_exit_check) (emacs_env *env) 426 | EMACS_ATTRIBUTE_NONNULL(1); 427 | 428 | void (*non_local_exit_clear) (emacs_env *env) 429 | EMACS_ATTRIBUTE_NONNULL(1); 430 | 431 | enum emacs_funcall_exit (*non_local_exit_get) 432 | (emacs_env *env, 433 | emacs_value *non_local_exit_symbol_out, 434 | emacs_value *non_local_exit_data_out) 435 | EMACS_ATTRIBUTE_NONNULL(1, 2, 3); 436 | 437 | void (*non_local_exit_signal) (emacs_env *env, 438 | emacs_value non_local_exit_symbol, 439 | emacs_value non_local_exit_data) 440 | EMACS_ATTRIBUTE_NONNULL(1); 441 | 442 | void (*non_local_exit_throw) (emacs_env *env, 443 | emacs_value tag, 444 | emacs_value value) 445 | EMACS_ATTRIBUTE_NONNULL(1); 446 | 447 | /* Function registration. */ 448 | 449 | emacs_value (*make_function) (emacs_env *env, 450 | ptrdiff_t min_arity, 451 | ptrdiff_t max_arity, 452 | emacs_value (*function) (emacs_env *env, 453 | ptrdiff_t nargs, 454 | emacs_value args[], 455 | void *) 456 | EMACS_NOEXCEPT 457 | EMACS_ATTRIBUTE_NONNULL(1), 458 | const char *documentation, 459 | void *data) 460 | EMACS_ATTRIBUTE_NONNULL(1, 4); 461 | 462 | emacs_value (*funcall) (emacs_env *env, 463 | emacs_value function, 464 | ptrdiff_t nargs, 465 | emacs_value args[]) 466 | EMACS_ATTRIBUTE_NONNULL(1); 467 | 468 | emacs_value (*intern) (emacs_env *env, 469 | const char *symbol_name) 470 | EMACS_ATTRIBUTE_NONNULL(1, 2); 471 | 472 | /* Type conversion. */ 473 | 474 | emacs_value (*type_of) (emacs_env *env, 475 | emacs_value value) 476 | EMACS_ATTRIBUTE_NONNULL(1); 477 | 478 | bool (*is_not_nil) (emacs_env *env, emacs_value value) 479 | EMACS_ATTRIBUTE_NONNULL(1); 480 | 481 | bool (*eq) (emacs_env *env, emacs_value a, emacs_value b) 482 | EMACS_ATTRIBUTE_NONNULL(1); 483 | 484 | intmax_t (*extract_integer) (emacs_env *env, emacs_value value) 485 | EMACS_ATTRIBUTE_NONNULL(1); 486 | 487 | emacs_value (*make_integer) (emacs_env *env, intmax_t value) 488 | EMACS_ATTRIBUTE_NONNULL(1); 489 | 490 | double (*extract_float) (emacs_env *env, emacs_value value) 491 | EMACS_ATTRIBUTE_NONNULL(1); 492 | 493 | emacs_value (*make_float) (emacs_env *env, double value) 494 | EMACS_ATTRIBUTE_NONNULL(1); 495 | 496 | /* Copy the content of the Lisp string VALUE to BUFFER as an utf8 497 | NUL-terminated string. 498 | 499 | SIZE must point to the total size of the buffer. If BUFFER is 500 | NULL or if SIZE is not big enough, write the required buffer size 501 | to SIZE and return true. 502 | 503 | Note that SIZE must include the last NUL byte (e.g. "abc" needs 504 | a buffer of size 4). 505 | 506 | Return true if the string was successfully copied. */ 507 | 508 | bool (*copy_string_contents) (emacs_env *env, 509 | emacs_value value, 510 | char *buffer, 511 | ptrdiff_t *size_inout) 512 | EMACS_ATTRIBUTE_NONNULL(1, 4); 513 | 514 | /* Create a Lisp string from a utf8 encoded string. */ 515 | emacs_value (*make_string) (emacs_env *env, 516 | const char *contents, ptrdiff_t length) 517 | EMACS_ATTRIBUTE_NONNULL(1, 2); 518 | 519 | /* Embedded pointer type. */ 520 | emacs_value (*make_user_ptr) (emacs_env *env, 521 | void (*fin) (void *) EMACS_NOEXCEPT, 522 | void *ptr) 523 | EMACS_ATTRIBUTE_NONNULL(1); 524 | 525 | void *(*get_user_ptr) (emacs_env *env, emacs_value uptr) 526 | EMACS_ATTRIBUTE_NONNULL(1); 527 | void (*set_user_ptr) (emacs_env *env, emacs_value uptr, void *ptr) 528 | EMACS_ATTRIBUTE_NONNULL(1); 529 | 530 | void (*(*get_user_finalizer) (emacs_env *env, emacs_value uptr)) 531 | (void *) EMACS_NOEXCEPT EMACS_ATTRIBUTE_NONNULL(1); 532 | void (*set_user_finalizer) (emacs_env *env, 533 | emacs_value uptr, 534 | void (*fin) (void *) EMACS_NOEXCEPT) 535 | EMACS_ATTRIBUTE_NONNULL(1); 536 | 537 | /* Vector functions. */ 538 | emacs_value (*vec_get) (emacs_env *env, emacs_value vec, ptrdiff_t i) 539 | EMACS_ATTRIBUTE_NONNULL(1); 540 | 541 | void (*vec_set) (emacs_env *env, emacs_value vec, ptrdiff_t i, 542 | emacs_value val) 543 | EMACS_ATTRIBUTE_NONNULL(1); 544 | 545 | ptrdiff_t (*vec_size) (emacs_env *env, emacs_value vec) 546 | EMACS_ATTRIBUTE_NONNULL(1); 547 | 548 | /* Returns whether a quit is pending. */ 549 | bool (*should_quit) (emacs_env *env) 550 | EMACS_ATTRIBUTE_NONNULL(1); 551 | 552 | /* Processes pending input events and returns whether the module 553 | function should quit. */ 554 | enum emacs_process_input_result (*process_input) (emacs_env *env) 555 | EMACS_ATTRIBUTE_NONNULL (1); 556 | 557 | struct timespec (*extract_time) (emacs_env *env, emacs_value value) 558 | EMACS_ATTRIBUTE_NONNULL (1); 559 | 560 | emacs_value (*make_time) (emacs_env *env, struct timespec time) 561 | EMACS_ATTRIBUTE_NONNULL (1); 562 | 563 | bool (*extract_big_integer) (emacs_env *env, emacs_value arg, int *sign, 564 | ptrdiff_t *count, emacs_limb_t *magnitude) 565 | EMACS_ATTRIBUTE_NONNULL (1); 566 | 567 | emacs_value (*make_big_integer) (emacs_env *env, int sign, ptrdiff_t count, 568 | const emacs_limb_t *magnitude) 569 | EMACS_ATTRIBUTE_NONNULL (1); 570 | }; 571 | 572 | /* Every module should define a function as follows. */ 573 | extern int emacs_module_init (struct emacs_runtime *ert) 574 | EMACS_NOEXCEPT 575 | EMACS_ATTRIBUTE_NONNULL(1); 576 | 577 | #ifdef __cplusplus 578 | } 579 | #endif 580 | 581 | #endif /* EMACS_MODULE_H */ 582 | -------------------------------------------------------------------------------- /src/get_msg_hook.cc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; coding: utf-8 -*- 2 | 3 | // This file is part of 4 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 5 | // https://github.com/trueroad/tr-emacs-ime-module 6 | // 7 | // Copyright (C) 2020 Masamichi Hosoda 8 | // 9 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 10 | // is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 16 | // is distributed in the hope that it will be useful, 17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | // GNU General Public License for more details. 20 | // 21 | // You should have received a copy of the GNU General Public License 22 | // along with tr-ime. 23 | // If not, see . 24 | 25 | #include "get_msg_hook.hh" 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | 35 | #include "debug-message.hh" 36 | #include "message.hh" 37 | 38 | bool 39 | get_msg_hook::install (DWORD thread_id) 40 | { 41 | std::lock_guard lock (mtx_); 42 | 43 | if (threads_.find (thread_id) != threads_.end ()) 44 | { 45 | DEBUG_MESSAGE ("already installed\n"); 46 | return true; 47 | } 48 | 49 | auto hhook = 50 | SetWindowsHookExW (WH_GETMESSAGE, get_msg_proc_, hmodule_, thread_id); 51 | if (!hhook) 52 | { 53 | auto e = GetLastError (); 54 | WARNING_MESSAGE ("SetWindowsHookExW failed: " + 55 | get_format_message (e) + "\n"); 56 | return false; 57 | } 58 | 59 | threads_[thread_id] = hhook; 60 | 61 | return true; 62 | } 63 | 64 | void 65 | get_msg_hook::uninstall (DWORD thread_id) 66 | { 67 | std::lock_guard lock (mtx_); 68 | 69 | if (threads_.find (thread_id) == threads_.end ()) 70 | { 71 | WARNING_MESSAGE ("not installed\n"); 72 | return; 73 | } 74 | 75 | if (!UnhookWindowsHookEx (threads_[thread_id])) 76 | { 77 | auto e = GetLastError (); 78 | WARNING_MESSAGE ("UnhookWindowsHookExW failed" + 79 | get_format_message (e) + "\n"); 80 | } 81 | 82 | threads_.erase (thread_id); 83 | } 84 | 85 | void 86 | get_msg_hook::uninstall_all (void) 87 | { 88 | while (true) 89 | { 90 | DWORD thread_id; 91 | { 92 | std::lock_guard lock (mtx_); 93 | 94 | if (!threads_.size ()) 95 | break; 96 | 97 | thread_id = threads_.begin ()->first; 98 | } 99 | uninstall (thread_id); 100 | } 101 | } 102 | 103 | void 104 | get_msg_hook::subclassify (HWND hwnd, bool b_all) 105 | { 106 | // SendMessage does not work 107 | PostMessageW (hwnd, u_WM_TR_IME_SUBCLASSIFY_, 108 | static_cast (b_all), 0); 109 | } 110 | 111 | void 112 | get_msg_hook::unsubclassify (HWND hwnd, bool b_all) 113 | { 114 | // SendMessage does not work 115 | PostMessageW (hwnd, u_WM_TR_IME_UNSUBCLASSIFY_, 116 | static_cast (b_all), 0); 117 | } 118 | 119 | void 120 | get_msg_hook::unsubclassify (DWORD thread_id) 121 | { 122 | PostThreadMessageW (thread_id, u_WM_TR_IME_UNSUBCLASSIFY_, 123 | static_cast (true), 0); 124 | } 125 | 126 | void 127 | get_msg_hook::unsubclassify_all (void) 128 | { 129 | std::lock_guard lock (mtx_); 130 | 131 | for (const auto &t: threads_) 132 | unsubclassify (t.first); 133 | } 134 | 135 | bool 136 | get_msg_hook::exists_subclassified (DWORD thread_id) 137 | { 138 | std::promise p; 139 | 140 | PostThreadMessageW (thread_id, u_WM_TR_IME_EXISTS_SUBCLASSIFIED_, 141 | reinterpret_cast (&p), 0); 142 | 143 | auto future = p.get_future (); 144 | auto results = future.wait_for (std::chrono::seconds (1)); 145 | if (results == std::future_status::ready) 146 | { 147 | DEBUG_MESSAGE ("ready\n"); 148 | return future.get (); 149 | } 150 | 151 | DEBUG_MESSAGE ("timeout\n"); 152 | 153 | return false; 154 | } 155 | 156 | bool 157 | get_msg_hook::exists_subclassified_all (void) 158 | { 159 | std::vector v; 160 | 161 | { 162 | std::lock_guard lock (mtx_); 163 | 164 | for (const auto &t: threads_) 165 | v.push_back (t.first); 166 | } 167 | 168 | for (auto id: v) 169 | { 170 | if (exists_subclassified (id)) 171 | return true; 172 | } 173 | 174 | return false; 175 | } 176 | -------------------------------------------------------------------------------- /src/get_msg_hook.hh: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; coding: utf-8 -*- 2 | 3 | // This file is part of 4 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 5 | // https://github.com/trueroad/tr-emacs-ime-module 6 | // 7 | // Copyright (C) 2020, 2022 Masamichi Hosoda 8 | // 9 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 10 | // is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 16 | // is distributed in the hope that it will be useful, 17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | // GNU General Public License for more details. 20 | // 21 | // You should have received a copy of the GNU General Public License 22 | // along with tr-ime. 23 | // If not, see . 24 | 25 | #ifndef INCLUDE_GUARD_GET_MSG_HOOK_HH 26 | #define INCLUDE_GUARD_GET_MSG_HOOK_HH 27 | 28 | #include 29 | #include 30 | 31 | #include 32 | 33 | class get_msg_hook final 34 | { 35 | public: 36 | explicit 37 | get_msg_hook (HOOKPROC get_msg_proc, HMODULE hmodule) 38 | : get_msg_proc_ (get_msg_proc), hmodule_ (hmodule) 39 | { 40 | } 41 | ~get_msg_hook () 42 | { 43 | uninstall_all (); 44 | } 45 | get_msg_hook (const get_msg_hook &) = delete; 46 | get_msg_hook (get_msg_hook &&) = delete; 47 | get_msg_hook& operator = (const get_msg_hook &) = delete; 48 | get_msg_hook& operator = (get_msg_hook &&) = delete; 49 | 50 | bool install (DWORD thread_id); 51 | void uninstall (DWORD thread_id); 52 | void uninstall_all (void); 53 | 54 | void subclassify (HWND hwnd, bool b_all); 55 | void unsubclassify (HWND hwnd, bool b_all); 56 | void unsubclassify (DWORD thread_id); 57 | void unsubclassify_all (void); 58 | 59 | bool exists_subclassified (DWORD thread_id); 60 | bool exists_subclassified_all (void); 61 | 62 | private: 63 | const HOOKPROC get_msg_proc_; 64 | const HMODULE hmodule_; 65 | 66 | std::mutex mtx_; 67 | std::unordered_map threads_; 68 | }; 69 | 70 | #endif // INCLUDE_GUARD_GET_MSG_HOOK_HH 71 | -------------------------------------------------------------------------------- /src/get_msg_proc.cc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; coding: utf-8 -*- 2 | 3 | // This file is part of 4 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 5 | // https://github.com/trueroad/tr-emacs-ime-module 6 | // 7 | // Copyright (C) 2020, 2022 Masamichi Hosoda 8 | // 9 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 10 | // is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 16 | // is distributed in the hope that it will be useful, 17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | // GNU General Public License for more details. 20 | // 21 | // You should have received a copy of the GNU General Public License 22 | // along with tr-ime. 23 | // If not, see . 24 | 25 | #include "get_msg_proc.hh" 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | 36 | #include "debug-message.hh" 37 | #include "message.hh" 38 | #include "subclass_proc.hh" 39 | 40 | constexpr WCHAR get_msg_proc::target_class_name_[]; 41 | thread_local bool get_msg_proc::bsubclassify_all_ {false}; 42 | thread_local std::unordered_set get_msg_proc::hwnds_; 43 | thread_local std::unordered_set get_msg_proc::exclude_hwnds_; 44 | std::atomic get_msg_proc::ab_dispatch_thread_messages_ {false}; 45 | std::atomic get_msg_proc::ab_dispatch_thread_wm_timer_ {false}; 46 | 47 | LRESULT 48 | get_msg_proc::wm_tr_ime_subclassify (int code, WPARAM wparam, LPARAM lparam) 49 | { 50 | // WM_TR_IME_SUBCLASSIFY does not work with SendMessage () 51 | // because only the "post" ed message is passed to GetMsgProc (). 52 | 53 | DEBUG_MESSAGE ("enter\n"); 54 | 55 | // This can be called multiple times. 56 | // So doesn't check whether PM_REMOVE or PM_NOREMOVE. 57 | 58 | auto msg = reinterpret_cast (lparam); 59 | bsubclassify_all_ = static_cast (msg->wParam); 60 | 61 | if (!msg->hwnd) 62 | { 63 | DEBUG_MESSAGE_STATIC (" thread message\n"); 64 | } 65 | else if (!find_hwnd (msg->hwnd)) 66 | { 67 | if (SetWindowSubclass (msg->hwnd, &subclass_proc::proc, 68 | subclass_proc::get_subclass_id (), 0)) 69 | { 70 | DEBUG_MESSAGE_STATIC (" SetWindowSubclass succeeded\n"); 71 | add_hwnd (msg->hwnd); 72 | } 73 | else 74 | { 75 | auto e = GetLastError (); 76 | WARNING_MESSAGE ("SetWindowSubclass failed: " + 77 | get_format_message (e) + "\n"); 78 | } 79 | } 80 | else 81 | { 82 | DEBUG_MESSAGE_STATIC (" already subclassified\n"); 83 | } 84 | 85 | return CallNextHookEx (nullptr, code, wparam, lparam); 86 | } 87 | 88 | LRESULT 89 | get_msg_proc::wm_tr_ime_unsubclassify (int code, WPARAM wparam, LPARAM lparam) 90 | { 91 | // WM_TR_IME_UNSUBCLASSIFY does not work with SendMessage () 92 | // because only the "post" ed message is passed to GetMsgProc (). 93 | 94 | DEBUG_MESSAGE ("enter\n"); 95 | 96 | // This can be called multiple times. 97 | // So doesn't check whether PM_REMOVE or PM_NOREMOVE. 98 | 99 | auto msg = reinterpret_cast (lparam); 100 | auto bunsubclassify_all = static_cast (msg->wParam); 101 | bsubclassify_all_ = false; 102 | 103 | if (!msg->hwnd) 104 | { 105 | DEBUG_MESSAGE_STATIC (" thread message\n"); 106 | } 107 | else if (find_hwnd (msg->hwnd)) 108 | { 109 | if (RemoveWindowSubclass (msg->hwnd, &subclass_proc::proc, 110 | subclass_proc::get_subclass_id ())) 111 | { 112 | DEBUG_MESSAGE_STATIC (" RemoveWindowSubclass succeeded\n"); 113 | remove_hwnd (msg->hwnd); 114 | } 115 | else 116 | { 117 | auto e = GetLastError (); 118 | WARNING_MESSAGE ("RemoveWindowSubclass failed: " + 119 | get_format_message (e) + "\n"); 120 | } 121 | } 122 | else 123 | { 124 | DEBUG_MESSAGE_STATIC (" already unsubclassified\n"); 125 | } 126 | 127 | if (bunsubclassify_all) 128 | { 129 | for (auto h: hwnds_) 130 | // SendMessage does not work 131 | PostMessageW (h, u_WM_TR_IME_UNSUBCLASSIFY_, 132 | static_cast (false), 0); 133 | } 134 | 135 | return CallNextHookEx (nullptr, code, wparam, lparam); 136 | } 137 | 138 | LRESULT 139 | get_msg_proc::wm_tr_ime_exists_subclassified 140 | (int code, WPARAM wparam, LPARAM lparam) 141 | { 142 | // WM_TR_IME_EXISTS_SUBCLASSIFIED does not work with SendMessage () 143 | // because only the "post" ed message is passed to GetMsgProc (). 144 | 145 | DEBUG_MESSAGE ("enter\n"); 146 | 147 | if (wparam != PM_REMOVE) 148 | { 149 | // Not processed because this may be called again. 150 | DEBUG_MESSAGE_STATIC (" wparam != PM_REMOVE\n"); 151 | return CallNextHookEx (nullptr, code, wparam, lparam); 152 | } 153 | 154 | auto msg = reinterpret_cast (lparam); 155 | auto p = reinterpret_cast*> (msg->wParam); 156 | 157 | p->set_value (!hwnds_.empty ()); 158 | 159 | return CallNextHookEx (nullptr, code, wparam, lparam); 160 | } 161 | 162 | bool 163 | get_msg_proc::is_target_class (HWND hwnd) 164 | { 165 | DEBUG_MESSAGE ("enter\n"); 166 | 167 | if (GetParent (hwnd)) 168 | { 169 | DEBUG_MESSAGE_STATIC (" false (hwnd has parent)\n"); 170 | add_exclude_hwnd (hwnd); 171 | 172 | return false; 173 | } 174 | 175 | constexpr auto class_size = 176 | sizeof (target_class_name_) / sizeof (target_class_name_[0]); 177 | std::array buff; 178 | auto n = GetClassNameW (hwnd, buff.data (), buff.size ()); 179 | 180 | if (!std::equal (std::begin (target_class_name_), 181 | std::begin (target_class_name_) + class_size, 182 | buff.begin (), 183 | buff.begin () + n + 1)) 184 | { 185 | DEBUG_MESSAGE_STATIC (" false (class is different)\n"); 186 | add_exclude_hwnd (hwnd); 187 | 188 | return false; 189 | } 190 | 191 | DEBUG_MESSAGE_STATIC (" true\n"); 192 | 193 | return true; 194 | } 195 | 196 | LRESULT 197 | get_msg_proc::proc (int code, WPARAM wparam, LPARAM lparam) 198 | { 199 | if (code < 0) 200 | { 201 | DEBUG_MESSAGE ("code < 0\n"); 202 | return CallNextHookEx (nullptr, code, wparam, lparam); 203 | } 204 | if (code != HC_ACTION) 205 | { 206 | DEBUG_MESSAGE ("code != HC_ACTION\n"); 207 | return CallNextHookEx (nullptr, code, wparam, lparam); 208 | } 209 | 210 | auto msg = reinterpret_cast (lparam); 211 | if (!msg) 212 | { 213 | WARNING_MESSAGE ("msg broken\n"); 214 | return CallNextHookEx (nullptr, code, wparam, lparam); 215 | } 216 | 217 | if (msg->message == u_WM_TR_IME_SUBCLASSIFY_) 218 | return wm_tr_ime_subclassify (code, wparam, lparam); 219 | else if (msg->message == u_WM_TR_IME_UNSUBCLASSIFY_) 220 | return wm_tr_ime_unsubclassify (code, wparam, lparam); 221 | else if (msg->message == u_WM_TR_IME_EXISTS_SUBCLASSIFIED_) 222 | return wm_tr_ime_exists_subclassified (code, wparam, lparam); 223 | 224 | if (!msg->hwnd) 225 | { 226 | if (wparam != PM_REMOVE) 227 | return CallNextHookEx (nullptr, code, wparam, lparam); 228 | 229 | if (msg->message == WM_TIMER && get_b_dispatch_thread_wm_timer ()) 230 | { 231 | DispatchMessageW (msg); 232 | msg->message = WM_NULL; 233 | 234 | return CallNextHookEx (nullptr, code, wparam, lparam); 235 | } 236 | else 237 | { 238 | auto r = CallNextHookEx (nullptr, code, wparam, lparam); 239 | if (get_b_dispatch_thread_messages () && msg->message != WM_QUIT) 240 | DispatchMessageW (msg); 241 | 242 | return r; 243 | } 244 | } 245 | 246 | if (bsubclassify_all_ && 247 | !find_exclude_hwnd (msg->hwnd) && !find_hwnd (msg->hwnd) && 248 | is_target_class (msg->hwnd)) 249 | { 250 | // SendMessage does not work 251 | PostMessageW (msg->hwnd, u_WM_TR_IME_SUBCLASSIFY_, 252 | static_cast (true), 0); 253 | } 254 | 255 | return CallNextHookEx (nullptr, code, wparam, lparam); 256 | } 257 | -------------------------------------------------------------------------------- /src/get_msg_proc.hh: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; coding: utf-8 -*- 2 | 3 | // This file is part of 4 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 5 | // https://github.com/trueroad/tr-emacs-ime-module 6 | // 7 | // Copyright (C) 2020, 2022 Masamichi Hosoda 8 | // 9 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 10 | // is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 16 | // is distributed in the hope that it will be useful, 17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | // GNU General Public License for more details. 20 | // 21 | // You should have received a copy of the GNU General Public License 22 | // along with tr-ime. 23 | // If not, see . 24 | 25 | #ifndef INCLUDE_GUARD_GET_MSG_PROC_HH 26 | #define INCLUDE_GUARD_GET_MSG_PROC_HH 27 | 28 | #include 29 | #include 30 | 31 | #include 32 | 33 | class get_msg_proc final 34 | { 35 | public: 36 | static LRESULT CALLBACK proc (int, WPARAM, LPARAM); 37 | static void destroy (HWND hwnd) 38 | { 39 | remove_hwnd (hwnd); 40 | remove_exclude_hwnd (hwnd); 41 | } 42 | static void set_b_dispatch_thread_messages (bool bset) 43 | { 44 | ab_dispatch_thread_messages_.store (bset); 45 | } 46 | static void set_b_dispatch_thread_wm_timer (bool bset) 47 | { 48 | ab_dispatch_thread_wm_timer_.store (bset); 49 | } 50 | 51 | explicit get_msg_proc () = delete; 52 | ~get_msg_proc () = delete; 53 | get_msg_proc (const get_msg_proc &) = delete; 54 | get_msg_proc (get_msg_proc &&) = delete; 55 | get_msg_proc& operator = (const get_msg_proc &) = delete; 56 | get_msg_proc& operator = (get_msg_proc &&) = delete; 57 | 58 | private: 59 | static bool find_hwnd (HWND hwnd) 60 | { 61 | return (hwnds_.find (hwnd) != hwnds_.end ()); 62 | } 63 | static void add_hwnd (HWND hwnd) 64 | { 65 | hwnds_.insert (hwnd); 66 | } 67 | static void remove_hwnd (HWND hwnd) 68 | { 69 | hwnds_.erase (hwnd); 70 | } 71 | static bool find_exclude_hwnd (HWND hwnd) 72 | { 73 | return (exclude_hwnds_.find (hwnd) != exclude_hwnds_.end ()); 74 | } 75 | static void add_exclude_hwnd (HWND hwnd) 76 | { 77 | exclude_hwnds_.insert (hwnd); 78 | } 79 | static void remove_exclude_hwnd (HWND hwnd) 80 | { 81 | exclude_hwnds_.erase (hwnd); 82 | } 83 | static bool get_b_dispatch_thread_messages (void) 84 | { 85 | return ab_dispatch_thread_messages_.load (); 86 | } 87 | static bool get_b_dispatch_thread_wm_timer (void) 88 | { 89 | return ab_dispatch_thread_wm_timer_.load (); 90 | } 91 | 92 | static LRESULT wm_tr_ime_subclassify (int, WPARAM, LPARAM); 93 | static LRESULT wm_tr_ime_unsubclassify (int, WPARAM, LPARAM); 94 | static LRESULT wm_tr_ime_exists_subclassified (int, WPARAM, LPARAM); 95 | static bool is_target_class (HWND); 96 | 97 | static constexpr WCHAR target_class_name_[] {L"Emacs"}; 98 | 99 | static thread_local bool bsubclassify_all_; 100 | static thread_local std::unordered_set hwnds_; 101 | static thread_local std::unordered_set exclude_hwnds_; 102 | 103 | static std::atomic ab_dispatch_thread_messages_; 104 | static std::atomic ab_dispatch_thread_wm_timer_; 105 | }; 106 | 107 | #endif // INCLUDE_GUARD_GET_MSG_PROC_HH 108 | -------------------------------------------------------------------------------- /src/lisp-in-cc.hh: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; coding: utf-8 -*- 2 | 3 | // This file is part of 4 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 5 | // https://github.com/trueroad/tr-emacs-ime-module 6 | // 7 | // Copyright (C) 2020, 2022 Masamichi Hosoda 8 | // 9 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 10 | // is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 16 | // is distributed in the hope that it will be useful, 17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | // GNU General Public License for more details. 20 | // 21 | // You should have received a copy of the GNU General Public License 22 | // along with tr-ime. 23 | // If not, see . 24 | 25 | #ifndef INCLUDE_GUARD_LISP_IN_CC_HH 26 | #define INCLUDE_GUARD_LISP_IN_CC_HH 27 | 28 | #include 29 | 30 | emacs_value 31 | Ftr_ime_modadv__install_message_hook_hwnd (emacs_env*, ptrdiff_t, 32 | emacs_value[], void*) noexcept; 33 | extern const char *doc_tr_ime_modadv__install_message_hook_hwnd; 34 | 35 | emacs_value 36 | Ftr_ime_modadv__uninstall_message_hook_hwnd (emacs_env*, ptrdiff_t, 37 | emacs_value[], void*) noexcept; 38 | extern const char *doc_tr_ime_modadv__uninstall_message_hook_hwnd; 39 | 40 | emacs_value 41 | Ftr_ime_modadv__subclassify_hwnd (emacs_env*, ptrdiff_t, emacs_value[], void*) 42 | noexcept; 43 | extern const char *doc_tr_ime_modadv__subclassify_hwnd; 44 | 45 | emacs_value 46 | Ftr_ime_modadv__unsubclassify_hwnd (emacs_env*, ptrdiff_t, 47 | emacs_value[], void*) noexcept; 48 | extern const char *doc_tr_ime_modadv__unsubclassify_hwnd; 49 | 50 | emacs_value 51 | Ftr_ime_modadv__exists_subclassified (emacs_env*, ptrdiff_t, 52 | emacs_value[], void*) noexcept; 53 | extern const char *doc_tr_ime_modadv__exists_subclassified; 54 | 55 | emacs_value 56 | Ftr_ime_modadv__set_dispatch_thread_message (emacs_env*, ptrdiff_t, 57 | emacs_value[], void*) noexcept; 58 | extern const char *doc_tr_ime_modadv__set_dispatch_thread_message; 59 | 60 | emacs_value 61 | Ftr_ime_modadv__set_dispatch_thread_wm_timer (emacs_env*, ptrdiff_t, 62 | emacs_value[], void*) noexcept; 63 | extern const char *doc_tr_ime_modadv__set_dispatch_thread_wm_timer; 64 | 65 | emacs_value 66 | Ftr_ime_modadv__setopenstatus (emacs_env*, ptrdiff_t, 67 | emacs_value[], void*) noexcept; 68 | extern const char *doc_tr_ime_modadv__setopenstatus; 69 | 70 | emacs_value 71 | Ftr_ime_modadv__getopenstatus (emacs_env*, ptrdiff_t, 72 | emacs_value[], void*) noexcept; 73 | extern const char *doc_tr_ime_modadv__getopenstatus; 74 | 75 | emacs_value 76 | Ftr_ime_modadv__set_font (emacs_env*, ptrdiff_t, 77 | emacs_value[], void*) noexcept; 78 | extern const char *doc_tr_ime_modadv__set_font; 79 | 80 | emacs_value 81 | Ftr_ime_modadv__set_composition_window (emacs_env*, ptrdiff_t, 82 | emacs_value[], void*) noexcept; 83 | extern const char *doc_tr_ime_modadv__set_composition_window; 84 | 85 | emacs_value 86 | Ftr_ime_modadv__set_startcomposition_defsubclassproc (emacs_env*, ptrdiff_t, 87 | emacs_value[], void*) 88 | noexcept; 89 | extern const char *doc_tr_ime_modadv__set_startcomposition_defsubclassproc; 90 | 91 | emacs_value 92 | Ftr_ime_modadv__set_prefix_keys (emacs_env*, ptrdiff_t, 93 | emacs_value[], void*) noexcept; 94 | extern const char *doc_tr_ime_modadv__set_prefix_keys; 95 | 96 | emacs_value 97 | Ftr_ime_modadv__resume_prefix_key (emacs_env*, ptrdiff_t, 98 | emacs_value[], void*) noexcept; 99 | extern const char *doc_tr_ime_modadv__resume_prefix_key; 100 | 101 | extern const char *doc_tr_ime_modadv__setopenstatus_hook; 102 | extern const char *doc_tr_ime_modadv__reconvertstring_hook; 103 | extern const char *doc_tr_ime_modadv__documentfeed_hook; 104 | 105 | emacs_value 106 | Ftr_ime_modadv__language_change_handler (emacs_env*, ptrdiff_t, 107 | emacs_value[], void*) noexcept; 108 | extern const char *doc_tr_ime_modadv__language_change_handler; 109 | 110 | emacs_value 111 | Ftr_ime_modadv__notify_reconvert_string (emacs_env*, ptrdiff_t, 112 | emacs_value[], void*) noexcept; 113 | extern const char *doc_tr_ime_modadv__notify_reconvert_string; 114 | 115 | emacs_value 116 | Ftr_ime_modadv__set_reconversion (emacs_env*, ptrdiff_t, 117 | emacs_value[], void*) noexcept; 118 | extern const char *doc_tr_ime_modadv__set_reconversion; 119 | 120 | emacs_value 121 | Ftr_ime_modadv__set_documentfeed (emacs_env*, ptrdiff_t, 122 | emacs_value[], void*) noexcept; 123 | extern const char *doc_tr_ime_modadv__set_documentfeed; 124 | 125 | emacs_value 126 | Ftr_ime_modadv__get_dpi (emacs_env*, ptrdiff_t, 127 | emacs_value[], void*) noexcept; 128 | extern const char *doc_tr_ime_modadv__get_dpi; 129 | 130 | emacs_value 131 | Ftr_ime_modadv__set_verbose_level (emacs_env*, ptrdiff_t, 132 | emacs_value[], void*) noexcept; 133 | extern const char *doc_tr_ime_modadv__set_verbose_level; 134 | 135 | emacs_value 136 | Ftr_ime_modadv_unload_function (emacs_env*, ptrdiff_t, 137 | emacs_value[], void*) noexcept; 138 | extern const char *doc_tr_ime_modadv_unload_function; 139 | 140 | #ifndef NDEBUG 141 | 142 | emacs_value 143 | Ftr_ime_modadv__debug_output (emacs_env*, ptrdiff_t, 144 | emacs_value[], void*) noexcept; 145 | extern const char *doc_tr_ime_modadv__debug_output; 146 | 147 | emacs_value 148 | Ftr_ime_modadv__debug_rectangle (emacs_env*, ptrdiff_t, 149 | emacs_value[], void*) noexcept; 150 | extern const char *doc_tr_ime_modadv__debug_rectangle; 151 | 152 | #endif // NDEBUG 153 | 154 | #endif // INCLUDE_GUARD_LISP_IN_CC_HH 155 | -------------------------------------------------------------------------------- /src/message.cc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; coding: utf-8 -*- 2 | 3 | // This file is part of 4 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 5 | // https://github.com/trueroad/tr-emacs-ime-module 6 | // 7 | // Copyright (C) 2020 Masamichi Hosoda 8 | // 9 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 10 | // is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 16 | // is distributed in the hope that it will be useful, 17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | // GNU General Public License for more details. 20 | // 21 | // You should have received a copy of the GNU General Public License 22 | // along with tr-ime. 23 | // If not, see . 24 | 25 | #include "message.hh" 26 | 27 | #include 28 | 29 | constexpr WCHAR s_WM_TR_IME_SUBCLASSIFY_[] = L"WM_TR_IME_SUBCLASSIFY"; 30 | const UINT u_WM_TR_IME_SUBCLASSIFY_ = 31 | RegisterWindowMessageW (s_WM_TR_IME_SUBCLASSIFY_); 32 | 33 | constexpr WCHAR s_WM_TR_IME_UNSUBCLASSIFY_[] = L"WM_TR_IME_UNSUBCLASSIFY"; 34 | const UINT u_WM_TR_IME_UNSUBCLASSIFY_ = 35 | RegisterWindowMessageW (s_WM_TR_IME_UNSUBCLASSIFY_); 36 | 37 | constexpr WCHAR s_WM_TR_IME_EXISTS_SUBCLASSIFIED_[] = 38 | L"WM_TR_IME_EXISTS_SUBCLASSIFIED"; 39 | const UINT u_WM_TR_IME_EXISTS_SUBCLASSIFIED_ = 40 | RegisterWindowMessageW (s_WM_TR_IME_EXISTS_SUBCLASSIFIED_); 41 | 42 | constexpr WCHAR s_WM_TR_IME_SET_OPEN_STATUS_[] = L"WM_TR_IME_SET_OPEN_STATUS"; 43 | const UINT u_WM_TR_IME_SET_OPEN_STATUS_ = 44 | RegisterWindowMessageW (s_WM_TR_IME_SET_OPEN_STATUS_); 45 | 46 | constexpr WCHAR s_WM_TR_IME_GET_OPEN_STATUS_[] = L"WM_TR_IME_GET_OPEN_STATUS"; 47 | const UINT u_WM_TR_IME_GET_OPEN_STATUS_ = 48 | RegisterWindowMessageW (s_WM_TR_IME_GET_OPEN_STATUS_); 49 | 50 | constexpr WCHAR s_WM_TR_IME_SET_FONT_[] = L"WM_TR_IME_SET_FONT"; 51 | const UINT u_WM_TR_IME_SET_FONT_ = 52 | RegisterWindowMessageW (s_WM_TR_IME_SET_FONT_); 53 | 54 | constexpr WCHAR s_WM_TR_IME_SET_COMPOSITIONWINDOW_[] = 55 | L"WM_TR_IME_SET_COMPOSITIONWINDOW"; 56 | const UINT u_WM_TR_IME_SET_COMPOSITIONWINDOW_ = 57 | RegisterWindowMessageW (s_WM_TR_IME_SET_COMPOSITIONWINDOW_); 58 | 59 | constexpr WCHAR s_WM_TR_IME_SET_PREFIX_KEYS_[] = 60 | L"WM_TR_IME_SET_PREFIX_KEYS"; 61 | const UINT u_WM_TR_IME_SET_PREFIX_KEYS_ = 62 | RegisterWindowMessageW (s_WM_TR_IME_SET_PREFIX_KEYS_); 63 | 64 | constexpr WCHAR s_WM_TR_IME_NOTIFY_RECONVERT_STRING_[] = 65 | L"WM_TR_IME_NOTIFY_RECONVERT_STRING"; 66 | const UINT u_WM_TR_IME_NOTIFY_RECONVERT_STRING_ = 67 | RegisterWindowMessageW (s_WM_TR_IME_NOTIFY_RECONVERT_STRING_); 68 | 69 | constexpr WCHAR s_WM_TR_IME_NOTIFY_BACKWARD_COMPLETE_[] = 70 | L"WM_TR_IME_NOTIFY_BACKWARD_COMPLETE"; 71 | const UINT u_WM_TR_IME_NOTIFY_BACKWARD_COMPLETE_ = 72 | RegisterWindowMessageW (s_WM_TR_IME_NOTIFY_BACKWARD_COMPLETE_); 73 | -------------------------------------------------------------------------------- /src/message.hh: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; coding: utf-8 -*- 2 | 3 | // This file is part of 4 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 5 | // https://github.com/trueroad/tr-emacs-ime-module 6 | // 7 | // Copyright (C) 2020 Masamichi Hosoda 8 | // 9 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 10 | // is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 16 | // is distributed in the hope that it will be useful, 17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | // GNU General Public License for more details. 20 | // 21 | // You should have received a copy of the GNU General Public License 22 | // along with tr-ime. 23 | // If not, see . 24 | 25 | #ifndef INCLUDE_GUARD_MESSAGE_HH 26 | #define INCLUDE_GUARD_MESSAGE_HH 27 | 28 | #include 29 | 30 | extern const UINT u_WM_TR_IME_SUBCLASSIFY_; 31 | extern const UINT u_WM_TR_IME_UNSUBCLASSIFY_; 32 | extern const UINT u_WM_TR_IME_EXISTS_SUBCLASSIFIED_; 33 | extern const UINT u_WM_TR_IME_SET_OPEN_STATUS_; 34 | extern const UINT u_WM_TR_IME_GET_OPEN_STATUS_; 35 | extern const UINT u_WM_TR_IME_SET_FONT_; 36 | extern const UINT u_WM_TR_IME_SET_COMPOSITIONWINDOW_; 37 | extern const UINT u_WM_TR_IME_SET_PREFIX_KEYS_; 38 | extern const UINT u_WM_TR_IME_NOTIFY_RECONVERT_STRING_; 39 | extern const UINT u_WM_TR_IME_NOTIFY_BACKWARD_COMPLETE_; 40 | 41 | #endif // INCLUDE_GUARD_MESSAGE_HH 42 | -------------------------------------------------------------------------------- /src/queue.cc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; coding: utf-8 -*- 2 | 3 | // This file is part of 4 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 5 | // https://github.com/trueroad/tr-emacs-ime-module 6 | // 7 | // Copyright (C) 2020 Masamichi Hosoda 8 | // 9 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 10 | // is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 16 | // is distributed in the hope that it will be useful, 17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | // GNU General Public License for more details. 20 | // 21 | // You should have received a copy of the GNU General Public License 22 | // along with tr-ime. 23 | // If not, see . 24 | 25 | #include "queue.hh" 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | std::mutex ui_to_lisp_queue::mtx_; 33 | std::deque> ui_to_lisp_queue::queue_; 34 | 35 | bool 36 | ui_to_lisp_queue::empty (void) 37 | { 38 | std::lock_guard lock (mtx_); 39 | 40 | return queue_.empty (); 41 | } 42 | 43 | void 44 | ui_to_lisp_queue::enqueue (std::unique_ptr &&m) 45 | { 46 | std::lock_guard lock (mtx_); 47 | 48 | queue_.push_back (std::move (m)); 49 | } 50 | 51 | void 52 | ui_to_lisp_queue::enqueue_fast (std::unique_ptr &&m) 53 | { 54 | std::lock_guard lock (mtx_); 55 | 56 | queue_.push_front (std::move (m)); 57 | } 58 | 59 | void 60 | ui_to_lisp_queue::enqueue_one (std::unique_ptr &&m) 61 | { 62 | std::lock_guard lock (mtx_); 63 | 64 | if (std::find_if (queue_.begin (), queue_.end (), 65 | [&m] (const std::unique_ptr &p) 66 | { 67 | return p->get_message () == m->get_message (); 68 | } 69 | ) == queue_.end ()) 70 | queue_.push_back (std::move (m)); 71 | } 72 | 73 | void 74 | ui_to_lisp_queue::enqueue_fast_one (std::unique_ptr &&m) 75 | { 76 | std::lock_guard lock (mtx_); 77 | 78 | while (!queue_.empty ()) 79 | { 80 | auto it = std::find_if (queue_.begin (), queue_.end (), 81 | [&m] (const std::unique_ptr &p) 82 | { 83 | return p->get_message () == m->get_message (); 84 | } 85 | ); 86 | if (it == queue_.end ()) 87 | break; 88 | queue_.erase (it); 89 | } 90 | 91 | queue_.push_front (std::move (m)); 92 | } 93 | 94 | std::unique_ptr 95 | ui_to_lisp_queue::dequeue (void) 96 | { 97 | std::lock_guard lock (mtx_); 98 | 99 | if (queue_.empty ()) 100 | return nullptr; 101 | 102 | std::unique_ptr m = std::move (queue_.front ()); 103 | if (m) 104 | { 105 | queue_.pop_front (); 106 | return m; 107 | } 108 | 109 | return nullptr; 110 | } 111 | -------------------------------------------------------------------------------- /src/queue.hh: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; coding: utf-8 -*- 2 | 3 | // This file is part of 4 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 5 | // https://github.com/trueroad/tr-emacs-ime-module 6 | // 7 | // Copyright (C) 2020 Masamichi Hosoda 8 | // 9 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 10 | // is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 16 | // is distributed in the hope that it will be useful, 17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | // GNU General Public License for more details. 20 | // 21 | // You should have received a copy of the GNU General Public License 22 | // along with tr-ime. 23 | // If not, see . 24 | 25 | #ifndef INCLUDE_GUARD_QUEUE_HH 26 | #define INCLUDE_GUARD_QUEUE_HH 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | 34 | class queue_message 35 | { 36 | public: 37 | enum class message 38 | { setopenstatus, reconvertstring, documentfeed, 39 | backward_char, delete_char 40 | }; 41 | 42 | explicit queue_message (message msg, HWND hwnd): 43 | message_ (msg), hwnd_ (hwnd), parameter_ (0) 44 | { 45 | } 46 | explicit queue_message (message msg, HWND hwnd, int param): 47 | message_ (msg), hwnd_ (hwnd), parameter_ (param) 48 | { 49 | } 50 | virtual ~queue_message () 51 | { 52 | } 53 | 54 | message get_message (void) const 55 | { 56 | return message_; 57 | } 58 | HWND get_hwnd (void) const 59 | { 60 | return hwnd_; 61 | } 62 | int get_parameter (void) const 63 | { 64 | return parameter_; 65 | } 66 | 67 | private: 68 | const message message_; 69 | const HWND hwnd_; 70 | const int parameter_; 71 | }; 72 | 73 | class ui_to_lisp_queue 74 | { 75 | public: 76 | explicit ui_to_lisp_queue () = delete; 77 | ~ui_to_lisp_queue () = delete; 78 | ui_to_lisp_queue (const ui_to_lisp_queue &) = delete; 79 | ui_to_lisp_queue (ui_to_lisp_queue &&) = delete; 80 | ui_to_lisp_queue& operator = (const ui_to_lisp_queue &) = delete; 81 | ui_to_lisp_queue& operator = (ui_to_lisp_queue &&) = delete; 82 | 83 | static bool empty(void); 84 | static void enqueue (std::unique_ptr &&); 85 | static void enqueue_fast (std::unique_ptr &&); 86 | static void enqueue_one (std::unique_ptr &&); 87 | static void enqueue_fast_one (std::unique_ptr &&); 88 | static std::unique_ptr dequeue (void); 89 | 90 | private: 91 | static std::mutex mtx_; 92 | static std::deque> queue_; 93 | }; 94 | 95 | #endif // INCLUDE_GUARD_QUEUE_HH 96 | -------------------------------------------------------------------------------- /src/subclass_proc.hh: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; coding: utf-8 -*- 2 | 3 | // This file is part of 4 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 5 | // https://github.com/trueroad/tr-emacs-ime-module 6 | // 7 | // Copyright (C) 2020 Masamichi Hosoda 8 | // 9 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 10 | // is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 16 | // is distributed in the hope that it will be useful, 17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | // GNU General Public License for more details. 20 | // 21 | // You should have received a copy of the GNU General Public License 22 | // along with tr-ime. 23 | // If not, see . 24 | 25 | #ifndef INCLUDE_GUARD_SUBCLASS_PROC_HH 26 | #define INCLUDE_GUARD_SUBCLASS_PROC_HH 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include 36 | 37 | class subclass_proc final 38 | { 39 | public: 40 | static LRESULT CALLBACK 41 | proc (HWND, UINT, WPARAM, LPARAM, UINT_PTR, DWORD_PTR); 42 | 43 | explicit subclass_proc () = delete; 44 | ~subclass_proc () = delete; 45 | subclass_proc (const subclass_proc &) = delete; 46 | subclass_proc (subclass_proc &&) = delete; 47 | subclass_proc& operator = (const subclass_proc &) = delete; 48 | subclass_proc& operator = (subclass_proc &&) = delete; 49 | 50 | static constexpr UINT_PTR get_subclass_id (void) 51 | { 52 | return subclass_id_; 53 | } 54 | 55 | static void lisp_resume_prefix_key (void) 56 | { 57 | prefix_key::lisp_resume (); 58 | } 59 | static void lisp_set_startcomposition_defsubclassproc (bool flag) 60 | { 61 | ab_startcomposition_defsubclassproc_.store (flag); 62 | } 63 | static void lisp_set_reconversion (bool flag) 64 | { 65 | ab_reconversion_.store (flag); 66 | } 67 | static void lisp_set_documentfeed (bool flag) 68 | { 69 | ab_documentfeed_.store (flag); 70 | } 71 | 72 | static void set_last_ime_state (bool flag) 73 | { 74 | ab_last_ime_state_set_.store (flag); 75 | } 76 | 77 | private: 78 | class prefix_key 79 | { 80 | public: 81 | static void set (HWND); 82 | static void lisp_resume (void); 83 | private: 84 | static std::mutex mtx_; 85 | static HWND hwnd_; 86 | static bool b_before_ime_mode_; 87 | }; 88 | 89 | class reconvert_string 90 | { 91 | public: 92 | // offset is a byte count from the beginning of the string 93 | // to indicate the cursor position, similar to 94 | // RECONVERTSTRING dwCompStrOffset. 95 | static void set (std::basic_string &&str, DWORD offset) 96 | { 97 | str_ = std::move (str); 98 | offset_ = offset; 99 | len_ = 0; 100 | ab_set_.store (true); 101 | } 102 | static void add_comp (const std::basic_string &compstr) 103 | { 104 | str_.insert (offset_ / sizeof (WCHAR), compstr); 105 | len_ = compstr.size (); 106 | } 107 | static void clear (void) 108 | { 109 | ab_set_.store (false); 110 | } 111 | static std::basic_string &get_str (void) 112 | { 113 | return str_; 114 | } 115 | // For RECONVERTSTRING dwSize 116 | // byte count for the struct 117 | static DWORD get_dwSize (void) 118 | { 119 | return sizeof (RECONVERTSTRING) + 120 | (get_dwStrLen () + 1) * sizeof (WCHAR); 121 | } 122 | // For RECONVERTSTRING dwStrLen 123 | // WCHAR count for the length of the full string 124 | static DWORD get_dwStrLen (void) 125 | { 126 | return str_.size (); 127 | } 128 | // For RECONVERTSTRING dwStrOffset 129 | // byte count from the beginning of the struct to indicate the offset 130 | // of the full string 131 | static constexpr DWORD get_dwStrOffset (void) 132 | { 133 | return sizeof (RECONVERTSTRING); 134 | } 135 | // For RECONVERTSTRING dwComStrOffset 136 | // byte count from the beginning of the string to indicate the offset 137 | // of the composition string 138 | static DWORD get_dwCompStrOffset (void) 139 | { 140 | return offset_; 141 | } 142 | // For RECONVERTSTRING dwCompStrLen 143 | // WCHAR count for the length of the composition string 144 | static DWORD get_dwCompStrLen (void) 145 | { 146 | return len_; 147 | } 148 | static bool isset (void) 149 | { 150 | return ab_set_.load (); 151 | } 152 | private: 153 | static thread_local std::basic_string str_; 154 | static thread_local DWORD offset_; 155 | static thread_local DWORD len_; 156 | static thread_local std::atomic ab_set_; 157 | }; 158 | 159 | class backward_complete 160 | { 161 | public: 162 | static void set(void) 163 | { 164 | ab_set_.store (true); 165 | } 166 | static void clear (void) 167 | { 168 | ab_set_.store (false); 169 | } 170 | static bool isset (void) 171 | { 172 | return ab_set_.load (); 173 | } 174 | private: 175 | static thread_local std::atomic ab_set_; 176 | }; 177 | 178 | static bool wait_message (HWND, std::function); 179 | static bool set_reconvert_string (RECONVERTSTRING*); 180 | 181 | static LRESULT wm_tr_ime_set_open_status (HWND, UINT, WPARAM, LPARAM); 182 | static LRESULT wm_tr_ime_get_open_status (HWND, UINT, WPARAM, LPARAM); 183 | static LRESULT wm_tr_ime_set_font (HWND, UINT, WPARAM, LPARAM); 184 | static LRESULT wm_tr_ime_set_compositionwindow (HWND, UINT, WPARAM, LPARAM); 185 | static LRESULT wm_tr_ime_set_prefix_keys (HWND, UINT, WPARAM, LPARAM); 186 | static LRESULT 187 | wm_tr_ime_notify_reconvert_string (HWND, UINT, WPARAM, LPARAM); 188 | static LRESULT 189 | wm_tr_ime_notify_backward_complete (HWND, UINT, WPARAM, LPARAM); 190 | 191 | static bool get_reconvert_string (HWND, bool); 192 | static bool add_composition_string (HWND); 193 | static void process_backward_characters (HWND, RECONVERTSTRING*, DWORD); 194 | static void process_delete_characters (HWND, RECONVERTSTRING*); 195 | static LRESULT imr_reconvertstring (HWND, UINT, WPARAM, LPARAM); 196 | static LRESULT imr_documentfeed (HWND, UINT, WPARAM, LPARAM); 197 | 198 | static LRESULT wm_keydown (HWND, UINT, WPARAM, LPARAM); 199 | static LRESULT wm_ime_notify (HWND, UINT, WPARAM, LPARAM); 200 | static LRESULT wm_ime_request (HWND, UINT, WPARAM, LPARAM); 201 | static LRESULT wm_ime_composition (HWND, UINT, WPARAM, LPARAM); 202 | static LRESULT wm_ime_startcomposition (HWND, UINT, WPARAM, LPARAM); 203 | static LRESULT wm_ime_endcomposition (HWND, UINT, WPARAM, LPARAM); 204 | 205 | static constexpr UINT_PTR subclass_id_ {0}; 206 | static thread_local LOGFONTW lf_imefont_; 207 | static thread_local COMPOSITIONFORM compform_; 208 | static thread_local std::unordered_set prefix_keys_; 209 | static std::atomic ab_startcomposition_defsubclassproc_; 210 | static std::atomic ab_last_ime_state_set_; 211 | static std::atomic ab_reconversion_; 212 | static std::atomic ab_documentfeed_; 213 | static std::atomic ai_delete_chars_reconversion_complete_; 214 | static thread_local std::unordered_set compositioning_hwnds_; 215 | 216 | static constexpr int i_wait_message_times_ = 100; 217 | static constexpr DWORD dw_wait_message_single_ = 1000; 218 | static constexpr DWORD dw_wait_message_total_ = 3000; 219 | }; 220 | 221 | #endif // INCLUDE_GUARD_SUBCLASS_PROC_HH 222 | -------------------------------------------------------------------------------- /src/tr-ime-mod-resource.rc: -------------------------------------------------------------------------------- 1 | // -*- coding: utf-8 -*- 2 | 3 | // This file is part of 4 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 5 | // https://github.com/trueroad/tr-emacs-ime-module 6 | // 7 | // Copyright (C) 2020 Masamichi Hosoda 8 | // 9 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 10 | // is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 16 | // is distributed in the hope that it will be useful, 17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | // GNU General Public License for more details. 20 | // 21 | // You should have received a copy of the GNU General Public License 22 | // along with tr-ime. 23 | // If not, see . 24 | 25 | #include "config.h" 26 | 27 | #include 28 | 29 | // UTF-8 30 | #pragma code_page(65001) 31 | 32 | VS_VERSION_INFO VERSIONINFO 33 | FILEVERSION PACKAGE_FILEVERSION 34 | PRODUCTVERSION PACKAGE_PRODUCTVERSION 35 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK 36 | FILEFLAGS VS_FF_PRERELEASE 37 | FILETYPE VFT_DLL 38 | FILESUBTYPE VFT2_UNKNOWN 39 | BEGIN 40 | BLOCK "StringFileInfo" 41 | BEGIN 42 | BLOCK "040904b0" 43 | BEGIN 44 | VALUE "FileDescription", PACKAGE_NAME " (" PACKAGE ")\0" 45 | VALUE "FileVersion", PACKAGE_VERSION "\0" 46 | VALUE "InternalName", PACKAGE "\0" 47 | VALUE "LegalCopyright", \ 48 | PACKAGE_COPYRIGHT " " PACKAGE_LICENSE "\0" 49 | VALUE "LegalTrademarks", PACKAGE_URL "\0" 50 | VALUE "OriginalFilename", "tr-ime-mod-" \ 51 | MOD_ABI_VERSION "-" HOST_PLATFORM ".dll\0" 52 | VALUE "ProductName", PACKAGE_NAME "\0" 53 | VALUE "ProductVersion", PACKAGE_VERSION "\0" 54 | END 55 | END 56 | BLOCK "VarFileInfo" 57 | BEGIN 58 | VALUE "Translation", 0x409, 0x04B0 59 | END 60 | END 61 | -------------------------------------------------------------------------------- /src/tr-ime-mod.c: -------------------------------------------------------------------------------- 1 | // -*- mode: c; coding: utf-8 -*- 2 | 3 | // This file is part of 4 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 5 | // https://github.com/trueroad/tr-emacs-ime-module 6 | // 7 | // Copyright (C) 2020 Masamichi Hosoda 8 | // 9 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 10 | // is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 16 | // is distributed in the hope that it will be useful, 17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | // GNU General Public License for more details. 20 | // 21 | // You should have received a copy of the GNU General Public License 22 | // along with tr-ime. 23 | // If not, see . 24 | 25 | #define TR_IME_MOD_DLL __declspec(dllexport) 26 | 27 | #include "config.h" 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | // Microsoft undocumented 34 | #ifndef IMC_GETOPENSTATUS 35 | #define IMC_GETOPENSTATUS 0x0005 36 | #endif 37 | #ifndef IMC_SETOPENSTATUS 38 | #define IMC_SETOPENSTATUS 0x0006 39 | #endif 40 | 41 | int TR_IME_MOD_DLL plugin_is_GPL_compatible; 42 | 43 | static emacs_value 44 | tr_ime_mod__setopenstatus 45 | (emacs_env *env, ptrdiff_t nargs, emacs_value *args, void *data) 46 | { 47 | if (nargs != 2) 48 | { 49 | OutputDebugString ("tr_ime_mod__setopenstatus: nargs != 2\n"); 50 | return env->intern (env, "nil"); 51 | } 52 | 53 | HWND hwnd = (HWND)(env->extract_integer (env, args[0])); 54 | BOOL bopen = env->is_not_nil (env, args[1]); 55 | 56 | if (!IsWindow (hwnd)) 57 | { 58 | OutputDebugString ("tr_ime_mod__setopenstatus: hwnd is not window\n"); 59 | return env->intern (env, "nil"); 60 | } 61 | 62 | HWND hwnd_ime = ImmGetDefaultIMEWnd (hwnd); 63 | if (!hwnd_ime) 64 | { 65 | OutputDebugString 66 | ("tr_ime_mod__setopenstatus: ImmGetDefaultIMEWnd failed\n"); 67 | return env->intern (env, "nil"); 68 | } 69 | 70 | // PostMessage does not work. 71 | LRESULT r = SendMessageW (hwnd_ime, WM_IME_CONTROL, 72 | IMC_SETOPENSTATUS, (LPARAM)bopen); 73 | 74 | if (r) 75 | { 76 | OutputDebugString 77 | ("tr_ime_mod__setopenstatus: IMC_SETOPENSTATUS failed\n"); 78 | return env->intern (env, "nil"); 79 | } 80 | 81 | return env->intern (env, "t"); 82 | } 83 | 84 | static emacs_value 85 | tr_ime_mod__getopenstatus 86 | (emacs_env *env, ptrdiff_t nargs, emacs_value *args, void *data) 87 | { 88 | if (nargs != 1) 89 | { 90 | OutputDebugString ("tr_ime_mod__getopenstatus: nargs != 1\n"); 91 | return env->intern (env, "nil"); 92 | } 93 | 94 | HWND hwnd = (HWND)(env->extract_integer (env, args[0])); 95 | 96 | if (!IsWindow (hwnd)) 97 | { 98 | OutputDebugString ("tr_ime_mod__getopenstatus: hwnd is not window\n"); 99 | return env->intern (env, "nil"); 100 | } 101 | 102 | HWND hwnd_ime = ImmGetDefaultIMEWnd (hwnd); 103 | if (!hwnd_ime) 104 | { 105 | OutputDebugString 106 | ("tr_ime_mod__getopenstatus: ImmGetDefaultIMEWnd failed\n"); 107 | return env->intern (env, "nil"); 108 | } 109 | 110 | LRESULT r = SendMessageW (hwnd_ime, WM_IME_CONTROL, 111 | IMC_GETOPENSTATUS, 0); 112 | 113 | if (r) 114 | return env->intern (env, "t"); // IME on 115 | 116 | return env->intern (env, "nil"); // IME off 117 | } 118 | 119 | static void 120 | regist_function (emacs_env *env, 121 | const char *name, 122 | ptrdiff_t min_arity, 123 | ptrdiff_t max_arity, 124 | emacs_value (*function) (emacs_env *env, 125 | ptrdiff_t nargs, 126 | emacs_value args[], 127 | void *), 128 | const char *documentation, 129 | void *data) 130 | { 131 | emacs_value defalias = env->intern (env, "defalias"); 132 | emacs_value symbol = env->intern (env, name); 133 | emacs_value func = 134 | env->make_function (env, min_arity, max_arity, function, 135 | documentation, data); 136 | emacs_value args[] = {symbol, func}; 137 | 138 | env->funcall (env, defalias, sizeof (args) / sizeof (args[0]), args); 139 | } 140 | 141 | static void 142 | provide_feature (emacs_env *env, const char *name) 143 | { 144 | emacs_value provide = env->intern (env, "provide"); 145 | emacs_value feature = env->intern (env, name); 146 | emacs_value args[] = {feature}; 147 | 148 | env->funcall (env, provide, sizeof (args) / sizeof (args[0]), args); 149 | } 150 | 151 | int TR_IME_MOD_DLL 152 | emacs_module_init (struct emacs_runtime *ert) 153 | { 154 | if (ert->size < sizeof (*ert)) 155 | { 156 | OutputDebugString ("tr-ime-mod: ert->size < sizeof (*ert)\n"); 157 | return 1; 158 | } 159 | 160 | emacs_env *env = ert->get_environment (ert); 161 | if (env->size < sizeof (*env)) 162 | { 163 | OutputDebugString ("tr-ime-mod: env->size < sizeof (*env)\n"); 164 | return 2; 165 | } 166 | 167 | regist_function (env, "tr-ime-mod--setopenstatus", 168 | 2, 2, tr_ime_mod__setopenstatus, 169 | "Send WM_IME_CONTROL message with IMC_SETOPENSTATUS (undocumented).\n\n" 170 | "ARG1 is interpreted as HWND and ARG2 is interpreted as BOOL.\n" 171 | "The message is then sent to the default IME window of the HWND.\n" 172 | "If the BOOL is FALSE, IME is turned off, otherwise, IME is turned on.\n\n" 173 | "Sample usage:\n" 174 | "(tr-ime-mod--setopenstatus\n" 175 | " (string-to-number (frame-parameter nil 'window-id)) t)", 176 | NULL); 177 | regist_function (env, "tr-ime-mod--getopenstatus", 178 | 1, 1, tr_ime_mod__getopenstatus, 179 | "Send WM_IME_CONTROL message with IMC_GETOPENSTATUS (undocumented).\n\n" 180 | "ARG1 is interpreted as HWND.\n" 181 | "The message is then sent to the default IME window of the HWND.\n" 182 | "If IME is off, nil is returned, otherwise non-nil is returned.\n\n" 183 | "Sample usage:\n" 184 | "(tr-ime-mod--getopenstatus\n" 185 | " (string-to-number (frame-parameter nil 'window-id)))", 186 | NULL); 187 | provide_feature (env, "tr-ime-mod"); 188 | 189 | return 0; 190 | } 191 | -------------------------------------------------------------------------------- /src/tr-ime-modadv-resource.rc: -------------------------------------------------------------------------------- 1 | // -*- coding: utf-8 -*- 2 | 3 | // This file is part of 4 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 5 | // https://github.com/trueroad/tr-emacs-ime-module 6 | // 7 | // Copyright (C) 2020 Masamichi Hosoda 8 | // 9 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 10 | // is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 16 | // is distributed in the hope that it will be useful, 17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | // GNU General Public License for more details. 20 | // 21 | // You should have received a copy of the GNU General Public License 22 | // along with tr-ime. 23 | // If not, see . 24 | 25 | #include "config.h" 26 | 27 | #include 28 | 29 | // UTF-8 30 | #pragma code_page(65001) 31 | 32 | VS_VERSION_INFO VERSIONINFO 33 | FILEVERSION PACKAGE_FILEVERSION 34 | PRODUCTVERSION PACKAGE_PRODUCTVERSION 35 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK 36 | FILEFLAGS VS_FF_PRERELEASE 37 | FILETYPE VFT_DLL 38 | FILESUBTYPE VFT2_UNKNOWN 39 | BEGIN 40 | BLOCK "StringFileInfo" 41 | BEGIN 42 | BLOCK "040904b0" 43 | BEGIN 44 | VALUE "FileDescription", PACKAGE_NAME " (" PACKAGE ")\0" 45 | VALUE "FileVersion", PACKAGE_VERSION "\0" 46 | VALUE "InternalName", PACKAGE "\0" 47 | VALUE "LegalCopyright", \ 48 | PACKAGE_COPYRIGHT " " PACKAGE_LICENSE "\0" 49 | VALUE "LegalTrademarks", PACKAGE_URL "\0" 50 | VALUE "OriginalFilename", "tr-ime-modadv-" \ 51 | MODADV_ABI_VERSION "-" HOST_PLATFORM ".dll\0" 52 | VALUE "ProductName", PACKAGE_NAME "\0" 53 | VALUE "ProductVersion", PACKAGE_VERSION "\0" 54 | END 55 | END 56 | BLOCK "VarFileInfo" 57 | BEGIN 58 | VALUE "Translation", 0x409, 0x04B0 59 | END 60 | END 61 | -------------------------------------------------------------------------------- /src/tr-ime-modadv.cc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; coding: utf-8 -*- 2 | 3 | // This file is part of 4 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 5 | // https://github.com/trueroad/tr-emacs-ime-module 6 | // 7 | // Copyright (C) 2020, 2022 Masamichi Hosoda 8 | // 9 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 10 | // is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // Emulator of GNU Emacs IME patch for Windows (tr-ime) 16 | // is distributed in the hope that it will be useful, 17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | // GNU General Public License for more details. 20 | // 21 | // You should have received a copy of the GNU General Public License 22 | // along with tr-ime. 23 | // If not, see . 24 | 25 | #define TR_IME_MODADV_DLL __declspec(dllexport) 26 | 27 | #ifdef HAVE_CONFIG_H 28 | #include "config.h" 29 | #endif 30 | 31 | #include 32 | #include 33 | 34 | #include 35 | 36 | #include 37 | 38 | #include "debug-message.hh" 39 | #include "lisp-in-cc.hh" 40 | 41 | int TR_IME_MODADV_DLL plugin_is_GPL_compatible; 42 | 43 | namespace 44 | { 45 | void 46 | regist_function (emacs_env *env, 47 | const char *name, 48 | ptrdiff_t min_arity, 49 | ptrdiff_t max_arity, 50 | emacs_value (*function) (emacs_env *env, 51 | ptrdiff_t nargs, 52 | emacs_value args[], 53 | void *) noexcept, 54 | const char *documentation, 55 | void *data) 56 | { 57 | emacs_value defalias = env->intern (env, "defalias"); 58 | emacs_value symbol = env->intern (env, name); 59 | emacs_value func = 60 | env->make_function (env, min_arity, max_arity, function, 61 | documentation, data); 62 | std::array args {symbol, func}; 63 | 64 | env->funcall (env, defalias, args.size (), args.data ()); 65 | } 66 | 67 | void 68 | regist_variable (emacs_env *env, 69 | const char *name, 70 | emacs_value value, 71 | const std::string &documentation) 72 | { 73 | std::array args_form 74 | { 75 | env->intern (env, "defvar"), 76 | env->intern (env, name), 77 | value, 78 | env->make_string (env, documentation.data (), documentation.size ()) 79 | }; 80 | emacs_value form = env->funcall (env, env->intern (env, "list"), 81 | args_form.size (), args_form.data ()); 82 | 83 | std::array args_eval {form, env->intern (env, "t")}; 84 | env->funcall (env, env->intern (env, "eval"), 85 | args_eval.size (), args_eval.data ()); 86 | } 87 | 88 | void 89 | provide_feature (emacs_env *env, const char *name) 90 | { 91 | emacs_value provide = env->intern (env, "provide"); 92 | emacs_value feature = env->intern (env, name); 93 | std::array args {feature}; 94 | 95 | env->funcall (env, provide, args.size (), args.data ()); 96 | } 97 | }; 98 | 99 | int TR_IME_MODADV_DLL 100 | emacs_module_init (struct emacs_runtime *ert) EMACS_NOEXCEPT 101 | { 102 | DEBUG_MESSAGE ("enter\n"); 103 | 104 | if (ert->size < sizeof (*ert)) 105 | { 106 | WARNING_MESSAGE ("ert->size < sizeof (*ert)\n"); 107 | return 1; 108 | } 109 | 110 | emacs_env *env = ert->get_environment (ert); 111 | if (env->size < sizeof (*env)) 112 | { 113 | WARNING_MESSAGE ("env->size < sizeof (*env)\n"); 114 | return 2; 115 | } 116 | 117 | regist_function (env, "tr-ime-modadv--install-message-hook-hwnd", 118 | 1, 1, Ftr_ime_modadv__install_message_hook_hwnd, 119 | doc_tr_ime_modadv__install_message_hook_hwnd, 120 | nullptr); 121 | regist_function (env, "tr-ime-modadv--uninstall-message-hook-hwnd", 122 | 1, 1, Ftr_ime_modadv__uninstall_message_hook_hwnd, 123 | doc_tr_ime_modadv__uninstall_message_hook_hwnd, 124 | nullptr); 125 | regist_function (env, "tr-ime-modadv--subclassify-hwnd", 126 | 1, 2, Ftr_ime_modadv__subclassify_hwnd, 127 | doc_tr_ime_modadv__subclassify_hwnd, 128 | nullptr); 129 | regist_function (env, "tr-ime-modadv--unsubclassify-hwnd", 130 | 0, 2, Ftr_ime_modadv__unsubclassify_hwnd, 131 | doc_tr_ime_modadv__unsubclassify_hwnd, 132 | nullptr); 133 | regist_function (env, "tr-ime-modadv--exists-subclassified", 134 | 0, 0, Ftr_ime_modadv__exists_subclassified, 135 | doc_tr_ime_modadv__exists_subclassified, 136 | nullptr); 137 | regist_function (env, "tr-ime-modadv--set-dispatch-thread-message", 138 | 1, 1, Ftr_ime_modadv__set_dispatch_thread_message, 139 | doc_tr_ime_modadv__set_dispatch_thread_message, 140 | nullptr); 141 | regist_function (env, "tr-ime-modadv--set-dispatch-thread-wm-timer", 142 | 1, 1, Ftr_ime_modadv__set_dispatch_thread_wm_timer, 143 | doc_tr_ime_modadv__set_dispatch_thread_wm_timer, 144 | nullptr); 145 | regist_function (env, "tr-ime-modadv--setopenstatus", 146 | 2, 2, Ftr_ime_modadv__setopenstatus, 147 | doc_tr_ime_modadv__setopenstatus, 148 | nullptr); 149 | regist_function (env, "tr-ime-modadv--getopenstatus", 150 | 1, 1, Ftr_ime_modadv__getopenstatus, 151 | doc_tr_ime_modadv__getopenstatus, 152 | nullptr); 153 | regist_function (env, "tr-ime-modadv--set-font", 154 | 15, 15, Ftr_ime_modadv__set_font, 155 | doc_tr_ime_modadv__set_font, 156 | nullptr); 157 | regist_function (env, "tr-ime-modadv--set-composition-window", 158 | 8, 8, Ftr_ime_modadv__set_composition_window, 159 | doc_tr_ime_modadv__set_composition_window, 160 | nullptr); 161 | regist_function (env, "tr-ime-modadv--set-startcomposition-defsubclassproc", 162 | 2, 2, Ftr_ime_modadv__set_startcomposition_defsubclassproc, 163 | doc_tr_ime_modadv__set_startcomposition_defsubclassproc, 164 | nullptr); 165 | regist_function (env, "tr-ime-modadv--set-prefix-keys", 166 | 2, 2, Ftr_ime_modadv__set_prefix_keys, 167 | doc_tr_ime_modadv__set_prefix_keys, 168 | nullptr); 169 | regist_function (env, "tr-ime-modadv--resume-prefix-key", 170 | 0, 0, Ftr_ime_modadv__resume_prefix_key, 171 | doc_tr_ime_modadv__resume_prefix_key, 172 | nullptr); 173 | regist_variable (env, "tr-ime-modadv--setopenstatus-hook", 174 | env->intern (env, "nil"), 175 | doc_tr_ime_modadv__setopenstatus_hook); 176 | regist_variable (env, "tr-ime-modadv--reconvertstring-hook", 177 | env->intern (env, "nil"), 178 | doc_tr_ime_modadv__reconvertstring_hook); 179 | regist_variable (env, "tr-ime-modadv--documentfeed-hook", 180 | env->intern (env, "nil"), 181 | doc_tr_ime_modadv__documentfeed_hook); 182 | regist_function (env, "tr-ime-modadv--language-change-handler", 183 | 0, 0, Ftr_ime_modadv__language_change_handler, 184 | doc_tr_ime_modadv__language_change_handler, 185 | nullptr); 186 | regist_function (env, "tr-ime-modadv--notify-reconvert-string", 187 | 3, 3, Ftr_ime_modadv__notify_reconvert_string, 188 | doc_tr_ime_modadv__notify_reconvert_string, 189 | nullptr); 190 | regist_function (env, "tr-ime-modadv--set-reconversion", 191 | 2, 2, Ftr_ime_modadv__set_reconversion, 192 | doc_tr_ime_modadv__set_reconversion, 193 | nullptr); 194 | regist_function (env, "tr-ime-modadv--set-documentfeed", 195 | 2, 2, Ftr_ime_modadv__set_documentfeed, 196 | doc_tr_ime_modadv__set_documentfeed, 197 | nullptr); 198 | regist_function (env, "tr-ime-modadv--get-dpi", 199 | 0, 0, Ftr_ime_modadv__get_dpi, 200 | doc_tr_ime_modadv__get_dpi, 201 | nullptr); 202 | regist_function (env, "tr-ime-modadv--set-verbose-level", 203 | 1, 1, Ftr_ime_modadv__set_verbose_level, 204 | doc_tr_ime_modadv__set_verbose_level, 205 | nullptr); 206 | regist_function (env, "tr-ime-modadv-unload-function", 207 | 0, 0, Ftr_ime_modadv_unload_function, 208 | doc_tr_ime_modadv_unload_function, 209 | nullptr); 210 | 211 | #ifndef NDEBUG 212 | 213 | regist_function (env, "tr-ime-modadv--debug-output", 214 | 1, 1, Ftr_ime_modadv__debug_output, 215 | doc_tr_ime_modadv__debug_output, 216 | nullptr); 217 | regist_function (env, "tr-ime-modadv--debug-rectangle", 218 | 5, 5, Ftr_ime_modadv__debug_rectangle, 219 | doc_tr_ime_modadv__debug_rectangle, 220 | nullptr); 221 | 222 | #endif // NDEBUG 223 | 224 | provide_feature (env, "tr-ime-modadv"); 225 | 226 | return 0; 227 | } 228 | 229 | #ifndef NDEBUG 230 | extern "C" 231 | BOOL WINAPI DllMain (HINSTANCE, DWORD dwReason, LPVOID) 232 | { 233 | switch (dwReason) 234 | { 235 | case DLL_PROCESS_ATTACH: 236 | DEBUG_MESSAGE_STATIC ("debug: DllMain: DLL_PROCESS_ATTACH\n"); 237 | break; 238 | 239 | case DLL_THREAD_ATTACH: 240 | DEBUG_MESSAGE_STATIC ("debug: DllMain: DLL_THREAD_ATTACH\n"); 241 | break; 242 | 243 | case DLL_PROCESS_DETACH: 244 | DEBUG_MESSAGE_STATIC ("debug: DllMain: DLL_PROCESS_DETACH\n"); 245 | break; 246 | 247 | case DLL_THREAD_DETACH: 248 | DEBUG_MESSAGE_STATIC ("debug: DllMain: DLL_THREAD_DETACH\n"); 249 | break; 250 | 251 | default: 252 | DEBUG_MESSAGE_STATIC ("debug: DllMain: dwReason is unknown\n"); 253 | break; 254 | } 255 | 256 | return TRUE; 257 | } 258 | #endif // NDEBUG 259 | --------------------------------------------------------------------------------