Advertisement
pk3456

auto suggestion

Sep 8th, 2023 (edited)
688
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Autohotkey 11.33 KB | Source Code | 0 0
  1. #Requires AutoHotkey v2.0
  2.  
  3. ; example: type `` then type "wdyw" to trigger "what do you want"
  4. :B0X?*:````::AutoSuggestion("
  5. (
  6.    as a reminder
  7.    as a result
  8.    at any rate
  9.    what do you expect
  10.    what do you have
  11.    what do you like
  12.    what do you mean
  13.    what do you think
  14.    what do you want
  15.    any time
  16.    all things considered
  17.    all-time high
  18.    all-time low
  19.    at the moment
  20.    according to my memory
  21.    at this rate
  22.    all the same
  23.    all that time
  24.    attention
  25. )")
  26.  
  27. AutoSuggestion(textList) {
  28.     static txtList := Sort(textList), ih, g, LB, _ := Init(), TriggerLength := StrLen(RegExReplace(A_ThisHotkey, "^:.*?:"))
  29.     Init() {
  30.         ih := InputHook("V M I101")
  31.         ih.OnChar := OnChar
  32.         ih.OnKeyDown := OnKeyDown
  33.         ih.KeyOpt("{LAlt}{RAlt}{LWin}{RWin}{AppsKey}{F1}{F2}{F3}{F4}{F5}{F6}{F7}{F8}{F9}{F10}{F11}{F12}{Left}{Right}{Home}{End}{PgUp}{PgDn}{Del}{Ins}{BS}{CapsLock}{ScrollLock}{NumLock}{PrintScreen}{Esc}", "N")
  34.         g := Gui("+AlwaysOnTop -Caption +ToolWindow -DPIScale +E0x02000000") ;  WS_EX_COMPOSITED
  35.         g.SetFont("s12", "Segoe UI")
  36.         g.MarginX := g.MarginY := 1
  37.         LB := g.Add("ListBox", "xm ym r10 -E0x200")
  38.         g.Show("AutoSize Hide")
  39.         ; start the inputhook if ` is pressed
  40.         ; restarts inputhook if ih is in progress
  41.         HotIfWinExist "ahk_id" g.hwnd
  42.         ; Up selects previous item or last item.
  43.         Hotkey "Up", (*) => LB.Value = 1 ? ControlSend("{End}", LB) : --LB.Value
  44.         ; Down selcts next item or first item.
  45.         Hotkey "Down", (*) => LB.Value = ControlGetItems(LB).Length ? ControlSend("{Home}", LB) : ++LB.Value
  46.         Hotkey "Esc", (*) => WinExist("ahk_id" g.hwnd) && (g.Hide(), ih.Stop() )
  47.         Hotkey "Tab", Submit
  48.         Hotkey "Enter", Submit
  49.         ; Click any mouse button to close the menu
  50.         Hotkey "~LButton", MouseAction
  51.         Hotkey "~RButton", MouseAction
  52.         Hotkey "~MButton", MouseAction
  53.         Hotkey "~XButton1", MouseAction
  54.         Hotkey "~XButton2", MouseAction
  55.         ; bind number keys to send item at the position number
  56.         loop 9
  57.             Hotkey A_Index, Choose.Bind(A_Index)
  58.         Hotkey 0, Choose.Bind(10)
  59.         HotIf
  60.         return 1
  61.     }
  62.  
  63.     ih.Stop()
  64.     g.Hide()
  65.     ih.Start()
  66.     Return
  67.  
  68.     MouseAction(ThisHotkey) {
  69.         MouseGetPos(,, &Win)
  70.         if Win = g.hwnd {
  71.             if SubStr(ThisHotkey, 2) = "LButton" {
  72.                 KeyWait "LButton"
  73.                 Submit()
  74.             }
  75.         } else {
  76.             g.Hide(), ih.Stop()
  77.         }
  78.     }
  79.  
  80.     Choose(p, *) {
  81.         if ControlGetItems(LB).Length >= p {
  82.             LB.Value := p
  83.             Submit()
  84.         }
  85.     }
  86.  
  87.     Submit(*) {
  88.         g.Hide()
  89.         SetKeyDelay -1, 1
  90.         RegExMatch(LB.Text, "(^\d\. )|(^ {4})|(^z)", &M) ; remove the number or space in front
  91.         if M.Pos[1]
  92.             Text := SubStr(LB.Text, M.Len[1] + 1)
  93.         else if M[2]
  94.             Text := SubStr(LB.Text, 5)
  95.         SendEvent "{BS " StrLen(ih.Input) + TriggerLength "}" ; remove ` and input
  96.         ; Send using the clipboard
  97.         oc := ClipboardAll()
  98.         Sleep 80
  99.         A_Clipboard := Text
  100.         Sleep 10
  101.         SendEvent "^v"
  102.         Sleep 10
  103.         A_Clipboard := oc
  104.         ih.Stop()
  105.     }
  106.  
  107.     OnChar(ih, char) {
  108.         if (char = "")
  109.         || (Ord(char) >= 1 && Ord(char) <= 26) { ; Ctrl+Key
  110.             g.Hide(), ih.Stop()
  111.             return
  112.         }
  113.         if ih.Input {
  114.             LB.Delete()
  115.             Count := 0
  116.             textWidth := 0
  117.             loop parse txtList, "`n", "`r`t " {
  118.                 ; Match if input contains letters from A_Loopfield without matching exactly
  119.                 matchRegex := RegExReplace(SubStr(ih.Input, 1, 1), "(.)", "(?i:$1).*")
  120.                 if StrLen(ih.Input) > 1
  121.                     matchRegex .= RegExReplace(SubStr(ih.Input, 2), "(.)", "$1.*")
  122.                 If RegExMatch(A_LoopField, "^" matchRegex) {
  123.                     Capitalized := ""
  124.                     if IsUpper(SubStr(ih.Input, 1, 1)) ; If first letter of input is upper case
  125.                         Capitalized := RegExReplace(A_LoopField, "^(.)", "$U1") ; replace first letter of Text with upper case
  126.                     ; Number items from 1 - 9. Make last item 0.
  127.                     if ++Count <= 10
  128.                         Num := (Count < 10 ? Count : "0") ". "
  129.                     else
  130.                         Num := "    "
  131.                     ItemName := Num (Capitalized || A_LoopField)
  132.                     size := GetTextSize(LB, ItemName)
  133.                     textWidth := Max(textWidth, size.W)
  134.                     LB.Add([ItemName])
  135.                 }
  136.             }
  137.             if Count = 0 {
  138.                 ; stop inputhook if you type `, the gui is not open, and there is not match.
  139.                 if !WinExist("ahk_id" g.hwnd)
  140.                     ih.Stop()
  141.                 return
  142.             }
  143.             if Count = 1 {
  144.                 LB.Choose(1)
  145.                 Submit()
  146.                 return
  147.             }
  148.             textWidth += 10
  149.             if Count > 10
  150.                 textWidth += 25
  151.             LB.Move(,, textWidth)
  152.         } else {
  153.             g.Hide() ; Hide menu if input is empty
  154.             ih.Stop()
  155.             return
  156.         }
  157.         LB.Choose(1)
  158.         GetCaretPos(&X, &Y,, &H)
  159.         hMon := DllCall("MonitorFromWindow", "ptr", g.hwnd, "uint", 2, "ptr")
  160.         NumPut("uint", 40, MI := Buffer(40))
  161.         DllCall("user32\GetMonitorInfo", "ptr", hMon, "ptr", MI)
  162.         WR := NumGet(MI, 28, "int")
  163.         WB := NumGet(MI, 32, "int")
  164.         ; make sure menu stays within monitor
  165.         g.GetPos(&gX, &gY, &gW, &gH)
  166.         if X + gW > WR
  167.             X -= gW
  168.         if Y + gH > WB
  169.             Y -= gH
  170.         else
  171.             Y += H
  172.         g.Show("NA x" X " y" Y " AutoSize")
  173.     }
  174.  
  175.     OnKeyDown(ih, VK, SC) {
  176.         if vk = 8 { ; Backspace
  177.             if GetKeyState("Ctrl")
  178.                 OnChar(ih, "")
  179.             else
  180.                 OnChar(ih, "{BS}")
  181.         } else
  182.             OnChar(ih, "")
  183.     }
  184.  
  185.     GetTextSize(ctrl, text) {
  186.         static WM_GETFONT := 0x31, DT_CALCRECT := 0x400
  187.         hFont := SendMessage(WM_GETFONT,,, ctrl)
  188.         hDC := DllCall('GetDC', 'Ptr', 0, 'Ptr')
  189.         hObj := DllCall('SelectObject', 'Ptr', hDC, 'Ptr', hFont, 'Ptr')
  190.         RECT := Buffer(16)
  191.         height := DllCall('DrawText', 'Ptr', hDC, 'Str', text, 'Int', StrLen(text), 'Ptr', RECT, 'UInt', DT_CALCRECT)
  192.         DllCall('SelectObject', 'Ptr', hDC, 'Ptr', hObj, 'Ptr')
  193.         DllCall('ReleaseDC', 'Ptr', 0, 'Ptr', hDC)
  194.         return {w: NumGet(RECT, 8, 'UInt') - NumGet(RECT, 'UInt'), h: height}
  195.     }
  196. }
  197.  
  198. /**
  199.  * Gets the position of the caret with UIA, Acc or CaretGetPos.
  200.  * Descolada's implementation: https://www.autohotkey.com/boards/viewtopic.php?p=576439#p576439
  201.  * @param X Value is set to the screen X-coordinate of the caret
  202.  * @param Y Value is set to the screen Y-coordinate of the caret
  203.  * @param W Value is set to the width of the caret
  204.  * @param H Value is set to the height of the caret
  205.  */
  206. GetCaretPos(&X?, &Y?, &W?, &H?) {
  207.     ; Default caret
  208.     savedCaret := A_CoordModeCaret
  209.     CoordMode "Caret", "Screen"
  210.     CaretGetPos(&X, &Y)
  211.     CoordMode "Caret", savedCaret
  212.     if IsInteger(X) && (X | Y) != 0 {
  213.         W := 4, H := 20
  214.         return
  215.     }
  216.  
  217.     ; Acc caret
  218.     static _ := DllCall("LoadLibrary", "Str","oleacc", "Ptr")
  219.     try {
  220.         idObject := 0xFFFFFFF8 ; OBJID_CARET
  221.         if DllCall("oleacc\AccessibleObjectFromWindow", "ptr", WinExist("A"), "uint",idObject &= 0xFFFFFFFF
  222.             , "ptr",-16 + NumPut("int64", idObject == 0xFFFFFFF0 ? 0x46000000000000C0 : 0x719B3800AA000C81, NumPut("int64", idObject == 0xFFFFFFF0 ? 0x0000000000020400 : 0x11CF3C3D618736E0, IID := Buffer(16)))
  223.             , "ptr*", oAcc := ComValue(9,0)) = 0 {
  224.             x:=Buffer(4), y:=Buffer(4), w:=Buffer(4), h:=Buffer(4)
  225.             oAcc.accLocation(ComValue(0x4003, x.ptr, 1), ComValue(0x4003, y.ptr, 1), ComValue(0x4003, w.ptr, 1), ComValue(0x4003, h.ptr, 1), 0)
  226.             X:=NumGet(x,0,"int"), Y:=NumGet(y,0,"int"), W:=NumGet(w,0,"int"), H:=NumGet(h,0,"int")
  227.             if (X | Y) != 0
  228.                 return
  229.         }
  230.     }
  231.  
  232.     static JAB := InitJAB() ; Source: https://github.com/Elgin1/Java-Access-Bridge-for-AHK
  233.     if JAB && (hWnd := WinExist("A")) && DllCall(JAB.module "\isJavaWindow", "ptr", hWnd, "CDecl Int") {
  234.         if JAB.firstRun
  235.             Sleep(200), JAB.firstRun := 0
  236.         prevThreadDpiAwarenessContext := DllCall("SetThreadDpiAwarenessContext", "ptr", -2, "ptr")
  237.         DllCall(JAB.module "\getAccessibleContextWithFocus", "ptr", hWnd, "Int*", &vmID:=0, JAB.acType "*", &ac:=0, "Cdecl Int") "`n"
  238.         DllCall(JAB.module "\getCaretLocation", "Int", vmID, JAB.acType, ac, "Ptr", Info := Buffer(16,0), "Int", 0, "Cdecl Int")
  239.         DllCall(JAB.module "\releaseJavaObject", "Int", vmId, JAB.acType, ac, "CDecl")
  240.         DllCall("SetThreadDpiAwarenessContext", "ptr", prevThreadDpiAwarenessContext, "ptr")
  241.         X := NumGet(Info, 0, "Int"), Y := NumGet(Info, 4, "Int"), W := NumGet(Info, 8, "Int"), H := NumGet(Info, 12, "Int")
  242.         hMonitor := DllCall("MonitorFromWindow", "ptr", hWnd, "int", 2, "ptr") ; MONITOR_DEFAULTTONEAREST
  243.         DllCall("Shcore.dll\GetDpiForMonitor", "ptr", hMonitor, "int", 0, "uint*", &dpiX:=0, "uint*", &dpiY:=0)
  244.         if dpiX
  245.             X := DllCall("MulDiv", "int", X, "int", dpiX, "int", 96, "int"), Y := DllCall("MulDiv", "int", Y, "int", dpiX, "int", 96, "int")
  246.         if X || Y || W || H
  247.             return
  248.     }
  249.  
  250.     ; UIA caret
  251.     static IUIA := ComObject("{e22ad333-b25f-460c-83d0-0581107395c9}", "{34723aff-0c9d-49d0-9896-7ab52df8cd8a}")
  252.     try {
  253.         ComCall(8, IUIA, "ptr*", &FocusedEl:=0) ; GetFocusedElement
  254.         ComCall(16, FocusedEl, "int", 10014, "ptr*", &patternObject:=0), ObjRelease(FocusedEl) ; GetCurrentPattern. TextPattern = 10014
  255.         if patternObject {
  256.             ComCall(5, patternObject, "ptr*", &selectionRanges:=0), ObjRelease(patternObject) ; GetSelections
  257.             ComCall(4, selectionRanges, "int", 0, "ptr*", &selectionRange:=0) ; GetElement
  258.             ComCall(10, selectionRange, "ptr*", &boundingRects:=0), ObjRelease(selectionRange), ObjRelease(selectionRanges) ; GetBoundingRectangles
  259.             if (Rect := ComValue(0x2005, boundingRects)).MaxIndex() = 3 { ; VT_ARRAY | VT_R8
  260.                 X:=Round(Rect[0]), Y:=Round(Rect[1]), W:=Round(Rect[2]), H:=Round(Rect[3])
  261.                 return
  262.             }
  263.         }
  264.     }
  265.  
  266.     InitJAB() {
  267.         ret := {}, ret.firstRun := 1, ret.module := A_PtrSize = 8 ? "WindowsAccessBridge-64.dll" : "WindowsAccessBridge-32.dll", ret.acType := "Int64"
  268.         ret.DefineProp("__Delete", {call: (this) => DllCall("FreeLibrary", "ptr", this)})
  269.         if !(ret.ptr := DllCall("LoadLibrary", "Str", ret.module, "ptr")) && A_PtrSize = 4 {
  270.              ; try legacy, available only for 32-bit
  271.              ret.acType := "Int", ret.module := "WindowsAccessBridge.dll", ret.ptr := DllCall("LoadLibrary", "Str", ret.module, "ptr")
  272.         }
  273.         if !ret.ptr
  274.             return ; Failed to load library. Make sure you are running the script in the correct bitness and/or Java for the architecture is installed.
  275.         DllCall(ret.module "\Windows_run", "Cdecl Int")
  276.         return ret
  277.     }
  278. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement