AutoHotkey.ahk, from darwin16

AutoHotkey.ahk, from darwin16

; Tips {{{
; #: win
; !: alt
; ^: ctrl
; +: shift
; &: and
; <: only left, >: only right
; *: wildecard
; ~: pass through
; }}}

; Auto-execute section {{{
; Auto execute section is the region before any return/hotkey

; Windows size
TMargin=5
BMargin=5
LMargin=5
RMargin=5 ; sidebar = 150px
MinSize=0.7

; For Terminal/Vim
GroupAdd Terminal, ahk_class PuTTY
GroupAdd Terminal, ahk_class mintty ; cygwin
GroupAdd Terminal, ahk_class TMobaXtermForm
GroupAdd Terminal, ahk_class TFormDetachedTab
GroupAdd TerminalVim, ahk_group Terminal
GroupAdd TerminalVim, ahk_class Vim

#Include  %A_ScriptDir%\vim.ahk

Return
; }}}

; Basic Settings, HotKeys, Functions {{{
; Settings

#UseHook On ; Make it a bit slow, but can avoid infinitude loop
            ; Same as "$" for each hotkey
#InstallKeybdHook ; For checking key history
                  ; Use ~500kB memory?

#HotkeyInterval 1000 ; Hotkey inteval (default 2000 milliseconds).
#MaxHotkeysPerInterval 100 ; Max hotkeys perinterval (default 50).

; For HHKB
;vkFFsc079::RAlt
;vkFFsc07b::LAlt
vkFFsc079::RCtrl
vkFFsc07b::LCtrl

;; Ref for IME: http://www6.atwiki.jp/eamat/pages/17.html
;; Get IME Status. 0: Off, 1: On
;IME_GET(WinTitle="A")  {
;  ControlGet,hwnd,HWND,,,%WinTitle%
;  if (WinActive(WinTitle)) {
;    ptrSize := !A_PtrSize ? 4 : A_PtrSize
;    VarSetCapacity(stGTI, cbSize:=4+4+(PtrSize*6)+16, 0)
;    NumPut(cbSize, stGTI,  0, "UInt")   ;   DWORD   cbSize;
;    hwnd := DllCall("GetGUIThreadInfo", Uint,0, Uint,&stGTI)
;        ? NumGet(stGTI,8+PtrSize,"UInt") : hwnd
;  }
;
;  Return DllCall("SendMessage"
;      , UInt, DllCall("imm32\ImmGetDefaultIMEWnd", Uint,hwnd)
;      , UInt, 0x0283  ;Message : WM_IME_CONTROL
;      ,  Int, 0x0005  ;wParam  : IMC_GETOPENSTATUS
;      ,  Int, 0)      ;lParam  : 0
;}
;; Get input status. 1: Converting, 2: Have converting window, 0: Others
;IME_GetConverting(WinTitle="A",ConvCls="",CandCls="") {
;  ; Input windows, candidate windows (Add new IME with "|")
;  ConvCls .= (ConvCls ? "|" : "")                 ;--- Input Window ---
;    .  "ATOK\d+CompStr"                           ; ATOK
;    .  "|imejpstcnv\d+"                           ; MS-IME
;    .  "|WXGIMEConv"                              ; WXG
;    .  "|SKKIME\d+\.*\d+UCompStr"                 ; SKKIME Unicode
;    .  "|MSCTFIME Composition"                    ; Google IME
;  CandCls .= (CandCls ? "|" : "")                 ;--- Candidate Window ---
;    .  "ATOK\d+Cand"                              ; ATOK
;    .  "|imejpstCandList\d+|imejpstcand\d+"       ; MS-IME 2002(8.1)XP
;    .  "|mscandui\d+\.candidate"                  ; MS Office IME-2007
;    .  "|WXGIMECand"                              ; WXG
;    .  "|SKKIME\d+\.*\d+UCand"                    ; SKKIME Unicode
; CandGCls := "GoogleJapaneseInputCandidateWindow" ; Google IME
;
;  ControlGet,hwnd,HWND,,,%WinTitle%
;  if (WinActive(WinTitle)) {
;    ptrSize := !A_PtrSize ? 4 : A_PtrSize
;    VarSetCapacity(stGTI, cbSize:=4+4+(PtrSize*6)+16, 0)
;    NumPut(cbSize, stGTI,  0, "UInt")   ;   DWORD   cbSize;
;    hwnd := DllCall("GetGUIThreadInfo", Uint,0, Uint,&stGTI)
;      ? NumGet(stGTI,8+PtrSize,"UInt") : hwnd
;  }
;
;  WinGet, pid, PID,% "ahk_id " hwnd
;  tmm:=A_TitleMatchMode
;  SetTitleMatchMode, RegEx
;  ret := WinExist("ahk_class " . CandCls . " ahk_pid " pid) ? 2
;      :  WinExist("ahk_class " . CandGCls                 ) ? 2
;      :  WinExist("ahk_class " . ConvCls . " ahk_pid " pid) ? 1
;      :  0
;  SetTitleMatchMode, %tmm%
;  Return ret
;}
;; Set IME, SetSts=0: Off, 1: On, return 0 for success, others for non-success
;IME_SET(SetSts=0, WinTitle="A")    {
;  ControlGet,hwnd,HWND,,,%WinTitle%
;  if(WinActive(WinTitle)){
;    ptrSize := !A_PtrSize ? 4 : A_PtrSize
;    VarSetCapacity(stGTI, cbSize:=4+4+(PtrSize*6)+16, 0)
;    NumPut(cbSize, stGTI,  0, "UInt")   ;   DWORD   cbSize;
;    hwnd := DllCall("GetGUIThreadInfo", Uint,0, Uint,&stGTI)
;        ? NumGet(stGTI,8+PtrSize,"UInt") : hwnd
;  }
;
;  Return DllCall("SendMessage"
;    , UInt, DllCall("imm32\ImmGetDefaultIMEWnd", Uint,hwnd)
;    , UInt, 0x0283  ;Message : WM_IME_CONTROL
;    ,  Int, 0x006   ;wParam  : IMC_SETOPENSTATUS
;    ,  Int, SetSts) ;lParam  : 0 or 1
;}

; }}}

; Terminal/Vim {{{
; ESC + IME
#IfWInActive, ahk_group TerminalVim
Esc:: ; Just send Esc at converting.
  if (VIM_IME_GET(A)) {
    if (VIM_IME_GetConverting(A)) {
      Send,{Esc}
    } else {
      VIM_IME_SET()
    }
  } else {
    Send,{Esc}
  }
  Return
^[:: ; Go to Normal mode (for vim) with IME off even at converting.
  if (VIM_IME_GetConverting(A)) {
    Send,{Esc}
    Sleep 1 ; wait 1 ms (Need to stop converting)
  }
  if (VIM_IME_GET(A)) {
    VIM_IME_SET()
    Send,{Esc}
  } else {
    Send,{Esc}
  }
  Return
^m::Send,^m ; Use Ctrl-m as is
#IfWInActive

; Paste
#IfWInActive, ahk_group Terminal
!v::
  ;StringSplit, strout, clipboard, `n
  ;If(strout0>1 or InStr(clipboard, "sudo")>0) {
  ;  MsgBox, 308, Clipboard, %clipboard%`n`n Do you want to paste?
  ;  IfMsgBox, No
  ;  {
  ;    Return
  ;  }
  ;}
  Sleep,200
  MouseClick, Right, 50, 50, 1
  Return
#IfWInActive
#IfWInActive, ahk_class Vim
!v::Send,{Alt}ep
#IfWInActive

; Other than Terminal/Vim
#IfWInNotActive, ahk_group TerminalVim
^[::Send,{Esc}             ; Always C-[ to ESC, like vim
^d::Send,{Del}             ; Always Delete with C-d
#IfWInNotActive
; }}} Terminal/Vim

; Power Point {{{
#IfWInActive, ahk_class PP12FrameClass
; Select one character
^Space::Send,{Right}+{Left}

; Subscript/Superscript
^=::Send,^tb{Enter}
^+=::Send,^tp{Enter}
; For JP keyboards
;^-::Send,^tb{Enter}
;^+-::Send,^tp{Enter}

; Fonts
^+s::Send,^tfsymbol{Enter}
^+a::Send,^tfarial{Enter}
^+h::Send,^tfhelvetica{Enter}
#IfWInActive
; }}} Power Point

; Word {{{
#IfWInActive, ahk_class OpusApp
^Space::Send,{Right}+{Left}
^=::Send,^tb{Enter}
^+=::Send,^tp{Enter}
; for JP keyboards
;^-::Send,^tb{Enter}
;^+-::Send,^tp{Enter}
#IfWInActive
; }}} Word

; Explorer {{{
#IfWInActive, ahk_class CabinetWClass
; Next/Previous page
^i::Send,!{Right}
^o::Send,!{Left}
#IfWInActive
; }}} Explorer

; CLCL {{{
;#IfWInActive, ahk_class CLCLMain
#IfWInActive, CLCL ; both window/title do not working...
j::
  Msgbox, clcl_down
  Send,{Down}
  Return
K::Send,{Up}
#IfWInActive
; }}} Explorer

; Everthing {{{
#IfWInActive, ahk_class EVERYTHING
Return::
  Send,{Enter}
  Sleep,200
  IfWinActive, ahk_class EVERYTHING
  {
    Send,{Enter}
    Sleep,500
  }
  WinActivate, ahk_class EVERYTHING
  Sleep,200
  Send,{Esc}
  Return
#IfWInActive
; }}} Everything

; Command Prompt {{{
#IfWinActive ahk_class ConsoleWindowClass
^v::
  SendInput %clipboard%
  Return
#IfWInActive
; }}} Command Prompt

; Fiefox {{{
;#IfWinActive ahk_exe firefox.exe
;^j::Send ^j
;#IfWInActive
; }}} Firefox

; Global Settings {{{
#if
; Basic Settings {{{

; Suspend
;Esc & Tab::
;  Suspend, Toggle
;  Return
; For Alt-Ctrl Swap (swapped by KeySwap)
LCtrl & Tab::AltTab
Alt & Tab::
  if GetKeyState("Shift","P") {
    Send,^+{taB} ; dosen't work ()
  }else{
    Send,^{Tab}
  }
  Return
;!m::Send,^m
;^m::Send,!m
;>^m::Send,!m
;Ctrl & Left::Send,!{Left}
;Ctrl & Right::Send,!{Right}

; Virtual desktop
^+h::Send,#^{Left}
^+l::Send,#^{Right}

; Cortana
!^f::Send,#s

; Other basic settings
!Space::Send,{vkF3sc029}   ; IME by A-Space
^Space::Send,{vkF3sc029}   ; IME by C-Space
; {vkF3sc029}              ; 変換
; {vk1Dsc07B}              ; 無変換
!a::Send,^{Space}n        ; Minimize window
!4::Send,!{F4}             ; Close window
^4::Send,!{F4}             ; Close window
!d::Send,{Del}             ; Always Delete with A-d
;^o::Send,!{Left}           ; Go to previous page
;^i::Send,!{Right}          ; Go to nexe page
^Space::!`                 ; IME

^h::Send,{BS}              ; Always BS with C-h
;^h::
;  While GetKeyState("h","p"){
;    Send {BS}
;    TrayTip,Start:,%n%,10,,
;    Sleep 50
;  }
;  return

;^j::Send,{Enter}      ; C-j to Enter

; For HHKB
; ESC to ` like normal keyboard (ESC is placed on the left of 1 in HHKB)
!1::!`                ; IME
; }}} Basic Settings

; Cursor, Mouse, Window move/size {{{
; Cursor {{{
!^h::Send,{Left}
!^j::Send,{Down}
!^k::Send,{Up}
!^l::Send,{Right}
; }}} Cursor

; Mouse {{{
; Mouse Move
!^y::MouseMove, -10, 0, 0, R
!^u::MouseMove, 0, 10, 0, R
!^i::MouseMove, 0, -10, 0, R
!^o::MouseMove, 10, 0, 0, R

; Click
!^n::MouseClick, Left
!^p::MouseClick, Right
; Right click on current window

; Mouse wheel
!^m::MouseClick, WheelDown,,,  2
!^,::MouseClick, WheelUp,,,  2
; }}} Mouse

; Window move {{{
^+y::
  WinGetPos, X, Y, , , A ;A for Active Window
  ;Msgbox, Pos At %X% %Y%
  WinMove, A, ,X-20, Y,
  ;Msgbox, Moved At %X%-20 %Y%
  Return ; Necessary for mapping which has at least 2 commands
^+u::
  WinGetPos, X, Y, , , A
  WinMove, A, ,X, Y+20
  Return
^+i::
  WinGetPos, X, Y, , , A
  WinMove, A, ,X, Y-20
  Return
^+o::
  WinGetPos, X, Y, , , A
  WinMove, A, ,X+20, Y
  Return
; }}} Window move

; Window size {{{
^!Enter::
  ;WinGetPos, X, Y, W, H, Program Manager ; Full Desktop
  ;Msgbox, Pos At %X% %Y% %W% %H%
  SysGet, MWA, MonitorWorkArea ; w/o Taskbar
  ;Msgbox, %MWALeft% %MWATop% %MWARight% %MWABottom%
  WinMove, A, , MWALeft+LMargin, MWATop+TMargin
    , MWARight-MWALeft-LMargin-RMargin
    , MWABottom-MWATop-TMargin-BMargin
  Return
^!+Enter::
  SysGet, MWA, MonitorWorkArea ; w/o Taskbar
  WinMove, A, , MWALeft+LMargin, MWATop+TMargin
    , (MWARight-MWALeft-LMargin-RMargin)*Minsize
    , (MWABottom-MWATop-TMargin-BMargin)*Minsize
  Return
!+h::
  SysGet, MWA, MonitorWorkArea ; w/o Taskbar
  WinMove, A, , MWALeft+LMargin, MWATop+TMargin
    , (MWARight-MWALeft-LMargin-RMargin)*0.5
    , MWABottom-MWATop-TMargin-BMargin
  Return
!+j::
  SysGet, MWA, MonitorWorkArea ; w/o Taskbar
  WinMove, A, , MWALeft+LMargin
    , MWATop+(MWABottom-MWATop)*0.5
    , MWARight-MWALeft-LMargin-RMargin
    , (MWABottom-MWATop-TMargin-BMargin)*0.5
  Return
!+k::
  SysGet, MWA, MonitorWorkArea ; w/o Taskbar
  WinMove, A, , MWALeft+LMargin, MWATop+TMargin
    , MWARight-MWALeft-LMargin-RMargin
    , (MWABottom-MWATop-TMargin-BMargin)*0.5
  Return
!+l::
  SysGet, MWA, MonitorWorkArea ; w/o Taskbar
  WinMove, A, , MWALeft+(MWARight-MWALeft)*0.5
    , MWATop+TMargin
    , (MWARight-MWALeft-LMargin-RMargin)*0.5
    , MWABottom-MWATop-TMargin-BMargin
  Return
; }}} Window size
; }}} Cursor, Mouse, Window move
; }}} Global Settings

; Tips {{{
; #: win
; !: alt
; ^: ctrl
; +: shift
; &: and
; <: only left, >: only right
; *: wildecard
; ~: pass through
; }}}

; Auto-execute section {{{
; Auto execute section is the region before any return/hotkey

; Windows size
TMargin=5
BMargin=5
LMargin=5
RMargin=5 ; sidebar = 150px
MinSize=0.7

; For Terminal/Vim
GroupAdd Terminal, ahk_class PuTTY
GroupAdd Terminal, ahk_class mintty ; cygwin
GroupAdd Terminal, ahk_class TMobaXtermForm
GroupAdd Terminal, ahk_class TFormDetachedTab
GroupAdd TerminalVim, ahk_group Terminal
GroupAdd TerminalVim, ahk_class Vim

#Include  %A_ScriptDir%\vim.ahk

Return
; }}}

