wxPythonでAA管理ツールを作ろう!第七回 直前のウィンドウに貼り付け

あいさつ

つかさです。
今回は、直前までアクティブだったウィンドウにAAを貼り付けられるようにします。

モジュールの導入

pyautoモジュールを入手しましょう。これは、Windowsの操作をカスタマイズ/自動化するためのモジュールです。
解凍したものを、スクリプトと同じフォルダにおきます。


スクリプト

  1. 新たにpyautoをインポートし
  2. Enterを押したときの挙動に「直前のウィンドウをアクティブにして」「貼り付け」を付け足してます
  • AAlist08.py
import wx,os,migemo,re,pyauto


migemo_object = None

class MyPopupWindow(wx.PopupWindow):
    def __init__(self, parent, style):
        wx.PopupWindow.__init__(self, parent, style)
        self.st = wx.StaticText(self, -1,pos=(10,10))

    def ChangeTxt(self,message,pos):
        
        self.st.SetLabel(message)
        sz = self.st.GetBestSize()
        gps = self.GetSize()
        self.SetDimensions(pos[0], pos[1], sz.width + 20 , sz.height + 20)
        self.Show(True)

class IncrementalSearch:
    def __init__(self,pattern,list):
        self.pattern = pattern
        self.new_list = []
        self.old_list = list

    def GetBackList(self):
        global migemo_object
        
        if migemo_object==None:
            migemo_object = migemo.Migemo('Dict\migemo-dict')
        re_pattern = migemo_object.query(self.pattern)
        try:
            migemo_re_object = re.compile(re_pattern, re.IGNORECASE)
        except re.error:
            return False
                    
        for x in self.old_list:
            if migemo_re_object.search(x):
                self.new_list.append(x)
        return self.new_list


class MyTxtFrm(wx.Frame):
    def __init__(self, parent, id):
        wx.Frame.__init__(self, parent, id)
        
        aa_list = os.listdir("AAList")
        self.AA_Dict = {}
        for x in aa_list:
            key = os.path.splitext(x)[0].decode("shift-jis")
            path = os.path.join("AAlist",x)
            self.AA_Dict[key] = path

        self.win = MyPopupWindow(self,
                                 wx.SIMPLE_BORDER)

        self.TxtCtr = wx.TextCtrl(self, -1)
        self.LBox = wx.ListBox(self, -1, choices = self.AA_Dict.keys())
        self.TxtCtr.Bind(wx.EVT_KEY_DOWN, self.OnKeyChar)
        self.TxtCtr.Bind(wx.EVT_TEXT,self.OnText)
        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.sizer.Add(self.TxtCtr, 0, wx.EXPAND)
        self.sizer.Add(self.LBox, 1, wx.EXPAND)
        self.SetSizer(self.sizer)
        self.SetAutoLayout(1)
        self.sizer.Fit(self)


    def OnKeyChar(self,event):
        key = event.GetKeyCode()
        if key ==  wx.WXK_ESCAPE:
            wx.Exit()
        elif key == wx.WXK_UP:
            count = self.LBox.GetCount()
            next = self.LBox.GetSelection() - 1
            if next >=  0:
                self.LBox.SetSelection(next)
            else: self.LBox.SetSelection(count - 1)
            
            f = open(self.AA_Dict[self.LBox.GetStringSelection()])
            fr = f.read()
            
            gps = self.GetSize()
            gp = self.GetPosition()
            pos = (gp.x + gps.x, gp.y + 45)
            self.win.ChangeTxt(fr,pos)
        
        elif key == wx.WXK_DOWN:
            count = self.LBox.GetCount()
            next = self.LBox.GetSelection() + 1
            if next < count:
                self.LBox.SetSelection(next)
            else: self.LBox.SetSelection(0)
            
            f = open(self.AA_Dict[self.LBox.GetStringSelection()])
            fr = f.read()
            
            gps = self.GetSize()
            gp = self.GetPosition()
            pos = (gp.x + gps.x, gp.y + 45)
            self.win.ChangeTxt(fr,pos)

        elif key in (wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER):
            c_board = wx.Clipboard()
            f = open(self.AA_Dict[self.LBox.GetStringSelection()])
            fr = f.read()
            c_board.SetData(wx.TextDataObject(fr))
            c_board.Flush()
            c_board.Close()
            pyauto.Input.send([
                pyauto.KeyDown(pyauto.VK_MENU ),
                pyauto.Key(pyauto.VK_ESCAPE ),
                pyauto.KeyUp(pyauto.VK_MENU),
                pyauto.KeyDown(pyauto.VK_CONTROL),
                pyauto.Key(ord('V')),
                pyauto.KeyUp(pyauto.VK_CONTROL)
            ])
            wx.Exit()
        else: event.Skip()

    def OnText(self,event):
        word = self.TxtCtr.GetValue()
        isearch = IncrementalSearch(word,self.AA_Dict.keys())
        try:
            new_list = isearch.GetBackList()
        except:
            return False
        if new_list:
            self.LBox.Set(new_list)
            self.LBox.SetSelection(0)
            self.ShowToolTip()
        else: event.Skip()
        event.Skip()
        

    def ShowToolTip(self):
        f = open(self.AA_Dict[self.LBox.GetStringSelection()])
        fr = f.read()
        
        gps = self.GetSize()
        gp = self.GetPosition()
        pos = (gp.x + gps.x, gp.y + 45)
        self.win.ChangeTxt(fr,pos)


class MyApp(wx.PySimpleApp): 
    def OnInit(self):

        self.TxtFrm = MyTxtFrm(None, -1)
        self.TxtFrm.SetSize( (180, 200) )
        self.TxtFrm.Show()
        self.TxtFrm.TxtCtr.SetFocus()
        return 1

app = MyApp()
app.MainLoop()

キー操作

OnKeyCharの下の方を見てください。

            pyauto.Input.send([
                pyauto.KeyDown(pyauto.VK_MENU ),
                pyauto.Key(pyauto.VK_ESCAPE ),
                pyauto.KeyUp(pyauto.VK_MENU),
                pyauto.KeyDown(pyauto.VK_CONTROL),
                pyauto.Key(ord('V')),
                pyauto.KeyUp(pyauto.VK_CONTROL)
            ])
            wx.GetApp().OnClose()

Enterを押したときの動作に、数行加えています。
クリップボードにAAテキストを入れた後、

  1. 直前のウィンドウをアクティブにして
  2. 貼り付け

という動作を追加してます。

まず、直前のウインドウをアクティブに。これは、Alt+Escで実現できますね。Alt+Tabしか知らなかったひとは試してみましょう^^
次の貼り付けは、Ctrl+Vでできます。

pyauto.Input.sendで、それに対応したキーを送ります。

  1. Altキーを押して→Escapeキーを一瞬押して離して→Altキーを離してから
  2. Ctrlキーを押して→Vキーを一瞬押して離して→Ctrlキーを離す

という感じですね。

まとめ

これで、

  1. 直前にアクティブだったウィンドウをアクティブにし
  2. クリップボードに格納したものを貼り付け
  3. 終了する

という一連の動作が可能になりました。メイン部分ですることはもう無いかな?

一連の流れ画像

  • AAを貼り付けたいウィンドウの上で

  • Enterで貼り付け

  • よくできました