# coding: UTF-8
"""
wx-jpBrailleKeyHook
Masataka Shinke
GPL
"""
import sys
import ctypes
try:
    from Queue import Queue
except:
    from queue import Queue
import wx

j01 = {
    u"⠁": u"ア",  # !
    u"⠃": u"イ",  # #
    u"⠉": u"ウ",  # )
    u"⠋": u"エ",  # +
    u"⠊": u"オ",  # *
    u"⠡": u"カ",  # A
    u"⠣": u"キ",  # C
    u"⠩": u"ク",  # I
    u"⠫": u"ケ",  # K
    u"⠪": u"コ",  # J
    u"⠱": u"サ",  # Q
    u"⠳": u"シ",  # S
    u"⠹": u"ス",  # Y
    u"⠻": u"セ",  # [
    u"⠺": u"ソ",  # Z
    u"⠕": u"タ",  # 5
    u"⠗": u"チ",  # 7
    u"⠝": u"ツ",  # =
    u"⠟": u"テ",  # ?
    u"⠞": u"ト",  # >
    u"⠅": u"ナ",  # %
    u"⠇": u"ニ",  # '
    u"⠍": u"ヌ",  # -
    u"⠏": u"ネ",  # /
    u"⠎": u"ノ",  # .
    u"⠥": u"ハ",  # E
    u"⠧": u"ヒ",  # G
    u"⠭": u"フ",  # M
    u"⠯": u"ヘ",  # O
    u"⠮": u"ホ",  # N
    u"⠵": u"マ",  # U
    u"⠷": u"ミ",  # W
    u"⠽": u"ム",  # ]
    u"⠿": u"メ",  # _
    u"⠾": u"モ",  # ^
    u"⠌": u"ヤ",  # ,
    u"⠬": u"ユ",  # L
    u"⠜": u"ヨ",  # <
    u"⠑": u"ラ",  # 1
    u"⠓": u"リ",  # 3
    u"⠙": u"ル",  # 9
    u"⠛": u"レ",  # ;
    u"⠚": u"ロ",  # :
    u"⠄": u"ワ",  # $
    u"⠒": u"ー",  # 2
    u"⠰": u"、",  # P
    u"⠲": u"。",  # R
    u"⠶": u"｜",  # V
    u"⠂": u"ッ",  # "
    u"⠤": u"＿",  # D
    u"⠢": u"！",  # B	? !
    u"⠀": u"　",  # <SPACE>
}

j02 = {
    u"⠐⠉": u"ヴ",  # )
    u"⠐⠡": u"ガ",  # A
    u"⠐⠣": u"ギ",  # C
    u"⠐⠩": u"グ",  # I
    u"⠐⠫": u"ゲ",  # K
    u"⠐⠪": u"ゴ",  # J
    u"⠐⠱": u"ザ",  # Q
    u"⠐⠳": u"ジ",  # S
    u"⠐⠹": u"ズ",  # Y
    u"⠐⠻": u"ゼ",  # [
    u"⠐⠺": u"ゾ",  # Z
    u"⠐⠕": u"ダ",  # 5
    u"⠐⠗": u"ヂ",  # 7
    u"⠐⠝": u"ヅ",  # =
    u"⠐⠟": u"デ",  # ?
    u"⠐⠞": u"ド",  # >
    u"⠐⠥": u"バ",  # E
    u"⠐⠧": u"ビ",  # G
    u"⠐⠭": u"ブ",  # M
    u"⠐⠯": u"ベ",  # O
    u"⠐⠮": u"ボ",  # N
}

j03 = {
    u"⠠⠥": u"パ",  # E
    u"⠠⠧": u"ピ",  # G
    u"⠠⠭": u"プ",  # M
    u"⠠⠯": u"ペ",  # O
    u"⠠⠮": u"ポ",  # N
}

j04 = {
    u"⠈⠋": u"イェ",  # +
    u"⠈⠡": u"キャ",  # A
    u"⠈⠩": u"キュ",  # I
    u"⠈⠫": u"キェ",  # K
    u"⠈⠪": u"キョ",  # J
    u"⠈⠱": u"シャ",  # Q
    u"⠈⠳": u"スィ",  # S
    u"⠈⠹": u"シュ",  # Y
    u"⠈⠻": u"シェ",  # [
    u"⠈⠺": u"ショ",  # Z
    u"⠈⠕": u"チャ",  # 5
    u"⠈⠗": u"ティ",  # 7
    u"⠈⠝": u"チュ",  # =
    u"⠈⠟": u"チェ",  # ?
    u"⠈⠞": u"チョ",  # >
    u"⠈⠅": u"ニャ",  # %
    u"⠈⠍": u"ニュ",  # -
    u"⠈⠏": u"ニェ",  # /
    u"⠈⠎": u"ニョ",  # .
    u"⠈⠥": u"ヒャ",  # E
    u"⠈⠭": u"ヒュ",  # M
    u"⠈⠯": u"ヒェ",  # O
    u"⠈⠮": u"ヒョ",  # N
    u"⠈⠵": u"ミャ",  # U
    u"⠈⠽": u"ミュ",  # ]
    u"⠈⠿": u"ミェ",  # _
    u"⠈⠾": u"ミョ",  # ^
    u"⠈⠑": u"リャ",  # 1
    u"⠈⠙": u"リュ",  # 9
    u"⠈⠛": u"リェ",  # ;
    u"⠈⠚": u"リョ",  # :
}

