ウィンドウを好きなサイズで決まった位置に動かせるようだけでも QOL がかなり上がるというのが今年の大きな発見でした。
最近の PowerToys の FancyZones でも似たようなことができますが、キー入力で完結するのが好みです。
config.py
keymap_global["U1-L"] = "LWin-Right"
keymap_global["U1-H"] = "LWin-Left"
# 変換キーとMでカーソル移動の各種機能を呼び出す
keymap_global["U1-M"] = keymap.defineMultiStrokeKeymap("snap window position with key input!")
keymap_global["U1-M"]["X"] = lambda : keymap.getTopLevelWindow().maximize()
# ウィンドウのサイズを変更する(すでに指定サイズになっている場合は最大化)
def set_wnd_rect(rect):
wnd = keymap.getTopLevelWindow()
if list(wnd.getRect()) == rect:
wnd.maximize()
else:
if wnd.isMaximized():
wnd.restore()
delay()
wnd.setRect(rect)
# ウィンドウ配置先の座標ペアを辞書形式で取得する
def get_rects_to_snap():
rects = []
for mntr in get_monitor_areas():
left, top, right, bottom = mntr
width_max = right - left
width_half = int(width_max / 2)
width_narrower = int(width_max / 3)
width_wider = width_narrower * 2
height_max = bottom - top
height_half = int(height_max / 2)
height_shorter = int(height_max / 3)
height_taller = height_shorter * 2
def _horizontal_rect(rightward=False):
def __get_rect(width):
lx = left
if rightward:
lx = right - width
return [lx, top, lx + width, bottom]
return {
"small": __get_rect(width_narrower),
"large": __get_rect(width_wider),
"middle": __get_rect(width_half)
}
def _vertical_rect(lower=False):
def __get_rect(height):
ty = top
if lower:
ty = bottom - height
return [left, ty, right, ty + height]
return {
"small": __get_rect(height_shorter),
"large": __get_rect(height_taller),
"middle": __get_rect(height_half)
}
rects.append({
"left": _horizontal_rect(False),
"right": _horizontal_rect(True),
"top": _vertical_rect(False),
"bottom": _vertical_rect(True),
})
return rects
WND_RECTS = get_rects_to_snap()
各モニタについて、上下左右4エリア × 小(1/3)中(1/2)大(2/3)の12通りの情報を辞書形式で取得します。configure()
直下に変数として格納し、この設定内のグローバル変数のような扱いにしています。
組み合わせが多岐にわたるのでクロージャを作成してキーを割り当てるのもひと苦労です。多重ループで割り当ててみました。
config.py
def snap_wnd(monitor_index=0, position="left", size="middle"):
rect = None
if monitor_index < len(WND_RECTS):
rect = WND_RECTS[monitor_index][position][size]
def _snap():
if rect:
set_wnd_rect(rect)
return _snap
for mod_mntr, mntr_idx in {
"": 0,
"A-": 1,
}.items():
for mod_area, size in {
"": "middle",
"S-": "large",
"C-": "small",
}.items():
for key, pos in {
"H": "left",
"L": "right",
"J": "bottom",
"K": "top",
}.items():
keymap_global["U1-M"][mod_mntr+mod_area+key] = snap_wnd(mntr_idx, pos, size)
現在のウィンドウの幅でメインモニタ中央に持ってこれるようにもしてみました。
config.py
def centerize_wnd():
wnd = keymap.getTopLevelWindow()
if wnd.isMaximized():
return None
wnd_left, wnd_top, wnd_right, wnd_bottom = wnd.getRect()
width = wnd_right - wnd_left
mntr_left, mntr_top, mntr_right, mntr_bottom = get_monitor_areas()[0]
center = (mntr_right - mntr_left) / 2
lx = int(center - width/2)
to_rect = (lx, mntr_top, lx+width, mntr_bottom)
set_wnd_rect(to_rect)
keymap_global["U1-M"]["M"] = centerize_wnd
隣のモニタに移動させて最大化することもできます。
config.py
def snap_and_maximize(rightward=False):
key = "Left"
if rightward:
key = "Right"
def _snap():
send_keys("LShift-LWin-"+key)
delay()
keymap.getTopLevelWindow().maximize()
return _snap
keymap_global["LC-U1-L"] = snap_and_maximize(True)
keymap_global["LC-U1-H"] = snap_and_maximize(False)