AutoHotkey Tip of the Week: Instant Upper Case, Lower Case, and Initial Cap Text—September 2, 2019

Tips: Quick Hotkeys for Changing Text To/From Capital Letters and How to Initial Cap Everything, Plus, How to Write Robust Clipboard Routines

Light Bulb!This week I offer two useful tips: one for editing text and the other for improving your AutoHotkey scripts.

When reviewing my books, I look for those tips which I use all the time. I’ve found that I developed some scripts primarily for demonstration purposes and rarely ever use them again. Yet, I have a few which I use so much that I feel like they have become a part of my Windows system.

AHKNewCover200In this case, while perusing my Beginner’s Guide to AutoHotkey, I noticed in “Chapter Four: Hotkeys and Text Editing with Windows Clipboard” the Hotkeys for changing selected portions of text into all capital letters, all lowercase letters, or initial cap every word in the section. I originally wrote these Hotkeys when I edited articles submitted by freelance writers.

Some writers have a penchant for placing their article headlines and topic subheadings in all uppercase letters. By creating a Hotkey for converting the entire line to Title Mode (initial capital letter for each word), I quickly solved the retyping problem:

+^k:: ; SHIFT+CTRL+K converts text to capitalized
  Clipboard := ""
  SendInput, ^c ;copies selected text
  StringUpper Clipboard, Clipboard, T ; Title mode conversion
  SendInput %Clipboard%

This Hotkey mostly fixes the all-caps text by converting every word to initial caps. However, I did need to revert some prepositions and connectors to lowercase as appropriate (e.g. Andand, Forfor, Toto, etc):

^l:: ; CTRL+L converts text to lower
  Clipboard := ""
  SendInput, ^c ;copies selected text
  StringLower Clipboard, Clipboard
  SendInput %Clipboard%

Less often, when I wanted to yell, I included a routine for changing the selected text to all caps:

^u:: ; CTRL+U converts text to upper
  Clipboard := ""
  SendInput, ^c ;copies selected text
  StringUpper Clipboard, Clipboard
  SendInput %Clipboard%

Although I rarely edit other people’s writing these days, I continue to use the three Hotkeys regularly.

Tip #2: Standard AutoHotkey Windows Clipboard Routine

hotkeycover200As shown in “Chapter Five: Sharing AutoHotkey Scripts and Restoring the Clipboard’s Original Contents” of my Beginner’s Guide and discussed in greater detail in Chapter Nine of my AutoHotkey Hotkey Techniques book, you can add a number of features to the AutoHotkey Clipboard routines shown above which make them more robust. I recommend that you add these extras to every Clipboard routine you write (shown in red):

OldClipboard := ClipboardAll
Clipboard := "" ; Clears the Clipboard
SendInput, ^c
ClipWait 0 ; Pause for Clipboard data
If ErrorLevel
MsgBox, No text selected!
StringUpper Clipboard, Clipboard ; Clipboard manipulation code
SendInput, %Clipboard%
Sleep 200
Clipboard := OldClipboard

This routine saves and restores the original contents of the Windows Clipboard. It also uses ErrorLevel in conjunction with the ClipWait command to warn you if the Clipboard copy fails. When writing other Clipboard dependent routines, replace the StringUpper Clipboard, Clipboard statement with the relevant Clipboard manipulation code. You can use this example as a template for your Clipboard routines.

Alternative Approach with Format() Function

Starting with AutoHotkey Version [v1.1.20+]: you can replace the StringLower command with the Format() function for case conversions, as shown below:

MsgBox % Format("{:U}, {:L}, {:T}", "upper", "LOWER", "title")

For the examples in this tip, send all caps:

SendInput % Format("{:U}", Clipboard)

Convert to lowercase:

SendInput % Format("{:L}", Clipboard)

Capitalize the first letter of each word:

SendInput % Format("{:T}", Clipboard)

You can use each single line to replace two lines in each Hotkey:

StringUpper Clipboard, Clipboard, T
SendInput %Clipboard%

Click the Follow button at the top of the sidebar on the right of this page for e-mail notification of new blogs. (If you’re reading this on a tablet or your phone, then you must scroll all the way to the end of the blog—pass any comments—to find the Follow button.)


This post was proofread by Grammarly
(Any other mistakes are all mine.)

(Full disclosure: If you sign up for a free Grammarly account, I get 20¢. I use the spelling/grammar checking service all the time, but, then again, I write a lot more than most people. I recommend Grammarly because it works and it’s free.)



