見出し画像

IME未確定時はKeyboardEvent.keyを無視したい

はじめに

toridori開発部の大谷と申します。

春の温かみを感じるいい時期となりましたね。
そして人類の怨敵である花粉症の時期でもあり、私も毎年苦しめられていました。
あらゆる薬等全く効果を出さず、花粉に怯える生活をしてきた私ですが、今年は奮発して花粉をも浄化すると言われる空気清浄機を購入してみました。
その効果は抜群、私の部屋は聖域と化し、外にさえでなければ花粉に悩むことがなくなりました。
リモート等で家から出る機会があまりない人は是非検討してみてください。
人生の幸福度が上昇します。

さて、今回はエンジニアブログの第4弾として、keyboardEvent.keyをIME未確定時は発火させないようにする方法について説明したいと思います。

なお、本記事ではReact.jsとMaterial-UIを使用しています。

IME未確定のときの動作

keyboardEvent.keyを使うことで、押したキーの値を取得することができます。

普段はあまり気にすることは無いと思いますが、特定の動作を行ったときに問題が生じることがあります。

どのような問題があるのか見てみましょう。

入力フォーム内の文字をEnterで確定すると、フォームの下に確定した文字が出力されます。
日本語入力時は変換時の確定で文字が出力されてしまっているのがわかるかと思います。

画像1

実装を見てみましょう。

TextFieldのonKeyDown内(14行目〜20行目)で、

if (e.key !== "Enter") return

を行っています。そのため、Enterの場合のみ後続の処理を実行するように実装していますが、変換時のEnterにも反応しています。

 export default function App() {
 const [chips, setChips] = useState([]);
 const [chip, setChip] = useState();
 const classes = useStyles();

 return (
   <>
     <TextField
       className={classes.root}
       label="入力したらEnterを押してね"
       variant="filled"
       onChange={(e) => setChip(e.target.value)}
       value={chip}
       onKeyDown={(e) => {
         if (e.key !== "Enter") return;
         let array = chips;
         array.push(chip);
         setChips(array);
         setChip("");
       }}
     />
     <Box mt={2}>
       {chips.map((c, i) => {
         return (
           <Chip
             key={i}
             className={classes.chip}
             label={c}
             color="primary"
             variant="outlined"
             onDelete={() => {
               const t = chips.filter((_chi, index) => index !== i);
               setChips(t);
             }}
           />
         );
       })}
     </Box>
   </>
 );
}

compositionstartとcompositionend

keyboardEvent.keyは変換の確定も

Enter

として取得してしまいますが、JavaScriptにはcompositionstartとcompositionendという変換開始と変換完了を検知するイベントが用意されています。
※compositionupdateというイベントもありますが、割愛します。

Material UIのTextFieldのオプションにも

onCompositionStart

onCompositionEnd

といったものが用意されているので使っていきましょう。

それでは実際に使ってみましょう。
7行目と8行目にonCompositionStartとonCompositionEndを追加しました。
また、onKeyDown内にも入力が終わっているかどうかの判定を追加しています。


画像2
<TextField
 className={classes.root}
 label="入力したらEnterを押してね"
 variant="filled"
 onChange={(e) => setChip(e.target.value)}
 value={chip}
 onCompositionStart={() => setTyping(true)}
 onCompositionEnd={() => setTyping(false)}
 onKeyDown={(e) => {
   if (e.key !== "Enter" || typing) return;
   let array = chips;
   array.push(chip);
   setChips(array);
   setChip("");
 }}
/>

挙動としては以下のようになります。

うまく確定できていますね。

おわりに

今回はReactとMaterial UIでIME未確定時の処理について書きました。
javascriptの記事は多く見かけますが、フレームワークを用いた実装はなかなか見ないと思うので参考になれば幸いです。

また、onCompositionを利用する場合は、ブラウザによって発火タイミングなどが異なるので、実装する場合はブラウザごとの挙動を確認するようにしましょう。

toridoriの開発部はサービスの機能を最適化し、企業やインフルエンサー、”誰もがより使いやすいサービス”を目指して、日々試行錯誤を繰り返しながらみなさんのもとへお届けしています。

そんなtoridori開発部では新メンバーを募集中です。
インフルエンサーマーケティングという、この先5年間で市場規模が2倍以上になると言われている成長業界の中で、時代を創っていく企業のメンバーとして、一緒に働きませんか?

画像3


この記事が気に入ったらサポートをしてみませんか?