LoginSignup
14
10

More than 1 year has passed since last update.

AutoHotKey v1->v2への移行 ~Emacs-likeなキーバインド設定編~

Last updated at Posted at 2023-04-10

AutoHotKeyのバージョンがv2に正式に移行になり、スクリプト内で使える文法が変更になりました。v2対応に必要な変更点が多いので、変更メモを残しておきます。最後に、Emacs風なキーバインド用の設定ファイルも掲載しておきます。

■AutoHotKey v1->v2への変更点

自分の使ってるスクリプトで、主に必要になった変更点は下記の通りです。

  • ①変数代入式「a = 10」が「a := 10」に変更。
v1) a = 10
v2) a := 10
  • ②if式の等号比較が、「==」から「=」に変更になった。
v1) if (a == b)
v2) if (a = b)
  • ③ホットキーの中身が複数行になるときは、{}で囲う
v1) ^a::
      move_beginning_of_line()
      Return
v2) ^a::
    {
      move_beginning_of_line()
      Return
    }
v1) IfWinActive,ahk_class Notepad
      func()
v2) #HotIf WinActive("ahk_class Notepad")
    ^a::func()
  • ⑤Send キーが、Send "キー"になった。
v1) Send ^a
    Send {Esc}
v2) Send "^a"
    Send "{Esc}"
  • ⑥SetBatchLines -1がなくなり、デフォルトになった。
v1) SetBatchLines -1
v2) ;; SetBatchLines -1
  • ⑦#InstallKeybdHook->InstallKeybdHookに変更
v1) #InstallKeybdHook
v2) InstallKeybdHook
  • ⑧ListLines OffのOffが使えなくなった。0にすればよい。
v1) ListLines Off
v2) ListLines 0
  • ⑨SendModeの第1引数が、Stringになった
v1) SendMode Input
v2) SendMode "Input"
v1) Suspend Toggle
v2) Suspend ;; default is -1 (= Toggle)
  • ⑪予約語の修飾子%%が要らなくなった。%A_ThisHotKey%->A_ThisHotKey
v1) Send %A_ThisHotKey%
v2) Send A_ThisHotKey
  • ⑫nullの代入が右辺空欄から、右辺""に変わった
v1) var =
v2) var := ""
v1) var = Clipboard
v2) var := A_Clipboard

■Emacs-likeな設定ファイル(v2対応)

emacs-like.ahk
;;
;; An autohotkey script that provides emacs-like keybinding on Windows
;;

;; global constants
DEBUG_MODE := 0

;; global variables
; turns to be 1 when ctrl-x is pressed
gIsCtrlXPressed := 0
; turns to be 1 when ctrl-space is pressed
gIsMarkDown := 0
; turns to be 1 when escape key is pressed
gIsEscapePressed := 0
; turns to be 1 when Ctrl-s, Ctrl-r
gIsSearching := 0

