Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Kommand - A cross-application VIM-like hot key solution


  • Please log in to reply
9 replies to this topic
kylirh
  • Members
  • 19 posts
  • Last active: Nov 13 2009 11:58 PM
  • Joined: 18 Jun 2009
Kommand
By Kylir Horton

Version 0.3 - Updated on November 11, 2009

The Kommand script with Snarl integration and helper files can be downloaded from kylirhorton.com/kommand.zip

Kommand is a cross-application VIM-like hot key solution. Kommand's goal is to make window management, opening programs and files, and text editing (especially coding) easier and faster. Kommand is modular, like VIM. It has three states: Kommand, Viper, and Insert modes. Kommand mode is used to manage windows. Viper mode provides a number of hot keys to navigate programs and modify text using Vi keybindings. Insert mode passes all key strokes as if typed normally. Kommand's mode is indicated by its system tray icon (It changes depending on the mode you're in). In addition, if you're using Snarl, Kommand will display its current state as a Snarl message.

Kommand can be easily customized and I highly encourage you to do so. I've included all of my own personal key bindings and custom logic (Look in the Custom folder).

Future versions will include more window management and text editing goodness. As I develop it, I will build upon the current framework that Kommand uses. If you have any feature requests, please let me know!

Special thanks go out to Lexikos for writing WindowPad and corrupt for writing nomousy.

Here's a list of the some of the key bindings (Look at the CoreHotKeys script in the Scripts folder to see them all):

All Modes
capslock = Escape key (I've found this incredibly convenient for use with Gvim, Vimperator, and ViEmu)
shift+capslock = Toggle capslock
win+escape = Disable or enable Kommand completely. Only hot keys defined in the custom hot keys script might be active.

Kommand Mode
i = Go to Insert mode
v = Go to Viper mode
h, j, k, l = Move active window left/down/up/right
shift+h = Maximize active window
shift+l = Minimize active window
shift+m = Restore or toggle maximize on the active window
d = Close active window
shift+d = Close all explorer windows
o = Move window to next screen
ctrl+n = Move to next window on task bar (Only works in Windows Vista and 7)
ctrl+p = Move to previous window on task bar (Only works in Windows Vista and 7)
ctrl+t = Toggle transparency on active window

Viper Mode*
win+capslock = Go to Kommand mode
i = Go to insert mode
h, j, k, l = Move cursor left/down/up/right
o = Insert new line below current line and enter insert mode
ctrl+f = Page down
ctrl+b = Page up
w = Move cursor forward one word
b = Move cursor back one word
u = Undo

*While in Windows Explorer, Viper behaves a little differently. For example, a will "add" a new folder, shift+h goes back, shift+l goes forward, shift+k goes up, and shift+j goes down or opens. Look at the code for a better understanding.

Insert Mode
win+capslock = Go to Viper mode
All other key strokes are sent through as normal!

Core Kommand Logic File
;
||=================================||;
;||                                 ||;
;||          -= KOMMAND =-          ||;
;||                                 ||;
;||=================================||;

;
; Kommand.ahk
; Version: 0.3
; Last Updated: 11/5/2009
; Author: Kylir Horton <kylirh@gmail.com>
; Website: http://www.kylirhorton.com/kommand
;
; This is the main executable file for Kommand. All other files are loaded from this one and some basic functions and global variables are defined.
;

#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
#SingleInstance, Force ; Make sure there is only one instance of Kommand running at a time.
#WinActivateForce ; Forces windows to appear when they're called.

; Initialize Kommand and load custom logic and supporting functions.
KMD_Init()
#Include Custom\CustomLogic.ahk
#Include Scripts\WindowPad.ahk

; Initialize the script and load hotkeys.
KMD_ComponentInit(false)
#Include Scripts\CoreHotkeys.ahk
#Include Custom\CustomHotkeys.ahk
return

KMD_Init()
{
     global
     DetectHiddenWindows, on ; Be able to find hidden windows.
     SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
     SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
     SetBatchlines, -1 ; Make the script run as fast as possible.
     SetKeyDelay, -1 ; Make sure it is fast!

     ; Set the initial variables.
     KMD_Enabled := true
     KMD_InsertMode := false
     KMD_KommandMode := false
     KMD_ViperMode := false
     KMD_Silent := false
     KMD_InitialMode := 2
     KMD_LastMode := 0
}

KMD_ComponentInit(silent)
{
     global
     if (KMD_Enabled == true)
     {
          SetCapsLockState, Off
          KMD_LastMode := 0

          if (KMD_InitialMode == 1)
               KMD_StartInsertMode(silent)
          else if (KMD_InitialMode == 2)
               KMD_StartKommandMode(silent)
          else if (KMD_InitialMode == 3)
               KMD_StartViperMode(silent)
          else
               KMD_StartViperMode(silent)
     }
}

KMD_StartInsertMode(silent)
{
     global
     if (KMD_Enabled == true)
     {
          KMD_InsertMode := true
          KMD_KommandMode := false
          KMD_ViperMode := false
          Menu, Tray, Icon, %A_ScriptDir%\Images\Insert.ico, 0, 1
          if ((KMD_Silent == false) && (silent == false))
               ShowMessage("Insert Mode", "Keystrokes are now passed through.", "Insert.png")
     }
}

KMD_StartKommandMode(silent)
{
     global
     if (KMD_Enabled == true)
     {
          KMD_InsertMode := false
          KMD_KommandMode := true
          KMD_ViperMode := false
          Menu, Tray, Icon, %A_ScriptDir%\Images\Kommand.ico, 0, 1
          if ((KMD_Silent == false) && (silent == false))
               ShowMessage("Kommand Mode", "Window management keybindings are enabled.", "Kommand.png")
     }
}

KMD_StartViperMode(silent)
{
     global
     if (KMD_Enabled == true)
     {
          KMD_InsertMode := false
          KMD_KommandMode := false
          KMD_ViperMode := true
          Menu, Tray, Icon, %A_ScriptDir%\Images\Viper.ico, 0, 1
          if ((KMD_Silent == false) && (silent == false))
               ShowMessage("Viper Mode", "Some Vi keybindings are enabled.", "Viper.png")
     }
}

KMD_Disable(silent)
{
     global
     if (KMD_Enabled == true)
     {
          KMD_Enabled := false
          KMD_InsertMode := false
          KMD_KommandMode := false
          KMD_ViperMode := false
          Menu, Tray, Icon, %A_ScriptDir%\Images\Disabled.ico, 0, 1
          if ((KMD_Silent == false) && (silent == false))
               ShowMessage("Disabled", "Kommand is now disabled.", "Disabled.png")
     }
}

KMD_Enable(silent)
{
     global
     if (KMD_Enabled == false)
     {
          KMD_Enabled := true
          KMD_ComponentInit(silent)
     }
}

ShowMessage(title, message, icon)
{
     Run Utilities\SnarlCMD.exe snShowMessage 5 "%title%" "%message%" "%A_ScriptDir%\Images\%icon%",,UseErrorLevel
}

RunAndFocus(command)
{
     Run %command%,,UseErrorLevel
     if (A_LastError == 0)
          WinActivate
}

RunAndFocusInMode(command, mode)
{
     Run %command%,,UseErrorLevel
     if (A_LastError == 0)
     {
          WinActivate
          if (mode == 1)
               KMD_StartInsertMode(true)
          else if (mode == 2)
               KMD_StartKommandMode(true)
          else
               KMD_StartViperMode(true)
     }
}

Core Hot Keys
;
; CoreHotkeys.ahk
; Version: 0.4
; Last Updated: 11/5/2009
;
; This file contains all of the core keybindings for Kommand.
;

; Modifiers Keys ================================================== ;

#UseHook on

CapsLock::
     if (KMD_Enabled == true)
          Send, {Esc}
     else
          SetCapsLockState, % GetKeyState( "CapsLock", "T" ) ? "OFF" : "ON"
return

#UseHook off

+Capslock:: SetCapsLockState, % GetKeyState( "CapsLock", "T" ) ? "OFF" : "ON"

#CapsLock::
     if (KMD_Enabled == true)
          if (KMD_Enabled == true)
          {
               if (KMD_ViperMode == true)
                    KMD_StartKommandMode(false)
               else if (KMD_InsertMode == true)
                    KMD_StartViperMode(false)
          }
     else
          SetCapsLockState, % GetKeyState( "CapsLock", "T" ) ? "OFF" : "ON"
return

#Esc::
     if (KMD_Enabled == true)
          KMD_Disable(false)
     else
          KMD_Enable(false)
return

; Special Characters ============================================ ;

#UseHook on

$::
     if (KMD_ViperMode == true)
          Send, {End}
     else
          Send, $
return

Tab::
     if (KMD_KommandMode == true)
          Send, {Alt down}{Tab}{Alt up}
     else
          Send, {Tab}
return

; Numbers ======================================================= ;

0::
     if (KMD_ViperMode == true)
          Send, {Home}
     else
          Send, 0
return

; Letters ======================================================= ;

a::
     if (KMD_ViperMode == true)
     {
          if (WinActive("ahk_class CabinetWClass"))
               Send, ^+n
          else
          {
               Send, {Right}
               KMD_StartInsertMode(true)
          }
     }
     else
          Send, a
return

+a::
     if (KMD_ViperMode == true)
     {
          Send, {End}
          KMD_StartInsertMode(true)
     }
     else
          Send, +a
return

b::
     if (KMD_ViperMode == true)
          Send, ^{Left}
     else
          Send, b
return

^b::
     if (KMD_ViperMode == true)
          Send, {Page down}
     else if (KMD_KommandMode == true)
     {
          WinSet, AlwaysOnTop, Off, A
          WinSet, Bottom,, A
     }
     else
          Send, ^b
return

+c::
     if (KMD_ViperMode == true)
     {
          Send, {Shift down}{End}{Delete}
          KMD_StartInsertMode(true)
     }
     else
          Send, +c
return

d::
     if ((KMD_ViperMode == true) && (WinActive("ahk_class CabinetWClass")))
          Send, {Delete}
     else if (KMD_KommandMode == true)
          WinClose A
     else
          Send, d
return

+d::
     if (KMD_KommandMode == true)
          Run Utilities\CloseWindows.exe,,UseErrorLevel
     else
          Send, +d
return

^d::
     if (KMD_ViperMode == true)
          Send, {Page down}
     else
          Send ^d
return

^f::
     if (KMD_ViperMode == true)
          Send, {Page down}
     else if (KMD_KommandMode == true)
		WinSet, AlwaysOnTop, Toggle, A
     else
          Send, ^f
return

h::
     if (KMD_ViperMode == true)
          Send, {Left}
     else if (KMD_KommandMode == true)
          WindowPadMove("-1,  0,  0.5, 1.0")
     else
          Send, h
return

+h::
     if ((KMD_ViperMode == true) && WinActive("ahk_class CabinetWClass"))
          Send, !{Left}
     else if (KMD_KommandMode == true)
          WinMaximize, A
     else
          Send, +h
return

i::
     if ((KMD_ViperMode == true) OR (KMD_KommandMode == true))
          KMD_StartInsertMode(true)
     else
          Send, i
return

+i::
     if (KMD_ViperMode == true)
     {
          Send, {Home}
          KMD_StartInsertMode(true)
     }
     else
          Send, +i
return

j::
     if (KMD_ViperMode == true)
          Send, {Down}
     else if (KMD_KommandMode == true)
          WindowPadMove("0, +1,  1.0, 0.5")
     else
          Send, j
return

+j::
     if ((KMD_ViperMode == true) && (WinActive("ahk_class CabinetWClass")))
          Send, {Enter}
     else
          Send, +j
return

k::
     if (KMD_ViperMode == true)
          Send, {Up}
     else if (KMD_KommandMode == true)
          WindowPadMove("0, -1,  1.0, 0.5")
     else
          Send, k
return

+k::
     if ((KMD_ViperMode == true) && (WinActive("ahk_class CabinetWClass")))
          Send, !{Up}
     else
          Send, +k
return

^k::
     if (KMD_ViperMode == true)
          KMD_StartKommandMode(false)
     else
          Send, ^k
return

l::
     if (KMD_ViperMode == true)
          Send, {Right}
     else if (KMD_KommandMode == true)
          WindowPadMove("+1,  0,  0.5, 1.0")
     else
          Send, l
return

+l::
     if ((KMD_ViperMode == true) && (WinActive("ahk_class CabinetWClass")))
          Send, !{Right}
     if (KMD_KommandMode == true)
          WinMinimize, A
     else
          Send, +l
return

^l::
     if (KMD_KommandMode == true)
     {
          if WinExist(GetLastMinimizedWindow())
               WinRestore
     }
     else
          Send, ^l
return

+m::
     if (KMD_KommandMode == true)
          MaximizeToggle(A)
     else
          Send, +m
return

^n::
     if (KMD_KommandMode == true)
          Send, #t
     else
          Send, ^n
return

o::
     if (KMD_ViperMode == true)
     {
          Send, {End}{Enter}
          KMD_StartInsertMode(true)
     }
     else if (KMD_KommandMode == true)
          WindowScreenMove(Next)
     else
          Send, o
return

+o::
     if (KMD_ViperMode == true)
     {
          Send, {Home}{Enter}{Up}
          KMD_StartInsertMode(true)
     }
     else if (KMD_KommandMode == true)
          WindowScreenMove(Next)
     else
          Send, +o
return

^p::
     if (KMD_KommandMode == true)
          Send, #+t
     else
          Send, ^p
return

s::
     if (KMD_ViperMode == true)
     {
          Send, {Delete}
          KMD_StartInsertMode(true)
     }
     else
          Send, s
return

+s::
     if (KMD_ViperMode == true)
     {
          Send, {End}{Shift down}{Home}{Shift up}{Delete}
          KMD_StartInsertMode(true)
     }
     else
          Send, +s
return

^t::
     if (KMD_KommandMode == true)
     {
          WinGet, Transparent, Transparent, A
          if (Transparent = 120)
               WinSet, Transparent, 255, A
          else
               WinSet, Transparent, 120, A
     }
     else
          Send, ^t
return

u::
     if (KMD_ViperMode == true)
          Send, ^z
     else
          Send, u
return

^u::
     if (KMD_ViperMode == true)
          Send, {Page up}
     else
          Send, ^u
return

v::
     if (KMD_KommandMode == true)
          KMD_StartViperMode(false)
     else
          Send, v
return

^v::
     if (KMD_KommandMode == true)
          KMD_StartViperMode(false)
     else
          Send, ^v
return

w::
     if (KMD_ViperMode == true)
     {
          if (WinActive("ahk_class CabinetWClass"))
          {
               RegRead, HiddenFiles_Status, HKEY_CURRENT_USER, Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced, Hidden

               if HiddenFiles_Status = 2
                    RegWrite, REG_DWORD, HKEY_CURRENT_USER, Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced, Hidden, 1
               else
                    RegWrite, REG_DWORD, HKEY_CURRENT_USER, Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced, Hidden, 2

               WinGetClass, eh_Class, A
               if (eh_Class = "#32770" OR A_OSVersion = "WIN_VISTA")
                    SendInput, {F5}
               else
                    PostMessage, 0×111, 28931,,, A
          }
          else
               Send, ^{Right}
     }
     else
          Send, w
return

x::
     if (KMD_ViperMode == true)
          Send, {Delete}
     else
          Send, x
return

+x::
     if (KMD_ViperMode == true)
          Send, {Backspace}
     else
          Send, +x
return

#UseHook, off
[/code]

automaticman
  • Members
  • 658 posts
  • Last active: Nov 20 2012 06:10 PM
  • Joined: 27 Oct 2006
Wow, vim is cool, I will try this one, thanks for sharing.

sickpuma
  • Members
  • 8 posts
  • Last active: Nov 18 2009 05:25 AM
  • Joined: 28 May 2009
This looks interesting, however I would like to know more about it before I start using it.

Could you please clarify as to what the purpose of SnarlCMD.exe is? Do we need snarl to be installed on our own computer and SnarlCMD.exe simply interfaces with our installed version of Snarl? Or is SnarlCMD.exe a standalone application that simply shows message popups that doesn't require anything to be installed on our computers? Where is SnarlCMD.exe from? Did you make it? How can we trust that it won't cause problems on our computers?

Also if you could answer basically the same questions about CloseWindows.exe.

Please forgive me, as I don't like running exe files which I don't know what they do. The ahk file is alright since I can see the source code and know exactly what it is doing.

As for the code itself, is there any particular reason you have the hotkeys always enabled and just send the same value when not in Viper mode? Wouldn't it have been better to create the hotkeys on the fly every time you enter/exit Viper mode?

I noticed it has stuff that seems very specific to you (e.g. JENIVICE, C:\Application\iTunes\PlayPause.vbs, all the shortcuts for launching applications). Would you consider putting all those shortcut keys in a different script and simply making that one run kommand, this would help both you by not exposing all your personal stuff on the internet, as well as people that download the script by not binding a bunch of shortcut keys they don't know how to use, which would also make the script smaller and a bit easier to understand.

Also, with so many shortcut keys to launch applications, how do you remember what each one does?

Thanks

kylirh
  • Members
  • 19 posts
  • Last active: Nov 13 2009 11:58 PM
  • Joined: 18 Jun 2009
@sickpuma - Thanks for your questions! I've been working on Kommand since I originally posted it and I've made quite a few changes. I'd recommend that you download it again and use the new version. Anyway, the concept is still the same, so I'll try to answer your questions below.

Could you please clarify as to what the purpose of SnarlCMD.exe is?


SnarlCMD.exe is used to pass messages from Kommand to Snarl. If you don't have Snarl installed on your machine, then it shouldn't do anything (although I haven't tested that out). It is NOT a standalone application. I grabbed SnarlCMD.exe from http://www.fullphat....ipts/index.html. It shouldn't cause any problems (I use this script and the included executables on three of my own machines.)

Also if you could answer basically the same questions about CloseWindows.exe.


CloseWindows.exe is something that I found somewhere on the Internets that closes all windows explorer windows. I don't recall where I found it. It works well though. Likewise, nomousy.exe is the compiled version of the nomousy script. The plan is to convert these executables into part of the Kommand script at some future time.

If you're nervous about any of these executables, please remove them. They don't provide that much more additional functionality, but I consider them as a nice touch.

As for the code itself, is there any particular reason you have the hotkeys always enabled and just send the same value when not in Viper mode? Wouldn't it have been better to create the hotkeys on the fly every time you enter/exit Viper mode?


Maybe. I don't know. I did this because it works and seems to work well. What advantages are there dynamically creating them? Would there be a slowdown when switching modes? I don't consider myself as really good with AutoHotKey yet, so I'm always on the lookout for ways to improve.

I noticed it has stuff that seems very specific to you (e.g. JENIVICE, C:\Application\iTunes\PlayPause.vbs, all the shortcuts for launching applications). Would you consider putting all those shortcut keys in a different script?


I moved out all of my custom hot keys into a script in the custom folder. I've left them there in case anyone finds the useful, otherwise I would expect that most users would delete them out. In any event, they're separate now.

Also, with so many shortcut keys to launch applications, how do you remember what each one does?


I use it a lot. :) It is amazing how you can remember so many of these things after using them for a while.

sickpuma
  • Members
  • 8 posts
  • Last active: Nov 18 2009 05:25 AM
  • Joined: 28 May 2009
Thanks for answering the questions and splitting up the script.

Could you please mention that WindowPad is required in order for this script to run? Additionally, could you explain which settings we should use in the ini file that WindowPad uses? By default it seems like WindowPad already binds the caps lock key to something, as does your script. What settings should the ini file have so that there are no conflicts?

Thanks

kylirh
  • Members
  • 19 posts
  • Last active: Nov 13 2009 11:58 PM
  • Joined: 18 Jun 2009
Kommand has a stripped down and slightly modified version of WindowPad in it, so WindowPad isn't "required". Kommand uses some of WindowPad's core functions to move windows around and a few other small things.

If you're going to use WindowPad with Kommand, make sure you start it AFTER Kommand is running. This way WindowPad's keybindings will override Kommand's. You can set whatever settings you want in WindowPad's ini file.

Kommand already has all of the useful features of WindowPad in it. If you're going to pursue the Vi ideology of using the "home row" and not moving all over the keyboard (or using the mouse, heaven forbid!), Kommand should prove to be more than adequate for window management. I would recommend that you don't use WindowPad in conjunction with Kommand.

If you're going to run them both, just keep in mind that Kommand maps to literally every letter on your keyboard. You'll want to keep Win+Capslock open (that toggles "back up" from Insert Mode to Viper Mode to Kommand Mode). Win+Esc completely disables Kommand. Other than that, Kommand mostly binds to letters and numbers. You should be safe using the keypad as those aren't used and probably won't ever be used by Kommand.

sickpuma
  • Members
  • 8 posts
  • Last active: Nov 18 2009 05:25 AM
  • Joined: 28 May 2009
The .zip file that you link to is dated July 13, 2009. The Code you updated in your original post is dated 11/5/09, however it doesn't contain the WindowPad code you are describing. Only the .zip file contains that and it's intertwined with all the old code. I notice that the newer code does however link to WindowPad.ahk; which I'm now guessing is your stripped down version of WindowPad. Could you please include the code for this file as well?

Thanks

kylirh
  • Members
  • 19 posts
  • Last active: Nov 13 2009 11:58 PM
  • Joined: 18 Jun 2009
Weird. I uploaded it again. Can you get to http://kylirhorton.com/kommand.zip?

kli6891
  • Members
  • 46 posts
  • Last active: Nov 24 2012 08:12 PM
  • Joined: 01 Aug 2009
Just as a fyi, the ^+n hotkey to create a new folder in explorer only works on Win7.

kiki
  • Guests
  • Last active:
  • Joined: --
Really nice. As I really like vim I really appreciate your work
fyi ctrl b and ctrl f don't work. I am in windows 7. Perhaps is it time for me to learn a bit autohotkey scripting.