; Basic Settings, HotKeys, Functions {{{
; Settings

#UseHook On ; Make it a bit slow, but can avoid infinitude loop
            ; Same as "$" for each hotkey
#InstallKeybdHook ; For checking key history
                  ; Use ~500kB memory?

#HotkeyInterval 1000 ; Hotkey inteval (default 2000 milliseconds).
#MaxHotkeysPerInterval 100 ; Max hotkeys perinterval (default 50).

; For HHKB
;vkFFsc079::RAlt
;vkFFsc07b::LAlt
vkFFsc079::RCtrl
vkFFsc07b::LCtrl

;; Ref for IME: http://www6.atwiki.jp/eamat/pages/17.html
;; Get IME Status. 0: Off, 1: On
;IME_GET(WinTitle="A")  {
;  ControlGet,hwnd,HWND,,,%WinTitle%
;  if (WinActive(WinTitle)) {
;    ptrSize := !A_PtrSize ? 4 : A_PtrSize
;    VarSetCapacity(stGTI, cbSize:=4+4+(PtrSize*6)+16, 0)
;    NumPut(cbSize, stGTI,  0, "UInt")   ;   DWORD   cbSize;
;    hwnd := DllCall("GetGUIThreadInfo", Uint,0, Uint,&stGTI)
;        ? NumGet(stGTI,8+PtrSize,"UInt") : hwnd
;  }
;
;  Return DllCall("SendMessage"
;      , UInt, DllCall("imm32\ImmGetDefaultIMEWnd", Uint,hwnd)
;      , UInt, 0x0283  ;Message : WM_IME_CONTROL
;      ,  Int, 0x0005  ;wParam  : IMC_GETOPENSTATUS
;      ,  Int, 0)      ;lParam  : 0
;}
;; Get input status. 1: Converting, 2: Have converting window, 0: Others
;IME_GetConverting(WinTitle="A",ConvCls="",CandCls="") {
;  ; Input windows, candidate windows (Add new IME with "|")
;  ConvCls .= (ConvCls ? "|" : "")                 ;--- Input Window ---
;    .  "ATOK\d+CompStr"                           ; ATOK
;    .  "|imejpstcnv\d+"                           ; MS-IME
;    .  "|WXGIMEConv"                              ; WXG
;    .  "|SKKIME\d+\.*\d+UCompStr"                 ; SKKIME Unicode
;    .  "|MSCTFIME Composition"                    ; Google IME
;  CandCls .= (CandCls ? "|" : "")                 ;--- Candidate Window ---
;    .  "ATOK\d+Cand"                              ; ATOK
;    .  "|imejpstCandList\d+|imejpstcand\d+"       ; MS-IME 2002(8.1)XP
;    .  "|mscandui\d+\.candidate"                  ; MS Office IME-2007
;    .  "|WXGIMECand"                              ; WXG
;    .  "|SKKIME\d+\.*\d+UCand"                    ; SKKIME Unicode
; CandGCls := "GoogleJapaneseInputCandidateWindow" ; Google IME
;
;  ControlGet,hwnd,HWND,,,%WinTitle%
;  if (WinActive(WinTitle)) {
;    ptrSize := !A_PtrSize ? 4 : A_PtrSize
;    VarSetCapacity(stGTI, cbSize:=4+4+(PtrSize*6)+16, 0)
;    NumPut(cbSize, stGTI,  0, "UInt")   ;   DWORD   cbSize;
;    hwnd := DllCall("GetGUIThreadInfo", Uint,0, Uint,&stGTI)
;      ? NumGet(stGTI,8+PtrSize,"UInt") : hwnd
;  }
;
;  WinGet, pid, PID,% "ahk_id " hwnd
;  tmm:=A_TitleMatchMode
;  SetTitleMatchMode, RegEx
;  ret := WinExist("ahk_class " . CandCls . " ahk_pid " pid) ? 2
;      :  WinExist("ahk_class " . CandGCls                 ) ? 2
;      :  WinExist("ahk_class " . ConvCls . " ahk_pid " pid) ? 1
;      :  0
;  SetTitleMatchMode, %tmm%
;  Return ret
;}
;; Set IME, SetSts=0: Off, 1: On, return 0 for success, others for non-success
;IME_SET(SetSts=0, WinTitle="A")    {
;  ControlGet,hwnd,HWND,,,%WinTitle%
;  if(WinActive(WinTitle)){
;    ptrSize := !A_PtrSize ? 4 : A_PtrSize
;    VarSetCapacity(stGTI, cbSize:=4+4+(PtrSize*6)+16, 0)
;    NumPut(cbSize, stGTI,  0, "UInt")   ;   DWORD   cbSize;
;    hwnd := DllCall("GetGUIThreadInfo", Uint,0, Uint,&stGTI)
;        ? NumGet(stGTI,8+PtrSize,"UInt") : hwnd
;  }
;
;  Return DllCall("SendMessage"
;    , UInt, DllCall("imm32\ImmGetDefaultIMEWnd", Uint,hwnd)
;    , UInt, 0x0283  ;Message : WM_IME_CONTROL
;    ,  Int, 0x006   ;wParam  : IMC_SETOPENSTATUS
;    ,  Int, SetSts) ;lParam  : 0 or 1
;}

; }}}

; Terminal/Vim {{{
; ESC + IME
#IfWInActive, ahk_group TerminalVim
Esc:: ; Just send Esc at converting.
  if (VIM_IME_GET(A)) {
    if (VIM_IME_GetConverting(A)) {
      Send,{Esc}
    } else {
      VIM_IME_SET()
    }
  } else {
    Send,{Esc}
  }
  Return
^[:: ; Go to Normal mode (for vim) with IME off even at converting.
  if (VIM_IME_GetConverting(A)) {
    Send,{Esc}
    Sleep 1 ; wait 1 ms (Need to stop converting)
  }
  if (VIM_IME_GET(A)) {
    VIM_IME_SET()
    Send,{Esc}
  } else {
    Send,{Esc}
  }
  Return
^m::Send,^m ; Use Ctrl-m as is
#IfWInActive

; Paste
#IfWInActive, ahk_group Terminal
!v::
  ;StringSplit, strout, clipboard, `n
  ;If(strout0>1 or InStr(clipboard, "sudo")>0) {
  ;  MsgBox, 308, Clipboard, %clipboard%`n`n Do you want to paste?
  ;  IfMsgBox, No
  ;  {
  ;    Return
  ;  }
  ;}
  Sleep,200
  MouseClick, Right, 50, 50, 1
  Return
#IfWInActive
#IfWInActive, ahk_class Vim
!v::Send,{Alt}ep
#IfWInActive

; Other than Terminal/Vim
#IfWInNotActive, ahk_group TerminalVim
^[::Send,{Esc}             ; Always C-[ to ESC, like vim
^d::Send,{Del}             ; Always Delete with C-d
#IfWInNotActive
; }}} Terminal/Vim

; Power Point {{{
#IfWInActive, ahk_class PP12FrameClass
; Select one character
^Space::Send,{Right}+{Left}

; Subscript/Superscript
^=::Send,^tb{Enter}
^+=::Send,^tp{Enter}
; For JP keyboards
;^-::Send,^tb{Enter}
;^+-::Send,^tp{Enter}

; Fonts
^+s::Send,^tfsymbol{Enter}
^+a::Send,^tfarial{Enter}
^+h::Send,^tfhelvetica{Enter}
#IfWInActive
; }}} Power Point

; Word {{{
#IfWInActive, ahk_class OpusApp
^Space::Send,{Right}+{Left}
^=::Send,^tb{Enter}
^+=::Send,^tp{Enter}
; for JP keyboards
;^-::Send,^tb{Enter}
;^+-::Send,^tp{Enter}
#IfWInActive
; }}} Word

; Explorer {{{
#IfWInActive, ahk_class CabinetWClass
; Next/Previous page
^i::Send,!{Right}
^o::Send,!{Left}
#IfWInActive
; }}} Explorer

; CLCL {{{
;#IfWInActive, ahk_class CLCLMain
#IfWInActive, CLCL ; both window/title do not working...
j::
  Msgbox, clcl_down
  Send,{Down}
  Return
K::Send,{Up}
#IfWInActive
; }}} Explorer

; Everthing {{{
#IfWInActive, ahk_class EVERYTHING
Return::
  Send,{Enter}
  Sleep,200
  IfWinActive, ahk_class EVERYTHING
  {
    Send,{Enter}
    Sleep,500
  }
  WinActivate, ahk_class EVERYTHING
  Sleep,200
  Send,{Esc}
  Return
#IfWInActive
; }}} Everything

; Command Prompt {{{
#IfWinActive ahk_class ConsoleWindowClass
^v::
  SendInput %clipboard%
  Return
#IfWInActive
; }}} Command Prompt

; Fiefox {{{
#IfWinActive ahk_exe firefox.exe
^j::Send ^j
#IfWInActive
; }}} Firefox

; Global Settings {{{
#if
; Basic Settings {{{

; Suspend
;Esc & Tab::
;  Suspend, Toggle
;  Return
; For Alt-Ctrl Swap (swapped by KeySwap)
LCtrl & Tab::AltTab
Alt & Tab::
  if GetKeyState("Shift","P") {
    Send,^+{taB} ; dosen't work ()
  }else{
    Send,^{Tab}
  }
  Return
;!m::Send,^m
;^m::Send,!m
;>^m::Send,!m
;Ctrl & Left::Send,!{Left}
;Ctrl & Right::Send,!{Right}

; Virtual desktop
^+h::Send,#^{Left}
^+l::Send,#^{Right}

; Cortana
!^f::Send,#s

; Other basic settings
!Space::Send,{vkF3sc029}   ; IME by A-Space
^Space::Send,{vkF3sc029}   ; IME by C-Space
; {vkF3sc029}              ; 変換
; {vk1Dsc07B}              ; 無変換
!a::Send,^{Space}n        ; Minimize window
!4::Send,!{F4}             ; Close window
^4::Send,!{F4}             ; Close window
!d::Send,{Del}             ; Always Delete with A-d
;^o::Send,!{Left}           ; Go to previous page
;^i::Send,!{Right}          ; Go to nexe page
^Space::!`                 ; IME

^h::Send,{BS}              ; Always BS with C-h
;^h::
;  While GetKeyState("h","p"){
;    Send {BS}
;    TrayTip,Start:,%n%,10,,
;    Sleep 50
;  }
;  return

^j::Send,{Enter}      ; C-j to Enter

; For HHKB
; ESC to ` like normal keyboard (ESC is placed on the left of 1 in HHKB)
!1::!`                ; IME
; }}} Basic Settings

; Cursor, Mouse, Window move/size {{{
; Cursor {{{
!^h::Send,{Left}
!^j::Send,{Down}
!^k::Send,{Up}
!^l::Send,{Right}
; }}} Cursor

; Mouse {{{
; Mouse Move
!^y::MouseMove, -10, 0, 0, R
!^u::MouseMove, 0, 10, 0, R
!^i::MouseMove, 0, -10, 0, R
!^o::MouseMove, 10, 0, 0, R

; Click
!^n::MouseClick, Left
!^p::MouseClick, Right
; Right click on current window

; Mouse wheel
!^m::MouseClick, WheelDown,,,  2
!^,::MouseClick, WheelUp,,,  2
; }}} Mouse

; Window move {{{
^+y::
  WinGetPos, X, Y, , , A ;A for Active Window
  ;Msgbox, Pos At %X% %Y%
  WinMove, A, ,X-20, Y,
  ;Msgbox, Moved At %X%-20 %Y%
  Return ; Necessary for mapping which has at least 2 commands
^+u::
  WinGetPos, X, Y, , , A
  WinMove, A, ,X, Y+20
  Return
^+i::
  WinGetPos, X, Y, , , A
  WinMove, A, ,X, Y-20
  Return
^+o::
  WinGetPos, X, Y, , , A
  WinMove, A, ,X+20, Y
  Return
; }}} Window move

; Window size {{{
^!Enter::
  ;WinGetPos, X, Y, W, H, Program Manager ; Full Desktop
  ;Msgbox, Pos At %X% %Y% %W% %H%
  SysGet, MWA, MonitorWorkArea ; w/o Taskbar
  ;Msgbox, %MWALeft% %MWATop% %MWARight% %MWABottom%
  WinMove, A, , MWALeft+LMargin, MWATop+TMargin
    , MWARight-MWALeft-LMargin-RMargin
    , MWABottom-MWATop-TMargin-BMargin
  Return
^!+Enter::
  SysGet, MWA, MonitorWorkArea ; w/o Taskbar
  WinMove, A, , MWALeft+LMargin, MWATop+TMargin
    , (MWARight-MWALeft-LMargin-RMargin)*Minsize
    , (MWABottom-MWATop-TMargin-BMargin)*Minsize
  Return
!+h::
  SysGet, MWA, MonitorWorkArea ; w/o Taskbar
  WinMove, A, , MWALeft+LMargin, MWATop+TMargin
    , (MWARight-MWALeft-LMargin-RMargin)*0.5
    , MWABottom-MWATop-TMargin-BMargin
  Return
!+j::
  SysGet, MWA, MonitorWorkArea ; w/o Taskbar
  WinMove, A, , MWALeft+LMargin
    , MWATop+(MWABottom-MWATop)*0.5
    , MWARight-MWALeft-LMargin-RMargin
    , (MWABottom-MWATop-TMargin-BMargin)*0.5
  Return
!+k::
  SysGet, MWA, MonitorWorkArea ; w/o Taskbar
  WinMove, A, , MWALeft+LMargin, MWATop+TMargin
    , MWARight-MWALeft-LMargin-RMargin
    , (MWABottom-MWATop-TMargin-BMargin)*0.5
  Return
!+l::
  SysGet, MWA, MonitorWorkArea ; w/o Taskbar
  WinMove, A, , MWALeft+(MWARight-MWALeft)*0.5
    , MWATop+TMargin
    , (MWARight-MWALeft-LMargin-RMargin)*0.5
    , MWABottom-MWATop-TMargin-BMargin
  Return
; }}} Window size
; }}} Cursor, Mouse, Window move
; }}} Global Settings


use abs path for chrome and chrome canary

^Tab::
Send #{Tab}
return

^`::
IfWinActive, ahk_exe vcxsrv.exe
    Send !{Tab}
else
    WinActivate ahk_exe vcxsrv.exe
return

^!`::
IfWinActive, ahk_exe ubuntu.exe
    Send !{Tab}
else
    WinActivate ahk_exe ubuntu.exe
return

^!1::
IfWinActive, ahk_exe powershell.exe
    Send !{Tab}
else
    WinActivate ahk_exe powershell.exe
return

^!t::
IfWinActive, ahk_exe mintty.exe
    Send !{Tab}
else
    WinActivate ahk_exe mintty.exe
return

^!m::
IfWinActive, ahk_exe C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
    Send !{Tab}
else
    WinActivate ahk_exe C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
return

^!w::
IfWinActive, ahk_exe C:\Users\yjpark\AppData\Local\Google\Chrome SxS\Application\chrome.exe
    Send !{Tab}
else
    WinActivate ahk_exe C:\Users\yjpark\AppData\Local\Google\Chrome SxS\Application\chrome.exe
return

^!u::
IfWinActive, ahk_exe Unity.exe
    Send !{Tab}
else
    WinActivate ahk_exe Unity.exe
