If I could bring only one to the uninhabited island, I would bring keyhac.
Edit the configure ()
function in config.py
, which is located in the same directory as the exe.
config.py
import sys
import os
import datetime
import re #add to
import time #add to
import urllib.parse #add to
import pyauto
from keyhac import *
def configure(keymap):
#Edit with vscode obtained from scoop (notepad if not)
EDITOR_PATH = r"C:\Users\{}\scoop\apps\vscode\current\Code.exe".format(os.environ.get("USERNAME"))
if not os.path.exists(EDITOR_PATH):
EDITOR_PATH = "notepad.exe"
keymap.editor = EDITOR_PATH
# theme
keymap.setFont("HackGen Console", 16)
keymap.setTheme("black")
#Set the conversion / non-conversion key as user modifier
keymap.replaceKey("(29)", 235) #Let unconverted (29) be 235
keymap.defineModifier(235, "User0") #Use no conversion as a U0 modifier key
keymap.replaceKey("(28)", 236) #Let the conversion (28) be 236
keymap.defineModifier(236, "User1") #Use the transform as a U1 modifier key
#Clipboard history enabled
keymap.clipboard_history.enableHook(True)
#Maximum size of history
keymap.clipboard_history.maxnum = 200
keymap.clipboard_history.quota = 10*1024*1024
#Ctrl from history+Symbol when pasting a quote with Enter
keymap.quote_mark = "> "
I like the font HackGen.
Below, all customization details will be written in configure ()
. Please close your eyes that there are no rules for variable names and function names.
config.py
#Kili map that is always valid
keymap_global = keymap.defineWindowKeymap()
for modifier in ("", "S-", "C-", "A-", "C-S-", "C-A-", "S-A-", "C-A-S-"):
#Up down left right
keymap_global[modifier + "U0-H"] = modifier + "Left"
keymap_global[modifier + "U0-J"] = modifier + "Down"
keymap_global[modifier + "U0-K"] = modifier + "Up"
keymap_global[modifier + "U0-L"] = modifier + "Right"
# Home / End
keymap_global[modifier + "U0-A"] = modifier + "Home"
keymap_global[modifier + "U0-E"] = modifier + "End"
# Enter
keymap_global[modifier + "U0-Space"] = modifier + "Enter"
#Thoroughly ignore the "Katakana Hiragana Rome" key
keymap_global["D-" + modifier + "(240)"] = lambda: None
keymap_global["U-" + modifier + "(240)"] = lambda: None
keymap_global["D-" + modifier + "(241)"] = lambda: None
keymap_global["U-" + modifier + "(241)"] = lambda: None
keymap_global["D-" + modifier + "(242)"] = lambda: None
keymap_global["U-" + modifier + "(242)"] = lambda: None
# [B]ackSpace / [D]elete
keymap_global["U0-D"] = "Delete"
keymap_global["U0-B"] = "Back"
keymap_global["C-U0-D"] = "C-Delete"
keymap_global["C-U0-B"] = "C-Back"
keymap_global["S-U0-B"] = "S-Home", "C-X" #Cut to the beginning
keymap_global["S-U0-D"] = "S-End", "C-X" #Cut to the end
keymap_global["C-S-U0-B"] = "Home", "Back", "End" #Concatenate with previous line
keymap_global["C-S-U0-D"] = "End", "Delete", "End" #Concatenate with next line
Refer to this site for how to define cursor movement by modifier keys collectively. In Autohotkey, you can make modifier keys transparent by adding {blind}
.
IME on / off is controlled by conversion + J and no conversion + F. When I thought about Japanese and Foreign, it was useful because the key had a protrusion for the home position.
config.py
# [J]apanese / [F]oreign
keymap_global["U1-J"] = lambda: keymap.getWindow().setImeStatus(1)
keymap_global["U0-F"] = lambda: keymap.getWindow().setImeStatus(0)
config.py
#1 line selection
keymap_global["U1-A"] = "End", "S-Home"
#Original reconversion
keymap_global["U0-R"] = "LWin-Slash"
#The one I saw on emacs
keymap_global["LC-H"] = "Back"
#Focus on taskbar
keymap_global["C-U0-W"] = "W-T"
#Insert one line up and down
keymap_global["U0-I"] = "End", "Enter"
keymap_global["S-U0-I"] = "Home", "Enter", "Up"
# escape
keymap_global["O-(235)"] = "Esc"
keymap_global["U0-X"] = "Esc"
#List of open windows
keymap_global["U0-W"] = "LCtrl-LAlt-Tab", "U-LAlt" #Explicitly raise Alt to avoid holding down
#Confirmed by alphanumeric
keymap_global["U1-N"] = "F10", "(243)"
keymap_global["S-U1-N"] = "F10", "Enter"
#Context menu
keymap_global["U0-C"] = "S-F10"
#rename
keymap_global["U0-N"] = "F2", "Right"
keymap_global["S-U0-N"] = "F2", "C-Home"
keymap_global["C-U0-N"] = "F2"
Create the following functions to hotkey frequently used functions.
config.py
def delay(sec = 0.05):
time.sleep(sec)
def get_clippedText():
return (getClipboardText() or "")
def paste_string(s):
setClipboardText(s)
delay()
keymap.InputKeyCommand("C-V")()
def copy_string(sec = 0.05):
keymap.InputKeyCommand("C-C")()
delay(sec)
return get_clippedText()
def send_input(ime_mode, keys, sleep = 0.01):
if ime_mode is not None:
if keymap.getWindow().getImeStatus() != ime_mode:
keymap.InputKeyCommand("(243)")()
for key in keys:
delay(sleep)
try:
keymap.InputKeyCommand(key)()
except:
keymap.InputTextCommand(key)()
keyhac treats the key input ʻInputKeyCommand () and the string input ʻInputTextCommand ()
separately. I created the final send_input ()
function to implement input specifications like Send, ABC {Enter}
in Autohotkey. IME can also be specified ((243)
is a half-width / full-width key).
Use the above send_input ()
to reduce the effort of entering characters as much as possible.
config.py
#Enter parentheses and move the cursor in between
def wrap_with_brackets(pair, after_ime_mode):
keys = [pair, "Left"]
if after_ime_mode == 1:
keys.append("(243)")
return lambda: send_input(0, keys, 0.05)
brackets = [
("U0-2" , '""' , 0),
("U0-7" , "''" , 0),
("U0-8" , "\u300E\u300F", 1), # WHITE CORNER BRACKET 『』
("U0-9" , "\u3010\u3011", 1), # BLACK LENTICULAR BRACKET 【】
("U0-AtMark" , "``" , 0),
("U1-2" , "\u201C\u201D", 1), # DOUBLE QUOTATION MARK “”
("U1-7" , "\u3014\u3015", 1), # TORTOISE SHELL BRACKET 〔〕
("U1-8" , "\uFF08\uFF09", 1), # FULLWIDTH PARENTHESIS ()
("U1-9" , "()" , 0),
("U0-OpenBracket" , "\u300c\u300d", 1), # CORNER BRACKET 「」
("U1-OpenBracket" , "\uFF3B\uFF3D", 1), # FULLWIDTH SQUARE BRACKET []
("U0-CloseBracket" , "[]" , 0),
("U1-CloseBracket" , "{}" , 0),
("C-U0-Comma" , "<>" , 0),
("C-U0-Period" , "</>" , 0),
("U0-Y" , "\u3008\u3009", 1), # Angle Bracket 〈〉
("U1-Y" , "\u300A\u300B", 1), # Double Angle Bracket 《》
]
for brc in brackets:
keymap_global[brc[0]] = wrap_with_brackets(brc[1], brc[2])
Specifying special parentheses with unicode code points is a matter of appearance in the editor. There is no problem with direct send_input (0, ["U0-8 "," "" "," (243) "])
.
Since it is rare to enter punctuation marks, commas, colons, etc. with keys and then convert them further, we make it possible to enter them directly.
The mechanism is simple, if you look at the IME state at the time of input and it is on, you just press Ctrl + M (shortcut for confirmation in most IME) additionally. IME can be turned off automatically after entering characters such as @
that are rarely entered in Japanese.
There is a reason why Enter is not confirmed, and it is a device to prevent accidentally pressing Enter when it is already in the direct input state such as a password input form. However, be aware that some browsers have a function assigned to Ctrl + M (toggle the mute function in Firefox). For Google Japanese input, pressing the half-width / full-width key (243) again confirms the input content at that time, but this method is adopted in consideration of versatility.
config.py
#Enter directly regardless of whether IME is on or off
def direct_input(key, turnoff_ime_later = False):
key_list = [key]
if keymap.getWindow().getImeStatus() == 1:
key_list.append("C-M")
if turnoff_ime_later:
key_list.append("(243)")
send_input(None, key_list)
for key in [
("AtMark" , True),
("Caret" , False),
("CloseBracket", False),
("Colon" , False),
("Comma" , False),
("LS-AtMark" , True),
("LS-Caret" , False),
("LS-Colon" , False),
("LS-Comma" , False),
("LS-Minus" , False),
("LS-Period" , False),
("LS-SemiColon", False),
("LS-Slash" , False),
("LS-Yen" , True),
("OpenBracket" , False),
("Period" , False),
("SemiColon" , False),
("Slash" , False),
("Yen" , True),
]:
def _wrapper(k, i):
return lambda: direct_input(k, i)
keymap_global[key[0]] = _wrapper(key[0], key[1])
#Left shift+Symbol with number keys
for n in "123456789":
def _wrapper(k, i):
return lambda: direct_input(k, i)
key = "LS-" + n
if n in ("2", "3", "4"):
keymap_global[key] = _wrapper(key, True)
else:
keymap_global[key] = _wrapper(key, False)
#If you enter an uppercase alphabet with a left shift, turn off subsequent IMEs.
for alphabet in "ABCDEFGHIJKLMNOPQRSTUVWXYZ":
def _wrapper(k):
return lambda: direct_input(k, True)
key = "LS-" + alphabet
keymap_global[key] = _wrapper(key)
I learned how to create _wrapper ()
when assigning a lambda expression in a loop at this site.
We will make it possible to directly enter other symbols (the following is an example). Since the IME state can be specified with the first argument of send_input ()
above, the character string is directly input in a pseudo manner by selecting "IME off-> character input-> half-width / full-width key press". ..
config.py
keymap_global["BackSlash"] = lambda: direct_input("S-BackSlash", False)
keymap_global["U0-Minus"] = lambda: send_input(0, ["\u2015\u2015", "(243)"]) # HORIZONTAL BAR * 2
keymap_global["U1-Minus"] = lambda: send_input(0, ["Minus"])
keymap_global["U0-U"] = lambda: send_input(0, "_")
keymap_global["U0-Colon"] = lambda: send_input(0, ["Colon"])
keymap_global["U0-Comma"] = lambda: send_input(0, ["\uFF0C", "(243)"]) # FULLWIDTH COMMA ,
keymap_global["U0-Period"] = lambda: send_input(0, ["Period"])
keymap_global["U0-Slash"] = lambda: send_input(0, ["Slash"])
config.py
def input_date(fmt):
d = datetime.datetime.today()
if fmt == "jp":
date_str = "{}Year{}Month{}Day".format(d.year, d.month, d.day)
send_input(0, [date_str, "(243)"])
else:
date_str = d.strftime(fmt)
send_input(0, date_str, 0)
keymap_global["U1-D"] = keymap.defineMultiStrokeKeymap("date format: 1=>YYYYMMDD, 2=>YYYY/MM/DD, 3=>YYYY.MM.DD, 4=>YYYY-MM-DD, 5=>YYYY MM month DD day")
keymap_global["U1-D"]["1"] = lambda: input_date(r"%Y%m%d")
keymap_global["U1-D"]["2"] = lambda: input_date(r"%Y/%m/%d")
keymap_global["U1-D"]["3"] = lambda: input_date(r"%Y.%m.%d")
keymap_global["U1-D"]["4"] = lambda: input_date(r"%Y-%m-%d")
keymap_global["U1-D"]["5"] = lambda: input_date("jp")
config.py
#Paste as plain text
keymap_global["U0-V"] = lambda: paste_string(get_clippedText())
#Remove whitespace and paste as plain text
keymap_global["U1-V"] = lambda: paste_string(re.sub(r"\s", "", get_clippedText()))
#IME off mom When you type, select the last word and IME on
keymap_global["U1-Space"] = lambda: send_input(1, ["C-S-Left"])
#Open the selected URL
def open_url():
url = (copy_string()).strip()
if url.startswith("http"):
run_url = url
elif url.startswith("file:///"):
local_path = url.replace("file:///", "")
local_path = urllib.parse.unquote(local_path)
if not os.path.exists(local_path):
return None
run_url = local_path
else:
return None
keymap.ShellExecuteCommand("open", run_url, None, None)()
keymap_global["D-U0-O"] = open_url
#Re-enter the selected half-width alphanumeric characters with IME on
def re_input_as_kana():
origin = get_clippedText()
if origin:
setClipboardText("")
selection = copy_string(0.1)
if selection:
key_list = []
noblank = re.sub(r"\s", "", selection)
for k in noblank:
if k == "-":
key_list.append("Minus")
else:
key_list.append(k)
send_input(1, key_list, 0)
if origin:
setClipboardText(origin)
keymap_global["U1-I"] = re_input_as_kana
If you press the key after no conversion + S in the selected state, it will be searched by various engines (if it is not copied correctly, it will be searched by the character string that was in the clipboard immediately before).
Hold down Shift when pressing the second key to search for keywords by enclosing each word in double quotes, and hold down Ctrl to erase hiragana.
Unless you search for keywords with Shift, punctuation marks such as commas are converted to spaces, so it's okay if the string selection is a little appropriate.
config.py
def quote_each_word(s):
ret = []
for w in re.split(r"\s+", s):
ret.append('"{}"'.format(w))
return " ".join(ret)
def punctuation_to_space(s):
ret = re.sub(r"[\W_]+", " ", s)
return ret.strip()
def search_on_web(URLstr, mode = None):
selection = copy_string(0.1)
if len(selection) < 200:
single_spaced = (re.sub(r"\s+", " ", selection)).strip()
if mode == "strict":
search_str = quote_each_word(single_spaced)
else:
search_str = punctuation_to_space(single_spaced)
if mode == "without_hira":
search_str = re.sub(r"[Ah-Hmm]+", " ", search_str)
search_str = re.sub(r"\s+", " ", search_str)
search_str = search_str.strip()
encoded = urllib.parse.quote(search_str)
keymap.ShellExecuteCommand("open", URLstr + encoded, None, None)()
engine_url = [
("A", r"https://www.amazon.co.jp/s?i=stripbooks&k="),
("C", r"https://ci.nii.ac.jp/books/search?q="),
("E", r"http://webcatplus.nii.ac.jp/pro/?q="),
("G", r"http://www.google.co.jp/search?q="),
("I", r"https://www.google.com/search?tbm=isch&q="),
("M", r"https://www.google.co.jp/maps/search/"),
("N", r"https://iss.ndl.go.jp/books?any="),
("O", r"https://map.goo.ne.jp/search/q/"),
("S", r"https://scholar.google.co.jp/scholar?q="),
("T", r"https://twitter.com/search?f=live&q="),
("Y", r"http://www.google.co.jp/search?tbs=li:1&q=site%3Ayuhikaku.co.jp%20intitle%3A"),
("W", r"https://www.worldcat.org/search?q="),
]
mode_modifier = [
("" , None),
("S-", "strict"),
("C-", "without_hira"),
]
keymap_global["U0-S"] = keymap.defineMultiStrokeKeymap('S-:quote-each, C-:without-hiragana')
for e in engine_url:
for m in mode_modifier:
search_key = m[0] + e[0]
engine_url = e[1]
mode = m[1]
def _wrapper(url, md):
return lambda: search_on_web(url, md)
keymap_global["U0-S"][search_key] = _wrapper(engine_url, mode)
With no conversion + Q, if the chrome window is open, activate it to open a new tab, if not, launch chrome.
def find_window(arg_exe, arg_class):
wnd = pyauto.Window.getDesktop().getFirstChild()
last_found = None
while wnd:
if wnd.isVisible() and not wnd.getOwner():
if wnd.getClassName() == arg_class and wnd.getProcessName() == arg_exe:
last_found = wnd
wnd = wnd.getNext()
return last_found
def google_search():
if keymap.getWindow().getProcessName() == "chrome.exe":
send_input(1, ["C-T", "C-K"])
else:
wnd = find_window("chrome.exe", "Chrome_WidgetWin_1")
if wnd:
send_input(1, ["C-LWin-1", "C-T", "C-K"], 0.05)
else:
send_input(1, ["LWin-1"])
keymap_global["U0-Q"] = google_search
When I tried to activate the window with the provided ʻActivateWindowCommand ()`, the phenomenon that "the taskbar only blinks and does not go into the foreground" occurred at a frequency that cannot be ignored, so call the chrome registered in the taskbar with Win + numbers. I am doing it. (If the window can be forcibly and surely brought to the front by the program, it can be used for malicious viruses, so it is unavoidable for security.)
There is also a method called pyauto.Window.find ()
that identifies the window, but only the class name can be specified as an argument. Chromium apps such as slack and vscode that have a window class of Chrome_WidgetWin_1
cannot be identified from chrome, so I tried to loop through the open window and search.
Just adding a commentary to the contents of my daily life has made it quite long ...
In addition, I am customizing various things such as processing and pasting the character string of the clipboard, activating a specific window, manipulating the window size, etc. (If you are motivated) I will summarize it in another article.
Recommended Posts