tkinter.Text で、IME の Ctrl-M 変換確定入力が捨てられる件

あんまりまじめに Python 3.0 を追いかけていなかったわたしですが、せっかく PC を新調したのでこれはいい機会と、 新しい環境では、Python 3.0 だけインストールして、 強制的に 2.x 環境からの移行を進めようと考えました。

そうして、お手製ツールの移植を始めたのですが、けっこういろいろ動かないもんですね。転けるところがお勉強ポイントなので、それはそれでいいのですが、いきなり 2.5 から 3.0 への移行はちょっと無謀だったかしら(^^; *1

そんなこんなでよく使う手製ツールはだいたい移行を終えたのですが、一つだけイヤンな問題が。以前、Python 2.4 -> 2.5 移行の時、直っていてうれしかった、tkinter.Textが Ctrl-M での ATOK の変換確定(全文確定)入力を捨ててしまう件が 3.0では 再発してしまってる様です。(あ、Windows環境です)

前は「直ったから、ま、いいか」で、全然調査してなかったのですが、そのときチラッと見た限りでは、たしかKeyイベントで拾うとそこでは変換確定入力が取れるんでしたよね、と思い出しました。とりあえず、どうにか避ける方法を検討するため、こんなコードを書いてKeyイベントをちょっと眺めてみます。

from tkinter import *
from tkinter.scrolledtext import *

class TestFrame( Frame ):
   def __init__(self, master=None):
       Frame.__init__(self, master)

       text = ScrolledText( self )

       def onKey(evt):
           print('[%s](%s) keycode=%x keysym=%s type=%s' % 
                 (evt.char,
                  '%02x' % ord(evt.char) if len(evt.char) != 0 else '',
                  evt.keycode ,
                  evt.keysym,
                  evt.type))
       text.bind('<Key>',onKey)

       text.pack(side=TOP)
       self.pack(fill=BOTH)

TestFrame().mainloop()

これで、普通に abc とか入力した場合

[a](61) keycode=41 keysym=a type=2
[b](62) keycode=42 keysym=b type=2
[c](63) keycode=43 keysym=c type=2

なふうにコンソールに出力が出ます。

これで早速、IME を使った入力を眺めてみます。すると、Enter とか 下矢印で確定した場合

[]() keycode=e5 keysym=?? type=2             # あ
[]() keycode=e5 keysym=?? type=2             # い
[]() keycode=e5 keysym=?? type=2             # う
[]() keycode=e5 keysym=?? type=2             # Enterとか↓
[あ](3042) keycode=0 keysym=?? type=2
[い](3044) keycode=0 keysym=?? type=2
[う](3046) keycode=0 keysym=?? type=2

と、Ctrl-M で確定した場合

[]() keycode=e5 keysym=?? type=2             # あ
[]() keycode=e5 keysym=?? type=2             # い
[]() keycode=e5 keysym=?? type=2             # う
[]() keycode=11 keysym=Control_L type=2      # Ctrl...
[]() keycode=11 keysym=Control_L type=2      #  (キーリピート)
[]() keycode=11 keysym=Control_L type=2
[]() keycode=11 keysym=Control_L type=2
[]() keycode=11 keysym=Control_L type=2
[]() keycode=11 keysym=Control_L type=2
[]() keycode=11 keysym=Control_L type=2
[]() keycode=11 keysym=Control_L type=2
[]() keycode=e5 keysym=?? type=2             # ...M
[あ](3042) keycode=0 keysym=?? type=2
[い](3044) keycode=0 keysym=?? type=2
[う](3046) keycode=0 keysym=?? type=2

では、本当に Ctrlキーが押しっぱなしなことくらいしか違いが無いみたいに見えます。みゅー、Ctrl修飾が掛かっていること自体がダメの原因かしら?でもなー。むーむ、なんだかよくわからにゃいな。

とりあえす、Ctrl修飾付きの Keyイベントをフックして、キーコードが 0 な入力を見つけたら、手前で text.insert してあげればうまく回避できるかな?なので、やってみます。

さっきのコードに、

class TestFrame( Frame ):
   def __init__(self, master=None):
         ・
         ・
       # IME Ctrl-M 確定入力パッチ
       def ime_ctrl_m(evt):
           if evt.keycode == 0:
               text.insert( INSERT, evt.char )
       text.bind('<Control-Key>',ime_ctrl_m)

を追加。

いろんな入力操作を試してみましたが、いままでのところ暴走や二重入力もなく、こんな手抜き補修でも一応 大丈夫そうです。とりあえず、これで行きましょ。

ホントの所、なんでダメなのかはまたもや棚上げです。(ここらへんが ワナビクォリテイ)

*1:調べてみれば、Cエクステンションを使ったライブラリに3.0未対応が多いとか、いきなり実用環境を移行するにはまだ時期尚早、とのことらしい。ちょい無謀だったかな。でも、わたしはお花畑の住人なので、きっとなんとかなるでしょう。