Skip to content

Instantly share code, notes, and snippets.

@shikishima
Last active February 21, 2023 10:44
Show Gist options
  • Select an option

  • Save shikishima/3d6fe941f274fe5e466b2c64bb45922f to your computer and use it in GitHub Desktop.

Select an option

Save shikishima/3d6fe941f274fe5e466b2c64bb45922f to your computer and use it in GitHub Desktop.
regionなど最低限必要な機能に絞り込んだkeyhacの設定
import datetime
import glob
import os
import logging
import unicodedata
import configparser
from keyhac import *
logging.basicConfig(filename="debug.log", level=logging.DEBUG)
def configure(keymap):
keymap.setFont("Migu 1M", 14)
keymap.clipboard_history.maxnum = 10000
global_exclude_target = [
"bash.exe",
"emacs.exe",
"gvim.exe",
"xyzzy.exe",
"VirtualBox.exe",
"putty.exe",
"poderosa.exe",
"fenrir.exe",
]
minimum_bindings_target = [
"explorer.exe",
"KeePass.exe",
"firefox.exe",
"msedge.exe",
]
clipboard_key = "242" # ひらがなキー
applications_key = "240" # Caps
# Launcher
def command_PopApplicationList():
# If the list window is already opened, just close it
if keymap.isListWindowOpened():
keymap.cancelListWindow()
return
def popApplicationList():
# items
priority_directories = []
for priority_directory in ["opt", "share", "Data", "work", "lib", "tmp"]:
priority_directories += glob.glob("{0}{1}{2}".format(os.environ["home"], os.sep, priority_directory))
priority_directories += glob.glob("{0}{1}{2}*{1}*".format(os.environ["home"], os.sep, priority_directory))
# application
local_apps1 = glob.glob(
"{0}{1}opt{1}local{1}*{1}**{1}*.exe".format(os.environ["home"], os.sep),
)
local_apps1.sort(key=len)
local_apps2 = glob.glob(
"{0}{1}opt{1}windows_apps{1}*{1}**{1}*.exe".format(os.environ["home"], os.sep),
recursive=True
)
local_apps2.sort(key=len)
emu = glob.glob("{0}{1}opt{1}emu{1}*{1}**.exe".format(os.environ["home"], os.sep))
emu.sort(key=len)
scripts = glob.glob("{0}{1}opt{1}scripts{1}*".format(os.environ["home"], os.sep))
# 64Bit版PythonはPROGRAMFILESとPROGRAMFILES(X64)で同じ値を返すのでPROGRAMW6432を使う
windows_apps = glob.glob("{0}**{1}*.exe".format(os.environ["ProgramFiles(X86)"], os.path),
recursive=True,
) + glob.glob(
"{0}**{1}*.exe".format(os.environ["PROGRAMW6432"], os.path),
recursive=True,
)
windows_apps.sort(key=len)
launchList = []
# アプリ本体をディレクトリ(opt_recursive_directories)より優先する
for items in (
priority_directories
+ scripts
+ local_apps1
+ local_apps2
+ emu
+ windows_apps
):
launchList.append(
(
items,
keymap.ShellExecuteCommand(
None, items, "", os.path.dirname(items)
),
) # たまに動作しないアプリがあるので作業フォルダを指定
)
listers = [
("Launcher", cblister_FixedPhrase(launchList)),
]
item, mod = keymap.popListWindow(listers)
if item:
item[1]()
# Because the blocking procedure cannot be executed in the key-hook,
# delayed-execute the procedure by delayedCall().
keymap.delayedCall(popApplicationList, 0)
keymap.delayedCall(keymap.InputKeyCommand("F"), 1)
# 定型文
# 関数を受け取り、現在のクリップボード内容をその引数に与えて実行する関数を返す
# https://zenn.dev/awtnb/books/adf6c5162a9f08/viewer/de6e84
def format_cb(func):
def _format():
cb = getClipboardText()
if cb:
return func(cb)
return _format
fixed_items = [
("おはようございます。", "おはようございます。\n今日はいい天気です。"),
(
"休憩に入ります。",
lambda: "休憩に入ります。\n"
+ (datetime.datetime.now() + datetime.timedelta(hours=1)).strftime("%H:%M")
+ "に再開します。",
),
("全角英数→半角英数,半角カナ→全角カナ", format_cb(lambda s: unicodedata.normalize('NFKC', s))),
("大文字→小文字&スペース→-", format_cb(lambda s: s.lower().replace(' ', '-'))),
("Reload config.py", keymap.command_ReloadConfig),
]
# 設定ファイル(keyhac.exeと同階層のuser.ini)読み込み
config = configparser.ConfigParser(allow_no_value=True)
config.read(os.path.join(getAppExePath(), 'user.ini'), 'UTF-8')
# sample
# [templates]
# Gmail1=foo@gmail.com
# Gmail2=bar@gmail.com
for key, name in config.items('templates'):
temp_tuple = key, name
fixed_items.append(temp_tuple)
keymap.cblisters += [
("定型文", cblister_FixedPhrase(fixed_items)),
]
# for Vivaldi
def is_chrome(window):
if window.getClassName() in ("Chrome_WidgetWin_1"):
return True
return False
class Region:
enabled = False
def on(self):
keymap.popBalloon("region.enabled", "Region On.", 200)
self.enabled = True
def off(self):
keymap.InputKeyCommand("Left")()
keymap.InputKeyCommand("Right")()
keymap.closeBalloon("region.enabled")
self.enabled = False
def esc(self):
if self.enabled:
self.off()
else:
keymap.InputKeyCommand("Esc")()
def toggle(self):
if self.enabled:
self.off()
else:
self.on()
def send_key_through_ime(self, before_input, after_input):
# Google日本語入力が有効なら何もしない
wnd = keymap.getWindow()
# 候補窓が表示されている時
# google_ime_candidate = wnd.find("GoogleJapaneseInputCandidateWindow", None)
# google_ime_candidate.isVisible()
# Google日本語入力クラス上でIMEが有効
google_ime_composition = wnd.find("MSCTFIME Composition", None)
if google_ime_composition and google_ime_composition.getImeStatus():
return keymap.InputKeyCommand(before_input)()
else:
return self.send_key(after_input)
def send_key(self, key, use_region_key=False):
send_key = key
if self.enabled:
if use_region_key:
send_key = use_region_key
else:
send_key = "S-" + key
return keymap.InputKeyCommand(send_key)()
def forward_char(self):
self.send_key("Right")
def forward_word(self):
self.send_key("C-Right", "C-S-Right")
def backward_word(self):
self.send_key("C-Left", "C-S-Left")
def delete_word(self):
self.on()
self.forward_word()
keymap.InputKeyCommand("S-Delete")()
self.off()
def backward_char(self):
self.send_key("Left")
def beginning_of_line(self):
self.send_key("Home")
def end_of_line(self):
self.send_key("End")
def kill_line(self):
self.on()
self.end_of_line()
keymap.InputKeyCommand("S-Delete")()
self.off()
def scroll_up_command(self):
self.send_key("Pagedown")
def scroll_down_command(self):
self.send_key("Pageup")
def next_line(self):
self.send_key_through_ime("C-N", "Down")
def previous_line(self):
self.send_key_through_ime("C-P", "Up")
def beginning_of_buffer(self):
self.send_key("C-Home", "C-S-Home")
def end_of_buffer(self):
self.send_key("C-End", "C-S-End")
def mark_whole_buffer(self):
self.send_key("C-End")
self.on()
self.send_key("C-Home")
def kill_region(self):
keymap.InputKeyCommand("S-Delete")()
self.enabled = False
def kill_ring_save(self):
keymap.InputKeyCommand("C-Insert")()
self.enabled = False
region = Region()
keymap_global = keymap.defineWindowKeymap(
check_func=lambda window: not window.getProcessName() in global_exclude_target
)
keymap_maximum = keymap.defineWindowKeymap(
check_func=lambda window: not is_chrome(window)
and not window.getProcessName() in global_exclude_target
and not window.getProcessName() in minimum_bindings_target
)
keymap_minimum = keymap.defineWindowKeymap(
check_func=lambda window: is_chrome(window)
or window.getProcessName() in minimum_bindings_target
)
# for global
keymap_global[clipboard_key] = keymap.command_ClipboardList # ひらがな
keymap.replaceKey(applications_key, "235") # Capslockを仮想キーに
keymap_global["235"] = command_PopApplicationList # Capslockをランチャーに
# Quattro TKLの機能をどこでも使う
keymap_global["29"] = keymap.MouseButtonClickCommand("left") # 無変換
keymap_global["A-C-N"] = "A-Down"
keymap_global["A-S-Comma"] = region.beginning_of_buffer
keymap_global["A-S-Period"] = region.end_of_buffer
keymap_global["A-B"] = region.backward_word
keymap_global["A-D"] = region.delete_word
keymap_global["A-F"] = region.forward_word
keymap_global["A-W"] = region.kill_ring_save
keymap_global["A-H"] = region.mark_whole_buffer
keymap_global["A-V"] = region.scroll_down_command
keymap_global["C-A"] = region.beginning_of_line
keymap_global["C-E"] = region.end_of_line
keymap_global["C-K"] = region.kill_line
keymap_global["C-V"] = region.scroll_up_command
keymap_global["C-B"] = region.backward_char
keymap_global["C-C"] = region.kill_ring_save
keymap_global["C-D"] = "Delete"
keymap_global["C-E"] = region.end_of_line
keymap_global["C-F"] = region.forward_char
keymap_global["C-G"] = region.esc
keymap_global["C-H"] = "Back"
keymap_global["C-M"] = "Enter"
keymap_global["C-N"] = region.next_line
keymap_global["C-P"] = region.previous_line
keymap_global["C-S"] = "C-F"
keymap_global["C-Slash"] = "C-z"
keymap_global["C-Space"] = region.toggle
keymap_global["C-Y"] = "S-Insert"
keymap_global["C-BackSlash"] = "243" # 半角/全角
# 標準アプリ
keymap_maximum["A-Y"] = keymap.command_ClipboardList
keymap_maximum["C-BackSlash"] = "243" # 半角/全角
keymap_maximum["C-OpenBracket"] = "Esc"
keymap_maximum["C-X"] = keymap.defineMultiStrokeKeymap("C-X")
keymap_maximum["C-X"]["C-F"] = "C-F"
# 全てのキーをクオート
keymap_global["C-Q"] = keymap.defineMultiStrokeKeymap("C-Q")
for alphabet in [chr(ord("A") + i) for i in range(26)]:
for modifier in ["A-", "C-", "A-C-", "C-S-"]:
keymap_global["C-Q"][modifier + alphabet] = modifier + alphabet
# ブラウザなど元々のキーを活かすアプリ用
keymap_minimum["C-X"] = region.kill_region
# https://github.com/kumamotone/keyhac/blob/master/config.py
# ExplorerでCtrl+Mでフォルダを開こうとするとCtrlキーが押されてるからって
# 新しいウィンドウで開こうとして最悪なのでそれを半ば無理やり回避するコード
# http://anago.2ch.net/test/read.cgi/software/1239109333#569
keymap_explorer = keymap.defineWindowKeymap(exe_name="explorer.exe")
def input_enter():
del keymap_explorer["U-LCtrl"]
keymap.wnd = 0
keymap.InputKeyCommand("U-LCtrl", "Enter")()
def set_trap():
keymap_explorer["U-LCtrl"] = input_enter
keymap.wnd = 0
keymap_explorer["C-M"] = set_trap
def configure_ListWindow(window):
def key_repeat(key):
print(key)
keymap.InputKeyCommand(key)()
keymap.InputKeyCommand(key)()
def cut(item):
keymap.ShellExecuteCommand(None, items, "", os.path.dirname(items))
del window.keymap["Enter"]
del window.keymap["C-M"]
window.keymap["Enter"] = key_repeat("Enter")
window.keymap["C-G"] = key_repeat("Esc")
window.keymap["C-M"] = key_repeat("Enter")
@shikishima
Copy link
Author

ローカルアプリのディレクトリは名前が短い順にソート。
同じディレクトリに大量の実行ファイルがある場合に余計なものが上に表示されるため。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment