先日、この記事で改行をトリガーにしてselectedTextがおかしくなる現象について紹介しました。
しかし続けて調べたところ、selectedTextのみならずdocumentContextBeforeInputとdocumentContextAfterInputにも類似の仕様があり、さらにトリガーになっているのは改行というよりむしろ「文」であり、また文字数ではなくバイト(utf16.count
)であることが分かりました。
結果
documentContextBeforeInputとdocumentContextAfterInput
- documentContextBeforeInputは「前の一文」を返します。これはバイト数に依りません。
- documentContextAfterInputは「後の一文」を返します。これはバイト数に依りません。
前後の一文
ここでいう「文」の定義ですが、確認できている限り以下の文字によって区切られているものを指します。
- 英語のピリオド
.
- 日本語の句点
。
- 改行
\n
- 全角・半角の感嘆符
!
- 全角・半角の疑問符
?
なお、例外的に「英文(英字と空白とピリオドによる構成)」ではこの動作が確認できませんでした。英字+句点や英字+半角感嘆符では動作が確認できたので、何かが違います。
末尾にこれらの記号が付く、または終端に達するまでを「1文」として扱います。ただしこれらの記号が複合した形、例えば「。。。」や「!?」などは1つの区切りとして扱われているようです。
selectedText
- selectedTextは「3文」以上かつ「65バイト」以上選択していると、最初と最後の2文を連結したものを返してきます。
3文
ここでいう「文」の定義ですが、確認できている限り以下の文字によって区切られているものを指します。
- 英語のピリオド
.
- 日本語の句点
。
- 改行
\n
- 全角・半角の感嘆符
!
- 全角・半角の疑問符
?
documentContextシリーズと同様、末尾にこれらの記号が付く、または終端に達するまでを「1文」として扱います。
65バイト
前回の記事では65文字と書きましたが、試してみると例えば2バイトである「💪」を使ってみると切れ目が変わります。「💪?💪?……」を21個連ねる部分までは全体が選択されますが、「💪?
×21+💪
」に至ったタイミングで正しく選択できなくなります。また3バイトの「飴󠄀(飴に異体字セレクタがついたもの)」を用いてみると「飴󠄀!
×16+飴󠄀
」で正しく選択できなくなります。これらのことから、おそらく書記素クラスタでの文字数ではなくutf16としての文字数で判断されているようです。
不具合ではない
前回の記事にも追記しましたが、Appleからは「クラッシュさせないためのexpected behavior」だよ、との趣旨の回答をもらいました。これがunexpectedな振る舞いだったら怖いのでよかったです。
この制限自体はおそらくkeyboard extensionに想定外に大量のデータを与えてしまわないようにするためのものでしょう。リミットが適切かは別として、存在自体は納得できました。
影響
自作しているキーボードにつけていた「文字数カウント」はselectedTextを利用していたのですが、この仕様上まともに動作させるほうが困難なので削除しました。現状、受け取った文字列が確実に全体を反映しているとわかる状況は「内部に区切り文字を含んでいない状況」のみです。区切り文字のリストが公開されていない以上、私が発見した以外にも区切り文字があるかもしれないので、この判定方法も潜在的に不具合の可能性を孕みます。
受け取っているテキストが正しいものなのか正しくないものなのかを判断することが出来ない点がかなり苦しいです。どうにかならないでしょうか。
また、この辺りの振る舞いはほとんどドキュメントが見つからず、気づいていない仕様がまだまだある可能性が高いです。今後何かわかったら追記します。