return

^!a::
IfWinActive, ahk_exe atom.exe
    Send !{Tab}
else
    WinActivate ahk_exe atom.exe
return

^!v::
IfWinActive, ahk_exe devenv.exe
    Send !{Tab}
else
    WinActivate ahk_exe devenv.exe
return

^!x::
IfWinActive, ahk_exe devenv.exe
    Send !{Tab}
else
    WinActivate ahk_exe devenv.exe
return

^!s::
IfWinActive, ahk_exe ApplicationFrameHost.exe
    Send !{Tab}
else
    WinActivate ahk_exe ApplicationFrameHost.exe
return

^!i::
IfWinActive, ahk_exe idea.exe
    Send !{Tab}
else
    WinActivate ahk_exe idea.exe
return

^!h::
IfWinActive, ahk_exe zeal.exe
    Send !{Tab}
else
    WinActivate ahk_exe zeal.exe
return

^!e::
IfWinActive, ahk_exe Evernote.exe
    Send !{Tab}
else
    WinActivate ahk_exe Evernote.exe
return

^!n::
IfWinActive, ahk_exe xmind.exe
    Send !{Tab}
else
    WinActivate ahk_exe xmind.exe
return

^!d::
IfWinActive, ahk_exe code.exe
    Send !{Tab}
else
    WinActivate ahk_exe code.exe
return

^!Space::
Process,close,explorer.exe
sleep, 50 ;This sleep 5000 is to let you see what actually happens. Decrease it later
run, explorer.exe
WinWait, ahk_class CabinetWClass
WinClose ;close the new explorer window
return

^Tab::
Send #{Tab}
return

^`::
IfWinActive, ahk_exe vcxsrv.exe
    Send !{Tab}
else
    WinActivate ahk_exe vcxsrv.exe
return

^!`::
IfWinActive, ahk_exe ubuntu.exe
    Send !{Tab}
else
    WinActivate ahk_exe ubuntu.exe
return

^!1::
IfWinActive, ahk_exe powershell.exe
    Send !{Tab}
else
    WinActivate ahk_exe powershell.exe
return

^!t::
IfWinActive, ahk_exe mintty.exe
    Send !{Tab}
else
    WinActivate ahk_exe mintty.exe
return

^!m::
IfWinActive, ahk_exe chrome.exe
    Send !{Tab}
else
    WinActivate ahk_exe chrome.exe
return

^!w::
IfWinActive, ahk_exe iridium.exe
    Send !{Tab}
else
    WinActivate ahk_exe iridium.exe
return

^!u::
IfWinActive, ahk_exe Unity.exe
    Send !{Tab}
else
    WinActivate ahk_exe Unity.exe
return

^!a::
IfWinActive, ahk_exe atom.exe
    Send !{Tab}
else
    WinActivate ahk_exe atom.exe
return

^!v::
IfWinActive, ahk_exe devenv.exe
    Send !{Tab}
else
    WinActivate ahk_exe devenv.exe
return

^!x::
IfWinActive, ahk_exe devenv.exe
    Send !{Tab}
else
    WinActivate ahk_exe devenv.exe
return

^!s::
IfWinActive, ahk_exe ApplicationFrameHost.exe
    Send !{Tab}
else
    WinActivate ahk_exe ApplicationFrameHost.exe
return

^!i::
IfWinActive, ahk_exe idea.exe
    Send !{Tab}
else
    WinActivate ahk_exe idea.exe
return

^!h::
IfWinActive, ahk_exe zeal.exe
    Send !{Tab}
else
    WinActivate ahk_exe zeal.exe
return

^!e::
IfWinActive, ahk_exe Evernote.exe
    Send !{Tab}
else
    WinActivate ahk_exe Evernote.exe
return

^!n::
IfWinActive, ahk_exe xmind.exe
    Send !{Tab}
else
    WinActivate ahk_exe xmind.exe
return

^!d::
IfWinActive, ahk_exe code.exe
    Send !{Tab}
else
    WinActivate ahk_exe code.exe
return

^!Space::
Process,close,explorer.exe
sleep, 50 ;This sleep 5000 is to let you see what actually happens. Decrease it later
run, explorer.exe
WinWait, ahk_class CabinetWClass
WinClose ;close the new explorer window
return


update for Win11, remove invalid settings

; Tips {{{
; #: win
; !: alt
; ^: ctrl
; +: shift
; &: and
; <: only left, >: only right
; *: wildecard
; ~: pass through
; }}}