j05 = {
    u"⠘⠡": u"ギャ",  # A
    u"⠘⠩": u"ギュ",  # I
    u"⠘⠫": u"ギェ",  # K
    u"⠘⠪": u"ギョ",  # J
    u"⠘⠱": u"ジャ",  # Q
    u"⠘⠳": u"ズィ",  # S
    u"⠘⠹": u"ジュ",  # Y
    u"⠘⠻": u"ジェ",  # [
    u"⠘⠺": u"ジョ",  # Z
    u"⠘⠕": u"ヂャ",  # 5
    u"⠘⠗": u"ディ",  # 7
    u"⠘⠝": u"ヂュ",  # =
    u"⠘⠟": u"ヂェ",  # ?
    u"⠘⠞": u"ヂョ",  # >
    u"⠘⠥": u"ビャ",  # E
    u"⠘⠭": u"ビュ",  # M
    u"⠘⠯": u"ビェ",  # O
    u"⠘⠮": u"ビョ",  # N
}

j06 = {
    u"⠨⠝": u"テュ",  # =
    u"⠨⠥": u"ピャ",  # E
    u"⠨⠭": u"ピュ",  # M
    u"⠨⠮": u"ピョ",  # N
    u"⠨⠬": u"フュ",  # L
    u"⠨⠜": u"フョ",  # <
}

j07 = {
    u"⠸⠝": u"デュ",  # =
    u"⠸⠬": u"ヴュ",  # L
    u"⠸⠜": u"ヴョ",  # <
}

j08 = {
    u"⠢⠁": u"ウァ",  # !
    u"⠢⠃": u"ウィ",  # #
    u"⠢⠋": u"ウェ",  # +
    u"⠢⠊": u"ウォ",  # *
    u"⠢⠡": u"クァ",  # A
    u"⠢⠣": u"クィ",  # C
    u"⠢⠫": u"クェ",  # K
    u"⠢⠪": u"クォ",  # J
    u"⠢⠕": u"ツァ",  # 5
    u"⠢⠗": u"ツィ",  # 7
    u"⠢⠝": u"トゥ",  # =
    u"⠢⠟": u"ツェ",  # ?
    u"⠢⠞": u"ツォ",  # >
    u"⠢⠥": u"ファ",  # E
    u"⠢⠧": u"フィ",  # G
    u"⠢⠯": u"フェ",  # O
    u"⠢⠮": u"フォ",  # N
}

j09 = {
    u"⠲⠡": u"グァ",  # A
    u"⠲⠣": u"グィ",  # C
    u"⠲⠫": u"グェ",  # K
    u"⠲⠪": u"グォ",  # J
    u"⠲⠕": u"ヅァ",  # 5
    u"⠲⠗": u"ヅィ",  # 7
    u"⠲⠝": u"ドゥ",  # =
    u"⠲⠟": u"ヅェ",  # ?
    u"⠲⠞": u"ヅォ",  # >
    u"⠲⠥": u"ヴァ",  # E
    u"⠲⠧": u"ヴィ",  # G
    u"⠲⠯": u"ヴェ",  # O
    u"⠲⠮": u"ヴォ",  # N
}

j00 = {}
j00.update(j02)
j00.update(j03)
j00.update(j04)
j00.update(j05)
j00.update(j06)
j00.update(j07)
j00.update(j08)
j00.update(j09)

j10 = {
    u"⠁": u"１",  # !
    u"⠃": u"２",  # #
    u"⠉": u"３",  # )
    u"⠋": u"６",  # +
    u"⠊": u"９",  # *
    u"⠑": u"５",  # 1
    u"⠓": u"８",  # 3
    u"⠙": u"４",  # 9
    u"⠛": u"７",  # ;
    u"⠚": u"０",  # :
    u"⠂": u"．",  # "
    u"⠼": u"⠼",
}


