Advertisement
pk3456

ahk text expander 1.1

Apr 28th, 2023 (edited)
173
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #SingleInstance, Force
  2.  
  3. #Hotstring *1 B0
  4. #LTrim
  5.  
  6. ::shape::
  7.     TextExpandList("
  8.    (
  9.        triangle
  10.        square
  11.        pentagon
  12.        hexagon
  13.        heptagon
  14.        octagon
  15.        nonagon
  16.        decagon
  17.        item 9
  18.        item 10
  19.        item 11
  20.        item 12
  21.        item 13
  22.        item 14
  23.        item 15
  24.        item 16
  25.        item 17
  26.        item 18
  27.        item 19
  28.        item 20
  29.    )")
  30. Return
  31.  
  32. ; example
  33. ::Num::
  34.     TextExpandList("
  35.    (
  36.        one
  37.        two
  38.        three
  39.        four
  40.        five
  41.        six
  42.    )")
  43. Return
  44.  
  45. #Hotstring *0 B1
  46. #LTrim Off
  47.  
  48. ; ----------------------------------------------------------------------------------------
  49.  
  50. #If WinExist("ahk_id" TextExpandList.GuiHwnd)
  51.  
  52.     Tab::TextExpandList.NextPage()
  53.  
  54.     NumpadDown::
  55.     Down::
  56.         TextExpandList.SelectDown(1)
  57.     Return
  58.  
  59.     +Tab::TextExpandList.PrevPage()
  60.  
  61.     NumpadUp::
  62.     Up::
  63.         TextExpandList.SelectUp(1)
  64.     Return
  65.  
  66.     Enter::TextExpandList.Submit()
  67.  
  68.     Esc::TextExpandList.HideGui()
  69.  
  70. #If
  71.  
  72. TextExpandList(MatchList) {
  73.     TextExpandList.ShowGui(MatchList)
  74. }
  75.  
  76. ; ----------------------------------------------------------------------------------------
  77. class TextExpandList {
  78.  
  79.     static  Title := "Custom Text Expander"
  80.           , TypeSize := 12
  81.           , TypeFace := "Segoe UI"
  82.           , AutoInsertSpace := True
  83.  
  84.     ShowGui(MatchList) {
  85.         static GuiCreated
  86.  
  87.         ; Make new gui if not created yet
  88.         if !GuiCreated {
  89.             static WS_EX_COMPOSITED    := 0x2000000
  90.             static WS_EX_LAYERED       := 0x0080000
  91.             static DOUBLE_BUFFER       := WS_EX_COMPOSITED | WS_EX_LAYERED
  92.             Gui New, -Caption +ToolWindow +AlwaysOnTop +hwndGuiHwnd -DPIScale +E%DOUBLE_BUFFER%, % this.Title
  93.             ; hwnd of Gui root window
  94.             this.GuiHwnd := GuiHwnd
  95.             Gui font, % "s" this.TypeSize, % this.TypeFace
  96.             Gui Margin, 0, 0
  97.             ; AltSubmit makes listbox save position instead of name
  98.             Gui Add, ListBox, VScroll x0 y0 +hwndHLB +AltSubmit
  99.             ; hwnd to listbox
  100.             this.HLB := HLB
  101.             ; get height of a single item in listbox
  102.             this.ItemHeight := this.LB_GetItemHeight(this.HLB)
  103.             GuiCreated := True
  104.  
  105.             ih := this.KeyHook := InputHook("V")
  106.             ih.KeyOpt("{All}", "+E")
  107.             ih.KeyOpt("1234567890", "-E +SN")
  108.             ih.KeyOpt("{LCtrl}{RCtrl}{LAlt}{RAlt}{LShift}{RShift}{LWin}{RWin}{NumLock}{CapsLock}{ScrollLock}{PrintScreen}", "-NE")
  109.             ih.OnKeyDown := ObjBindMethod(TextExpandList, "OnKeyDown_TextExpandLB")
  110.             ih.OnEnd := ObjBindMethod(TextExpandList, "OnEnd_TextExpandLB")
  111.         }
  112.  
  113.         Gui % this.GuiHwnd ":Default"
  114.         ; remember the hotstring used to trigger this function, remove the options and colons at the front
  115.         this.HotstringText := RegExReplace(A_ThisHotkey, "^:.*?:")
  116.  
  117.         caret := this.GetCaret()
  118.         Gui % this.GuiHwnd ":Show", % "Hide AutoSize x" caret.x " y" caret.y + 40
  119.  
  120.         this.MatchList := MatchList
  121.         this.MatchListItemCount := StrSplit(this.MatchList, "`n", "`r").Length()
  122.         this.ItemRangeMin := 1
  123.         this.ItemRangeMax := 10
  124.  
  125.         this.UpdateListBox()
  126.  
  127.         this.KeyHook.Start()
  128.         WinWaitClose % "ahk_id" this.GuiHwnd
  129.         (this.KeyHook.InProgress) && this.KeyHook.Stop()
  130.     }
  131.  
  132.     UpdateListBox() {
  133.         newList := this.ItemListFromRange(this.ItemRangeMin, this.ItemRangeMax)
  134.  
  135.         ; modify ListBox content
  136.         ; you need the leading | to replace the content
  137.         GuiControl, , % this.HLB, |%newList%
  138.  
  139.         ; get width
  140.         MaxWidth := 0
  141.         Loop Parse, newList, |
  142.         {
  143.             Width := this.TextWidth(A_LoopField, this.TypeFace, this.TypeSize)
  144.             MaxWidth := Max(Width, MaxWidth)
  145.         }
  146.         ; add a little room to the end of the item
  147.         MaxWidth += 20
  148.  
  149.         ; get height
  150.         GuiControlGet, List, Pos, % this.HLB
  151.         Items := this.LB_GetCount(this.HLB)
  152.         ClientHeight := this.GetClientHeight(this.HLB)
  153.         VisibleItems := ClientHeight // this.ItemHeight
  154.         if (Items > 10) {
  155.             Items := 10
  156.             MaxWidth += 15
  157.         }
  158.         ListH += (Items - VisibleItems) * this.ItemHeight
  159.         ; resize control
  160.         GuiControl Move, % this.HLB, % "h" ListH " w" MaxWidth
  161.         Gui % this.GuiHwnd ":Show", NA AutoSize
  162.         GuiControl MoveDraw, % this.HLB
  163.     }
  164.  
  165.     ItemListFromRange(lowRange, highRange) {
  166.         newList := ""
  167.         index := 1
  168.         Loop Parse, % this.MatchList, `n, `r
  169.         {
  170.             if !(lowRange <= A_Index && A_Index <= highRange)
  171.                 continue
  172.  
  173.             ; put the item number in front of the current item
  174.             newList .= A_Index (A_Index < 10 ? "     " : "   ")
  175.  
  176.             ; append each item
  177.             newList .= A_LoopField (index = 1 ? "||" : "|")
  178.             index++
  179.         }
  180.         return newList
  181.     }
  182.  
  183.     NextPage() {
  184.         this.ItemRangeMin += 10
  185.         this.ItemRangeMax += 10
  186.         if (this.ItemRangeMin > this.MatchListItemCount) {
  187.             this.ItemRangeMin := 1
  188.             this.ItemRangeMax := 10
  189.         }
  190.         this.UpdateListBox()
  191.     }
  192.  
  193.     PrevPage() {
  194.         this.ItemRangeMin -= 10
  195.         this.ItemRangeMax := this.ItemRangeMin + 9
  196.         if !(pageItemCount := Mod(this.MatchListItemCount, 10))
  197.             pageItemCount := 10
  198.         if (this.ItemRangeMin < 1) {
  199.             this.ItemRangeMin := this.MatchListItemCount - pageItemCount + 1
  200.             this.ItemRangeMax := this.ItemRangeMin + pageItemCount
  201.         }
  202.         this.UpdateListBox()
  203.     }
  204.  
  205.     ; ----------------------------------------------------------------------------------------
  206.     OnKeyDown_TextExpandLB(InputHook, VK, SC) {
  207.         static chooseNum := ""
  208.         static timeSinceLastKey := ""
  209.         key := GetKeyName(Format("vk{:x}", VK) Format("sc{:x}", SC))
  210.         ChooseNum := (key = 0) ? 10 : key
  211.         if (ChooseNum <= this.LB_GetCount(this.HLB)) {
  212.             GuiControl Choose, % this.HLB, % chooseNum
  213.             this.Submit()
  214.         } else {
  215.             this.HideGui()
  216.         }
  217.     }
  218.     OnEnd_TextExpandLB(InputHook) {
  219.         this.HideGui()
  220.     }
  221.     ; ----------------------------------------------------------------------------------------
  222.     ; function when item is selected
  223.     Submit() {
  224.         Gui % this.GuiHwnd ":Default"
  225.         ; remove AltSubmit to get text instead of pos
  226.         GuiControl -AltSubmit, % this.HLB
  227.         GuiControlGet, LBText,, % this.HLB
  228.         GuiControl +AltSubmit, % this.HLB
  229.         GuiControlGet LBPos,, % this.HLB
  230.         this.HideGui()
  231.  
  232.         ; use length of hotstring trigger to delete the hotstring word
  233.         SendInput % "{BS " StrLen(this.HotstringText) "}"
  234.  
  235.         ; send the item selected from listbox
  236.         ClipSend(RegExReplace(LBText, "^\d+ +"))
  237.  
  238.         if (this.AutoInsertSpace)
  239.             SendInput % A_Space
  240.     }
  241.     ; ----------------------------------------------------------------------------------------
  242.     ; function for selecting previous item
  243.     ; item selection wraps around to last item if first item is selected when pressing up
  244.     SelectUp(steps := 1) {
  245.         Gui % this.GuiHwnd ":Default"
  246.         GuiControlGet ItemPos,, % this.HLB
  247.         LastItem := this.LB_GetCount(this.HLB)
  248.         newPos := itemPos - steps
  249.         if (newPos < 1)
  250.             newPos := LastItem + 1 - steps
  251.         GuiControl Choose, % this.HLB, % newPos
  252.     }
  253.     ; ----------------------------------------------------------------------------------------
  254.     ; function for selecting next item
  255.     ; item selection wraps around to first item if last item is selected when pressing up
  256.     SelectDown(steps := 1) {
  257.         Gui % this.GuiHwnd ":Default"
  258.         GuiControlGet itemPos,, % this.HLB
  259.         LastItem := this.LB_GetCount(this.HLB)
  260.         newPos := itemPos + steps
  261.         if (newPos > LastItem)
  262.             newPos -= LastItem
  263.         GuiControl Choose, % this.HLB, % newPos
  264.     }
  265.     ; ----------------------------------------------------------------------------------------
  266.     HideGui() {
  267.         Gui % this.GuiHwnd ":Hide"
  268.         Hotstring("Reset")
  269.     }
  270.     ; ----------------------------------------------------------------------------------------
  271.     GetClientHeight(HWND) { ; Retrieves the height of the client area.
  272.         VarSetCapacity(RECT, 16, 0)
  273.         DllCall("User32.dll\GetClientRect", "Ptr", HWND, "Ptr", &RECT)
  274.         Return NumGet(RECT, 12, "Int")
  275.     }
  276.     ; ----------------------------------------------------------------------------------------
  277.     LB_GetItemHeight(HLB) { ; Retrieves the height of a single list box item.
  278.     ; LB_GETITEMHEIGHT = 0x01A1
  279.     SendMessage, 0x01A1, 0, 0, , ahk_id %HLB%
  280.     Return ErrorLevel
  281.     }
  282.     ; ----------------------------------------------------------------------------------------
  283.     LB_GetCount(HLB) { ; Retrieves the number of items in the list box.
  284.         ; LB_GETCOUNT = 0x018B
  285.         SendMessage, 0x018B, 0, 0, , ahk_id %HLB%
  286.         Return ErrorLevel
  287.     }
  288.     ; ----------------------------------------------------------------------------------------
  289.     TextWidth(String, Typeface:="Segoe UI", Size:=12)
  290.     {
  291.         static hDC, hFont := 0, Extent
  292.         If !hFont
  293.         {
  294.             hDC := DllCall("GetDC","UPtr",0,"UPtr")
  295.             Height := -DllCall("MulDiv","Int",Size,"Int",DllCall("GetDeviceCaps","UPtr",hDC,"Int",90),"Int",72)
  296.             hFont := DllCall("CreateFont","Int",Height,"Int",0,"Int",0,"Int",0,"Int",400,"UInt",False,"UInt",False,"UInt",False,"UInt",0,"UInt",0,"UInt",0,"UInt",0,"UInt",0,"Str",Typeface)
  297.             hOriginalFont := DllCall("SelectObject","UPtr",hDC,"UPtr",hFont,"UPtr")
  298.             VarSetCapacity(Extent,8)
  299.         }
  300.         DllCall("GetTextExtentPoint32","UPtr",hDC,"Str",String,"Int",StrLen(String),"UPtr",&Extent)
  301.         Return, NumGet(Extent,0,"UInt")
  302.     }
  303.     ; ----------------------------------------------------------------------------------------
  304.     GetCaret() {
  305.         oc := A_CoordModeCaret
  306.         CoordMode Caret, Screen
  307.         ; get caret using A_CaretX and A_CaretY
  308.         ; if A_CaretX and A_CaretY cannot be found, use acc method
  309.         if (A_CaretX) {
  310.             caret := { x: A_CaretX, y: A_CaretY }
  311.         } else {
  312.             Sleep 20
  313.             activeHwnd := WinExist("A")
  314.             oAcc := this.Acc_ObjectFromWindow(activeHwnd, OBJID_CARET := 0xFFFFFFF8)
  315.             oAccCaret := this.Acc_Location(oAcc)
  316.             caret := { x: oAccCaret.x, y: oAccCaret.y }
  317.         }
  318.         ; revert caret coordmode to original
  319.         CoordMode Caret, % oc
  320.  
  321.         WinGetPos, X, Y, W, H, % "ahk_id " WinActive("A")
  322.  
  323.         ; no caret found?
  324.         ; try using the location of the focused acc
  325.         if (caret.x = 0) && (caret.y = 0) {
  326.             oAcc := this.Acc_Location(this.Acc_Focus(activeHwnd))
  327.             caret := {x: oAcc.x, y: oAcc.y}
  328.         }
  329.  
  330.         return caret
  331.     }
  332.     ; ----------------------------------------------------------------------------------------
  333.     ; https://www.autohotkey.com/boards/viewtopic.php?p=404749#p404749
  334.     ; the accFocus "call" returns an Object if successful and an error code if not.
  335.     ; So the while loop returns the last object were the accFocus call returns successfully.
  336.     Acc_Focus(hWnd)
  337.     {
  338.         Acc := this.Acc_ObjectFromWindow(hWnd)
  339.         While IsObject(Acc.accFocus)
  340.             Acc := Acc.accFocus
  341.  
  342.         return Acc
  343.     }
  344.     ; ----------------------------------------------------------------------------------------
  345.     Acc_WindowFromObject(pacc)
  346.     {
  347.         If  DllCall("oleacc\WindowFromAccessibleObject", "Ptr", IsObject(pacc)?ComObjValue(pacc):pacc, "Ptr*", hWnd)=0
  348.         Return  hWnd
  349.     }
  350.     ; ----------------------------------------------------------------------------------------
  351.     Acc_ObjectFromWindow(hWnd, idObject = -4)
  352.     {
  353.         static h := DllCall("LoadLibrary","Str","oleacc","Ptr")
  354.         If  DllCall("oleacc\AccessibleObjectFromWindow", "Ptr", hWnd, "UInt", idObject&=0xFFFFFFFF, "Ptr", -VarSetCapacity(IID,16)+NumPut(idObject==0xFFFFFFF0?0x46000000000000C0:0x719B3800AA000C81,NumPut(idObject==0xFFFFFFF0?0x0000000000020400:0x11CF3C3D618736E0,IID,"Int64"),"Int64"), "Ptr*", pacc)=0
  355.         Return ComObjEnwrap(9,pacc,1)
  356.     }
  357.     ; ----------------------------------------------------------------------------------------
  358.     Acc_Location(Acc, ChildId=0, byref Position="") { ; adapted from Sean's code
  359.         try Acc.accLocation(ComObj(0x4003,&x:=0), ComObj(0x4003,&y:=0), ComObj(0x4003,&w:=0), ComObj(0x4003,&h:=0), ChildId)
  360.         catch
  361.             return
  362.         Position := "x" NumGet(x,0,"int") " y" NumGet(y,0,"int") " w" NumGet(w,0,"int") " h" NumGet(h,0,"int")
  363.         return {x:NumGet(x,0,"int"), y:NumGet(y,0,"int"), w:NumGet(w,0,"int"), h:NumGet(h,0,"int")}
  364.     }
  365. }
  366.  
  367. ClipSend(toSend) {
  368.     static prevClip := ""
  369.     prevClip := ClipboardAll
  370.     Clipboard := ""
  371.     Clipboard := toSend
  372.     ClipWait, 1
  373.     Send, {ctrl down}v{ctrl up}
  374.     SetTimer, RevertClipboard, -100
  375.     Return
  376.     RevertClipboard:
  377.        Clipboard := prevClip
  378.         prevClip := ""
  379.     Return
  380. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement