リーディング時のWPM向上を支援するスクリプト書いてみた
自分は英文を読むのがクソ遅いんですが,知らないと損する英語の速読方法(1) - 一法律学徒の英語と読書な日々に感化されてちょっとWord Per Minute(WPM),つまり分あたりに読む単語数を改善しようと思い立った.
で,それっぽい支援ソフトウェアを探したんだがあまり自分の好みの物は見つからなかったので,pythonで適当に書いてみた.ウィンドウのフォーカスあたりでちょいちょいしてるので多分windowsのみサポート.そこを消せば他でも動くはずだけど実用レベルではない.
いやね,なんかフラッシュしながら表示するのはあるんだけど,ハイライトが見つからなかったんです.フラッシュ版は,Spreeder CX | なんかはある程度注目されてる模様.
で,ハイライトが好みの人向けのこのスクリプトの内容は,
- 設定したWPMに応じて,Ctrl+Shift+→ キーを送って,選択中の領域を単語ごとに拡大する
だけ.
要するに,表示テキストを選択できてCtrl+Shift+→ が有効なアプリケーションならなんでもよくて*1,ウィンドウを登録した後に開始付近の単語をマウスで選択状態にしてからスタートすると指定したWPMで単語がどんどんハイライトされる.
![f:id:asudofu:20101114144430p:image:h200 f:id:asudofu:20101114144430p:image:h200](https://cdn-ak.f.st-hatena.com/images/fotolife/a/asudofu/20101114/20101114144430.png)
一応ウィンドウのフォーカスをとっているので暴走はそこまでしないハズだけど,これを実行したことによって生じる不利益はなんの保証もできません.
いろいろと恥ずかしいコードだけど,まぁ自分の欲求は最低限満たしているし,時間が勿体無いから書き直すこともないだろうということで投げやりに記載*2.適当に改良してください.いや,本当はchromeのextensionでできたらよかった*3んだけど,今は新しいものに手を出す余裕が無い.まぁこのスクリプトはPDFファイルにも応用できるのでこれはこれでよしとする.
実行には,以下のインストールが必要.
あとは,下のスクリプトをコピペして"speedReader.py"とでも名前をつけて保存して,ダブルクリック.
#!usr/bin/python # coding: utf-8 # 使い方:まず使用の対象となる英文を表示しているウィンドウを登録 # マウスなどを使って開始したい位置の文字を選択状態(ハイライト)にし, # スタートすると指定したWPMで選択領域が拡大.原理的には Ctrl+Shift+->を送っているだけ # 止めたいときは,いったんフォーカスを他のものに移す:通常はspeedReaderをクリック # キー出力を乗っ取っているので,こちらからの入力がたまに被さる可能性がある # 自動スクロールは実用的でないので,キー入力などを使って手動でスクロール推奨. import sys import time import SendKeys import msvcrt import win32gui import win32con gGoalWPM = 250 gUnitTime = 0.0 gAutoScrollNum = 10 # auto scroll with this word count gThisWindow = win32gui.GetForegroundWindow() gTargetWindow = gThisWindow def setWPM(w): global gGoalWPM, gUnitTime if w < 10: w = 10 elif w > 1500: w = 1500 gGoalWPM = w gUnitTime = 1.0 / (float(gGoalWPM)/60.0) print "Goal WPM = %d" % gGoalWPM def selectWindow(): global gTargetWindow print "select target window" while True: gTargetWindow = win32gui.GetForegroundWindow() if gTargetWindow != gThisWindow: print "[", win32gui.GetWindowText(gTargetWindow), "]" return True if msvcrt.kbhit(): print "cancel" return False time.sleep(0.1) def printHelp(): print "s:start, o:stop, u/d:up/down speed" print "c:start in 3sec, 1-9:preset speed," print "w:register target window, r:reset, " print "h:help, p:print target window, q:quit" # main def main(): global gGoalWPM, gUnitTime, gTargetWindow, gCurrentWindow # variables mCurrentTime = time.clock() mLastTime = mCurrentTime mTotalTime = 0.1 # temp mShouldStop = True mDefocus = False mWordCount = 0 # variables # always on top, window size, position win32gui.SetWindowPos(gThisWindow,win32con.HWND_TOPMOST,500,200,350,200,0) if(len(sys.argv) > 1): gGoalWPM = sys.argv[1] setWPM(gGoalWPM) mTotalTime = gUnitTime printHelp() while True: firstLoop = True # wait untile goal WPM rate while firstLoop or (mCurrentTime - mLastTime) < gUnitTime: firstLoop = False time.sleep(0.001) mCurrentTime = time.clock() # keyboard interrupt if msvcrt.kbhit(): hitkey = msvcrt.getch() if hitkey == '\000': pass # Send key elif hitkey == 'q': print "exit" sys.exit() elif hitkey == 'u': setWPM(gGoalWPM + 10) elif hitkey == 'd': setWPM(gGoalWPM - 10) elif hitkey == '1': # preset 1 setWPM(150) elif hitkey == '2': # preset setWPM(200) elif hitkey == '3': # preset setWPM(250) elif hitkey == 'w': selectWindow() # win32gui.SetForegroundWindow() elif hitkey == 'h': printHelp() elif hitkey == 'p': print "[", win32gui.GetWindowText(gTargetWindow), "]" elif hitkey == 's': print "start" if gTargetWindow == gThisWindow: if selectWindow(): win32gui.SetForegroundWindow(gTargetWindow) mShouldStop = False else: win32gui.SetForegroundWindow(gTargetWindow) mShouldStop = False elif hitkey == 'o': print "stop" mShouldStop = True elif hitkey == 'c': if mShouldStop: print "wait 3 seconds..." time.sleep(3) win32gui.SetForegroundWindow(gTargetWindow) mShouldStop = False elif hitkey == 'r': print "reset" printHelp() setWPM(gGoalWPM) mLastTime = mCurrentTime mTotalTime = gUnitTime mShouldStop = True mWordCount = 0 if not mShouldStop: if not mDefocus: curWindow = win32gui.GetForegroundWindow() if curWindow != gTargetWindow: print "defocus" print "[", win32gui.GetWindowText(curWindow), "]" mDefocus = True else: SendKeys.SendKeys("""^+{RIGHT}""", 0.0) minutes = int(mTotalTime) / 60 seconds = int(mTotalTime) - minutes * 60 decisec = int((mTotalTime - float(minutes*60 + seconds)) * 100.0) print "%d/%d[wpm], " % (float(mWordCount+1)/mTotalTime*60.0, gGoalWPM), print "%3d[w], %02d:%02d:%02d" % (mWordCount, minutes, seconds, decisec) if gAutoScrollNum > 0 and mWordCount%gAutoScrollNum == 0: # I don't know why this doesn't work # win32gui.SendMessage(gTargetWindow, win32con.WM_VSCROLL, win32con.SB_LINEDOWN, 0) pass mTotalTime += gUnitTime mWordCount = mWordCount + 1 else: if gTargetWindow != gThisWindow and gTargetWindow == win32gui.GetForegroundWindow(): print "get focus" mDefocus = False mShouldStop = False mLastTime = mCurrentTime # main if __name__ == "__main__": main()
メモ
始めてwin32API使ったけど,なんかよくわからんことが多いのでメモ.
- ScrollWindowEx()で他のアプリケーションをスクロールさせるのは,スクロール領域がわからないので無理?
- 正当法であろう SendMessage() はなぜかうまく動かなかった
- SetForegroundWindow() は,自分自身を非アクティブからアクティブにできないらしい
追記
11/14 最大wpmが低かったのでコードを修正.
*1:メモ帳,firefox, Adobe Readerとか
*2:最近こんなんばっかだな
*3:単語でなく文字ごとにハイライトとか,適度に自動スクロールとか,領域先端の単語の意味表示とか.どなたかぜひ作ってください