--- title: 技術:なぜ漢字をタイピングする際、漢字が割れますか? tags: ja, tech description: 漢字を入力するあなたは、「漢字割れ」という苦境に陥ったことありますか?例えば、「共同」と二文字を入力したいのに、「kyoudou」になってしまって、そのままウェブページに表示されて、どうしても漢字に合成されません。 image: date: "2021-10-19" author: enen summary: | ![](https://i.imgur.com/280Cfej.gif) 漢字を入力するあなたは、「漢字割れ」という苦境に陥ったことありますか?例えば、「共同」と二文字を入力したいのに、「kyoudou」になってしまって、そのままウェブページに表示されて、どうしても漢字に合成されません。 --- # 技術:なぜ漢字をタイピングする際、漢字が割れますか? ![](https://i.imgur.com/TSqyqSg.png) 漢字を入力するあなたは、「漢字割れ」という苦境に陥ったことありますか?例えば、「共同」と二文字を入力したいのに、「kyoudou」になってしまって、そのままウェブページに表示されて、どうしても漢字に合成されません。 この問題について、テキストエディター自体は「コンポジションイベント」がちゃんと処理されなかった可能性があります。フェースブックメッセンジャーもちゃんと「コンポジションイベント」が処理されなかっただろう…毎回更新すると痛い目に遭う。 今回の内容は皆さんに簡単に「キーイベント」と「コンポジションイベント」、またこのイベントと「グループウェア」の関連性を紹介します。 この紹介を通して、 HackMD の中にどんな技術を秘めているのかを理解するための最初の礎になると思います。   :point_right: [HackMD Blog](https://hackmd.io/@hackmd/blog-tw) ## タイピングは入力するだけなのでは?キーイベント(Key Event)を紹介する ![](https://i.imgur.com/280Cfej.gif) ウェブブラウザーの文字は、キーボードを押した瞬間に、「キーイベント」が執行されます。簡単な動きに見えますが、実は三つの操作が含まれます:keypress, keydown, keyup. ここは先に **keydown** と **keyup** を紹介します。==Keydown==とは、名前通り、「押した瞬間」とのことで、キー毎に相応なキーコードが存在し、キーを押すと、そのコードが取得できます。同じに、==keyup==とは「指を離した瞬間」とのことです。 例えば、「h」キーを押した際、キーボード上は「h」と書いて、モニター上のウェブページも「h」と表示されて、非常に単純なことです。 ``` keydown: h keyup: h ``` だが、漢字を入力する際、例えば「共」という文字を入力する場合、発音入力の間、「共」が出てきて、更にスペースキーを押すことで、リストから「共」を探すため、もっとスペースキーキーを押します。 ではどうなるんでしょうか? ``` keydown: k keyup: k keydown: y keyup: y keydown: o keyup: o keydown: u keyup: u keydown: Space keyup: Space keydown: Space keyup: Space keydown: Enter keyup: Enter keydown: Enter keyup: Enter ``` ここまで見れば、英語と中国語がウェブページに入力する際の違いが理解できるだろうと思います。 ### keydown と keyup は違いますか? 上の down と up のコロン以降の内容は同じじゃないですか?と思えるかもしれません。 先ほど説明した down とは「押した瞬間」とのことですが、もし一瞬間押すではなく、押しっぱなしになると、キーイベントは「連続発生」になり、逆に、 up とは指を離した瞬間のことですので、連続発生ができません。 「共」の例から見ると、例えば家の猫 :cat2: がキーボードを踏んで、「kyou」を入力した直後、猫の手で「スペース」何秒押しっぱなしにすると、キーイベントがどうなるんでしょうか? ``` keydown: k keyup: k keydown: y keyup: y keydown: o keydown: u keyup: o keyup: u keydown: d keyup: d keydown: o keydown: u keyup: o keyup: u keydown: Space keydown: Space keydown: Space keydown: Space keydown: Space keydown: Space keydown: Space keydown: Space keyup: Space ``` そこで六つの keydownがあると分かります。ただ keyupが一つだけです。そうすると、両者の関連性が分かると思います。キーボードでパソコンゲームを遊んだことがある人なら、ここでなんとなく分かるだろうと思います。~~~射撃する際、押しっぱなしでは連続発射できますが、狙ってキーを離した瞬間に発動するボムだと一回しか投げれません。多分そうした仕組みで射撃とボム投げがよくkeydown と keyup と設定されるだろう。~~~ ### では keypress とは何でしょうか? 続きまして、 keypress とは何でしょうかを紹介します。名前通り、押さえることです。でもこれって keydown と同じじゃないでしょうか?いや、ここの操作は「文字キー」と「非文字キー」の間に差が出ます。 例えば、「h」を押すと、一つアルファベット「h」が表示されますが、「enter」キーだと「文字を表示」というイベントではないので、これに相応する keycodeしか執行されません。 **keypress は「文字を入力するキー」しか効果ありません。**「Esc」、「Enter」みたいなキーでは効果がありません。 例えば「英語の大小文字」の件ですが、キーが同じ「h/H」でも、 keypress という操作があるからこそ、違う keycode を取得することが区別できます。これは down と up だけでは判断できないことです。 ## ではなぜ漢字をタイピングする際、割れることになるんでしょうか?コンポジションイベントを紹介(Composition Event) Keydown、keypress、keyup を皆に紹介するのはもう一つ重要なことを強調したい目的があります。 先ほど説明していた keypress は「文字を入力するキー」しか発生しませんので、漢字を入力する際、次の問題が気付くかもしれません。 平仮名を入力するタイミング、漢字が入力されてますか? 平仮名では keypress の操作が発生しますか?ほどんとの状況が「ノー」です。:no_entry_sign: 先ほど「共」を入力する際、キーボードイベントから keydown と keyup の動作を分解しました。 down もしくは up がまだ個別のスペルだけで、==まだ漢字出てませんよね==? ``` keydown: k keyup: k keydown: y keyup: y keydown: o keyup: o keydown: u keyup: u keydown: Space keyup: Space keydown: Space keyup: Space keydown: Enter keyup: Enter keydown: Enter keyup: Enter ``` :eight_spoked_asterisk: ここでポイントです。もしテキストエディターの中に CJKを使いたければ (中国語、日本語、韓国語)、例えば中国語入力みたいなことで、私たち必要なのはキーボードイベントだけではなく(Key Event)、 **コンポジションイベント(Composition Event)** も必要です。 例えば、先ほど入力法で入力した「共同」の場合 「Kyoudou」の後はまた漢字リストから正しい文字を選びます。コンポジションイベントはこうなります: ``` Composition Events: compositionstart: compositionupdate: k compositionupdate: ky compositionupdate: きょ compositionupdate: 喬 compositionupdate: 喬d compositionupdate: きょうど compositionupdate: 匈奴う compositionupdate: 共同 compositionupdate: 共同 compositionend: 共同 ``` コンポジションイベントの過程では キーイベント の「Space、Space、Enter」と同時にコンポジションイベントの「きょうど、匈奴う、共同」に転換することに見えるでしょう? これこそコンポジションイベントで、キーイベントと違って、「合成が必要な言語」しか出てきません。 >P.S.:ブラウザー毎のデスクトップ、モバイルの違いによって、違う結果も出てきます。[私たちの開発者 Maxさんから作った codepen](https://codepen.io/jackycute/pen/EvNmWv)でテストしてみましょう。 ## 「コンポジション」を処理するがどうかによって、結構違います なぜたまにソフトウェアサービスが良いのに、更新した後、中国語入力がスムーズに使うことができないんでしょうか?よく「割れ」が発生し、コンポジションがうまくいかないでしょうか?~~例えばよくアップデートする フェースブックメッセンジャー~~ 実は、色んな文字編集の方から「コンポジション」を受け取る際、「合成する間、現れた『字』」という要素の考慮を欠けていて、テキストエディターの中に、処理しなかった可能性があり、もしくはソフトウェアを更新する際、言語テストを忘れる可能性もあります。 >この文書を書いてる同時、私たちのメンバー [Yukai]((https://hackmd.io/@Yukai)) さんも VSCode に対して、コンポジションイベントの文章を発表することを気づきました。 PR: [Fix backspace in IME composition on iOS Safari](https://github.com/microsoft/vscode/pull/40546)。 ## 更に「コラボレーション」! もしテキストエディターは言語入力の中に、「コンポジションが必要な言語入力」を考慮しなければ、keypress 側は「コンポジションの間に生まれる『準文字』」が漏れることになります。 勿論、考え方を変えると、もしコンポジションの言語のユーザーがいなければ、このような需要や問題も存在しなくなる。 更に重要なのは、もし「コラボレーション」エディターはキーボードイベントだけでなはなく、コンポジションイベントのことも考慮しないと、リアルタイムコラボレーション(Realtime Collaboration)上では様々な難関が出るだろう。 ソフトウェア毎にターゲットが違い、例えば Notion は同一ブロックのコラボレーション処理が少な目です。同時編集の際、相手がどこにいるのか見つからなくて(カーソルが表示されません)、同時同じブロックを編集すると、一方が上書きされます。 >「コラボレーション」をテストする一番厳しい試験は皆が一緒にエディターの中で同じ行を入力してみて、何が起こるのか確認します。 キーボードイベント、コンポジションイベントを紹介する目的は将来「コラボレーション」という技術を説明する際、解決策を理解できるようになるためです。 ## テキストエディターが「コンポジション」を処理したことがどうやって分かるんですか? 文章の最初に、「中国語割れ」という状況を提起しましたが、これは多くの人がGoogle Doc、Dropbox Paperを使用する時、同時入力する際遭った経験です。 コンポジションイベントを邪魔する要素は色々あって、ソフトウェアのアルゴリズムをもたらしたい体験によります。 HackMD は keypress のほう、「コンポジションの過程」(注音入力法に言うと、注音符号を合成して漢字を選ぶ)も一つのイベントとしてお送りますので、パートナーと一緒に作業する際、相手側の「コンポジションの過程」が見れます! ミーティング、共同編集は丸見え感があるかもしれません。入力する過程が全部リアルタイムで表示されます。 ## お使いになるソフトウェアはコンポジションイベントを送ったりしますか? 違うエディターとメモ用ソフトウェアによって、やり方が違います。思い出してみてください。 >「コンポジションの過程」はグループウェアのドキュメントに出たことありますか? 例えば共同作業の方が「共同」二つの漢字を入力したい場合: - ドキュメント上は ==「Kyou共 Dou同」== のような表示見たことありますか? それとも、相手は直接「共同」が出てくる - その後、0.X秒の間隔で、カーソルカラー、アンダーバーが点滅し、また相手は「協同」、「教導」、「京道」の文字が出てきますか? もしくは、何秒待った後、相手は既に入力済み。 - その後、また「共同」二文字に見えますか? やり方はそれぞれメリット、デメリットがあります。タイピングの流暢性、文字入力の速度を優先するHackMD にとって、コンポジションの過程も考える必要があって、同時にサーバー側に負担も重くなる。これをプロダクトのコアバリューによります。 ## メモ用ソフトウェアかと思っていたが、オンラインゲームだった HackMDの開発者 Max さんはある一言が言っていた:**「これはマルチプレイオンラインゲームみたです!」** 一人入力だけで、テキストエディターにタイピングし、文字入力の表示の速さだけでも重要な体験でした。 二人、三人、三十人など、同時に同じテキストエディターに閲覧、編集の際、まるでマルチプレイオンラインゲームみたいです。あるプレイヤーは一つの動きをし、もう一人のプレイヤーがフィードバックを受け取る。ゲーム内のキャラクターは複数キャッチボールや干渉を処理し、うまくクリアできるのか。 一つ嵌めることで、巨獣がいきなり飛んでくるみたいな感じで、プレイヤーが逃げる時、ポータルを使って、戦場から安全地域に戻る。あと、チームワークでパートナーと戦術を連携するなどみたいな感じで、グループウェアの中でもそういったシチュエーションがあります。 **キーボード、コンポジション、マルチユーザー、リアルタイムでドキュメントに入力する、尚且つスムーズ、これは思ったより複雑な作業です。** ゲーム体感のコンセプトから始まり、「皆に楽しくメモする」がコアとしてプロダクトを開発、これは私たちのコアバリューです。 こちらの技術はまだ色々深堀できる面白い内容があります。また少しずつシェアしましょう。 ### 参考文献 - [現代ブラウザのスペルMaxWu @ COSCUP 2017](https://hackmd.io/@MaxWu/HackMD-COSCUP2017#/) - [Composition Eventsを通じて、非ラテン入力法の入力ボックスに対するサポートを強化](https://kuro.tw/posts/2016/10/11/%E7%AD%86%E8%A8%98-%E9%80%8F%E9%81%8E-Composition-Events-%E5%A2%9E%E5%BC%B7%E9%9D%9E%E6%8B%89%E4%B8%81%E8%AA%9E%E7%B3%BB%E8%BC%B8%E5%85%A5%E6%B3%95%E5%B0%8D%E8%BC%B8%E5%85%A5%E6%A1%86%E7%9A%84%E6%94%AF%E6%8F%B4/) - [keydown, keypress, keyup の違い](https://github.com/jijigo/notes/issues/30) - [keydown, keypress, keyup の違いを比較](https://medium.com/@yitailin/%E6%AF%94%E8%BC%83-keydown-keypress-keyup-%E7%9A%84%E5%B7%AE%E7%95%B0-4e873ba17e81)