; Auto execute section is the region before any return/hotkey {{{
; Windows size
TMargin := 5
BMargin := 5
LMargin := 5
RMargin := 5 ; sidebar = 150px
MinSize := 0.7

; For Terminal/Vim
GroupAdd Terminal, ahk_class PuTTY
GroupAdd Terminal, ahk_class mintty ; cygwin
GroupAdd Terminal, ahk_class TMobaXtermForm
GroupAdd Terminal, ahk_class TFormDetachedTab
GroupAdd Terminal, ahk_class ConsoleWindowClass
GroupAdd Terminal, ahk_exe Hyper.exe
GroupAdd Terminal, ahk_exe powershell.exe
GroupAdd Terminal, ahk_exe vim.exe
GroupAdd TerminalVim, ahk_group Terminal
GroupAdd TerminalVim, ahk_class Vim
GroupAdd TerminalVim, ahk_class mintty
GroupAdd TerminalVim, ahk_class CASCADIA_HOSTING_WINDOW_CLASS
GroupAdd TerminalVim, ahk_exe WindowsTerminal.exe

; For browsers
GroupAdd, Browser, ahk_exe chrome.exe
GroupAdd, Browser, ahk_exe firefox.exe
GroupAdd, Browser, ahk_exe msedge.exe

; External files (Only 1 file, at last of Auto execute section"
#Include %A_LineFile%\..\submodules\vim_ahk\vim.ahk

Return
; }}}

; External files w/o Auto execute section
#Include %A_LineFile%\..\AutoCorrect.ahk

;; Basic Settings, HotKeys, Functions {{{
; Settings

#UseHook On ; Make it a bit slow, but can avoid infinitude loop
            ; Same as "$" for each hotkey
#InstallKeybdHook ; For checking key history
                  ; Use ~500kB memory?

#HotkeyInterval 1000 ; Hotkey inteval (default 2000 milliseconds).
#MaxHotkeysPerInterval 100 ; Max hotkeys perinterval (default 50).

; For HHKB
;vkFFsc079::RCtrl
;vkFFsc07b::LCtrl
; }}}

; Terminal/Vim {{{
; ESC + IME
#IfWInActive, ahk_group TerminalVim
; Use ESC as ` or ESC with long push, especially for HHKB
;Esc:: ; Just send Esc at converting.
;  if(VIM_IME_GET(A)){
;    if(VIM_IME_GetConverting(A)){
;      Send, {Esc}
;    }else{
;      VIM_IME_SET()
;    }
;  }else{
;    Send, {Esc}
;  }
;Return

^[:: ; Go to Normal mode (for vim) with IME off even at converting.
  if(VIM_IME_GetConverting(A)){
    Send, {Esc}
    Sleep 1 ; wait 1 ms (Need to stop converting)
    VIM_IME_SET()
    Send, {Esc}
  }else if(VIM_IME_GET(A)){
    VIM_IME_SET()
    Send, {Esc}
  }else{
    Send, {Esc}
  }
Return

^m::Send, ^m ; Use Ctrl-m as is

; Paste
#IfWInActive, ahk_group Terminal
!v::
  ;StringSplit, strout, clipboard, `n
  ;If(strout0>1 or InStr(clipboard, "sudo")>0){
  ;  MsgBox, 308, Clipboard, %clipboard%`n`n Do you want to paste?
  ;  IfMsgBox, No
  ;  {
  ;    Return
  ;  }
  ;}
  ;SendInput %clipboard%
  ;Return
  Sleep,200
  MouseClick, Right, 50, 50, 1
Return

#IfWInActive, ahk_class Vim
!v::Send, {Alt}ep

; Other than Terminal/Vim
#IfWInNotActive, ahk_group TerminalVim
^[::Send, {Esc}             ; Always C-[ to ESC, like vim
^d::Send, {Del}             ; Always Delete with C-d
; }}} Terminal/Vim

; Power Point {{{
#IfWInActive, ahk_class PP12FrameClass
; Subscript/Superscript
^=::Send, ^tb{Enter}
^+=::Send, ^tp{Enter}
; For JP keyboards
;^-::Send, ^tb{Enter}
;^+-::Send, ^tp{Enter}

; Fonts
^!+s::Send, ^tfsymbol{Enter}
^!+a::Send, ^tfarial{Enter}
^!+h::Send, ^tfhelvetica{Enter}
; }}} Power Point

; Word {{{
#IfWInActive, ahk_class OpusApp
^=::Send, ^tb{Enter}
^+=::Send, ^tp{Enter}
; for JP keyboards
;^-::Send, ^tb{Enter}
;^+-::Send, ^tp{Enter}
; }}} Word

; Explorer {{{
#IfWInActive, ahk_class CabinetWClass
; Next/Previous page
^i::Send, !{Right}
^o::Send, !{Left}
; }}} Explorer

; CLCL {{{
#IfWInActive, ahk_exe CLCL.exe ; does not work...
j::
  Send, {Down}
Return

k::Send, {Up}
; }}} CLCL

; Everthing {{{
#IfWinActive, ahk_class EVERYTHING
Return::
  Send, {Enter}
  Sleep, 200
  IfWinActive, ahk_class EVERYTHING
  {
    Send,{Enter}
    Sleep, 500
  }
  WinActivate, ahk_class EVERYTHING
  Sleep, 200
  Send, {Esc}
Return
; }}} Everything

; Firefox/Chrome/Edge {{{
#IfWinActive, ahk_group Browser
^WheelDown::Send, {WheelDown}
^WheelUp::Send, {WheelUp}
; }}} Firefox/Chrome/Edge

; Global Settings {{{
#if
; Basic Settings {{{

; Suspend
;Esc & Tab::
;  Suspend, Toggle
;  Return
; For Alt-Ctrl Swap (swapped by KeySwap)
; To assign ^Tab, need to add < or > to choose left or right
<^Tab::AltTab
;<+<^Tab::ShiftAltTab ; can not assigned...
;LCtrl & Tab::
;  if GetKeyState("Shift","P"){
;    Send, {ShiftAltTab}
;  }else{
;    Send, {AltTab}
;  }
;Return
;Alt & Tab::
;  if GetKeyState("Shift","P"){
;    Send, ^+{taB}
;  }else{
;    Send, ^{Tab}
;  }
;Return
!Tab::Send, ^{Tab}
!+Tab::Send, ^+{Tab}

;!m::Send, ^m
;^m::Send, !m
;>^m::Send, !m
;Ctrl & Left::Send, !{Left}
;Ctrl & Right::Send, !{Right}

; Virtual desktop
^!+h::Send, #^{Left}
^!+l::Send, #^{Right}

; Cortana
!^f::Send, #s

; CLCL
#c::Send, !c

; Other basic settings
!Space::Send, {vkF3sc029} ; IME by A-Space
^Space::Send, {vkF3sc029} ; IME by C-Space
;{vkF3sc029}               ; 変換
;{vk1Dsc07B}               ; 無変換
!^a::Send, !{Space}n       ; Minimize window
!4::Send, !{F4}           ; Close window
^4::Send, !{F4}           ; Close window
!d::Send, {Del}           ; Always Delete with A-d
;^o::Send,!{Left}          ; Go to previous page
;^i::Send,!{Right}         ; Go to nexe page
^Space::!`                ; IME

^h::Send, {BS}            ; Always BS with C-h
;^h::
;  While GetKeyState("h","p"){
;    Send {BS}
;    TrayTip,Start:,%n%,10,,
;    Sleep 50
;  }
;  return

;^j::Send,{Enter}      ; C-j to Enter

; For HHKB
; ESC to ` like normal keyboard (ESC is placed on the left of 1 in HHKB)
Esc::
  KeyWait, Esc, T0.3
  If (ErrorLevel){
    Send, {Esc}
    KeyWait, Esc
  }else{
    Send, ``
    KeyWait, Esc
  }
Return

; Disable alt to menu
Alt::KeyWait, Alt
LAlt Up::Return
; }}} Basic Settings

; Cursor, Mouse, Window move/size {{{
; Cursor {{{
!^h::Send, {Left}
!^j::Send, {Down}
!^k::Send, {Up}
!^l::Send, {Right}
; }}} Cursor

; Mouse {{{
; Mouse Move
^+h::MouseMove, -10, 0, 0, R
^+j::MouseMove, 0, 10, 0, R
^+k::MouseMove, 0, -10, 0, R
^+l::MouseMove, 10, 0, 0, R

; Click
^+n::MouseClick, Left
^+p::MouseClick, Right
; Right click on current window

; Mouse wheel
!^m::MouseClick, WheelDown, , , 2
!^,::MouseClick, WheelUp, , , 2
; }}} Mouse

; Window move {{{

; Move a little
^+y::
  WinGetPos, X, Y, , , A ;A for Active Window
  WinMove, A, ,X-20, Y,
Return

^+u::
  WinGetPos, X, Y, , , A
  WinMove, A, , X, Y+20
Return

^+i::
  WinGetPos, X, Y, , , A
  WinMove, A, , X, Y-20
Return

^+o::
  WinGetPos, X, Y, , , A
  WinMove, A, , X+20, Y
Return

; Move to a different screen
!^+y:: Send, #^{Left}
!^+u:: Send, #^{Down}
!^+i:: Send, #^{Up}
!^+o:: Send, #^{Right}

; }}} Window move

; Window size {{{

; Almost full
^!Enter::
!+Enter::
  ;WinGetPos, X, Y, W, H, Program Manager ; Full Desktop
  ;Msgbox, Pos At %X% %Y% %W% %H%
  SysGet, MWA, MonitorWorkArea ; w/o Taskbar
  ;Msgbox, %MWALeft% %MWATop% %MWARight% %MWABottom%
  WinMove, A, , MWALeft+LMargin, MWATop+TMargin
    , MWARight-MWALeft-LMargin-RMargin
    , MWABottom-MWATop-TMargin-BMargin
Return

; Minsize
^!+Enter::
  SysGet, MWA, MonitorWorkArea ; w/o Taskbar
  WinMove, A, , MWALeft+LMargin, MWATop+TMargin
    , (MWARight-MWALeft-LMargin-RMargin)*Minsize
    , (MWABottom-MWATop-TMargin-BMargin)*Minsize
Return

; Half size
!+h::
  SysGet, MWA, MonitorWorkArea ; w/o Taskbar
  WinMove, A, , MWALeft+LMargin, MWATop+TMargin
    , (MWARight-MWALeft-LMargin-RMargin)*0.5
    , MWABottom-MWATop-TMargin-BMargin
Return

!+j::
  SysGet, MWA, MonitorWorkArea ; w/o Taskbar
  WinMove, A, , MWALeft+LMargin
    , MWATop+(MWABottom-MWATop)*0.5
    , MWARight-MWALeft-LMargin-RMargin
    , (MWABottom-MWATop-TMargin-BMargin)*0.5
Return

!+k::
  SysGet, MWA, MonitorWorkArea ; w/o Taskbar
  WinMove, A, , MWALeft+LMargin, MWATop+TMargin
    , MWARight-MWALeft-LMargin-RMargin
    , (MWABottom-MWATop-TMargin-BMargin)*0.5
Return

!+l::
  SysGet, MWA, MonitorWorkArea ; w/o Taskbar
  WinMove, A, , MWALeft+(MWARight-MWALeft)*0.5
    , MWATop+TMargin
    , (MWARight-MWALeft-LMargin-RMargin)*0.5
    , MWABottom-MWATop-TMargin-BMargin
Return

; Resize
!+y::
  WinGetPos, X, Y, W, H, A
  WinMove, A, ,X, Y, W-20, H
Return

!+u::
  WinGetPos, X, Y, W, H, A
  WinMove, A, ,X, Y, W, H+20
Return

!+i::
  WinGetPos, X, Y, W, H, A
  WinMove, A, ,X, Y, W, H-20
Return

!+o::
  WinGetPos, X, Y, W, H, A
  WinMove, A, ,X, Y, W+20, H
Return

; }}} Window size
; }}} Cursor, Mouse, Window move
; }}} Global Settings

; Tips {{{
; #: win
; !: alt
; ^: ctrl
; +: shift
; &: and
; <: only left, >: only right
; *: wildecard
; ~: pass through
; }}}

; Auto execute section is the region before any return/hotkey {{{
; Windows size
TMargin := 5
BMargin := 5
LMargin := 5
RMargin := 5 ; sidebar = 150px
MinSize := 0.7

; For Terminal/Vim
GroupAdd Terminal, ahk_class PuTTY
GroupAdd Terminal, ahk_class mintty ; cygwin
GroupAdd Terminal, ahk_class TMobaXtermForm
GroupAdd Terminal, ahk_class TFormDetachedTab
GroupAdd Terminal, ahk_class ConsoleWindowClass
GroupAdd Terminal, ahk_exe powershell.exe
GroupAdd Terminal, ahk_exe vim.exe
GroupAdd TerminalVim, ahk_group Terminal
GroupAdd TerminalVim, ahk_class Vim
GroupAdd TerminalVim, ahk_class mintty
GroupAdd TerminalVim, ahk_class CASCADIA_HOSTING_WINDOW_CLASS
GroupAdd TerminalVim, ahk_exe WindowsTerminal.exe
GroupAdd TerminalVim, ahk_exe Hyper.exe

; For browsers
GroupAdd, Browser, ahk_exe chrome.exe
GroupAdd, Browser, ahk_exe firefox.exe
GroupAdd, Browser, ahk_exe ApplicationFrameHost.exe ; Edge

; Mouse Gestures
GroupAdd, MouseGesture, ahk_group Broser
GroupAdd, MouseGesture, ahk_exe explorer.exe

; External files (Only 1 file, at last of Auto execute section"
#Include %A_LineFile%\..\submodules\vim_ahk\vim.ahk

Return
; }}}

; External files w/o Auto execute section
#Include %A_LineFile%\..\AutoCorrect.ahk

;; Basic Settings, HotKeys, Functions {{{
; Settings

#UseHook On ; Make it a bit slow, but can avoid infinitude loop
            ; Same as "$" for each hotkey
#InstallKeybdHook ; For checking key history
                  ; Use ~500kB memory?

#HotkeyInterval 1000 ; Hotkey inteval (default 2000 milliseconds).
#MaxHotkeysPerInterval 100 ; Max hotkeys perinterval (default 50).

; For HHKB
;vkFFsc079::RCtrl
;vkFFsc07b::LCtrl
; }}}

; Terminal/Vim {{{
; ESC + IME
#IfWInActive, ahk_group TerminalVim
; Use ESC as ` or ESC with long push, especially for HHKB
;Esc:: ; Just send Esc at converting.
;  if(VIM_IME_GET(A)){
;    if(VIM_IME_GetConverting(A)){
;      Send, {Esc}
;    }else{
;      VIM_IME_SET()
;    }
;  }else{
;    Send, {Esc}
;  }
;Return

^[:: ; Go to Normal mode (for vim) with IME off even at converting.
  if(VIM_IME_GetConverting(A)){
    Send, {Esc}
    Sleep 1 ; wait 1 ms (Need to stop converting)
    VIM_IME_SET()
    Send, {Esc}
  }else if(VIM_IME_GET(A)){
    VIM_IME_SET()
    Send, {Esc}
  }else{
    Send, {Esc}
  }
Return

^m::Send, ^m ; Use Ctrl-m as is

; Paste
#IfWInActive, ahk_group Terminal
!v::
  ;StringSplit, strout, clipboard, `n
  ;If(strout0>1 or InStr(clipboard, "sudo")>0){
  ;  MsgBox, 308, Clipboard, %clipboard%`n`n Do you want to paste?
  ;  IfMsgBox, No
  ;  {
  ;    Return
  ;  }
  ;}
  ;SendInput %clipboard%
  ;Return
  Sleep,200
  MouseClick, Right, 50, 50, 1
Return

#IfWInActive, ahk_class Vim
!v::Send, {Alt}ep

; Other than Terminal/Vim
#IfWInNotActive, ahk_group TerminalVim
^[::Send, {Esc}             ; Always C-[ to ESC, like vim
^d::Send, {Del}             ; Always Delete with C-d
; }}} Terminal/Vim

; Power Point {{{
#IfWInActive, ahk_class PP12FrameClass
; Subscript/Superscript
^=::Send, ^tb{Enter}
^+=::Send, ^tp{Enter}
; For JP keyboards
;^-::Send, ^tb{Enter}
;^+-::Send, ^tp{Enter}

; Fonts
^!+s::Send, ^tfsymbol{Enter}
^!+a::Send, ^tfarial{Enter}
^!+h::Send, ^tfhelvetica{Enter}
; }}} Power Point

; Word {{{
#IfWInActive, ahk_class OpusApp
^=::Send, ^tb{Enter}
^+=::Send, ^tp{Enter}
; for JP keyboards
;^-::Send, ^tb{Enter}
;^+-::Send, ^tp{Enter}
; }}} Word

; Explorer {{{
#IfWInActive, ahk_class CabinetWClass
; Next/Previous page
^i::Send, !{Right}
^o::Send, !{Left}
; }}} Explorer

; CLCL {{{
;#IfWInActive, ahk_class CLCLMain
#IfWInActive, CLCL ; both window/title do not working...
j::
  Send, {Down}
Return

K::Send, {Up}
; }}} Explorer

; Everthing {{{
#IfWinActive, ahk_class EVERYTHING
Return::
  Send, {Enter}
  Sleep, 200
  IfWinActive, ahk_class EVERYTHING
  {
    Send,{Enter}
    Sleep, 500
  }
  WinActivate, ahk_class EVERYTHING
  Sleep, 200
  Send, {Esc}
Return
; }}} Everything

; Firefox/Chrome/Edge {{{
#IfWinActive, ahk_group Browser
;^WheelDown::Send, {WheelDown}
;^WheelUp::Send, {WheelUp}
^WheelDown::Return
^WheelUp::Return
; }}} Firefox/Chrome

; Mouse Gestures {{{
#IfWinActive, ahk_group MouseGesture
;LButton & RButton::Send, ^{Tab}
;RButton & LButton::Send, ^+{Tab}

; }}} Firefox/Chrome

; Global Settings {{{
#if
; Basic Settings {{{

; Suspend
;Esc & Tab::
;  Suspend, Toggle
;  Return
; For Alt-Ctrl Swap (swapped by KeySwap)
; To assign ^Tab, need to add < or > to choose left or right
<^Tab::AltTab
;<+<^Tab::ShiftAltTab ; can not assigned...
;LCtrl & Tab::
;  if GetKeyState("Shift","P"){
;    Send, {ShiftAltTab}
;  }else{
;    Send, {AltTab}
;  }
;Return
;Alt & Tab::
;  if GetKeyState("Shift","P"){
;    Send, ^+{taB}
;  }else{
;    Send, ^{Tab}
;  }
;Return
!Tab::Send, ^{Tab}
!+Tab::Send, ^+{Tab}

;!m::Send, ^m
;^m::Send, !m
;>^m::Send, !m
;Ctrl & Left::Send, !{Left}
;Ctrl & Right::Send, !{Right}

; Virtual desktop
^!+h::Send, #^{Left}
^!+l::Send, #^{Right}

; Cortana
!^f::Send, #s

; CLCL
#c::Send, !c

; Other basic settings
!Space::Send, {vkF3sc029} ; IME by A-Space
^Space::Send, {vkF3sc029} ; IME by C-Space
;{vkF3sc029}               ; 変換
;{vk1Dsc07B}               ; 無変換
!^a::Send, !{Space}n       ; Minimize window
!4::Send, !{F4}           ; Close window
^4::Send, !{F4}           ; Close window
!d::Send, {Del}           ; Always Delete with A-d
;^o::Send,!{Left}          ; Go to previous page
;^i::Send,!{Right}         ; Go to nexe page
^Space::!`                ; IME

^h::Send, {BS}            ; Always BS with C-h
;^h::
;  While GetKeyState("h","p"){
;    Send {BS}
;    TrayTip,Start:,%n%,10,,
;    Sleep 50
;  }
;  return

;^j::Send,{Enter}      ; C-j to Enter

; For HHKB
; ESC to ` like normal keyboard (ESC is placed on the left of 1 in HHKB)
Esc::
  KeyWait, Esc, T0.3
  If (ErrorLevel){
    Send, {Esc}
    KeyWait, Esc
  }else{
    Send, ``
    KeyWait, Esc
  }
Return

; Disable alt to menu
Alt::KeyWait, Alt
LAlt Up::Return
; }}} Basic Settings

; Cursor, Mouse, Window move/size {{{
; Cursor {{{
!^h::Send, {Left}
!^j::Send, {Down}
!^k::Send, {Up}
!^l::Send, {Right}
; }}} Cursor

; Mouse {{{
; Mouse Move
^+h::MouseMove, -10, 0, 0, R
^+j::MouseMove, 0, 10, 0, R
^+k::MouseMove, 0, -10, 0, R
^+l::MouseMove, 10, 0, 0, R

; Click
^+n::MouseClick, Left
^+p::MouseClick, Right
; Right click on current window

; Mouse wheel
!^m::MouseClick, WheelDown, , , 2
!^,::MouseClick, WheelUp, , , 2
; }}} Mouse

; Window move {{{

; Move a little
^+y::
  WinGetPos, X, Y, , , A ;A for Active Window
  WinMove, A, ,X-20, Y,
Return

^+u::
  WinGetPos, X, Y, , , A
  WinMove, A, , X, Y+20
Return

^+i::
  WinGetPos, X, Y, , , A
  WinMove, A, , X, Y-20
Return

^+o::
  WinGetPos, X, Y, , , A
  WinMove, A, , X+20, Y
Return

; Move to a different screen
!^+y:: Send, #+{Left}
!^+u:: Send, #+{Down}
!^+i:: Send, #+{Up}
!^+o:: Send, #+{Right}

; }}} Window move

; Window size {{{

; Almost full
^!Enter::
!+Enter::
  ;WinGetPos, X, Y, W, H, Program Manager ; Full Desktop
  ;Msgbox, Pos At %X% %Y% %W% %H%
  SysGet, MWA, MonitorWorkArea ; w/o Taskbar
  ;Msgbox, %MWALeft% %MWATop% %MWARight% %MWABottom%
  WinMove, A, , MWALeft+LMargin, MWATop+TMargin
    , MWARight-MWALeft-LMargin-RMargin
    , MWABottom-MWATop-TMargin-BMargin
Return

; Minsize
^!+Enter::
  SysGet, MWA, MonitorWorkArea ; w/o Taskbar
  WinMove, A, , MWALeft+LMargin, MWATop+TMargin
    , (MWARight-MWALeft-LMargin-RMargin)*Minsize
    , (MWABottom-MWATop-TMargin-BMargin)*Minsize
Return

; Half size
!+h::
  SysGet, MWA, MonitorWorkArea ; w/o Taskbar
  WinMove, A, , MWALeft+LMargin, MWATop+TMargin
    , (MWARight-MWALeft-LMargin-RMargin)*0.5
    , MWABottom-MWATop-TMargin-BMargin
Return

!+j::
  SysGet, MWA, MonitorWorkArea ; w/o Taskbar
  WinMove, A, , MWALeft+LMargin
    , MWATop+(MWABottom-MWATop)*0.5
    , MWARight-MWALeft-LMargin-RMargin
    , (MWABottom-MWATop-TMargin-BMargin)*0.5
Return

!+k::
  SysGet, MWA, MonitorWorkArea ; w/o Taskbar
  WinMove, A, , MWALeft+LMargin, MWATop+TMargin
    , MWARight-MWALeft-LMargin-RMargin
    , (MWABottom-MWATop-TMargin-BMargin)*0.5
Return

!+l::
  SysGet, MWA, MonitorWorkArea ; w/o Taskbar
  WinMove, A, , MWALeft+(MWARight-MWALeft)*0.5
    , MWATop+TMargin
    , (MWARight-MWALeft-LMargin-RMargin)*0.5
    , MWABottom-MWATop-TMargin-BMargin
Return

; Resize
!+y::
  WinGetPos, X, Y, W, H, A
  WinMove, A, ,X, Y, W-20, H
Return

!+u::
  WinGetPos, X, Y, W, H, A
  WinMove, A, ,X, Y, W, H+20
Return

!+i::
  WinGetPos, X, Y, W, H, A
  WinMove, A, ,X, Y, W, H-20
Return

!+o::
  WinGetPos, X, Y, W, H, A
  WinMove, A, ,X, Y, W+20, H
Return

; }}} Window size
; }}} Cursor, Mouse, Window move
; }}} Global Settings


Add OpenContextMenu

Add OpenContextMenu

#NoEnv
#SingleInstance, Force
#NoTrayIcon

FileEncoding, utf-8
SendMode Input
SetWorkingDir %A_ScriptDir%

; 自动生成的命令文件
global g_SearchFileList := A_ScriptDir . "\Conf\SearchFileList.txt"
; 配置文件
global g_ConfFile := A_ScriptDir . "\Conf\RunZ.ini"
; 自动写入的配置文件
global g_AutoConfFile := A_ScriptDir . "\Conf\RunZ.auto.ini"

if !FileExist(g_ConfFile)
{
    FileCopy, %g_ConfFile%.help.txt, %g_ConfFile%
}

if (FileExist(g_AutoConfFile ".EasyIni.bak"))
{
    MsgBox, % "发现上次写入配置的备份文件：`n"
        . g_AutoConfFile . ".EasyIni.bak"
        . "`n确定则将其恢复，否则请手动检查文件内容再继续"
    FileMove, % g_AutoConfFile ".EasyIni.bak", % g_AutoConfFile
}
else if (!FileExist(g_AutoConfFile))
{
    FileAppend, % "; 此文件由 RunZ 自动写入，如需手动修改请先关闭 RunZ ！`n`n[Auto]`n[Rank]`n[History]" , % g_AutoConfFile
}

global g_Conf := class_EasyINI(g_ConfFile)
global g_AutoConf := class_EasyINI(g_AutoConfFile)

; 当前输入命令的参数，数组，为了方便没有添加 g_ 前缀
global Arg
; 不能是 RunZ.ahk 的子串，否则按键绑定会有问题
global g_WindowName := "RunZ    "
; 所有命令
global g_Commands
; 当搜索无结果时使用的命令
global g_FallbackCommands
; 编辑框当前内容
global g_CurrentInput
; 当前匹配到的第一条命令
global g_CurrentCommand
; 当前匹配到的所有命令
global g_CurrentCommandList
; 是否启用 TCMatch
global g_EnableTCMatch = TCMatchOn(g_Conf.Config.TCMatchPath)
; 列表第一列的首字母或数字
global g_FirstChar := Asc(g_Conf.Gui.FirstChar)
; 在列表中显示的行数
global g_DisplayRows := g_Conf.Gui.DisplayRows
; 在列表中显示的文字列数（多出的会被截断）
global g_DisplayCols := g_Conf.Gui.DisplayCols
; 命令使用了显示框
global g_UseDisplay
; 历史命令
global g_HistoryCommands
; 运行命令时临时设置，避免因为自身退出无法运行需要提权的软件
global g_DisableAutoExit
; 当前的命令在搜索结果的行数
global g_CurrentLine
; 使用备用的命令
global g_UseFallbackCommands
global g_InputArea := "Edit1"
global g_OutputArea := "Edit3"
global g_CommandArea := "Edit5"

if (g_Conf.Gui.ShowTrayIcon)
{
    Menu, Tray, Icon
    Menu, Tray, NoStandard
    if (!g_Conf.Config.ExitIfInactivate)
    {
        Menu, Tray, Add, 显示(&S), ActivateWindow
        Menu, Tray, Default, 显示(&S)
        Menu, Tray, Click, 1
    }
    Menu, Tray, Add, 配置(&C), EditConfig
    Menu, Tray, Add, 帮助(&H), KeyHelp
    Menu, Tray, Add,
    Menu, Tray, Add, 重启(&R), RestartRunZ
    Menu, Tray, Add, 退出(&X), ExitRunZ
}

Menu, Tray, Icon, %A_ScriptDir%\RunZ.ico

if (FileExist(g_SearchFileList))
{
    LoadFiles()
}
else
{
    GoSub, ReloadFiles
}

Gui, Font, % "s" g_Conf.Gui.FontSize, % g_Conf.Gui.FontName
Gui, Add, Edit, % "gProcessInputCommand vSearchArea"
        . " w" g_Conf.Gui.WidgetWidth " h" g_Conf.Gui.EditHeight,
Gui, Add, Edit, w0 h0 ReadOnly,
Gui, Add, Edit, % "ReadOnly vDisplayArea "
        . (g_Conf.Gui.HideDisplayAreaVScroll ? "-VScroll " : "")
        . " w" g_Conf.Gui.WidgetWidth " h" g_Conf.Gui.DisplayAreaHeight
        , % SearchCommand("", true)

if (g_Conf.Gui.ShowCurrentCommand)
{
    Gui, Add, Edit, w0 h0 ReadOnly,
    Gui, Add, Edit, % "ReadOnly"
        . " w" g_Conf.Gui.WidgetWidth " h" g_Conf.Gui.EditHeight,
}

if (g_Conf.Gui.HideTitle)
{
    Gui -Caption
}

Gui, Show, , % g_WindowName

if (g_Conf.Config.WindowAlwaysOnTop)
{
    WinSet, AlwaysOnTop, On, A
}

if (g_Conf.Config.ExitIfInactivate)
{
    OnMessage(0x06, "WM_ACTIVATE")
}

Hotkey, IfWinActive, % g_WindowName
; 如果是 ~enter，有时候会响
Hotkey, enter, RunCurrentCommand

Hotkey, esc, EscFunction
Hotkey, !f4, ExitRunZ

Hotkey, tab, TabFunction
Hotkey, f1, Help
Hotkey, +f1, KeyHelp
Hotkey, f2, EditConfig
Hotkey, ^q, RestartRunZ
Hotkey, ^l, ClearInput
Hotkey, ^d, OpenCurrentFileDir
Hotkey, ^x, DeleteCurrentFile
Hotkey, ^s, ShowCurrentFile
Hotkey, ^r, ReloadFiles
Hotkey, ^h, DisplayHistoryCommands
Hotkey, ^n, IncreaseRank
Hotkey, ^p, DecreaseRank
Hotkey, ^f, NextPage
Hotkey, ^b, PrevPage
Hotkey, ^i, HomeKey
Hotkey, ^o, EndKey
Hotkey, ^j, NextCommand
Hotkey, ^k, PrevCommand
Hotkey, down, NextCommand
Hotkey, up, PrevCommand
Hotkey, rbutton, OpenContextMenu

; 剩余按键 e g j m t w

Loop, % g_DisplayRows
{
    key := Chr(g_FirstChar + A_Index - 1)
    ; lalt +
    Hotkey, !%key%, RunSelectedCommand
    ; tab +
    Hotkey, ~%key%, RunSelectedCommand
    ; shift +
    Hotkey, ~+%key%, GotoCommand
}

; 用户映射的按键

for key, label in g_Conf.Hotkey
{
    if (label != "Default")
    {
        Hotkey, %key%, %label%
    }
    else
    {
        Hotkey, %key%, Off
    }
}

Hotkey, IfWinActive

for key, label in g_Conf.GlobalHotkey
{
    if (label != "Default")
    {
        Hotkey, %key%, %label%
    }
    else
    {
        Hotkey, %key%, Off
    }
}

if (g_Conf.Config.SaveInputText && g_AutoConf.Auto.InputText != "")
{
    Send, % g_AutoConf.Auto.InputText
}

if (g_Conf.Config.SaveHistory)
{
    g_HistoryCommands := Object()
    LoadHistoryCommands()
}

return

Default:
return

RestartRunZ:
    SaveAutoConf()
    Reload
return

Test:
    MsgBox, 测试
return

HomeKey:
    Send, {home}
return

EndKey:
    Send, {End}
return

NextPage:
    ControlFocus, %g_OutputArea%
    Send, {pgdn}
return

PrevPage:
    ControlFocus, %g_OutputArea%
    Send, {pgup}
return

ActivateWindow:
    Gui, Show, , % g_WindowName
return

OpenContextMenu:
    currentCommandText := "运行当前命令："
    if (!g_CurrentLine > 0)
    {
        currentCommandText .= Chr(g_FirstChar)
    }
    else
    {
        currentCommandText .= Chr(g_FirstChar + g_CurrentLine - 1)
    }
    Menu, ContextMenu, Add, %currentCommandText%, RunCurrentCommand
    Menu, ContextMenu, Add, 显示帮助(&A), Help
    Menu, ContextMenu, Add, 编辑配置(&E), EditConfig
    Menu, ContextMenu, Add, 重载文件(&S), ReloadFiles
    Menu, ContextMenu, Add, 显示历史(&H), DisplayHistoryCommands
    Menu, ContextMenu, Add, 重新启动(&R), RestartRunZ
    Menu, ContextMenu, Add, 退出程序(&X), ExitRunZ
    Menu, ContextMenu, Show
    Menu, ContextMenu, DeleteAll
return

TabFunction:
    ControlGetFocus, ctrl,
    if (ctrl == g_InputArea)
    {
        ; 定位到一个隐藏编辑框
        ControlFocus, Edit2
    }
    else
    {
        ControlFocus, %g_InputArea%
    }
return

EscFunction:
    ; 如果是后台运行模式，只关闭窗口，不退出程序
    if (g_Conf.Config.RunInBackground)
    {
        Gui, Hide
    }
    else
    {
        GoSub, ExitRunZ
    }
return

NextCommand:
    ChangeCommand(1)
return

PrevCommand:
    ChangeCommand(-1)
return

GotoCommand:
    ControlGetFocus, ctrl,
    if (ctrl == g_InputArea)
    {
        return
    }

    index := Asc(SubStr(A_ThisHotkey, 0, 1)) - g_FirstChar + 1

    if (g_CurrentCommandList[index] != "")
    {
        ChangeCommand(index - 1, true)
    }
return

ChangeCommand(step, resetCurrentLine = false)
{
    ControlGetText, g_CurrentInput, %g_InputArea%

    if (resetCurrentLine || SubStr(g_CurrentInput, 1, 1) != "@")
    {
        g_CurrentLine := 1
    }

    row := g_CurrentCommandList.Length()
    if (row > g_DisplayRows)
    {
        row := g_DisplayRows
    }

    g_CurrentLine := Mod(g_CurrentLine + step, row)
    if (g_CurrentLine == 0)
    {
        g_CurrentLine := row
    }

    ; 重置当前命令
    g_CurrentCommand := g_CurrentCommandList[g_CurrentLine]

    ; 修改输入框内容
    currentChar := Chr(g_FirstChar + g_CurrentLine - 1)
    newInput := "@" currentChar " "

    if (g_UseFallbackCommands)
    {
        if (SubStr(g_CurrentInput, 1, 1) == "@")
        {
            newInput .= SubStr(g_CurrentInput, 4)
        }
        else
        {
            newInput .= g_CurrentInput
        }
    }

    ControlGetText, result, %g_OutputArea%
    result := StrReplace(result, ">| ", " | ")
    if (currentChar == Chr(g_FirstChar))
    {
        result := currentChar ">" SubStr(result, 3)
    }
    else
    {
        result := StrReplace(result, "`n" currentChar " | ", "`n" currentChar ">| ")
    }

    DisplaySearchResult(result)

    ControlSetText, %g_InputArea%, %newInput%, %g_WindowName%
    Send, {end}
}

GuiClose()
{
    if (!g_Conf.Config.RunInBackground)
    {
        GoSub, ExitRunZ
    }
}

SaveAutoConf()
{
    if (g_Conf.Config.SaveInputText)
    {
        g_AutoConf.DeleteKey("Auto", "InputText")
        g_AutoConf.AddKey("Auto", "InputText", g_CurrentInput)
    }

    if (g_Conf.Config.SaveHistory)
    {
        g_AutoConf.DeleteSection("History")
        g_AutoConf.AddSection("History")

        for index, element in g_HistoryCommands
        {
            if (element != "")
            {
                g_AutoConf.AddKey("History", index, element)
            }
        }
    }

    Loop
    {
        g_AutoConf.Save()

        if (!FileExist(g_AutoConfFile))
        {
            MsgBox, 配置文件 %g_AutoConfFile% 写入后丢失，请检查磁盘并点确定来重试
        }
        else
        {
            break
        }
    }
}

ExitRunZ:
    SaveAutoConf()
    ExitApp
return

GenerateSearchFileList()
{
    FileDelete, %g_SearchFileList%

    searchFileType := g_Conf.Config.SearchFileType

    for dirIndex, dir in StrSplit(g_Conf.Config.SearchFileDir, " | ")
    {
        if (InStr(dir, "A_") == 1)
        {
            searchPath := %dir%
        }
        else
        {
            searchPath := dir
        }

        for extIndex, ext in StrSplit(searchFileType, " | ")
        {
            Loop, Files, %searchPath%\%ext%, R
            {
                if (g_Conf.Config.SearchFileExclude != ""
                        && RegexMatch(A_LoopFileLongPath, g_Conf.Config.SearchFileExclude))
                {
                    continue
                }
                FileAppend, file | %A_LoopFileLongPath%`n, %g_SearchFileList%,
            }
        }
    }
}

ReloadFiles:
    GenerateSearchFileList()

    LoadFiles()
return

ProcessInputCommand:
    ControlGetText, g_CurrentInput, %g_InputArea%

    SearchCommand(g_CurrentInput)
return

SearchCommand(command = "", firstRun = false)
{
    result := ""
    ; 供去重使用
    fullResult := ""
    commandPrefix := SubStr(command, 1, 1)

    if (commandPrefix == ";" || commandPrefix == ":")
    {
        if (commandPrefix == ";")
        {
            g_CurrentCommand := g_FallbackCommands[1]
        }
        else if (commandPrefix == ":")
        {
            g_CurrentCommand := g_FallbackCommands[2]
        }

        g_CurrentCommandList := Object()
        g_CurrentCommandList.Push(g_CurrentCommand)
        result .= Chr(g_FirstChar) ">| " . g_CurrentCommand
        DisplaySearchResult(result)
        return result
    }
    else if (commandPrefix == "@")
    {
        ; 搜索结果被锁定，直接退出
        return
    }
    else if (InStr(command, " ") && g_CurrentCommand != "")
    {
        ; 输入包含空格时锁定搜索结果
        return
    }

    g_CurrentCommandList := Object()

    order := g_FirstChar

    for index, element in g_Commands
    {
        if (InStr(fullResult, element "`n"))
        {
            continue
        }

        splitedElement := StrSplit(element, " | ")

        if (splitedElement[1] == "file")
        {
            SplitPath, % splitedElement[2], , fileDir, , fileNameNoExt

            ; 只搜索和展示不带扩展名的文件名
            elementToSearch := fileNameNoExt
            elementToShow := "file | " . fileNameNoExt

            if (splitedElement.Length() >= 3)
            {
                elementToSearch .= " " . splitedElement[3]
                elementToShow .= "（" . splitedElement[3] . "）"
            }

            elementToShow := SubStr(elementToShow, 1, g_DisplayCols)

            if (g_Conf.Config.SearchFullPath)
            {
                ; TCMatch 在搜索路径时只搜索文件名，强行将 \ 转成空格
                elementToSearch := StrReplace(fileDir, "\", " ") . " " . elementToSearch
            }
        }
        else
        {
            elementToShow := SubStr(element, 1, g_DisplayCols)
            elementToSearch := splitedElement[2]

            if (splitedElement.Length() >= 3)
            {
                elementToSearch .= " " . splitedElement[3]
            }
        }

        if (command == "" || MatchCommand(elementToSearch, command))
        {
            fullResult .= element "`n"
            g_CurrentCommandList.Push(element)

            if (order == g_FirstChar)
            {
                g_CurrentCommand := element
                result .= Chr(order++) . ">| " . elementToShow
            }
            else
            {
                result .= "`n" Chr(order++) . " | " . elementToShow
            }

            if (order - g_FirstChar >= g_DisplayRows)
            {
                break
            }
            ; 第一次运行只加载 function 类型
            if (firstRun && (order - g_FirstChar >= g_DisplayRows - 4))
            {
                result .= "`n`n现有 " g_Commands.Length() " 条命令。"
                result .= "`n`n键入内容 搜索，回车 执行当前命令，Alt + 字母 执行，F1 帮助，Esc 退出。"

                break
            }
        }
    }

    if (result == "")
    {
        g_UseFallbackCommands := true
        g_CurrentCommand := g_FallbackCommands[1]
        g_CurrentCommandList := g_FallbackCommands

        for index, element in g_FallbackCommands
        {
            if (index == 1)
            {
                result .= Chr(g_FirstChar - 1 + index++) . ">| " . element
            }
            else
            {
                result .= "`n"
                result .= Chr(g_FirstChar - 1 + index++) . " | " . element
            }
        }
    }
    else
    {
        g_UseFallbackCommands := false
    }

    result := StrReplace(result, "file | ", "文件 | ")
    result := StrReplace(result, "function | ", "功能 | ")
    result := StrReplace(result, "cmd | ", "命令 | ")

    DisplaySearchResult(result)
    return result
}

DisplaySearchResult(result)
{
    DisplayText(result)

    if (g_CurrentCommandList.Length() == 1 && g_Conf.Config.RunIfOnlyOne)
    {
        RunCommand(g_CurrentCommand)
    }

    if (g_Conf.Gui.ShowCurrentCommand)
    {
        commandToShow := SubStr(g_CurrentCommand, InStr(g_CurrentCommand, " | ") + 3)
        ControlSetText, %g_CommandArea%, %commandToShow%, %g_WindowName%
    }
}

ClearInput:
    ControlSetText, %g_InputArea%, , %g_WindowName%
    ControlFocus, %g_InputArea%
return

RunCurrentCommand:
    if (GetInputState() == 1)
    {
        Send, {enter}
    }

    if (g_CurrentInput != "")
    {
        RunCommand(g_CurrentCommand)
    }
return

ParseArg:
    commandPrefix := SubStr(g_CurrentInput, 1, 1)

    if (commandPrefix == ";" || commandPrefix == ":")
    {
        Arg := SubStr(g_CurrentInput, 2)
        return
    }
    else if (commandPrefix == "@")
    {
        ; 处理调整过顺序的命令
        Arg := SubStr(g_CurrentInput, 4)
        return
    }

    ; 用空格来判断参数
    if (InStr(g_CurrentInput, " ") && !g_UseFallbackCommands)
    {
        Arg := SubStr(g_CurrentInput, InStr(g_CurrentInput, " ") + 1)
    }
    else
    {
        Arg := g_CurrentInput
    }
return

MatchCommand(Haystack, Needle)
{
    if (g_EnableTCMatch)
    {
        return TCMatch(Haystack, Needle)
    }

    return InStr(Haystack, Needle)
}

RunCommand(originCmd)
{
    GoSub, ParseArg

    g_UseDisplay := false
    g_DisableAutoExit := true

    splitedOriginCmd := StrSplit(originCmd, " | ")
    ; 去掉括号内的注释
    cmd := StrSplit(splitedOriginCmd[2], "（")[1]

    if (splitedOriginCmd[1] == "file")
    {
        if (InStr(cmd, ".lnk"))
        {
            ; 处理 32 位 ahk 运行不了某些 64 位系统 .lnk 的问题
            FileGetShortcut, %cmd%, filePath
            if (!FileExist(filePath))
            {
                filePath := StrReplace(filePath, "C:\Program Files (x86)", "C:\Program Files")
                if (FileExist(filePath))
                {
                    cmd := filePath
                }
            }
        }

        Run, %cmd%
    }
    else if (splitedOriginCmd[1] == "function")
    {
        if (splitedOriginCmd.Length() >= 3)
        {
            Arg := splitedOriginCmd[3]
        }

        if (IsLabel(cmd))
        {
            GoSub, %cmd%
        }
    }
    else if (splitedOriginCmd[1] == "cmd")
    {
        RunWithCmd(cmd)
    }

    if (g_Conf.Config.SaveHistory && cmd != "DisplayHistoryCommands")
    {
        if (splitedOriginCmd.Length() == 2 && Arg != "")
        {
            g_HistoryCommands.InsertAt(1, originCmd " | " Arg)
        }
        else if (originCmd != "")
        {
            g_HistoryCommands.InsertAt(1, originCmd)
        }

        if (g_HistoryCommands.Length() > g_Conf.Config.HistorySize)
        {
            g_HistoryCommands.Pop()
        }
    }

    if (g_Conf.Config.AutoRank)
    {
        IncreaseRank(originCmd)
    }

    g_DisableAutoExit := false

    if (g_Conf.Config.RunOnce && !g_UseDisplay)
    {
        GoSub, EscFunction
    }
}

IncreaseRank(cmd, show = false, inc := 1)
{
    splitedCmd := StrSplit(cmd, " | ")

    if (splitedCmd.Length() >= 3 && splitedCmd[1] == "function")
    {
        ; 去掉参数
        cmd := splitedCmd[1]  " | " splitedCmd[2]
    }

    cmdRank := g_AutoConf.GetValue("Rank", cmd)
    if cmdRank is integer
    {
        g_AutoConf.DeleteKey("Rank", cmd)
        cmdRank += inc
    }
    else
    {
        cmdRank := inc
    }

    if (cmdRank > 0 && cmd != "")
    {
        g_AutoConf.AddKey("Rank", cmd, cmdRank)
    }
    else
    {
        cmdRank := 0
    }

    if (show)
    {
        ToolTip, 调整 %cmd% 的权重到 %cmdRank%
        SetTimer, RemoveToolTip, 800
    }
}

; 比较耗时，必要时才使用，也可以手动编辑 RunZ.auto.ini
CleanupRank:
    ; 先把 g_Commands 里的 Rank 信息清掉
    LoadFiles(false)

    for command, rank in g_AutoConf.Rank
    {
        cleanup := true
        for index, element in g_Commands
        {
            if (InStr(element, command) == 1)
            {
                cleanup := false
                break
            }
        }
        if (cleanup)
        {
            g_AutoConf.DeleteKey("Rank", command)
        }
    }

    Loop
    {
        g_AutoConf.Save()

        if (!FileExist(g_AutoConfFile))
        {
            MsgBox, 配置文件 %g_AutoConfFile% 写入后丢失，请检查磁盘并点确定来重试
        }
        else
        {
            break
        }
    }

    LoadFiles()
return

RunSelectedCommand:
    if (SubStr(A_ThisHotkey, 1, 1) == "~")
    {
        ControlGetFocus, ctrl,
        if (ctrl == g_InputArea)
        {
            return
        }
    }

    index := Asc(SubStr(A_ThisHotkey, 0, 1)) - g_FirstChar + 1

    RunCommand(g_CurrentCommandList[index])
return

IncreaseRank:
    if (g_CurrentCommand != "")
    {
        IncreaseRank(g_CurrentCommand, true)
        LoadFiles()
    }
return

DecreaseRank:
    if (g_CurrentCommand != "")
    {
        IncreaseRank(g_CurrentCommand, true, -1)
        LoadFiles()
    }
return

LoadFiles(loadRank := true)
{
    g_Commands := Object()
    g_FallbackCommands := Object()

    if (loadRank)
    {
        rankString := ""
        for command, rank in g_AutoConf.Rank
        {
            if (StrLen(command) > 0)
            {
                rankString .= rank "`t" command "`n"
            }
        }

        if (rankString != "")
        {
            Sort, rankString, R N

            Loop, Parse, rankString, `n
            {
                if (A_LoopField == "")
                {
                    continue
                }

                g_Commands.Push(StrSplit(A_loopField, "`t")[2])
            }
        }
    }

    for key, value in g_Conf.Command
    {
        if (value != "")
        {
            g_Commands.Push(key . "（" . value "）")
        }
        else
        {
            g_Commands.Push(key)
        }
    }

    if (FileExist(A_ScriptDir "\Conf\UserFunctions.ahk"))
    {
        userFunctionLabel := "UserFunctions"
        if (IsLabel(userFunctionLabel))
        {
            GoSub, %userFunctionLabel%
        }
        else
        {
            MsgBox, 未在 %A_ScriptDir%\Conf\UserFunctions.ahk 中发现 %userFunctionLabel% 标签，请修改！
        }
    }

    GoSub, Functions

    Loop, Read, %g_SearchFileList%
    {
        g_Commands.Push(A_LoopReadLine)
    }

    if (g_Conf.Config.LoadControlPanelFunctions)
    {
        Loop, Read, %A_ScriptDir%\Core\ControlPanelFunctions.txt
        {
            g_Commands.Push(A_LoopReadLine)
        }
    }
}

DisplayText(text)
{
    textToDisplay := StrReplace(text, "`n", "`r`n")
    ControlSetText, %g_OutputArea%, %textToDisplay%, %g_WindowName%
}

DisplayResult(result)
{
    DisplayText(result)
    g_UseDisplay := true
}

LoadHistoryCommands()
{
    for key, value in g_AutoConf.History
    {
        if (StrLen(value) > 0)
        {
            g_HistoryCommands.Push(value)
        }
    }
}

DisplayHistoryCommands:
    result := ""
    g_CurrentCommandList := Object()
    g_CurrentLine := 1

    for index, element in g_HistoryCommands
    {
        if (index == 1)
        {
            result .= SubStr(Chr(g_FirstChar + index - 1) . ">| " . element, 1, g_DisplayCols) "`n"
            g_CurrentCommand := element
        }
        else
        {
            result .= SubStr(Chr(g_FirstChar + index - 1) . " | " . element, 1, g_DisplayCols) "`n"
        }

        g_CurrentCommandList.Push(element)
    }

    result := StrReplace(result, "file | ", "文件 | ")
    result := StrReplace(result, "function | ", "功能 | ")
    result := StrReplace(result, "cmd | ", "命令 | ")

    DisplayResult(result)
return

@(label, info, fallback = false, key = "")
{
    if (!IsLabel(label))
    {
        MsgBox, 未找到 %label% 标签，请检查 %A_ScriptDir%\Conf\UserFunctions.ahk 文件格式！
        return
    }

    g_Commands.Push("function | " . label . "（" . info . "）")
    if (fallback)
    {
        g_FallbackCommands.Push("function | " . label . "（" . info . "）")
    }

    if (key != "")
    {
        Hotkey, %key%, %label%
    }
}

RunAndGetOutput(command)
{
    tempFileName := "RunZ.stdout.log"
    fullCommand = bash -c "%command% &> %tempFileName%"

    if (!FileExist("c:\msys64\usr\bin\bash.exe"))
    {
        fullCommand = %ComSpec% /C "%command% > %tempFileName%"
    }

    RunWait, %fullCommand%, %A_Temp%, Hide
    FileRead, result, %A_Temp%\%tempFileName%
    FileDelete, %A_Temp%\%tempFileName%
    return result
}

RunWithCmd(command)
{
    if (FileExist("c:\msys64\usr\bin\mintty.exe"))
    {
        Run, % "mintty -e sh -c '" command "; read'"
    }
    else
    {
        Run, % ComSpec " /C " command " & pause"
    }
}

OpenPath(filePath)
{
    if (!FileExist(filePath))
    {
        return
    }

    if (FileExist(g_Conf.Config.TCPath))
    {
        TCPath := g_Conf.Config.TCPath
        Run, %TCPath% /O /A /L="%filePath%"
    }
    else
    {
        SplitPath, filePath, , fileDir, ,
        Run, explorer "%fileDir%"
    }
}

GetAllFunctions()
{
    result := ""

    for index, element in g_Commands
    {
        if (InStr(element, "function | ") == 1 and !InStr(result, element "`n"))
        {
            result .= element "`n"
        }
    }

    result := StrReplace(result, "function | ", "功能 | ")

    return result
}

OpenCurrentFileDir:
    filePath := StrSplit(g_CurrentCommand, " | ")[2]
    OpenPath(filePath)
return

DeleteCurrentFile:
    filePath := StrSplit(g_CurrentCommand, " | ")[2]

    if (!FileExist(filePath))
    {
        return
    }

    FileRecycle, % filePath
    GoSub, ReloadFiles
return

ShowCurrentFile:
    clipboard := StrSplit(g_CurrentCommand, " | ")[2]
    ToolTip, % clipboard
    SetTimer, RemoveToolTip, 800
return

RemoveToolTip:
    ToolTip
    SetTimer, RemoveToolTip, Off
return

WM_ACTIVATE(wParam, lParam)
{
    if (g_DisableAutoExit)
    {
        return
    }

    if (wParam >= 1) ; 窗口激活
    {
        return
    }
    else if (wParam <= 0) ; 窗口非激活
    {
        SetTimer, ToExit, 50
    }
}

ToExit:
    if (!WinExist("RunZ.ahk"))
    {
        GoSub, EscFunction
    }

    SetTimer, ToExit, Off
return

KeyHelpText()
{
    return ""
    . "Win + j 显示窗口`n"
    . "键入内容 搜索，回车 执行，Alt + 字母 执行，Esc 退出`n"
    . "按 Tab 后再按 字母或数字 也可执行字母对应功能`n"
    . "按 Tab 后 Shift + 字母或数字 定位到对应功能`n"
    . "Ctrl + j 移动到下一条命令`n"
    . "Ctrl + k 移动到上一条命令`n"
    . "Ctrl + f 翻到下一页`n"
    . "Ctrl + b 翻到上一页`n"
    . "Win  + j 激活窗口`n"
    . "Ctrl + h 显示历史记录`n"
    . "Ctrl + n 可增加当前功能的权重`n"
    . "Ctrl + p 可减少当前功能的权重`n"
    . "Ctrl + l 清除编辑框内容`n"
    . "Ctrl + r 重新创建待搜索文件列表`n"
    . "Ctrl + q 重启`n"
    . "Ctrl + d 用 TC 打开第一个文件所在目录`n"
    . "Ctrl + s 显示并复制当前文件的完整路径`n"
    . "Ctrl + x 删除当前文件`n"
    . "Ctrl + i 移动光标当行首`n"
    . "Ctrl + o 移动光标当行尾`n"
    . "F2       编辑配置文件`n`n"
}

UrlDownloadToString(url)
{
    static whr := ComObjCreate("WinHttp.WinHttpRequest.5.1")
    whr.Open("GET", url, true)
    whr.Send()
    whr.WaitForResponse()
    return whr.ResponseText
}

; 修改自万年书妖的 Candy 里的 SksSub_UrlEncode 函数，用于转换编码。感谢！
UrlEncode(url, enc = "UTF-8")
{
    enc := trim(enc)
    If enc=
        return url
    formatInteger := A_FormatInteger
    SetFormat, IntegerFast, H
    VarSetCapacity(buff, StrPut(url, enc))
    Loop % StrPut(url, &buff, enc) - 1
    {
        byte := NumGet(buff, A_Index-1, "UChar")
        encoded .= byte > 127 or byte <33 ? "%" Substr(byte, 3) : Chr(byte)
    }
    SetFormat, IntegerFast, %formatInteger%
    return encoded
}

; 0：英文 1：中文
GetInputState(WinTitle = "A")
{
    ControlGet, hwnd, HWND, , , %WinTitle%
    if (A_Cursor = "IBeam")
        return 1
    if (WinActive(WinTitle))
    {
        ptrSize := !A_PtrSize ? 4 : A_PtrSize
        VarSetCapacity(stGTI, cbSize := 4 + 4 + (PtrSize * 6) + 16, 0)
        NumPut(cbSize, stGTI, 0, "UInt")   ;   DWORD   cbSize;
        hwnd := DllCall("GetGUIThreadInfo", Uint, 0, Uint, &stGTI)
                         ? NumGet(stGTI, 8 + PtrSize, "UInt") : hwnd
    }
    return DllCall("SendMessage"
        , UInt, DllCall("imm32\ImmGetDefaultIMEWnd", Uint, hwnd)
        , UInt, 0x0283  ;Message : WM_IME_CONTROL
        , Int, 0x0005  ;wParam  : IMC_GETOPENSTATUS
        , Int, 0)      ;lParam  : 0
}

#include %A_ScriptDir%\Lib\EasyIni.ahk
#include %A_ScriptDir%\Lib\TCMatch.ahk
#include %A_ScriptDir%\Lib\Eval.ahk
#include %A_ScriptDir%\Lib\JSON.ahk
#include %A_ScriptDir%\Lib\Kanji\Kanji.ahk
#include %A_ScriptDir%\Lib\Gdip.ahk
#include %A_ScriptDir%\Core\Functions.ahk
#include %A_ScriptDir%\Core\ReservedFunctions.ahk
; 用户自定义命令
#include *i %A_ScriptDir%\Conf\UserFunctions.ahk

#NoEnv
#SingleInstance, Force
#NoTrayIcon

FileEncoding, utf-8
SendMode Input
SetWorkingDir %A_ScriptDir%

; 自动生成的命令文件
global g_SearchFileList := A_ScriptDir . "\Conf\SearchFileList.txt"
; 配置文件
global g_ConfFile := A_ScriptDir . "\Conf\RunZ.ini"
; 自动写入的配置文件
global g_AutoConfFile := A_ScriptDir . "\Conf\RunZ.auto.ini"

if !FileExist(g_ConfFile)
{
    FileCopy, %g_ConfFile%.help.txt, %g_ConfFile%
}

if (FileExist(g_AutoConfFile ".EasyIni.bak"))
{
    MsgBox, % "发现上次写入配置的备份文件：`n"
        . g_AutoConfFile . ".EasyIni.bak"
        . "`n确定则将其恢复，否则请手动检查文件内容再继续"
    FileMove, % g_AutoConfFile ".EasyIni.bak", % g_AutoConfFile
}
else if (!FileExist(g_AutoConfFile))
{
    FileAppend, % "; 此文件由 RunZ 自动写入，如需手动修改请先关闭 RunZ ！`n`n[Auto]`n[Rank]`n[History]" , % g_AutoConfFile
}

global g_Conf := class_EasyINI(g_ConfFile)
global g_AutoConf := class_EasyINI(g_AutoConfFile)

; 当前输入命令的参数，数组，为了方便没有添加 g_ 前缀
global Arg
; 不能是 RunZ.ahk 的子串，否则按键绑定会有问题
global g_WindowName := "RunZ    "
; 所有命令
global g_Commands
; 当搜索无结果时使用的命令
global g_FallbackCommands
; 编辑框当前内容
global g_CurrentInput
; 当前匹配到的第一条命令
global g_CurrentCommand
; 当前匹配到的所有命令
global g_CurrentCommandList
; 是否启用 TCMatch
global g_EnableTCMatch = TCMatchOn(g_Conf.Config.TCMatchPath)
; 列表第一列的首字母或数字
global g_FirstChar := Asc(g_Conf.Gui.FirstChar)
; 在列表中显示的行数
global g_DisplayRows := g_Conf.Gui.DisplayRows
; 在列表中显示的文字列数（多出的会被截断）
global g_DisplayCols := g_Conf.Gui.DisplayCols
; 命令使用了显示框
global g_UseDisplay
; 历史命令
global g_HistoryCommands
; 运行命令时临时设置，避免因为自身退出无法运行需要提权的软件
global g_DisableAutoExit
; 当前的命令在搜索结果的行数
global g_CurrentLine
; 使用备用的命令
global g_UseFallbackCommands
global g_InputArea := "Edit1"
global g_OutputArea := "Edit3"
global g_CommandArea := "Edit5"

if (g_Conf.Gui.ShowTrayIcon)
{
    Menu, Tray, Icon
    Menu, Tray, NoStandard
    if (!g_Conf.Config.ExitIfInactivate)
    {
        Menu, Tray, Add, 显示(&S), ActivateWindow
        Menu, Tray, Default, 显示(&S)
        Menu, Tray, Click, 1
    }
    Menu, Tray, Add, 配置(&C), EditConfig
    Menu, Tray, Add, 帮助(&H), KeyHelp
    Menu, Tray, Add,
    Menu, Tray, Add, 重启(&R), RestartRunZ
    Menu, Tray, Add, 退出(&X), ExitRunZ
}

Menu, Tray, Icon, %A_ScriptDir%\RunZ.ico

if (FileExist(g_SearchFileList))
{
    LoadFiles()
}
else
{
    GoSub, ReloadFiles
}

Gui, Font, % "s" g_Conf.Gui.FontSize, % g_Conf.Gui.FontName
Gui, Add, Edit, % "gProcessInputCommand vSearchArea"
        . " w" g_Conf.Gui.WidgetWidth " h" g_Conf.Gui.EditHeight,
Gui, Add, Edit, w0 h0 ReadOnly,
Gui, Add, Edit, % "ReadOnly vDisplayArea "
        . (g_Conf.Gui.HideDisplayAreaVScroll ? "-VScroll " : "")
        . " w" g_Conf.Gui.WidgetWidth " h" g_Conf.Gui.DisplayAreaHeight
        , % SearchCommand("", true)

if (g_Conf.Gui.ShowCurrentCommand)
{
    Gui, Add, Edit, w0 h0 ReadOnly,
    Gui, Add, Edit, % "ReadOnly"
        . " w" g_Conf.Gui.WidgetWidth " h" g_Conf.Gui.EditHeight,
}

if (g_Conf.Gui.HideTitle)
{
    Gui -Caption
}

Gui, Show, , % g_WindowName

if (g_Conf.Config.WindowAlwaysOnTop)
{
    WinSet, AlwaysOnTop, On, A
}

if (g_Conf.Config.ExitIfInactivate)
{
    OnMessage(0x06, "WM_ACTIVATE")
}

Hotkey, IfWinActive, % g_WindowName
; 如果是 ~enter，有时候会响
Hotkey, enter, RunCurrentCommand

Hotkey, esc, EscFunction
Hotkey, !f4, ExitRunZ

Hotkey, tab, TabFunction
Hotkey, f1, Help
Hotkey, +f1, KeyHelp
Hotkey, f2, EditConfig
Hotkey, ^q, RestartRunZ
Hotkey, ^l, ClearInput
Hotkey, ^d, OpenCurrentFileDir
Hotkey, ^x, DeleteCurrentFile
Hotkey, ^s, ShowCurrentFile
Hotkey, ^r, ReloadFiles
Hotkey, ^h, DisplayHistoryCommands
Hotkey, ^n, IncreaseRank
Hotkey, ^p, DecreaseRank
Hotkey, ^f, NextPage
Hotkey, ^b, PrevPage
Hotkey, ^i, HomeKey
Hotkey, ^o, EndKey
Hotkey, ^j, NextCommand
Hotkey, ^k, PrevCommand
Hotkey, down, NextCommand
Hotkey, up, PrevCommand

; 剩余按键 e g j m t w

Loop, % g_DisplayRows
{
    key := Chr(g_FirstChar + A_Index - 1)
    ; lalt +
    Hotkey, !%key%, RunSelectedCommand
    ; tab +
    Hotkey, ~%key%, RunSelectedCommand
    ; shift +
    Hotkey, ~+%key%, GotoCommand
}

; 用户映射的按键

for key, label in g_Conf.Hotkey
{
    if (label != "Default")
    {
        Hotkey, %key%, %label%
    }
    else
    {
        Hotkey, %key%, Off
    }
}

Hotkey, IfWinActive

for key, label in g_Conf.GlobalHotkey
{
    if (label != "Default")
    {
        Hotkey, %key%, %label%
    }
    else
    {
        Hotkey, %key%, Off
    }
}

if (g_Conf.Config.SaveInputText && g_AutoConf.Auto.InputText != "")
{
    Send, % g_AutoConf.Auto.InputText
}

if (g_Conf.Config.SaveHistory)
{
    g_HistoryCommands := Object()
    LoadHistoryCommands()
}

return

Default:
return

RestartRunZ:
    SaveAutoConf()
    Reload
return

Test:
    MsgBox Test
return

HomeKey:
    Send, {home}
return

EndKey:
    Send, {End}
return

NextPage:
    ControlFocus, %g_OutputArea%
    Send, {pgdn}
return

PrevPage:
    ControlFocus, %g_OutputArea%
    Send, {pgup}
return

ActivateWindow:
    Gui, Show, , % g_WindowName
return

TabFunction:
    ControlGetFocus, ctrl,
    if (ctrl == g_InputArea)
    {
        ; 定位到一个隐藏编辑框
        ControlFocus, Edit2
    }
    else
    {
        ControlFocus, %g_InputArea%
    }
return

EscFunction:
    ; 如果是后台运行模式，只关闭窗口，不退出程序
    if (g_Conf.Config.RunInBackground)
    {
        Gui, Hide
    }
    else
    {
        GoSub, ExitRunZ
    }
return

NextCommand:
    ChangeCommand(1)
return

PrevCommand:
    ChangeCommand(-1)
return

GotoCommand:
    ControlGetFocus, ctrl,
    if (ctrl == g_InputArea)
    {
        return
    }

    index := Asc(SubStr(A_ThisHotkey, 0, 1)) - g_FirstChar + 1

    if (g_CurrentCommandList[index] != "")
    {
        ChangeCommand(index - 1, true)
    }
return

ChangeCommand(step, resetCurrentLine = false)
{
    ControlGetText, g_CurrentInput, %g_InputArea%

    if (resetCurrentLine || SubStr(g_CurrentInput, 1, 1) != "@")
    {
        g_CurrentLine := 1
    }

    row := g_CurrentCommandList.Length()
    if (row > g_DisplayRows)
    {
        row := g_DisplayRows
    }

    g_CurrentLine := Mod(g_CurrentLine + step, row)
    if (g_CurrentLine == 0)
    {
        g_CurrentLine := row
    }

    ; 重置当前命令
    g_CurrentCommand := g_CurrentCommandList[g_CurrentLine]

    ; 修改输入框内容
    currentChar := Chr(g_FirstChar + g_CurrentLine - 1)
    newInput := "@" currentChar " "

    if (g_UseFallbackCommands)
    {
        if (SubStr(g_CurrentInput, 1, 1) == "@")
        {
            newInput .= SubStr(g_CurrentInput, 4)
        }
        else
        {
            newInput .= g_CurrentInput
        }
    }

    ControlGetText, result, %g_OutputArea%
    result := StrReplace(result, ">| ", " | ")
    if (currentChar == Chr(g_FirstChar))
    {
        result := currentChar ">" SubStr(result, 3)
    }
    else
    {
        result := StrReplace(result, "`n" currentChar " | ", "`n" currentChar ">| ")
    }

    DisplaySearchResult(result)

    ControlSetText, %g_InputArea%, %newInput%
    Send, {end}
}

GuiClose()
{
    if (!g_Conf.Config.RunInBackground)
    {
        GoSub, ExitRunZ
    }
}

SaveAutoConf()
{
    if (g_Conf.Config.SaveInputText)
    {
        g_AutoConf.DeleteKey("Auto", "InputText")
        g_AutoConf.AddKey("Auto", "InputText", g_CurrentInput)
    }

    if (g_Conf.Config.SaveHistory)
    {
        g_AutoConf.DeleteSection("History")
        g_AutoConf.AddSection("History")

        for index, element in g_HistoryCommands
        {
            if (element != "")
            {
                g_AutoConf.AddKey("History", index, element)
            }
        }
    }

    Loop
    {
        g_AutoConf.Save()

        if (!FileExist(g_AutoConfFile))
        {
            MsgBox, 配置文件 %g_AutoConfFile% 写入后丢失，请检查磁盘并点确定来重试
        }
        else
        {
            break
        }
    }
}

ExitRunZ:
    SaveAutoConf()
    ExitApp
return

GenerateSearchFileList()
{
    FileDelete, %g_SearchFileList%

    searchFileType := g_Conf.Config.SearchFileType

    for dirIndex, dir in StrSplit(g_Conf.Config.SearchFileDir, " | ")
    {
        if (InStr(dir, "A_") == 1)
        {
            searchPath := %dir%
        }
        else
        {
            searchPath := dir
        }

        for extIndex, ext in StrSplit(searchFileType, " | ")
        {
            Loop, Files, %searchPath%\%ext%, R
            {
                if (g_Conf.Config.SearchFileExclude != ""
                        && RegexMatch(A_LoopFileLongPath, g_Conf.Config.SearchFileExclude))
                {
                    continue
                }
                FileAppend, file | %A_LoopFileLongPath%`n, %g_SearchFileList%,
            }
        }
    }
}

ReloadFiles:
    GenerateSearchFileList()

    LoadFiles()
return

ProcessInputCommand:
    ControlGetText, g_CurrentInput, %g_InputArea%

    SearchCommand(g_CurrentInput)
return

SearchCommand(command = "", firstRun = false)
{
    result := ""
    ; 供去重使用
    fullResult := ""
    commandPrefix := SubStr(command, 1, 1)

    if (commandPrefix == ";" || commandPrefix == ":")
    {
        if (commandPrefix == ";")
        {
            g_CurrentCommand := g_FallbackCommands[1]
        }
        else if (commandPrefix == ":")
        {
            g_CurrentCommand := g_FallbackCommands[2]
        }

        g_CurrentCommandList := Object()
        g_CurrentCommandList.Push(g_CurrentCommand)
        result .= Chr(g_FirstChar) ">| " . g_CurrentCommand
        DisplaySearchResult(result)
        return result
    }
    else if (commandPrefix == "@")
    {
        ; 搜索结果被锁定，直接退出
        return
    }
    else if (InStr(command, " ") && g_CurrentCommand != "")
    {
        ; 输入包含空格时锁定搜索结果
        return
    }

    g_CurrentCommandList := Object()

    order := g_FirstChar

    for index, element in g_Commands
    {
        if (InStr(fullResult, element "`n"))
        {
            continue
        }

        splitedElement := StrSplit(element, " | ")

        if (splitedElement[1] == "file")
        {
            SplitPath, % splitedElement[2], , fileDir, , fileNameNoExt

            ; 只搜索和展示不带扩展名的文件名
            elementToSearch := fileNameNoExt
            elementToShow := "file | " . fileNameNoExt

            if (splitedElement.Length() >= 3)
            {
                elementToSearch .= " " . splitedElement[3]
                elementToShow .= "（" . splitedElement[3] . "）"
            }

            elementToShow := SubStr(elementToShow, 1, g_DisplayCols)

            if (g_Conf.Config.SearchFullPath)
            {
                ; TCMatch 在搜索路径时只搜索文件名，强行将 \ 转成空格
                elementToSearch := StrReplace(fileDir, "\", " ") . " " . elementToSearch
            }
        }
        else
        {
            elementToShow := SubStr(element, 1, g_DisplayCols)
            elementToSearch := splitedElement[2]

            if (splitedElement.Length() >= 3)
            {
                elementToSearch .= " " . splitedElement[3]
            }
        }

        if (command == "" || MatchCommand(elementToSearch, command))
        {
            fullResult .= element "`n"
            g_CurrentCommandList.Push(element)

            if (order == g_FirstChar)
            {
                g_CurrentCommand := element
                result .= Chr(order++) . ">| " . elementToShow
            }
            else
            {
                result .= "`n" Chr(order++) . " | " . elementToShow
            }

            if (order - g_FirstChar >= g_DisplayRows)
            {
                break
            }
            ; 第一次运行只加载 function 类型
            if (firstRun && (order - g_FirstChar >= g_DisplayRows - 4))
            {
                result .= "`n`n现有 " g_Commands.Length() " 条命令。"
                result .= "`n`n键入内容 搜索，回车 执行当前命令，Alt + 字母 执行，F1 帮助，Esc 退出。"

                break
            }
        }
    }

    if (result == "")
    {
        g_UseFallbackCommands := true
        g_CurrentCommand := g_FallbackCommands[1]
        g_CurrentCommandList := g_FallbackCommands

        for index, element in g_FallbackCommands
        {
            if (index == 1)
            {
                result .= Chr(g_FirstChar - 1 + index++) . ">| " . element
            }
            else
            {
                result .= "`n"
                result .= Chr(g_FirstChar - 1 + index++) . " | " . element
            }
        }
    }
    else
    {
        g_UseFallbackCommands := false
    }

    result := StrReplace(result, "file | ", "文件 | ")
    result := StrReplace(result, "function | ", "功能 | ")
    result := StrReplace(result, "cmd | ", "命令 | ")

    DisplaySearchResult(result)
    return result
}

DisplaySearchResult(result)
{
    DisplayText(result)

    if (g_CurrentCommandList.Length() == 1 && g_Conf.Config.RunIfOnlyOne)
    {
        RunCommand(g_CurrentCommand)
    }

    if (g_Conf.Gui.ShowCurrentCommand)
    {
        commandToShow := SubStr(g_CurrentCommand, InStr(g_CurrentCommand, " | ") + 3)
        ControlSetText, %g_CommandArea%, %commandToShow%
    }
}

ClearInput:
    ControlSetText, %g_InputArea%,
    ControlFocus, %g_InputArea%
return

RunCurrentCommand:
    if (GetInputState() == 1)
    {
        Send, {enter}
    }

    if (g_CurrentInput != "")
    {
        RunCommand(g_CurrentCommand)
    }
return

ParseArg:
    commandPrefix := SubStr(g_CurrentInput, 1, 1)

    if (commandPrefix == ";" || commandPrefix == ":")
    {
        Arg := SubStr(g_CurrentInput, 2)
        return
    }
    else if (commandPrefix == "@")
    {
        ; 处理调整过顺序的命令
        Arg := SubStr(g_CurrentInput, 4)
        return
    }

    ; 用空格来判断参数
    if (InStr(g_CurrentInput, " ") && !g_UseFallbackCommands)
    {
        Arg := SubStr(g_CurrentInput, InStr(g_CurrentInput, " ") + 1)
    }
    else
    {
        Arg := g_CurrentInput
    }
return

MatchCommand(Haystack, Needle)
{
    if (g_EnableTCMatch)
    {
        return TCMatch(Haystack, Needle)
    }

    return InStr(Haystack, Needle)
}

RunCommand(originCmd)
{
    GoSub, ParseArg

    g_UseDisplay := false
    g_DisableAutoExit := true

    splitedOriginCmd := StrSplit(originCmd, " | ")
    ; 去掉括号内的注释
    cmd := StrSplit(splitedOriginCmd[2], "（")[1]

    if (splitedOriginCmd[1] == "file")
    {
        if (InStr(cmd, ".lnk"))
        {
            ; 处理 32 位 ahk 运行不了某些 64 位系统 .lnk 的问题
            FileGetShortcut, %cmd%, filePath
            if (!FileExist(filePath))
            {
                filePath := StrReplace(filePath, "C:\Program Files (x86)", "C:\Program Files")
                if (FileExist(filePath))
                {
                    cmd := filePath
                }
            }
        }

        Run, %cmd%
    }
    else if (splitedOriginCmd[1] == "function")
    {
        if (splitedOriginCmd.Length() >= 3)
        {
            Arg := splitedOriginCmd[3]
        }

        if (IsLabel(cmd))
        {
            GoSub, %cmd%
        }
    }
    else if (splitedOriginCmd[1] == "cmd")
    {
        RunWithCmd(cmd)
    }

    if (g_Conf.Config.SaveHistory && cmd != "DisplayHistoryCommands")
    {
        if (splitedOriginCmd.Length() == 2 && Arg != "")
        {
            g_HistoryCommands.InsertAt(1, originCmd " | " Arg)
        }
        else if (originCmd != "")
        {
            g_HistoryCommands.InsertAt(1, originCmd)
        }

        if (g_HistoryCommands.Length() > g_Conf.Config.HistorySize)
        {
            g_HistoryCommands.Pop()
        }
    }

    if (g_Conf.Config.AutoRank)
    {
        IncreaseRank(originCmd)
    }

    g_DisableAutoExit := false

    if (g_Conf.Config.RunOnce && !g_UseDisplay)
    {
        GoSub, EscFunction
    }
}

IncreaseRank(cmd, show = false, inc := 1)
{
    splitedCmd := StrSplit(cmd, " | ")

    if (splitedCmd.Length() >= 3 && splitedCmd[1] == "function")
    {
        ; 去掉参数
        cmd := splitedCmd[1]  " | " splitedCmd[2]
    }

    cmdRank := g_AutoConf.GetValue("Rank", cmd)
    if cmdRank is integer
    {
        g_AutoConf.DeleteKey("Rank", cmd)
        cmdRank += inc
    }
    else
    {
        cmdRank := inc
    }

    if (cmdRank > 0 && cmd != "")
    {
        g_AutoConf.AddKey("Rank", cmd, cmdRank)
    }
    else
    {
        cmdRank := 0
    }

    if (show)
    {
        ToolTip, 调整 %cmd% 的权重到 %cmdRank%
        SetTimer, RemoveToolTip, 800
    }
}

; 比较耗时，必要时才使用，也可以手动编辑 RunZ.auto.ini
CleanupRank:
    ; 先把 g_Commands 里的 Rank 信息清掉
    LoadFiles(false)

    for command, rank in g_AutoConf.Rank
    {
        cleanup := true
        for index, element in g_Commands
        {
            if (InStr(element, command) == 1)
            {
                cleanup := false
                break
            }
        }
        if (cleanup)
        {
            g_AutoConf.DeleteKey("Rank", command)
        }
    }

    Loop
    {
        g_AutoConf.Save()

        if (!FileExist(g_AutoConfFile))
        {
            MsgBox, 配置文件 %g_AutoConfFile% 写入后丢失，请检查磁盘并点确定来重试
        }
        else
        {
            break
        }
    }

    LoadFiles()
return

RunSelectedCommand:
    if (SubStr(A_ThisHotkey, 1, 1) == "~")
    {
        ControlGetFocus, ctrl,
        if (ctrl == g_InputArea)
        {
            return
        }
    }

    index := Asc(SubStr(A_ThisHotkey, 0, 1)) - g_FirstChar + 1

    RunCommand(g_CurrentCommandList[index])
return

IncreaseRank:
    if (g_CurrentCommand != "")
    {
        IncreaseRank(g_CurrentCommand, true)
        LoadFiles()
    }
return

DecreaseRank:
    if (g_CurrentCommand != "")
    {
        IncreaseRank(g_CurrentCommand, true, -1)
        LoadFiles()
    }
return

LoadFiles(loadRank := true)
{
    g_Commands := Object()
    g_FallbackCommands := Object()

    if (loadRank)
    {
        rankString := ""
        for command, rank in g_AutoConf.Rank
        {
            if (StrLen(command) > 0)
            {
                rankString .= rank "`t" command "`n"
            }
        }

        if (rankString != "")
        {
            Sort, rankString, R N

            Loop, Parse, rankString, `n
            {
                if (A_LoopField == "")
                {
                    continue
                }

                g_Commands.Push(StrSplit(A_loopField, "`t")[2])
            }
        }
    }

    for key, value in g_Conf.Command
    {
        if (value != "")
        {
            g_Commands.Push(key . "（" . value "）")
        }
        else
        {
            g_Commands.Push(key)
        }
    }

    if (FileExist(A_ScriptDir "\Conf\UserFunctions.ahk"))
    {
        userFunctionLabel := "UserFunctions"
        if (IsLabel(userFunctionLabel))
        {
            GoSub, %userFunctionLabel%
        }
        else
        {
            MsgBox, 未在 %A_ScriptDir%\Conf\UserFunctions.ahk 中发现 %userFunctionLabel% 标签，请修改！
        }
    }

    GoSub, Functions

    Loop, Read, %g_SearchFileList%
    {
        g_Commands.Push(A_LoopReadLine)
    }

    if (g_Conf.Config.LoadControlPanelFunctions)
    {
        Loop, Read, %A_ScriptDir%\Core\ControlPanelFunctions.txt
        {
            g_Commands.Push(A_LoopReadLine)
        }
    }
}

DisplayText(text)
{
    textToDisplay := StrReplace(text, "`n", "`r`n")
    ControlSetText, %g_OutputArea%, %textToDisplay%
}

DisplayResult(result)
{
    DisplayText(result)
    g_UseDisplay := true
}

LoadHistoryCommands()
{
    for key, value in g_AutoConf.History
    {
        if (StrLen(value) > 0)
        {
            g_HistoryCommands.Push(value)
        }
    }
}

DisplayHistoryCommands:
    result := ""
    g_CurrentCommandList := Object()
    g_CurrentLine := 1

    for index, element in g_HistoryCommands
    {
        if (index == 1)
        {
            result .= SubStr(Chr(g_FirstChar + index - 1) . ">| " . element, 1, g_DisplayCols) "`n"
            g_CurrentCommand := element
        }
        else
        {
            result .= SubStr(Chr(g_FirstChar + index - 1) . " | " . element, 1, g_DisplayCols) "`n"
        }

        g_CurrentCommandList.Push(element)
    }

    result := StrReplace(result, "file | ", "文件 | ")
    result := StrReplace(result, "function | ", "功能 | ")
    result := StrReplace(result, "cmd | ", "命令 | ")

    DisplayResult(result)
return

@(label, info, fallback = false, key = "")
{
    if (!IsLabel(label))
    {
        MsgBox, 未找到 %label% 标签，请检查 %A_ScriptDir%\Conf\UserFunctions.ahk 文件格式！
        return
    }

    g_Commands.Push("function | " . label . "（" . info . "）")
    if (fallback)
    {
        g_FallbackCommands.Push("function | " . label . "（" . info . "）")
    }

    if (key != "")
    {
        Hotkey, %key%, %label%
    }
}

RunAndGetOutput(command)
{
    tempFileName := "RunZ.stdout.log"
    fullCommand = bash -c "%command% &> %tempFileName%"

    if (!FileExist("c:\msys64\usr\bin\bash.exe"))
    {
        fullCommand = %ComSpec% /C "%command% > %tempFileName%"
    }

    RunWait, %fullCommand%, %A_Temp%, Hide
    FileRead, result, %A_Temp%\%tempFileName%
    FileDelete, %A_Temp%\%tempFileName%
    return result
}

RunWithCmd(command)
{
    if (FileExist("c:\msys64\usr\bin\mintty.exe"))
    {
        Run, % "mintty -e sh -c '" command "; read'"
    }
    else
    {
        Run, % ComSpec " /C " command " & pause"
    }
}

OpenPath(filePath)
{
    if (!FileExist(filePath))
    {
        return
    }

    if (FileExist(g_Conf.Config.TCPath))
    {
        TCPath := g_Conf.Config.TCPath
        Run, %TCPath% /O /A /L="%filePath%"
    }
    else
    {
        SplitPath, filePath, , fileDir, ,
        Run, explorer "%fileDir%"
    }
}

GetAllFunctions()
{
    result := ""

    for index, element in g_Commands
    {
        if (InStr(element, "function | ") == 1 and !InStr(result, element "`n"))
        {
            result .= element "`n"
        }
    }

    result := StrReplace(result, "function | ", "功能 | ")

    return result
}

OpenCurrentFileDir:
    filePath := StrSplit(g_CurrentCommand, " | ")[2]
    OpenPath(filePath)
return

DeleteCurrentFile:
    filePath := StrSplit(g_CurrentCommand, " | ")[2]

    if (!FileExist(filePath))
    {
        return
    }

    FileRecycle, % filePath
    GoSub, ReloadFiles
return

ShowCurrentFile:
    clipboard := StrSplit(g_CurrentCommand, " | ")[2]
    ToolTip, % clipboard
    SetTimer, RemoveToolTip, 800
return

RemoveToolTip:
    ToolTip
    SetTimer, RemoveToolTip, Off
return

WM_ACTIVATE(wParam, lParam)
{
    if (g_DisableAutoExit)
    {
        return
    }

    if (wParam >= 1) ; 窗口激活
    {
        return
    }
    else if (wParam <= 0) ; 窗口非激活
    {
        SetTimer, ToExit, 50
    }
}

ToExit:
    if (!WinExist("RunZ.ahk"))
    {
        GoSub, EscFunction
    }

    SetTimer, ToExit, Off
return

KeyHelpText()
{
    return ""
    . "Win + j 显示窗口`n"
    . "键入内容 搜索，回车 执行，Alt + 字母 执行，Esc 退出`n"
    . "按 Tab 后再按 字母或数字 也可执行字母对应功能`n"
    . "按 Tab 后 Shift + 字母或数字 定位到对应功能`n"
    . "Ctrl + j 移动到下一条命令`n"
    . "Ctrl + k 移动到上一条命令`n"
    . "Ctrl + f 翻到下一页`n"
    . "Ctrl + b 翻到上一页`n"
    . "Win  + j 激活窗口`n"
    . "Ctrl + h 显示历史记录`n"
    . "Ctrl + n 可增加当前功能的权重`n"
    . "Ctrl + p 可减少当前功能的权重`n"
    . "Ctrl + l 清除编辑框内容`n"
    . "Ctrl + r 重新创建待搜索文件列表`n"
    . "Ctrl + q 重启`n"
    . "Ctrl + d 用 TC 打开第一个文件所在目录`n"
    . "Ctrl + s 显示并复制当前文件的完整路径`n"
    . "Ctrl + x 删除当前文件`n"
    . "Ctrl + i 移动光标当行首`n"
    . "Ctrl + o 移动光标当行尾`n"
    . "F2       编辑配置文件`n`n"
}

UrlDownloadToString(url)
{
    static whr := ComObjCreate("WinHttp.WinHttpRequest.5.1")
    whr.Open("GET", url, true)
    whr.Send()
    whr.WaitForResponse()
    return whr.ResponseText
}

; 修改自万年书妖的 Candy 里的 SksSub_UrlEncode 函数，用于转换编码。感谢！
UrlEncode(url, enc = "UTF-8")
{
    enc := trim(enc)
    If enc=
        return url
    formatInteger := A_FormatInteger
    SetFormat, IntegerFast, H
    VarSetCapacity(buff, StrPut(url, enc))
    Loop % StrPut(url, &buff, enc) - 1
    {
        byte := NumGet(buff, A_Index-1, "UChar")
        encoded .= byte > 127 or byte <33 ? "%" Substr(byte, 3) : Chr(byte)
    }
    SetFormat, IntegerFast, %formatInteger%
    return encoded
}

; 0：英文 1：中文
GetInputState(WinTitle = "A")
{
    ControlGet, hwnd, HWND, , , %WinTitle%
    if (A_Cursor = "IBeam")
        return 1
    if (WinActive(WinTitle))
    {
        ptrSize := !A_PtrSize ? 4 : A_PtrSize
        VarSetCapacity(stGTI, cbSize := 4 + 4 + (PtrSize * 6) + 16, 0)
        NumPut(cbSize, stGTI, 0, "UInt")   ;   DWORD   cbSize;
        hwnd := DllCall("GetGUIThreadInfo", Uint, 0, Uint, &stGTI)
                         ? NumGet(stGTI, 8 + PtrSize, "UInt") : hwnd
    }
    return DllCall("SendMessage"
        , UInt, DllCall("imm32\ImmGetDefaultIMEWnd", Uint, hwnd)
        , UInt, 0x0283  ;Message : WM_IME_CONTROL
        , Int, 0x0005  ;wParam  : IMC_GETOPENSTATUS
        , Int, 0)      ;lParam  : 0
}

#include %A_ScriptDir%\Lib\EasyIni.ahk
#include %A_ScriptDir%\Lib\TCMatch.ahk
#include %A_ScriptDir%\Lib\Eval.ahk
#include %A_ScriptDir%\Lib\JSON.ahk
#include %A_ScriptDir%\Lib\Kanji\Kanji.ahk
#include %A_ScriptDir%\Lib\Gdip.ahk
#include %A_ScriptDir%\Core\Functions.ahk
#include %A_ScriptDir%\Core\ReservedFunctions.ahk
; 用户自定义命令
#include *i %A_ScriptDir%\Conf\UserFunctions.ahk


moved file

moved file

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

PlaceActiveWindow(mx, my, mw, mh)
{
    SetWinDelay 10
    SysGet mons, MonitorCount
    if (mons == 1)
    {
        SysGet, mon, MonitorWorkArea, 1
    }
    else if (mons == 2)
    {
        SysGet, mon1, MonitorWorkArea, 1
        SysGet, mon2, MonitorWorkArea, 2
        flip := mon1left > mon2left
        WinGetPos x, y, w, h, A
        xlimit := (flip ? mon1left : mon2left) - w/2
        monnumber := (x < xlimit) != flip ? 1 : 2
        SysGet, mon, MonitorWorkArea, %monnumber%
    }
    monwidth := monright - monleft
    monheight := monbottom - montop
    WinRestore A
    WinMove A, , monleft + mx*monwidth, montop + my*monheight, mw*monwidth, mh*monheight`
}