wx.stc.StyledTextCtrlで変換候補を正しく表示


wx.stc.StyledTextCtrlはScintillaと言うエディタコントロールのラッパで、
シンタックスハイライトなどの機能が揃っており、
これを使うだけで、もうそれなりのエディタが出来てしまうのだが・・・


日本語入力のときに、変換候補の表示が変。
(カーソル位置ではなく、常に画面左上に表示される)



そこで、変換候補をカーソル位置に表示させてみた。
変換候補のフォントは適宜変更する必要がある。



IMEの候補の表示は次のページのソースを参考にした。

http://miau.s9.xrea.com/blog/index.php?itemid=876

from __future__ import with_statement, division, print_function
import wx
import wx.stc as stc

from ctypes import windll
from ctypes import Structure, c_long, c_byte, c_wchar_p, c_ulong, byref
from ctypes import windll
class POINT(Structure):
    _fields_ = [
        ("x", c_long),
        ("y", c_long),
    ]

class RECT(Structure):
    _fields_ = [
        ("left", c_long),
        ("top", c_long),
        ("right", c_long),
        ("bottom", c_long),
    ]

class COMPOSITIONFORM(Structure):
    _fields_ = [
        ("dwStyle", c_ulong),
        ("ptCurrentPos", POINT),
        ("rcArea", RECT),
    ]

class LOGFONT(Structure):
    _fields_ = [
        ("lfHeight", c_long),
        ("lfWidth", c_long),
        ("lfEscapement", c_long),
        ("lfOrientation", c_long),
        ("lfWeight", c_long),
        ("lfItalic", c_byte),
        ("lfUnderline", c_byte),
        ("lfStrikeOut", c_byte),
        ("lfCharSet", c_byte),
        ("lfOutPrecision", c_byte),
        ("lfClipPrecision", c_byte),
        ("lfQuality", c_byte),
        ("lfPitchAndFamily", c_byte),
        ("lfFaceName", c_wchar_p),
    ]

class StyledTextCtrl(stc.StyledTextCtrl):
    def __init__(self, *a, **kw):
        stc.StyledTextCtrl.__init__(self, *a, **kw)
        
        self.char_height = 32
        self.font_facename = u"MSゴシック"
        self.Bind(stc.EVT_STC_PAINTED, self.OnEvent)
        wx.CallAfter(self.SetImeComposition)

    def IsImeOn(self):
        hIMC = windll.imm32.ImmGetContext(self.GetHandle())
        status = windll.imm32.ImmGetOpenStatus(hIMC)
        windll.imm32.ImmReleaseContext(self.GetHandle(), hIMC)
        return status
   
    def SetImeComposition(self):
        if not self.IsImeOn():
            return
        hIMC = windll.imm32.ImmGetContext(
            self.GetHandle())
        
        lf = LOGFONT()
        lf.lfHeight = -self.char_height
        lf.lfWidth = 0
        lf.lfPitchAndFamily = 1 & 48   
            # FIXED_PITCH & FF_MODERN
        lf.lfFaceName = self.font_facename
        windll.imm32.ImmSetCompositionFontW(hIMC, 
            byref(lf))
        
        cf = COMPOSITIONFORM()
        cf.dwStyle = 2      # CFS_POINT
        
        p = self.GetCurrentPos()
        x, y = self.PointFromPosition(p)
        cf.ptCurrentPos = POINT(x, y)
        windll.imm32.ImmSetCompositionWindow(hIMC,
            byref(cf))
        windll.imm32.ImmReleaseContext(self.GetHandle(),
            hIMC)
    
    def OnEvent(self, event):
        event.Skip()
        self.SetImeComposition()

def main():
    app = wx.PySimpleApp()
    f = wx.Frame(None, -1)
    s = StyledTextCtrl(f, -1)
    f.Show()
    app.MainLoop()

if __name__ == "__main__":
    main()