class MainFrame(wx.Frame):

    def __init__(self, parent, title, KeyGroup):
        self.font = wx.Font(32, wx.FONTFAMILY_DEFAULT,
                            wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
        self.frame = wx.Frame.__init__(
            self,  parent, title=title, size=(860, 640))

        self.splitter = wx.SplitterWindow(
            self, wx.ID_ANY, style=wx.SP_LIVE_UPDATE)
        self.splitter.SetMinimumPaneSize(12)

        self.control = wx.TextCtrl(
            self.splitter, wx.ID_ANY, style=wx.TE_MULTILINE | wx.HSCROLL)
        self.control.SetFont(self.font)

        self.control2 = wx.TextCtrl(
            self.splitter, wx.ID_ANY, style=wx.TE_MULTILINE | wx.HSCROLL)
        self.control2.SetFont(self.font)

        self.splitter.SplitVertically(self.control, self.control2)

        self.control.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
        self.control.Bind(wx.EVT_KEY_UP, self.OnKeyUp)
        self.control.Bind(wx.EVT_CHAR, self.OnKeyChar)
        self.control2.Bind(wx.EVT_CHAR, self.OnKeyControl2)

        self.BrailleKeyGroup = KeyGroup
        self.q = Queue()
        self.run = True
        self.mask = sum(self.BrailleKeyGroup.values())

        try:
            DLLPATH = '.\\nvdaControllerClient32.dll'
            self.clientLib = ctypes.windll.LoadLibrary(DLLPATH)
            self.Pitch = None
            if self.clientLib:
                res = self.clientLib.nvdaController_testIfRunning()
                if res == 0:
                    self.Pitch = self.clientLib.nvdaController_getPitch()
                    res = self.clientLib.nvdaController_setAppSleepMode(0)
        except:
            try:
                DLLPATH = '.\\nvdaControllerClient64.dll'
                self.clientLib = ctypes.windll.LoadLibrary(DLLPATH)
                self.Pitch = None
                if self.clientLib:
                    res = self.clientLib.nvdaController_testIfRunning()
                    if res == 0:
                        self.Pitch = self.clientLib.nvdaController_getPitch()
                        res = self.clientLib.nvdaController_setAppSleepMode(0)
            except:
                self.clientLib = None
                self.Pitch = None

    def __del__(self):
        if self.clientLib:
            res = self.clientLib.nvdaController_testIfRunning()
            if res == 0:
                self.clientLib.nvdaController_setPitch(self.Pitch)
                res = self.clientLib.nvdaController_setAppSleepMode(0)

    def num(self, buff):
        ret = list(buff)
        flag = False
        pos = 0
        for i in ret:
            if(i == u"⠼"):
                flag = True
            if(flag):
                if i in j10.keys():
                    ret[pos] = j10[i]
                else:
                    flag = False
            pos += 1
        return "".join(ret)

    def translation(self, buff):
        ret = self.num(buff)
        for key, value in j00.items():
            ret = ret.replace(key, value)
        for key, value in j01.items():
            ret = ret.replace(key, value)
        return ret

    def insert(self, code):
        Last = self.control.GetLastPosition()
        pos = self.control.GetInsertionPoint()
        if(Last == pos):
            self.control.AppendText(code)
        elif(pos != 0):
            buff = self.control.GetRange(pos - 1, pos) + code
            self.control.Replace(pos - 1, pos, buff)
        else:
            buff = code + self.control.GetRange(0, 1)
            self.control.Replace(0, 1, buff)
            self.control.SetInsertionPoint(0)
        if self.clientLib:
            res = self.clientLib.nvdaController_testIfRunning()
            if res == 0:
                self.clientLib.nvdaController_setPitch(self.Pitch + 50)
                self.clientLib.nvdaController_speakSpelling(code)

    def OnKeyDown(self, evt=None):
        vkCode = evt.GetKeyCode()
        if (vkCode in self.BrailleKeyGroup):
            self.q.put(vkCode)
            return
        elif vkCode in range(0x21, 0x7e):
            return
        if self.clientLib:
            res = self.clientLib.nvdaController_testIfRunning()
            if res == 0:
                self.clientLib.nvdaController_setPitch(self.Pitch)
        evt.Skip()

    def OnKeyUp(self, evt=None):
        vkCode = evt.GetKeyCode()
        if (vkCode in self.BrailleKeyGroup):
            if not self.q.empty():
                result = 0
                while(not self.q.empty()):
                    result = (result | self.BrailleKeyGroup[
                        self.q.get()]) & self.mask
                    self.q.task_done()
                try:
                    self.insert(unichr(0x2800 + result))
                except:
                    self.insert(chr(0x2800 + result))
                l, c = self.control.PositionToXY(
                    self.control.GetInsertionPoint())
                # self.control2.SetValue(
                #    self.translation(self.control.GetLineText(c)))
                self.control2.SetValue(
                    self.translation(self.control.GetValue()))
            return
        elif vkCode in range(0x21, 0x7e):
            return
        l, c = self.control.PositionToXY(self.control.GetInsertionPoint())
        # self.control2.SetValue(self.translation(self.control.GetLineText(c)))
        self.control2.SetValue(self.translation(self.control.GetValue()))
        evt.Skip()

    def OnKeyChar(self, evt=None):
        vkCode = evt.GetKeyCode()
        if (vkCode in self.BrailleKeyGroup):
            return
        evt.Skip()

    def OnKeyControl2(self, evt=None):
        vkCode = evt.GetKeyCode()
        if vkCode in [wx.WXK_LEFT, wx.WXK_RIGHT]:
            evt.Skip()

if __name__ == '__main__':
    app = wx.App(False)
    frame = MainFrame(
        None,
        'wx-jpBrailleKeyHook',
        KeyGroup={
            32: 0,  # " "
            83: 4,  # "S"
            68: 2,  # "D"
            70: 1,  # "F"
            74: 8,  # "J"
            75: 16,  # "K"
            76: 32,  # "L"
            # 86: 64 ,  # "V"
            # 78: 128,  # "N"
        }
    )
    frame.Centre()
    frame.Show(True)
    app.MainLoop()