7 thoughts on “AutoHotkey Tip of the Week: Instant Upper Case, Lower Case, and Initial Cap Text—September 2, 2019

    • There are a number of ways to do most of what you want but the easiest is to create a Hotstring for each possible capital letter:

      :C?*:. a::. A
      :C?*:. b::. B
      :C?*:. c::. C

      Then add all twenty-six letters. The C option forces the Hotstring to look at the case (it won’t fire for uppercase letters) and the asterisk makes it fire immediately. However, since the Hotstring resets, any other autocorrect will not work on the first word of a sentence.

      The following will capitalize the first new letter after a newline character:


      You still need to capitalize the first letter of the document (no newline character).

      Alternatively, you could write a script using Regular Expressions (RegEx) to search and capitalizes all sentences. That’s a little more complicated.

      See the next reply for a RegEx example.

      For the Hotstrings set up in a loop, see the third reply below.


    • I found this example which uses Regular Expressions (RegEx) to create Hotstrings. I plan to write about this one.

      Copy the following into an AutoHotkey script (.ahk):

      hotstrings("\.\s+(\w)", "label")
      Stringupper, $1, $1
      Sendinput, % ". " $1
          Function: HotStrings
              Dynamically adds regular expression hotstrings.
              c - regular expression hotstring
              a - (optional) text to replace hotstring with or a label to goto,
                  leave blank to remove hotstring definition from triggering an action
      > hotstrings("(B|b)tw\s", "%$1%y the way") ; type 'btw' followed by space, tab or return
      > hotstrings("i)omg", "oh my god!") ; type 'OMG' in any case, upper, lower or mixed
      > hotstrings("\bcolou?r", "rgb(128, 255, 0);") ; '\b' prevents matching with anything before the word, e.g. 'multicololoured'
              - RegEx Dynamic Hotstrings: Modified version by Edd  
              - Original: 
              - Dedicated to the public domain (CC0 1.0) 
      hotstrings(k, a = "", Options:="")
          static z, m = "~$", m_ = "*~$", s, t, w = 2000, sd, d = "Left,Right,Up,Down,Home,End,RButton,LButton", f = "!,+,^,#", f_="{,}"
          global $
          If z = ; init
              RegRead, sd, HKCU, Control Panel\International, sDecimal
              Loop, 94
                  c := Chr(A_Index + 32)
                  If A_Index between 33 and 58
                      Hotkey, %m_%%c%, __hs
                  else If A_Index not between 65 and 90
                      Hotkey, %m%%c%, __hs
              e = 0,1,2,3,4,5,6,7,8,9,Dot,Div,Mult,Add,Sub,Enter
              Loop, Parse, e, `,
                  Hotkey, %m%Numpad%A_LoopField%, __hs
              e = BS,Shift,Space,Enter,Return,Tab,%d%
              Loop, Parse, e, `,
                  Hotkey, %m%%A_LoopField%, __hs
              z = 1
          If (a == "" and k == "") ; poll
              q:=RegExReplace(A_ThisHotkey, "\*\~\$(.*)", "$1")
              q:=RegExReplace(q, "\~\$(.*)", "$1")
              If q = BS
                  If (SubStr(s, 0) != "}")
                      StringTrimRight, s, s, 1
              Else If q in %d%
                  s =
                  If q = Shift
                  Else If q = Space
                      q := " "
                  Else If q = Tab
                      q := "`t"
                  Else If q in Enter,Return,NumpadEnter
                      q := "`n"
                  Else If (RegExMatch(q, "Numpad(.+)", n))
                      q := n1 == "Div" ? "/" : n1 == "Mult" ? "*" : n1 == "Add" ? "+" : n1 == "Sub" ? "-" : n1 == "Dot" ? sd : ""
                      If n1 is digit
                          q = %n1%
                  Else If (GetKeyState("Shift") ^ !GetKeyState("CapsLock", "T"))
                      StringLower, q, q
                  s .= q
              Loop, Parse, t, `n ; check
                  StringSplit, x, A_LoopField, `r
                  If (RegExMatch(s, x1 . "$", $)) ; match
                      StringLen, l, $
                      StringTrimRight, s, s, l
                      if !(x3~="i)\bNB\b")        ; if No Backspce "NB"
                          SendInput, {BS %l%}
                      If (IsLabel(x2))
                          Gosub, %x2%
                          Transform, x0, Deref, %x2%
                          Loop, Parse, f_, `,
                              StringReplace, x0, x0, %A_LoopField%, ¥%A_LoopField%¥, All
                          Loop, Parse, f_, `,
                              StringReplace, x0, x0, ¥%A_LoopField%¥, {%A_LoopField%}, All
                          Loop, Parse, f, `,
                              StringReplace, x0, x0, %A_LoopField%, {%A_LoopField%}, All
                          SendInput, %x0%
              If (StrLen(s) > w)
                  StringTrimLeft, s, s, w // 2
          Else ; assert
              StringReplace, k, k, `n, \n, All ; normalize
              StringReplace, k, k, `r, \r, All
              Loop, Parse, t, `n
                  l = %A_LoopField%
                  If (SubStr(l, 1, InStr(l, "`r") - 1) == k)
                      StringReplace, t, t, `n%l%
              If a !=
                  t = %t%`n%k%`r%a%`r%Options%
          __hs: ; event
          hotstrings("", "", Options)


    • Using the Hotstring() function the following script should do the job:

      Loop, 26 
      	Hotstring(":C?*:. " . Chr(A_Index + 96),". " . Chr(A_Index + 64))
      Loop, 26 
      	Hotstring(":CR?*:! " . Chr(A_Index + 96),"! " . Chr(A_Index + 64))
      Loop, 26 
      	Hotstring(":C?*:? " . Chr(A_Index + 96),"? " . Chr(A_Index + 64))
      Loop, 26 
      	Hotstring(":C?*:`n" . Chr(A_Index + 96),"`ns" . Chr(A_Index + 64))

      This one also capitalizes after “!” and “?”.


  1. Hello is there any way to exclude the words you mentioned ” and, but, if, or” from being capitalized? Something that recognizes the word with blank spaces around it and leaves it alone?

    Btw love this script youve written! i always thought this should be a native function on windows.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s