AutoHotkeyでゆるゆるなemacsキーバインド

# 目的

emacsのキーバインドをEclipseやAtomなど、使いたいアプリケーションに応じて、個別に調べて設定するのは大変。にもかかわらず、本当にあったらうれしいキーバインドはC-hなどシンプルなものだけ。であれば、OSのキーバインドをフックして全般的に変えてくれる系がうれしい。

そこで、AutoHotkeyを使って自分が必要な最低限のキーバインドだけを残し、かつIMEのトグルとAutoHotkey自信のON/OFFも切り替えられるように調べてScriptを作る。

# ダウンロード＆インストール

[AutoHotkey](http://ahkscript.org/)からWindowsインストーラをダウンロード。
そのインストーラを叩くだけ。

# 設定の作成

ネットにある[emacsのScipt](https://github.com/usi3/emacs.ahk/blob/master/emacs.ahk)を参考に作る。変更後の設定は、この最後尾に載せる。

## emacsキーバインドで有効にしているもの

各ソフトのキーバインドと被るので、最小限のみ。

- C-f, C-b, C-n, C-pの十字移動
- C-a, C-eの先頭末尾移動
- C-h, C-dの削除
- C-mの改行

## IMEの設定

IMEはC-oで切り替えたいので、[AutoHotkeyを流行らせるアップローダ跡地](http://lukewarm.s101.xrea.com/up/index.php)から089のIMEの切り替えよう関数の設定をダウンロードして、下記のコードを埋め込む。

```
#Include IME.ahk

^o::
  If is_target()
    Send %A_ThisHotkey%
  Else
  {
    getIMEMode := IME_Get()
    If (%getIMEMode% = 0)
    {
      IME_SET(1)
      Return
    }
    Else
    {
      IME_SET(0)
      Return
    }
  }
  Return
```

## AutoHotkeyのON/OFF切り替え

どうしてもほかのソフトとバッティングする場合は、一時停止したい。C-@にSuspendを割り当てる。通知領域にAutoHotkeyを表示しておくと、Suspend中はSになる。

```
^@::
  Suspend, Toggle
  Return
```

# 全設定

```
;;
;; An autohotkey script that provides emacs-like keybinding on Windows
;;
#InstallKeybdHook
#UseHook
#Include IME.ahk

; The following line is a contribution of NTEmacs wiki http://www49.atwiki.jp/ntemacs/pages/20.html
SetKeyDelay 0

; turns to be 1 when ctrl-x is pressed
is_pre_x = 0
; turns to be 1 when ctrl-space is pressed
is_pre_spc = 0

; Applications you want to disable emacs-like keybindings
; (Please comment out applications you don't use)
is_target()
{
  IfWinActive,ahk_class ConsoleWindowClass ; Cygwin
    Return 1
  IfWinActive,ahk_class MEADOW ; Meadow
    Return 1
  IfWinActive,ahk_class cygwin/x X rl-xterm-XTerm-0
    Return 1
  IfWinActive,ahk_class MozillaUIWindowClass ; keysnail on Firefox
    Return 1
  ; Avoid VMwareUnity with AutoHotkey
  IfWinActive,ahk_class VMwareUnityHostWndClass
    Return 1
  IfWinActive,ahk_class Vim ; GVIM
    Return 1
;  IfWinActive,ahk_class SWT_Window0 ; Eclipse
;    Return 1
;   IfWinActive,ahk_class Xming X
;     Return 1
;   IfWinActive,ahk_class SunAwtFrame
;     Return 1
;   IfWinActive,ahk_class Emacs ; NTEmacs
;     Return 1  
;   IfWinActive,ahk_class XEmacs ; XEmacs on Cygwin
;     Return 1
  Return 0
}

delete_char()
{
  Send {Del}
  global is_pre_spc = 0
  Return
}
delete_backward_char()
{
  Send {BS}
  global is_pre_spc = 0
  Return
}
kill_line()
{
  Send {ShiftDown}{END}{SHIFTUP}
  Sleep 50 ;[ms] this value depends on your environment
  Send ^x
  global is_pre_spc = 0
  Return
}
open_line()
{
  Send {END}{Enter}{Up}
  global is_pre_spc = 0
  Return
}
quit()
{
  Send {ESC}
  global is_pre_spc = 0
  Return
}
newline()
{
  Send {Enter}
  global is_pre_spc = 0
  Return
}
indent_for_tab_command()
{
  Send {Tab}
  global is_pre_spc = 0
  Return
}
newline_and_indent()
{
  Send {Enter}{Tab}
  global is_pre_spc = 0
  Return
}
isearch_forward()
{
  Send ^f
  global is_pre_spc = 0
  Return
}
isearch_backward()
{
  Send ^f
  global is_pre_spc = 0
  Return
}
kill_region()
{
  Send ^x
  global is_pre_spc = 0
  Return
}
kill_ring_save()
{
  Send ^c
  global is_pre_spc = 0
  Return
}
yank()
{
  Send ^v
  global is_pre_spc = 0
  Return
}
undo()
{
  Send ^z
  global is_pre_spc = 0
  Return
}
find_file()
{
  Send ^o
  global is_pre_x = 0
  Return
}
save_buffer()
{
  Send, ^s
  global is_pre_x = 0
  Return
}
kill_emacs()
{
  Send !{F4}
  global is_pre_x = 0
  Return
}

move_beginning_of_line()
{
  global
  if is_pre_spc
    Send +{HOME}
  Else
    Send {HOME}
  Return
}
move_end_of_line()
{
  global
  if is_pre_spc
    Send +{END}
  Else
    Send {END}
  Return
}
previous_line()
{
  global
  if is_pre_spc
    Send +{Up}
  Else
    Send {Up}
  Return
}
next_line()
{
  global
  if is_pre_spc
    Send +{Down}
  Else
    Send {Down}
  Return
}
forward_char()
{
  global
  if is_pre_spc
    Send +{Right}
  Else
    Send {Right}
  Return
}
backward_char()
{
  global
  if is_pre_spc
    Send +{Left}
  Else
    Send {Left}
  Return
}
scroll_up()
{
  global
  if is_pre_spc
    Send +{PgUp}
  Else
    Send {PgUp}
  Return
}
scroll_down()
{
  global
  if is_pre_spc
    Send +{PgDn}
  Else
    Send {PgDn}
  Return
}



^f::
  If is_target()
    Send %A_ThisHotkey%
  Else
    forward_char()
  Return  
^d::
  If is_target()
    Send %A_ThisHotkey%
  Else
    delete_char()
  Return
^h::
  If is_target()
    Send %A_ThisHotkey%
  Else
    delete_backward_char()
  Return
^o::
  If is_target()
    Send %A_ThisHotkey%
  Else
  {
    getIMEMode := IME_Get()
    If (%getIMEMode% = 0)
    {
      IME_SET(1)
      Return
    }
    Else
    {
      IME_SET(0)
      Return
    }
  }
  Return
^g::
  If is_target()
    Send %A_ThisHotkey%
  Else
    quit()
  Return
^m::
  If is_target()
    Send %A_ThisHotkey%
  Else
    newline()
  Return
!s::
  If is_target()
    Send %A_ThisHotkey%
  Else
    isearch_forward()
  Return
;$^{Space}::
^vk20sc039::
  If is_target()
    Send {CtrlDown}{Space}{CtrlUp}
  Else
  {
    If is_pre_spc
      is_pre_spc = 0
    Else
      is_pre_spc = 1
  }
  Return
^@::
  Suspend, Toggle
  Return
^a::
  If is_target()
    Send %A_ThisHotkey%
  Else
    move_beginning_of_line()
  Return
^e::
  If is_target()
    Send %A_ThisHotkey%
  Else
    move_end_of_line()
  Return
^p::
  If is_target()
    Send %A_ThisHotkey%
  Else
    previous_line()
  Return
^n::
  If is_target()
    Send %A_ThisHotkey%
  Else
    next_line()
  Return
^b::
  If is_target()
    Send %A_ThisHotkey%
  Else
    backward_char()
  Return
```