keyhacでテキストエディタのF1キーに任意のヘルプファイルのキーワード表示に関連づける

またまたkeyhacでのカスタマイズネタ。テキストエディタでプログラムを書いていると、そのプログラム言語のヘルプファイルが見たいってことがしばしばあります。そんなときに役立つ設定です。

■ 使い方

使い方はカンタン。テキストエディタ上で調べたい単語を選択しF1を押します。
そうすれば設定しておいたchm形式のヘルプファイルからキーワード検索し、その項目を表示します。

■ コード

chm_viewer.py

まずは↓の部分をchm_viewer.pyという名前保存し、extensionフォルダに置いてください。

# chm_viewer.py
# http://d.hatena.ne.jp/pipehead/20071121/1195597559 のCraftLaunchEx用コードをほぼそのまま利用

# Windows 2000/XP では Unicode 版 (HtmlHelpW) を使用し、2000/XP 以外では ANSI 版 (HtmlHelpA) を使用します。
def _IsWinNT5OrLater():
    import sys

    (major, platform) = sys.getwindowsversion()[0:4:3]
    # VER_PLATFORM_WIN32_NT: 2
    return ((platform == 2) and (major >= 5))

winNT5OrLater = _IsWinNT5OrLater()


def _T(string):
    if isinstance(string, str):
        string = unicode(string, 'utf-8')
    if not winNT5OrLater:
        return string.encode('mbcs')
    return string


import ctypes

class c_tchar_p(ctypes._SimpleCData):
    if winNT5OrLater:
        _type_ = 'Z' # c_wchar_p
    else:
        _type_ = 'z' # c_char_p


# WinUser.h
GetDesktopWindow = ctypes.windll.user32.GetDesktopWindow


# HtmlHelp.h
HH_DISPLAY_TOC    = 0x0001
HH_KEYWORD_LOOKUP = 0x000D
HH_CLOSE_ALL      = 0x0012


from ctypes.wintypes import BOOL

class HH_AKLINK(ctypes.Structure):
    _fields_ = [
        ('cbStruct',     ctypes.c_int), # sizeof this structure
        ('fReserved',    BOOL),         # must be FALSE (really!)
        ('pszKeywords',  c_tchar_p),    # semi-colon separated keywords
        ('pszUrl',       c_tchar_p),    # URL to jump to if no keywords found (may be NULL)
        ('pszMsgText',   c_tchar_p),    # Message text to display in MessageBox if pszUrl is NULL and no keyword match
        ('pszMsgTitle',  c_tchar_p),    # Message text to display in MessageBox if pszUrl is NULL and no keyword match
        ('pszWindow',    c_tchar_p),    # Window to display URL in
        ('fIndexOnFail', BOOL)          # Displays index if keyword lookup fails.
    ]


if winNT5OrLater:
    HtmlHelp = ctypes.windll.LoadLibrary('hhctrl.ocx').HtmlHelpW
else:
    HtmlHelp = ctypes.windll.LoadLibrary('hhctrl.ocx').HtmlHelpA


def HtmlHelpDisplayTOC(chmPath, data=None):
    u"""指定されたヘルプウィンドウでヘルプトピックを開く

    引数  : chmPath - 文字列 - コンパイル済みヘルプまたはコンパイル済みヘルプ
            ファイル中のトピック
    引数  : data - 数値 - コンパイル済みヘルプファイル中のトピックへのポインタ
    戻り値: ヘルプウィンドウのハンドルを返す"""
    return HtmlHelp(GetDesktopWindow(), _T(chmPath), HH_DISPLAY_TOC, data)

def HtmlHelpKeywordLookup(chmPath, kwd):
    u"""コンパイル済みヘルプファイルからキーワードを検索する

    引数  : chmPath - 文字列 - コンパイル済みヘルプファイル
    引数  : kwd - 文字列 -  検索するキーワード
            複数の項目はセミコロン `;' で区切る
    戻り値: ヘルプウィンドウのハンドルを返す"""
    aklnk = HH_AKLINK(ctypes.sizeof(HH_AKLINK), False, _T(kwd), None, None,
                      None, None, True)
    return HtmlHelp(GetDesktopWindow(), _T(chmPath), HH_KEYWORD_LOOKUP,
                    ctypes.byref(aklnk))

def HtmlHelpCloseAll():
    u"""呼び出しプログラムによって開かれたヘルプウィンドウをすべて閉じる

    戻り値: なし"""
    HtmlHelp(None, None, HH_CLOSE_ALL, 0)
・ config.py

で、↓ がconfig.pyの設定部分で、キーの割り当てとヘルプファイルのパス設定などを行います。
下記の例ではメモ帳F1を押すとPythonのヘルプファイル(ダウンロードファイル一覧 - Python Japanese Environment - OSDN)を表示します。

# config.py

from keyhac import *

def configure(keymap):

    ## 選択文字列をヘルプファイル(*.chm)から検索
    def select_word_help():
        def _select_word_help():
            # ヘルプファイルのフルパス
            chm_path = r"C:\Program Files\craftware\keyhac\Python26-DocJa1.chm"

            before = getClipboardText()

            # 選択文字列をコピー
            copy_key = "C-c"
            keymap.command_InputKey(copy_key)()

            maxcnt = 10
            while maxcnt > 0:
                maxcnt -= 1

                # クリップボードから文字列取り込み
                select_word = getClipboardText()
                if select_word != before:
                    break

                # クリップボードの反映待ち
                import time
                time.sleep(0.1)

            if select_word:
                import chm_viewer
                chm_viewer.HtmlHelpKeywordLookup(chm_path, select_word)

            # クリップボードを元の状態に戻して終わり
            setClipboardText(before)

        # ホットキー経由での関数呼び出し
        keymap.callHotKey(_select_word_help)

    # メモ帳のキーマップ
    keymap_notepad = keymap.defineWindowKeymap(exe_name=u"notepad.exe")

    keymap_notepad["F1"] = select_word_help

■ さいごに

この前コードを書いていたら、ふとVisual Studioみたいに普段使いのエディタでもヘルプ表示ができたらいいのになァと思い立ち、ちょっと調べてみたら、ほぼそのまま流用可能なこちらのエントリを見つけたので、設定してみました。よければどうぞ。