reset_pre_keys()
{
  global
  gIsCtrlXPressed := 0
  gIsMarkDown := 0
  gIsEscapePressed := 0
  Return
}
reset_all_status()
{
  reset_pre_keys()
  global gIsSearching := 0
}
delete_char()
{
  Send "{Del}"
  reset_all_status()
  Return
}
delete_backward_char()
{
  Send "{BS}"
  reset_all_status()
  Return
}
kill_line()
{
  Send "{ShiftDown}{END}{ShiftUp}"
  Sleep 50 ;[ms] this value depends on your environment
  A_Clipboard := "" ; set empty
  Send "^x"
  ClipWait(0.1) ; wait for copy finish
  text := A_Clipboard ; get the copied text

  ;; if start pos is at line end (text is empty)
  if (text = "") {
    Send "{ShiftDown}{Right}{ShiftUp}"
    Sleep 50 ;[ms] this value depends on your environment
    Send "^x"
  }

  reset_all_status()
  Return
}
open_line()
{
  Send "{END}{Enter}{Up}"
  reset_all_status()
  Return
}
quit()
{
  Send "{ESC}"
  reset_all_status()
  Return
}
newline()
{
  Send "{Enter}"
  reset_all_status()
  Return
}
indent_for_tab_command()
{
  Send "{Tab}"
  reset_all_status()
  Return
}
newline_and_indent()
{
  Send "{Enter}{Tab}"
  reset_all_status()
  Return
}
isearch_forward()
{
  global
  If gIsSearching
    Send "{F3}"
  Else
  {
    Send "^f"
    gIsSearching := 1
  }
  reset_pre_keys()
  Return
}
isearch_backward()
{
  global
  If gIsSearching
    Send "+{F3}"
  Else
  {
    Send "^f"
    gIsSearching := 1
  }
  reset_pre_keys()
  Return
}
kill_region()
{
  Send "^x"
  reset_all_status()
  Return
}
kill_ring_save()
{
  Send "^c"
  reset_all_status()
  Return
}
yank()
{
  Send "^v"
  reset_all_status()
  Return
}
undo()
{
  Send "^z"
  reset_all_status()
  Return
}
find_file()
{
  Send "^o"
  reset_all_status()
  Return
}
save_buffer()
{
  Send "^s"
  reset_all_status()
  Return
}
kill_window()
{
  Send "!{F4}"
  reset_all_status()
  Return
}
kill_buffer()
{
  Send "^w"
  reset_all_status()
  Return
}
move_beginning_of_line()
{
  global
  If gIsMarkDown
    Send "+{HOME}"
  Else
  {
    Send "{HOME}"
    reset_all_status()
  }
  Return
}
move_end_of_line()
{
  global
  If gIsMarkDown
    Send "+{END}"
  Else
  {
    Send "{END}"
    reset_all_status()
  }
  Return
}
previous_line()
{
  global
  If gIsMarkDown
    Send "+{Up}"
  Else
  {
    Send "{Up}"
    reset_all_status()
  }
  Return
}
next_line()
{
  global
  If gIsMarkDown
    Send "+{Down}"
  Else
  {
    Send "{Down}"
    reset_all_status()
  }
  Return
}
forward_char()
{
  global
  If gIsMarkDown
    Send "+{Right}"
  Else
  {
    Send "{Right}"
    reset_all_status()
  }
  Return
}
backward_char()
{
  global
  If gIsMarkDown
    Send "+{Left}"
  Else
  {
    Send "{Left}"
    reset_all_status()
  }
  Return
}
scroll_up()
{
  global
  If gIsMarkDown
    Send "+{PgUp}"
  Else
  {
    Send "{PgUp}"
    reset_all_status()
  }
  Return
}
scroll_down()
{
  global
  If gIsMarkDown
    Send "+{PgDn}"
  Else
  {
    Send "{PgDn}"
    reset_all_status()
  }
  Return
}
; https://qiita.com/c-nuts/items/20d02e572b6a06d5dce7
ime_switch()
{
  global
  Send "{vkF3sc029}"
  reset_all_status()
  Return
}
pageup_top()
{
  global
  If gIsMarkDown
    Send "+^{Home}"
  Else
  {
    Send "^{Home}"
    reset_all_status()
  }
  Return
}
pagedown_bottom()
{
  global
  If gIsMarkDown
    Send "+^{End}"
  Else
  {
    Send "^{End}"
    reset_all_status()
  }
  Return
}
set_ignore_targets() {
  ; Applications you want to disable emacs-like keybindings
  ; (Please comment out applications you don't use)
  GroupAdd "IgnoreTargets", "ahk_class ConsoleWindowClass" ; Cygwin, Ubuntu
  GroupAdd "IgnoreTargets", "ahk_class cygwin/x X rl-xterm-XTerm-0"
  GroupAdd "IgnoreTargets", "ahk_class VMwareUnityHostWndClass"
  GroupAdd "IgnoreTargets", "ahk_class Vim" ; GVIM
  GroupAdd "IgnoreTargets", "ahk_class Emacs" ; NTEmacs
  GroupAdd "IgnoreTargets", "ahk_class XEmacs" ; XEmacs on Cygwin
  GroupAdd "IgnoreTargets", "ahk_exe vcxsrv.exe" ; gnome-terminal
  GroupAdd "IgnoreTargets", "ahk_exe xyzzy.exe" ; xyzzy
  GroupAdd "IgnoreTargets", "ahk_exe putty.exe" ; PuTTY
  GroupAdd "IgnoreTargets", "ahk_exe ttermpro.exe" ; TeraTerm
  GroupAdd "IgnoreTargets", "ahk_exe TurboVNC.exe" ; VNC
  GroupAdd "IgnoreTargets", "ahk_exe vncviewer.exe" ; VNC
}
main() {
  if (DEBUG_MODE > 0)
    InstallKeybdHook

  ;; Disable log
  ListLines 0

  ;; Disable delay
  SetControlDelay 0
  ;; SetKeyDelay 0
  SetKeyDelay -1 ;; disable key delay
  SetWinDelay 0
  SendMode "Input"
  ;;SendMode "Play"

  set_ignore_targets()
}

main()

#UseHook

;; Set suspend toggle key
#SuspendExempt
^F1::Suspend
#SuspendExempt False

#HotIf not WinActive("ahk_group IgnoreTargets")
^x::global gIsCtrlXPressed := 1
Esc::
{
  global
  If gIsEscapePressed
  {
    Send "{Esc}"
    gIsEscapePressed := 0
  }
  Else
    gIsEscapePressed := 1
  Return
}
^f::
{
  global
  If gIsCtrlXPressed
    find_file()
  Else
    forward_char()
  Return
}
^c::
{
  global
  If gIsCtrlXPressed
    kill_window()
  Return
}
^d::delete_char()
^h::delete_backward_char()
^k::kill_line()
k::
{
  global
  If gIsCtrlXPressed
    kill_buffer()
  Else
    Send A_ThisHotkey
  Return
}
;;^o::open_line()
^o::ime_switch()
; Ctrl-\ (Backslash) vkE2sc073 SC02B
;^\::
;^vkE2sc073::
^vkE2::ime_switch()
^g::quit()
^j::newline_and_indent()
^m::newline()
^i::indent_for_tab_command()
^s::
{
  global
  If gIsCtrlXPressed
    save_buffer()
  Else
    isearch_forward()
  Return
}
^r::isearch_backward()
^w::kill_region()
!w::kill_ring_save()
w::
{
  global
  If gIsEscapePressed
    kill_ring_save()
  Else
    Send A_ThisHotkey
  Return
}
^y::yank()
^/::undo()
;; ^{Space}::
;; ^vk20sc039::
^vk20::
{
  global
  If gIsMarkDown
    gIsMarkDown := 0
  Else
    gIsMarkDown := 1
  Return
}
^a::move_beginning_of_line()
^e::move_end_of_line()
^p::previous_line()
^n::next_line()
^b::backward_char()
^v::scroll_down()
!v::scroll_up()
v::
{
  global
  If gIsEscapePressed
    scroll_up()
  Else
    Send A_ThisHotkey
  Return
}
!<::pageup_top()
<::
{
  global
  If gIsEscapePressed
    pageup_top()
  Else
    Send A_ThisHotkey
  Return
}
!>::pagedown_bottom()
>::
{
  global
  If gIsEscapePressed
    pagedown_bottom()
  Else
    Send A_ThisHotkey
  Return
}

■参考サイト

  1. AutoHotKey公式サイト:Changes from v1.1 to v2.0
    https://www.autohotkey.com/docs/v2/v2-changes.htm
  2. 🚀 Make the switch to AutoHotkey v2! 🚀 Here's what you need to know 💡
    https://youtu.be/zpF1D7eMHXs
  3. AutoHotkey v2 is now the official version of ahk
    https://youtu.be/Tun3R634QgY
  4. autohotkey v1 を autohotkey v2 に移植
    https://benizara.hatenablog.com/entry/2023/03/05/014148
  5. Bug? HotIfWinActive
    https://www.autohotkey.com/boards/viewtopic.php?style=2&t=95739
  6. Windows 10でemacs風キーバーインド。AutoHotKeyの設定をちょい足し編。
    https://qiita.com/c-nuts/items/20d02e572b6a06d5dce7
  7. Windows 10でも「Emacs風キーバインド」を使おう【AutoHotKey】
    https://linuxfan.info/windows-emacs-keybindings
  8. Windows の操作を Emacs のキーバインドで行うための設定 (AutoHotKey版)
    https://w.atwiki.jp/ntemacs/pages/20.html
  9. GitHub - usi3 / emacs.ahk
    https://github.com/usi3/emacs.ahk
14
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
10