イベントハンドリング

http://d.hatena.ne.jp/yach/20070905 の続き。

チャットメッセージの受信とかは、イベントで処理する。イベントは、_ISkypeEvents (https://developer.skype.com/Docs/Skype4COMLib/ISkypeEvents) で定義されている。

win32com でCOMイベントを扱うには、以下のように書く。2パターンあり。

方法1 (DispatchWithEvents)

import sys
import win32com.client
from time import sleep

class SkypeEvents:
    def OnMessageStatus(self, msg, stat):
        msg = win32com.client.Dispatch(msg)
        print "[%s(%s)] %s: %s"%(
            conversion.ChatMessageStatusToText(stat), 
            str(stat), 
            msg.FromDisplayName, 
            msg.Body)
        sys.stdout.flush() 

skype = win32com.client.DispatchWithEvents('Skype4COM.Skype', SkypeEvents)
conversion = skype.Convert
skype.Attach()

while True:
    skype.CurrentUser
    sleep(1)

方法2 (getevents)

import sys
import win32com.client
from time import sleep

class SkypeEvents(win32com.client.getevents('Skype4COM.Skype')):
    def OnMessageStatus(self, msg, stat):
        msg = win32com.client.Dispatch(msg)
        print "[%s(%s)] %s: %s"%(
            conversion.ChatMessageStatusToText(stat), 
            str(stat), 
            msg.FromDisplayName, 
            msg.Body)
        sys.stdout.flush() 

skype = win32com.client.Dispatch('Skype4COM.Skype')
conversion = skype.Convert
handler = SkypeEvents(skype)
skype.Attach()

while True:
    skype.CurrentUser
    sleep(1)

1番目の方法はシンプル。DispatchWithEvent()で得られるオブジェクトは、SkypeオブジェクトとSkypeEventsオブジェクトの両方のメソッドを併せ持つようになる(ただしSkypeEventsのオブジェクトではないので注意)。

2番目の方法は、ちょっと面倒だが、後からハンドラを自由に定義できる。また、 handler は SkypeEvents のオブジェクトなので、取り扱いが便利かもしれない。


ポイント:

  • イベントに対するイベントハンドラは「On〜」
  • パラメータのうち、[in]はイベントハンドラのパラメータに、[out]は戻り値になる。
  • イベントは非同期に発生するのだが(当然)、イベントハンドラが呼び出されるためには、「skype.CurrentUser」の行が必要。おそらくメッセージループを回すのに必要なのではないか。
  • パラメータで受け取ったオブジェクトは、IPyDispatch。これは、win32com.client.Dispatch()に渡してやらないと、オブジェクトとして呼び出せない。
  • たぶんシングルスレッドモデルで動作する。マルチスレッド化するには?
  • statusの類を文字列化するには、Skype.Convertを使う。

2番目の方法でイベントハンドラを追加するには:

class SkypeEvents(win32com.client.getevents('Skype4COM.Skype')):
    def OnMessageStatus(self, msg, stat):
        msg = win32com.client.Dispatch(msg)
        print "[%s(%s)] %s: %s"%(
            conversion.ChatMessageStatusToText(stat), 
            str(stat), 
            msg.FromDisplayName, 
            msg.Body)
        sys.stdout.flush() 

skype = win32com.client.Dispatch('Skype4COM.Skype')
handler = SkypeEvents(skype)

class SkypeEvents2(win32com.client.getevents('Skype4COM.Skype')):
    def OnUserStatus(self,name):
        print "Event: UserStatus:" + str(name)
        sys.stdout.flush() 


handler2 = SkypeEvents2(skype)