├── (3) Class LV_Colors v2.0 - 2023-05-06 - AutoHotkey Community.md ├── (3) Hotstring Manager - AutoHotkey Community.md ├── AHK_V12V2.md ├── Chrome_ConvertBookmarks.py ├── Chrome_CreateShortcut.ahk ├── Chrome_Download.ahk ├── Chrome_GenBookmarks.ahk ├── Chrome_GetBookmarks.ahk ├── Chrome_GetIcon.md ├── Chrome_PinToTaskbar.ahk ├── Chrome_SmartClick.md ├── DownloadInfo.py ├── Everything_PasteTo.ahk ├── Everything_PasteTo.md ├── HelpFile.ahk ├── Ini_File_Lib.ahk ├── README.md ├── TC_AHK_Lib.ahk ├── TC_Minimal_interface.md ├── TC_Open.ahk ├── TC_Open.md ├── TC_OpenTCWithFileSelected.ahk ├── TC_QuickMove.ahk ├── TC_Run.ahk ├── TC_SendMessage.md ├── TC_SmartOpen.ahk ├── TC_替代Explorer的配置.md ├── Tools └── ColorPicker.ahk ├── TotalComander ├── TC_VBA_Interposer.ahk └── TC_VBA_SendData.vbs └── lib └── _JXON.ahk /(3) Class LV_Colors v2.0 - 2023-05-06 - AutoHotkey Community.md: -------------------------------------------------------------------------------- 1 | # (3) Class LV_Colors v2.0 - 2023-05-06 - AutoHotkey Community 2 | `#Requires AutoHotkey v2.0.1 ; ====================================================================================================================== ; Namespace: LV_Colors ; Function: Individual row and cell coloring for AHK ListView controls. ; Tested with: AHK 2.0.2 (U32/U64) ; Tested on: Win 10 (x64) ; Changelog: 2023-01-04/2.0.0/just me Initial release of the AHK v2 version ; ====================================================================================================================== ; CLASS LV_Colors ; ; The class provides methods to set individual colors for rows and/or cells, to clear all colors, to prevent/allow ; sorting and rezising of columns dynamically, and to deactivate/activate the notification handler for NM_CUSTOMDRAW ; notifications (see below). ; ; A message handler for NM_CUSTOMDRAW notifications will be activated for the specified ListView whenever a new ; instance is created. If you want to temporarily disable coloring call MyInstance.ShowColors(False). This must ; be done also before you try to destroy the instance. To enable it again, call MyInstance.ShowColors(). ; ; To avoid the loss of Gui events and messages the message handler is set 'critical'. To prevent 'freezing' of the ; list-view or the whole GUI this script requires AHK v2.0.1+. ; ====================================================================================================================== Class LV_Colors { ; =================================================================================================================== ; __New() Constructor - Create a new LV_Colors instance for the given ListView ; Parameters: HWND - ListView's HWND. ; Optional ------------------------------------------------------------------------------------------ ; StaticMode - Static color assignment, i.e. the colors will be assigned permanently to the row ; contents rather than to the row number. ; Values: True/False ; Default: False ; NoSort - Prevent sorting by click on a header item. ; Values: True/False ; Default: False ; NoSizing - Prevent resizing of columns. ; Values: True/False ; Default: False ; =================================================================================================================== __New(LV, StaticMode := False, NoSort := False, NoSizing := False) { If (LV.Type != "ListView") Throw TypeError("LV_Colors requires a ListView control!", -1, LV.Type) ; ---------------------------------------------------------------------------------------------------------------- ; Set LVS_EX_DOUBLEBUFFER (0x010000) style to avoid drawing issues. LV.Opt("+LV0x010000") ; Get the default colors BkClr := SendMessage(0x1025, 0, 0, LV) ; LVM_GETTEXTBKCOLOR TxClr := SendMessage(0x1023, 0, 0, LV) ; LVM_GETTEXTCOLOR ; Get the header control Header := SendMessage(0x101F, 0, 0, LV) ; LVM_GETHEADER ; Set other properties This.LV := LV This.HWND := LV.HWND This.Header := Header This.BkClr := BkCLr This.TxClr := Txclr This.IsStatic := !!StaticMode This.AltCols := False This.AltRows := False This.SelColors := False This.NoSort(!!NoSort) This.NoSizing(!!NoSizing) This.ShowColors() This.RowCount := LV.GetCount() This.ColCount := LV.GetCount("Col") This.Rows := Map() This.Rows.Capacity := This.RowCount This.Cells := Map() This.Cells.Capacity := This.RowCount } ; =================================================================================================================== ; __Delete() Destructor ; =================================================================================================================== __Delete() { This.ShowColors(False) If WinExist(This.HWND) WinRedraw(This.HWND) } ; =================================================================================================================== ; Clear() Clears all row and cell colors. ; Parameters: AltRows - Reset alternate row coloring (True / False) ; Default: False ; AltCols - Reset alternate column coloring (True / False) ; Default: False ; Return Value: Always True. ; =================================================================================================================== Clear(AltRows := False, AltCols := False) { If (AltCols) This.AltCols := False If (AltRows) This.AltRows := False This.Rows.Clear() This.Rows.Capacity := This.RowCount This.Cells.Clear() This.Cells.Capacity := This.RowCount Return True } ; =================================================================================================================== ; UpdateProps() Updates the RowCount, ColCount, BkClr, and TxClr properties. ; Return Value: True on success, otherwise false. ; =================================================================================================================== UpdateProps() { If !(This.HWND) Return False This.BkClr := SendMessage(0x1025, 0, 0, This.LV) ; LVM_GETTEXTBKCOLOR This.TxClr := SendMessage(0x1023, 0, 0, This.LV) ; LVM_GETTEXTCOLOR This.RowCount := This.LV.GetCount() This.Colcount := This.LV.GetCount("Col") If WinExist(This.HWND) WinRedraw(This.HWND) Return True } ; =================================================================================================================== ; AlternateRows() Sets background and/or text color for even row numbers. ; Parameters: BkColor - Background color as RGB color integer (e.g. 0xFF0000 = red) or HTML color name. ; Default: Empty -> default background color ; TxColor - Text color as RGB color integer (e.g. 0xFF0000 = red) or HTML color name. ; Default: Empty -> default text color ; Return Value: True on success, otherwise false. ; =================================================================================================================== AlternateRows(BkColor := "", TxColor := "") { If !(This.HWND) Return False This.AltRows := False If (BkColor = "") && (TxColor = "") Return True BkBGR := This.BGR(BkColor) TxBGR := This.BGR(TxColor) If (BkBGR = "") && (TxBGR = "") Return False This.ARB := (BkBGR != "") ? BkBGR : This.BkClr This.ART := (TxBGR != "") ? TxBGR : This.TxClr This.AltRows := True Return True } ; =================================================================================================================== ; AlternateCols() Sets background and/or text color for even column numbers. ; Parameters: BkColor - Background color as RGB color integer (e.g. 0xFF0000 = red) or HTML color name. ; Default: Empty -> default background color ; TxColor - Text color as RGB color integer (e.g. 0xFF0000 = red) or HTML color name. ; Default: Empty -> default text color ; Return Value: True on success, otherwise false. ; =================================================================================================================== AlternateCols(BkColor := "", TxColor := "") { If !(This.HWND) Return False This.AltCols := False If (BkColor = "") && (TxColor = "") Return True BkBGR := This.BGR(BkColor) TxBGR := This.BGR(TxColor) If (BkBGR = "") && (TxBGR = "") Return False This.ACB := (BkBGR != "") ? BkBGR : This.BkClr This.ACT := (TxBGR != "") ? TxBGR : This.TxClr This.AltCols := True Return True } ; =================================================================================================================== ; SelectionColors() Sets background and/or text color for selected rows. ; Parameters: BkColor - Background color as RGB color integer (e.g. 0xFF0000 = red) or HTML color name. ; Default: Empty -> default selected background color ; TxColor - Text color as RGB color integer (e.g. 0xFF0000 = red) or HTML color name. ; Default: Empty -> default selected text color ; Return Value: True on success, otherwise false. ; =================================================================================================================== SelectionColors(BkColor := "", TxColor := "") { If !(This.HWND) Return False This.SelColors := False If (BkColor = "") && (TxColor = "") Return True BkBGR := This.BGR(BkColor) TxBGR := This.BGR(TxColor) If (BkBGR = "") && (TxBGR = "") Return False This.SELB := BkBGR This.SELT := TxBGR This.SelColors := True Return True } ; =================================================================================================================== ; Row() Sets background and/or text color for the specified row. ; Parameters: Row - Row number ; Optional ------------------------------------------------------------------------------------------ ; BkColor - Background color as RGB color integer (e.g. 0xFF0000 = red) or HTML color name. ; Default: Empty -> default background color ; TxColor - Text color as RGB color integer (e.g. 0xFF0000 = red) or HTML color name. ; Default: Empty -> default text color ; Return Value: True on success, otherwise false. ; =================================================================================================================== Row(Row, BkColor := "", TxColor := "") { If !(This.HWND) Return False If (Row >This.RowCount) Return False If This.IsStatic Row := This.MapIndexToID(Row) If This.Rows.Has(Row) This.Rows.Delete(Row) If (BkColor = "") && (TxColor = "") Return True BkBGR := This.BGR(BkColor) TxBGR := This.BGR(TxColor) If (BkBGR = "") && (TxBGR = "") Return False ; Colors := {B: (BkBGR != "") ? BkBGR : This.BkClr, T: (TxBGR != "") ? TxBGR : This.TxClr} This.Rows[Row] := Map("B", (BkBGR != "") ? BkBGR : This.BkClr, "T", (TxBGR != "") ? TxBGR : This.TxClr) Return True } ; =================================================================================================================== ; Cell() Sets background and/or text color for the specified cell. ; Parameters: Row - Row number ; Col - Column number ; Optional ------------------------------------------------------------------------------------------ ; BkColor - Background color as RGB color integer (e.g. 0xFF0000 = red) or HTML color name. ; Default: Empty -> row's background color ; TxColor - Text color as RGB color integer (e.g. 0xFF0000 = red) or HTML color name. ; Default: Empty -> row's text color ; Return Value: True on success, otherwise false. ; =================================================================================================================== Cell(Row, Col, BkColor := "", TxColor := "") { If !(This.HWND) Return False If (Row > This.RowCount) || (Col > This.ColCount) Return False If This.IsStatic Row := This.MapIndexToID(Row) If This.Cells.Has(Row) && This.Cells[Row].Has(Col) This.Cells[Row].Delete(Col) If (BkColor = "") && (TxColor = "") Return True BkBGR := This.BGR(BkColor) TxBGR := This.BGR(TxColor) If (BkBGR = "") && (TxBGR = "") Return False If !This.Cells.Has(Row) This.Cells[Row] := [], This.Cells[Row].Capacity := This.ColCount If (Col > This.Cells[Row].Length) This.Cells[Row].Length := Col This.Cells[Row][Col] := Map("B", (BkBGR != "") ? BkBGR : This.BkClr, "T", (TxBGR != "") ? TxBGR : This.TxClr) Return True } ; =================================================================================================================== ; NoSort() Prevents/allows sorting by click on a header item for this ListView. ; Parameters: Apply - True/False ; Return Value: True on success, otherwise false. ; =================================================================================================================== NoSort(Apply := True) { If !(This.HWND) Return False This.LV.Opt((Apply ? "+" : "-") . "NoSort") Return True } ; =================================================================================================================== ; NoSizing() Prevents/allows resizing of columns for this ListView. ; Parameters: Apply - True/False ; Return Value: True on success, otherwise false. ; =================================================================================================================== NoSizing(Apply := True) { If !(This.Header) Return False ControlSetStyle((Apply ? "+" : "-") . "0x0800", This.Header) ; HDS_NOSIZING = 0x0800 Return True } ; =================================================================================================================== ; ShowColors() Adds/removes a message handler for NM_CUSTOMDRAW notifications of this ListView. ; Parameters: Apply - True/False ; Return Value: Always True ; =================================================================================================================== ShowColors(Apply := True) { If (Apply) && !This.HasOwnProp("OnNotifyFunc") { This.OnNotifyFunc := ObjBindMethod(This, "NM_CUSTOMDRAW") This.LV.OnNotify(-12, This.OnNotifyFunc) WinRedraw(This.HWND) } Else If !(Apply) && This.HasOwnProp("OnNotifyFunc") { This.LV.OnNotify(-12, This.OnNotifyFunc, 0) This.OnNotifyFunc := "" This.DeleteProp("OnNotifyFunc") WinRedraw(This.HWND) } Return True } ; =================================================================================================================== ; Internally used/called Methods ; =================================================================================================================== NM_CUSTOMDRAW(LV, L) { ; Return values: 0x00 (CDRF_DODEFAULT), 0x20 (CDRF_NOTIFYITEMDRAW / CDRF_NOTIFYSUBITEMDRAW) Static SizeNMHDR := A_PtrSize * 3 ; Size of NMHDR structure Static SizeNCD := SizeNMHDR + 16 + (A_PtrSize * 5) ; Size of NMCUSTOMDRAW structure Static OffItem := SizeNMHDR + 16 + (A_PtrSize * 2) ; Offset of dwItemSpec (NMCUSTOMDRAW) Static OffItemState := OffItem + A_PtrSize ; Offset of uItemState (NMCUSTOMDRAW) Static OffCT := SizeNCD ; Offset of clrText (NMLVCUSTOMDRAW) Static OffCB := OffCT + 4 ; Offset of clrTextBk (NMLVCUSTOMDRAW) Static OffSubItem := OffCB + 4 ; Offset of iSubItem (NMLVCUSTOMDRAW) Critical -1 If !(This.HWND) || (NumGet(L, "UPtr") != This.HWND) Return ; ---------------------------------------------------------------------------------------------------------------- DrawStage := NumGet(L + SizeNMHDR, "UInt"), Row := NumGet(L + OffItem, "UPtr") + 1, Col := NumGet(L + OffSubItem, "Int") + 1, Item := Row - 1 If This.IsStatic Row := This.MapIndexToID(Row) ; CDDS_SUBITEMPREPAINT = 0x030001 -------------------------------------------------------------------------------- If (DrawStage = 0x030001) { UseAltCol := (This.AltCols) && !(Col & 1), ColColors := (This.Cells.Has(Row) && This.Cells[Row].Has(Col)) ? This.Cells[Row][Col] : Map("B", "", "T", ""), ColB := (ColColors["B"] != "") ? ColColors["B"] : UseAltCol ? This.ACB : This.RowB, ColT := (ColColors["T"] != "") ? ColColors["T"] : UseAltCol ? This.ACT : This.RowT, NumPut("UInt", ColT, L + OffCT), NumPut("UInt", ColB, L + OffCB) Return (!This.AltCols && (Col > This.Cells[Row].Length)) ? 0x00 : 0x020 } ; CDDS_ITEMPREPAINT = 0x010001 ----------------------------------------------------------------------------------- If (DrawStage = 0x010001) { ; LVM_GETITEMSTATE = 0x102C, LVIS_SELECTED = 0x0002 If (This.SelColors) && SendMessage(0x102C, Item, 0x0002, This.HWND) { ; Remove the CDIS_SELECTED (0x0001) and CDIS_FOCUS (0x0010) states from uItemState and set the colors. NumPut("UInt", NumGet(L + OffItemState, "UInt") & ~0x0011, L + OffItemState) If (This.SELB != "") NumPut("UInt", This.SELB, L + OffCB) If (This.SELT != "") NumPut("UInt", This.SELT, L + OffCT) Return 0x02 ; CDRF_NEWFONT } UseAltRow := This.AltRows && (Item & 1), RowColors := This.Rows.Has(Row) ? This.Rows[Row] : "", This.RowB := RowColors ? RowColors["B"] : UseAltRow ? This.ARB : This.BkClr, This.RowT := RowColors ? RowColors["T"] : UseAltRow ? This.ART : This.TxClr If (This.AltCols || This.Cells.Has(Row)) Return 0x20 NumPut("UInt", This.RowT, L + OffCT), NumPut("UInt", This.RowB, L + OffCB) Return 0x00 } ; CDDS_PREPAINT = 0x000001 --------------------------------------------------------------------------------------- Return (DrawStage = 0x000001) ? 0x20 : 0x00 } ; ------------------------------------------------------------------------------------------------------------------- MapIndexToID(Row) { ; provides the unique internal ID of the given row number Return SendMessage(0x10B4, Row - 1, 0, This.HWND) ; LVM_MAPINDEXTOID } ; ------------------------------------------------------------------------------------------------------------------- BGR(Color, Default := "") { ; converts colors to BGR ; HTML Colors (BGR) Static HTML := {AQUA: 0xFFFF00, BLACK: 0x000000, BLUE: 0xFF0000, FUCHSIA: 0xFF00FF, GRAY: 0x808080, GREEN: 0x008000 , LIME: 0x00FF00, MAROON: 0x000080, NAVY: 0x800000, OLIVE: 0x008080, PURPLE: 0x800080, RED: 0x0000FF , SILVER: 0xC0C0C0, TEAL: 0x808000, WHITE: 0xFFFFFF, YELLOW: 0x00FFFF} If IsInteger(Color) Return ((Color >> 16) & 0xFF) | (Color & 0x00FF00) | ((Color & 0xFF) << 16) Return (HTML.HasOwnProp(Color) ? HTML.%Color% : Default) } }` -------------------------------------------------------------------------------- /(3) Hotstring Manager - AutoHotkey Community.md: -------------------------------------------------------------------------------- 1 | # (3) Hotstring Manager - AutoHotkey Community 2 | 来源:[(3) Hotstring Manager - AutoHotkey Community](https://www.autohotkey.com/boards/viewtopic.php?f=83&t=115835) 3 | 4 | ## 摘录内容 5 | ; Hotstring Manager ; Fanatic Guru ; ; Version 2023 04 06 ; ; #Requires AutoHotkey v2 ; ; Manager for Hotstrings ; ;{----------------------------------------------- ; ; Hotstring Manager allows you to create, edit, delete, and manage many hotstrings in an easy to use interface. ; ;} ;; INITIALIZATION - ENVIROMENT ;{----------------------------------------------- ; #Requires AutoHotkey v2.0 #Warn All, Off #SingleInstance force ; Ensures that only the last executed instance of script is running ;} ;; DEFAULT SETTING - VARIABLES ;{----------------------------------------------- ; Settings := { Save: {}, File: {}, Font: {} } Settings.Save.HS := true Settings.Save.INI := true Settings.File.HS := "Hotstring Manager.sav" Settings.File.INI := "Hotstring Manager.ini" Settings.Font.Size := 12 Settings.GuiPositions := { guiList: { X: A_ScreenWidth / 3.5, Y: A_ScreenHeight / 5, Width: A_ScreenWidth / 5, Height: A_ScreenHeight / 5 }, guiInput: { X: A_ScreenWidth / 3.25, Y: A_ScreenWidth / 6, Width: A_ScreenWidth / 6, Height: A_ScreenHeight / 6 }, guiSettings: { X: A_ScreenWidth / 3.25, Y: A_ScreenWidth / 6, Width: A_ScreenWidth / 6, Height: A_ScreenHeight / 10 } } ; load INI and overwrite default settings If Settings.Save.INI Load_Settings() ;} ;; INITIALIZATION - VARIABLES ;{----------------------------------------------- ; Hotstrings := Map(), Hotstrings.Default := "" OptionFlags := { NoEndChar: "*", CaseSensitive: "C", TriggerInside: "?", NoConformCase: "C1", NoAutoBack: "B0", OmitEndChar: "O", SendRaw: "R", TextRaw: "T" } Toggle_Active := true ;} ;; INITIALIZATION - GUI ;{----------------------------------------------- ; ;{ guiList guiList := Gui(, "Hotstring Manager - List"), guiList.Opt("+AlwaysOnTop +Resize +MinSize650x300") guiList.OnEvent("Size", GuiReSizer) guiList.OnEvent("Escape", gui_Hide) guiList.SetFont("s" Settings.Font.Size) guiList.Button := {} guiList.Button.Add := guiList.Add("Button", "Default", "&Add") guiList.Button.Add.OnEvent("Click", guiList\_Button\_Add_Click) GuiButtonIcon(guiList.Button.Add.Hwnd, A_WinDir '\\system32\\wmploc.dll', 12, "a1 r10 s" Settings.Font.Size * 2) guiList.Button.Edit := guiList.Add("Button", "yp", "&Edit") guiList.Button.Edit.OnEvent("Click", guiList\_Button\_Edit_Click) GuiButtonIcon(guiList.Button.Edit.Hwnd, A_WinDir '\\system32\\wmploc.dll', 133, "a1 r10 s" Settings.Font.Size * 2) guiList.Button.Delete := guiList.Add("Button", "yp", "&Delete") guiList.Button.Delete.OnEvent("Click", guiList\_Button\_Delete_Click) GuiButtonIcon(guiList.Button.Delete.Hwnd, A_WinDir '\\system32\\shell32.dll', 220, "a1 r10 s" Settings.Font.Size * 2) guiList.Button.Settings := guiList.Add("Button", "yp", "&Settings") guiList.Button.Settings.OnEvent("Click", guiList\_Button\_Settings_Click) GuiButtonIcon(guiList.Button.Settings.Hwnd, A_WinDir '\\system32\\shell32.dll', 315, "a1 r10 s" Settings.Font.Size * 2) guiList.ListView := guiList.Add("ListView", "+Grid -Multi xm r20 w750", \["Options", "Abbreviation", "Replacement"\]) guiList.ListView.OnEvent("DoubleClick", guiList\_Button\_Edit_Click) guiList.Button.Add.X := 10 guiList.Button.Add.WidthP := 0.20 guiList.Button.Edit.XP := 0.37 guiList.Button.Edit.OriginXP := 0.5 guiList.Button.Edit.WidthP := 0.20 guiList.Button.Delete.XP := 0.62 guiList.Button.Delete.OriginXP := 0.5 guiList.Button.Delete.WidthP := 0.20 guiList.Button.Settings.X := -10 guiList.Button.Settings.OriginXP := 1 guiList.Button.Settings.WidthP := 0.22 guiList.ListView.Width := -10 guiList.ListView.Height := -10 ;} ;{ guiInput guiInput := Gui(, "Hotstring Manager - Add"), guiInput.Opt("+AlwaysOnTop +Resize +MinSize" Settings.Font.Size * 48 "x" Settings.Font.Size * 25) guiInput.OnEvent("Size", GuiReSizer) guiInput.OnEvent("Escape", gui_Hide) guiInput.SetFont("s" Settings.Font.Size) guiInput.Edit := {}, guiInput.Checkbox := {}, guiInput.Button := {} guiInput.Add("Text", "Right w" Settings.Font.Size * 8, "Abbreviation:") guiInput.Edit.Abbr := guiInput.Add("Edit", "w400 yp x" Settings.Font.Size * 11) guiInput.Add("Text", "Right xm w" Settings.Font.Size * 8, "Replacement:") guiInput.Edit.Replace := guiInput.Add("Edit", "r4 w400 WantTab yp x" Settings.Font.Size * 11) guiInput.Line := guiInput.Add("Text", "x10 h1 w400 0x7") guiInput.Checkbox.NoEndChar := guiInput.Add("Checkbox", , "No ending character (*)") guiInput.Checkbox.CaseSensitive := guiInput.Add("Checkbox", , "Case sensitive (C)") guiInput.Checkbox.TriggerInside := guiInput.Add("Checkbox", , "Trigger inside another word (?)") guiInput.Checkbox.NoConformCase := guiInput.Add("Checkbox", , "Do not conform to typed case (C1)") guiInput.Checkbox.NoAutoBack := guiInput.Add("Checkbox", , "No automatic backspacing (B0)") guiInput.Checkbox.OmitEndChar := guiInput.Add("Checkbox", , "Omit ending character (O)") guiInput.Checkbox.SendRaw := guiInput.Add("Checkbox", , "Send raw (R)") guiInput.Checkbox.TextRaw := guiInput.Add("Checkbox", , "Send text raw (T)") guiInput.Edit.Abbr.Width := -10 guiInput.Edit.Replace.Width := -10 guiInput.Edit.Replace.Height := -Settings.Font.Size * 15 guiInput.Line.X := 10 guiInput.Line.Y := -Settings.Font.Size * 14 guiInput.Line.Width := -10 For FlagName, Val in OptionFlags.OwnProps() ; Position Checkboxes { Mod(A_Index, 2) ? guiInput.Checkbox.%FlagName%.XP := 0.05 : guiInput.Checkbox.%FlagName%.XP := 0.55 guiInput.Checkbox.%FlagName%.Y := -Settings.Font.Size * 14.5 + (Ceil(A_Index / 2) * Settings.Font.Size * 2) guiInput.Checkbox.%FlagName%.Cleanup := true } guiInput.Button.Confirm := guiInput.Add("Button", "Default", "&Confirm") guiInput.Button.Confirm.OnEvent("Click", guiInput\_Button\_Confirm_Click) guiInput.Button.Cancel := guiInput.Add("Button", , "&Cancel") guiInput.Button.Cancel.OnEvent("Click", guiInput\_Button\_Cancel_Click) guiInput.Button.Confirm.XP := 0.20 guiInput.Button.Confirm.Y := -Settings.Font.Size guiInput.Button.Confirm.OriginYP := 1 guiInput.Button.Confirm.WidthP := 0.25 guiInput.Button.Cancel.XP := 0.60 guiInput.Button.Cancel.Y := -Settings.Font.Size guiInput.Button.Cancel.OriginYP := 1 guiInput.Button.Cancel.WidthP := 0.25 ;} ;{ guiSettings guiSettings := Gui(, "Hotstring Manager - Settings"), guiSettings.Opt("+AlwaysOnTop +Resize +MinSize" Settings.Font.Size * 35 "x" Settings.Font.Size * 18 + 50) guiSettings.OnEvent("Size", GuiReSizer) guiSettings.OnEvent("Escape", gui_Hide) guiSettings.SetFont("s" Settings.Font.Size) guiSettings.Button := {}, guiSettings.Edit := {}, guiSettings.Checkbox := {}, guiSettings.DropDownList := {} guiSettings.Button.Load := guiSettings.Add("Button", "Default y10 x10 w150", "&Load`nHotstrings") guiSettings.Button.Load.OnEvent("Click", guiSettings\_Button\_Load_Click) GuiButtonIcon(guiSettings.Button.Load.Hwnd, A_WinDir '\\system32\\imageres.dll', 280, "a1 r10 s" Settings.Font.Size * 3) guiSettings.Button.Save := guiSettings.Add("Button", "Default yp x+50 w150", "&Save`nHotstrings") guiSettings.Button.Save.OnEvent("Click", guiSettings\_Button\_Save_Click) GuiButtonIcon(guiSettings.Button.Save.Hwnd, A_WinDir '\\system32\\wmploc.dll', 132, "a1 r10 s" Settings.Font.Size * 3) guiSettings.Line := guiSettings.Add("Text", "y+20 x10 w350 h1 0x7") ; horizontal line guiSettings.Text1 := guiSettings.Add("Text", "y+10 x10", "Auto Save/Load File Name:") guiSettings.Edit.SaveHS := guiSettings.Add("Edit", "r1 yp-5 x+10 w210", Settings.File.HS) guiSettings.Checkbox.SaveHS := guiSettings.Add("Checkbox", "y+10 x10", "Auto Save/Load Hotstrings") guiSettings.Checkbox.SaveHS.Value := Settings.Save.HS guiSettings.Text2 := guiSettings.Add("Text", "yp+" Settings.Font.Size * 3 " x10", "Font Size \[Reload Required\]:") guiSettings.DropDownList.Font := guiSettings.Add("DropDownList", "yp x+10 w50", \["10", "12", "14", "16", "18"\]) guiSettings.DropDownList.Font.Text := Settings.Font.Size guiSettings.Button.Confirm := guiSettings.Add("Button", "Default y+20 x10 w150", "&Confirm") guiSettings.Button.Confirm.OnEvent("Click", guiSettings\_Button\_Confirm_Click) guiSettings.Button.Cancel := guiSettings.Add("Button", "yp x+50 w150", "&Cancel") guiSettings.Button.Cancel.OnEvent("Click", guiSettings\_Button\_Cancel_Click) guiSettings.Button.Load.XP := 0.05 guiSettings.Button.Load.WidthP := 0.4 guiSettings.Button.Save.XP := -0.05 guiSettings.Button.Save.OriginXP := 1 guiSettings.Button.Save.WidthP := 0.4 guiSettings.Line.Width := -10 guiSettings.Edit.SaveHS.Width := -10 guiSettings.Button.Confirm.XP := 0.20 guiSettings.Button.Confirm.Y := -Settings.Font.Size guiSettings.Button.Confirm.OriginYP := 1 guiSettings.Button.Confirm.WidthP := 0.25 guiSettings.Button.Cancel.XP := 0.60 guiSettings.Button.Cancel.Y := -Settings.Font.Size guiSettings.Button.Cancel.OriginYP := 1 guiSettings.Button.Cancel.WidthP := 0.25 ;} ;} ;; AUTO-EXECUTE ;{----------------------------------------------- ; ; Load Hotstrings If Settings.Save.HS Load_Hotstrings(Settings.File.HS) ; Init positioning of Gui For GuiName, Pos in Settings.GuiPositions.OwnProps() { %GuiName%.Show("Hide") %GuiName%.Move(Pos.X, Pos.Y, Pos.Width, Pos.Height) GuiReSizer.Now(%GuiName%) } OnExit(OnExit_Save) ;} ;; HOTKEYS ;{----------------------------------------------- ; #SuspendExempt ; Only Hotstrings affected by Suspend #h:: guiList.Show ; <\-\- Hotstring Manager - List #Space:: ; <\-\- Space without expanding Hotstring { Hotstring("Reset") Send "{Space}" } ^#space:: ; <\-\- Toggle On/Off { Global Toggle_Active := !Toggle_Active ToolTip "Hotsting Manager`n" (Toggle_Active ? "ON" : "OFF") SetTimer () => ToolTip(), -5000 (Toggle_Active ? Suspend(false) : Suspend(true)) } #SuspendExempt false ;} ;; CLASSES & FUNCTIONS - GUI ;{----------------------------------------------- ; ;{ All Gui ;; Gui Escape gui_Hide(GuiObj) { GuiObj.Hide } ;} ;{ guiList guiList\_Button\_Add_Click(GuiCtrlObj, Info) { For PropDesc, Prop in guiInput.Edit.OwnProps() Prop.Text := "" For PropDesc, Prop in guiInput.Checkbox.OwnProps() Prop.Value := 0 guiInput.Title := "Hotstring Manager - Add" guiInput.Edit.Abbr.Focus() guiInput.Show } guiList\_Button\_Edit_Click(GuiCtrlObj, RowNumber := 0) ; also List View DoubleClick { Global CurrentHS If !RowNumber RowNumber := guiList.ListView.GetNext() If RowNumber = 0 { MsgBox "Select Hotsting to Edit" Return } Options := guiList.ListView.GetText(RowNumber) guiInput.Edit.Abbr.Text := Abbr := guiList.ListView.GetText(RowNumber, 2) guiInput.Edit.Replace.Text := StrReplace(Replace := Hotstrings\[Options ":" Abbr\], "`n", "\`r\`n") For Flag, Value in OptionFlags.OwnProps() { If RegExMatch(Options, "\\Q" Value "\\E(?!\\d)") guiInput.Checkbox.%Flag%.Value := true Else guiInput.Checkbox.%Flag%.Value := false } guiInput.Title := "Hotstring Manager - Edit" CurrentHS := { RowNumber: RowNumber, Options: Options, Abbr: Abbr, Replace: Replace } guiInput.Edit.Abbr.Focus() guiInput.Show } guiList\_Button\_Delete_Click(GuiCtrlObj, Info) { RowNumber := guiList.ListView.GetNext() If RowNumber = 0 { MsgBox "Select Hotsting to Delete" Return } For Index, Element in \["Options", "Abbr", "Replace"\] %Element% := guiList.ListView.GetText(RowNumber, Index) If MsgBox("Are you sure you want to Delete?\`n\`n" Abbr "`n" Replace, "Delete Hotstring", 4 + 32 + 256 + 4096) = "Yes" { guiList.ListView.Delete(RowNumber) Hotstrings.Delete(Options ":" Abbr) Hotstring(":" Options ":" Abbr, , false) } } guiList\_Button\_Settings_Click(GuiCtrlObj, Info) { guiSettings.Show } ;} ;{ guiInput guiInput\_Button\_Confirm_Click(*) { guiInput.Hide Options := "" For Opt, Flag in OptionFlags.OwnProps() If guiInput.Checkbox.%Opt%.Value Options .= Flag If guiInput.Title ~= "Edit" { ; when editting - delete current Hotstring to recreate guiList.ListView.Delete(CurrentHS.RowNumber) Hotstrings.Delete(CurrentHS.Options ":" CurrentHS.Abbr) Hotstring(":BCO0R0*0:" CurrentHS.Abbr, CurrentHS.Replace, false) ; Disable Exsisting Options Variants (C) Hotstring(":BC1O0R0*0:" CurrentHS.Abbr, CurrentHS.Replace, false) ; Disable Exsisting Options Variants (C1) Hotstring(":BC0O0R0*0:" CurrentHS.Abbr, CurrentHS.Replace, false) ; Disable Exsisting Options Variants (C0) } ; remove any list View duplicate Loop guiList.ListView.GetCount() If (guiList.ListView.GetText(A_Index) = Options and guiList.ListView.GetText(A_Index, 2) = guiInput.Edit.Abbr) guiList.ListView.Delete(A_Index) ; create Hotstring Hotstrings\[Options ":" guiInput.Edit.Abbr.Value\] := guiInput.Edit.Replace.Value Hotstring(":" Options ":" guiInput.Edit.Abbr.Value, guiInput.Edit.Replace.Value, true) guiList.ListView.Add(, Options, guiInput.Edit.Abbr.Value, Escape_CC(guiInput.Edit.Replace.Value)) } guiInput\_Button\_Cancel_Click(*) { guiInput.Hide } ;} ;{ guiSettings guiSettings\_Button\_Confirm_Click(Dialog, *) { Global Settings guiSettings.Hide (Settings.Font.Size != guiSettings.DropDownList.Font.Text) ? DoReload := true : DoReload := false Settings.Font.Size := guiSettings.DropDownList.Font.Text Settings.Save.HS := guiSettings.Checkbox.SaveHS.Value Settings.File.HS := guiSettings.Edit.SaveHS.Value If DoReload Reload } guiSettings\_Button\_Load_Click(*) { guiSettings.Opt("+OwnDialogs") FileName := FileSelect(3, , "Select Hotstring File to Load") If FileName Load_Hotstrings(FileName) } guiSettings\_Button\_Save_Click(*) { guiSettings.Opt("+OwnDialogs") FileName := FileSelect(3, , "Select Hotstring File for Save") If FileName Save_Hotstrings(FileName) } guiSettings\_Button\_Cancel_Click(*) { guiSettings.Hide } ;} ;} ;; FUNCTIONS ;{----------------------------------------------- ; ;{ Save/Load/Exit Save_Hotstrings(FileName) { For Opt_Abbr, Replacement in Hotstrings String .= ":" Opt_Abbr "::" Escape_CC(Replacement) "`n" Try FileMove(FileName, FileName ".bak", true) Try FileAppend(SubStr(String, 1, -1), FileName) } Load_Hotstrings(FileName) { Try String := FileRead(FileName) Catch Return Loop Parse, String, "`n", "`r" { If RegExMatch(A_LoopField, "U)^:(?.*):(?.*)::(?.*)$", &Match) { If Hotstrings\[Match.Options ":" Match.Abbr\] !== Match.Replace { guiList.ListView.Add(, Match.Options, Match.Abbr, Match.Replace) Match.Replace := Unescape_CC(Match.Replace) Hotstrings\[Match.Options ":" Match.Abbr\] := Match.Replace Hotstring(":" Match.Options ":" Match.Abbr, Match.Replace, true) } } } Loop 3 guiList.ListView.ModifyCol(A_Index, "AutoHdr") guiList.ListView.ModifyCol(3, "Sort") } Save_Settings() { Try FileMove(Settings.File.INI, Settings.File.INI ".bak", true) For GuiName, Pos in Settings.GuiPositions.OwnProps() { %GuiName%.GetPos(&X, &Y, &W, &H) Pos.X := X, Pos.Y := Y, Pos.Width := W, Pos.Height := H } For Section_Name, Section in Settings.OwnProps() For Setting_Name, Value in Section.OwnProps() If !IsObject(Value) IniWrite Value, Settings.File.INI, Section_Name, Setting_Name For Section_Name, Section in Settings.GuiPositions.OwnProps() For Setting_Name, Value in Section.OwnProps() IniWrite Value, Settings.File.INI, Section_Name, Setting_Name } Load_Settings() { For Section_Name, Section in Settings.OwnProps() For Setting_Name, Value in Section.OwnProps() If !IsObject(Value) Try Settings.%Section_Name%.%Setting_Name% := IniRead(Settings.File.INI, Section_Name, Setting_Name) For Section_Name, Section in Settings.GuiPositions.OwnProps() For Setting_Name, Value in Section.OwnProps() Try Settings.GuiPositions.%Section_Name%.%Setting_Name% := IniRead(Settings.File.INI, Section_Name, Setting_Name) } OnExit_Save(*) { If Settings.Save.HS Save_Hotstrings(Settings.File.HS) If Settings.Save.INI Save_Settings() } ;} ;{ Escape / Unescape Control Characters Escape_CC(String) ; Escape Control Characters { String := StrReplace(String, "`n", "``n") String := StrReplace(String, "`t", "``t") String := StrReplace(String, "`b", "``b") Return String } Unescape_CC(String) ; Unescape Control Characters { String := StrReplace(String, "``n", "`n") String := StrReplace(String, "``t", "`t") String := StrReplace(String, "``b", "`b") Return String } ;} ;} ;; Library ;{----------------------------------------------- ; ;{ \[Class\] GuiReSizer ;{ ------------------- ; Fanatic Guru ; Version 2023 03 13 ; ; Update 2023 02 15: Add more Min Max properties and renamed some properties ; Update 2023 03 13: Major rewrite. Converted to Class to allow for Methods ; Update 2023 03 17: Add function InTab3 to allow automatic anchoring of controls in Tab3 ; ; #Requires AutoHotkey v2.0.2+ ; ; Class to Handle the Resizing of Gui and ; Move and Resize Controls ; ;------------------------------------------------ ; ; Class GuiReSizer ; ; Call: GuiReSizer(GuiObj, WindowMinMax, Width, Height) ; ; Parameters: ; 1) {GuiObj} Gui Object ; 2) {WindowMinMax} Window status, 0 = neither minimized nor maximized, 1 = maximized, -1 = minimized ; 3) {Width} Width of GuiObj ; 4) {Height} Height of GuiObj ; ; Normally parameters are passed by a callback from {gui}.OnEvent("Size", GuiReSizer) ; ; Properties: Abbr Description ; X X positional offset from margins ; Y Y positional offset from margins ; XP X positional offset from margins as percentage of Gui width ; YP Y positional offset from margins as percentage of Gui height ; OriginX OX control origin X defaults to 0 or left side of control, this relocates the origin ; OriginXP OXP control origin X as percentage of Gui width defaults to 0 or left side of control, this relocates the origin ; OriginY OY control origin Y defaults to 0 or top side of control, this relocates the origin ; OriginYP OYP control origin Y as percentage of Gui height defaults to 0 or top side of control, this relocates the origin ; Width W width of control ; WidthP WP width of control as percentage of Gui width ; Height H height of control ; HeightP HP height of control as percentage of Gui height ; MinX mininum X offset ; MaxX maximum X offset ; MinY minimum Y offset ; MaxY maximum Y offset ; MinWidth MinW minimum control width ; MaxWidth MaxW maximum control width ; MinHeight MinH minimum control height ; MaxHeight MaxH maximum control height ; Cleanup C {true/false} when set to true will redraw this control each time to cleanup artifacts, normally not required and causes flickering ; Function F {function} custom function that will be called for this control ; Anchor A {contol object} anchor control so that size and position commands are in relation to another control ; AnchorIn AI {true/false} controls where the control is restricted to the inside of another control ; ; Methods: ; Now(GuiObj) will force a manual Call now for {GuiObj} ; Opt({switches}) same as Options method ; Options({switches}) all options are set as a string with each switch separated by a space "x10 yp50 oCM" ; Flags: ; x{number} X ; y{number} Y ; xp{number} XP ; yp{number} YP ; wp{number} WidthP ; hp{number} HeightP ; w{number} Width ; h{number} Height ; minx{number} MinX ; maxx{number} MaxX ; miny{number} MinY ; maxy{number} MaxY ; minw{number} MinWidth ; maxw{number} MaxWidth ; minh{number} MinHeight ; maxh{number} MaxHeight ; oxp{number} OriginXP ; oyp{number} OriginYP ; ox{number} OriginX ; oy{number} OriginY ; o{letters} Origin: "L" left, "C" center, "R" right, "T" top, "M" middle, "B" bottom; may use 1 or 2 letters ; ; Gui Properties: ; Init {Gui}.Init := 1, will cause all controls of the Gui to be redrawn on next function call ; {Gui}.Init := 2, will also reinitialize abbreviations ;} Class GuiReSizer { ;{ Call GuiReSizer Static Call(GuiObj, WindowMinMax, GuiW, GuiH) { ;{ GuiObj Checks if !GuiObj.HasProp('Init') GuiObj.Init := 2 ; Redraw Twice on Initial Call with Redraw (called on initial Show) If WindowMinMax = -1 ; Do nothing if window minimized Return ;} ;{ Loop through all Controls of Gui For Hwnd, CtrlObj in GuiObj { ;{ Initializations Control on First Call If GuiObj.Init = 2 { Try CtrlObj.OriginX := CtrlObj.OX Try CtrlObj.OriginXP := CtrlObj.OXP Try CtrlObj.OriginY := CtrlObj.OY Try CtrlObj.OriginYP := CtrlObj.OYP Try CtrlObj.Width := CtrlObj.W Try CtrlObj.WidthP := CtrlObj.WP Try CtrlObj.Height := CtrlObj.H Try CtrlObj.HeightP := CtrlObj.HP Try CtrlObj.MinWidth := CtrlObj.MinW Try CtrlObj.MaxWidth := CtrlObj.MaxW Try CtrlObj.MinHeight := CtrlObj.MinH Try CtrlObj.MaxHeight := CtrlObj.MaxH Try CtrlObj.Function := CtrlObj.F Try CtrlObj.Cleanup := CtrlObj.C Try CtrlObj.Anchor := CtrlObj.A Try CtrlObj.AnchorIn := CtrlObj.AI If !CtrlObj.HasProp("AnchorIn") CtrlObj.AnchorIn := true if Tab3 := InTab3(CtrlObj) CtrlObj.Anchor := Tab3 } ;} ;{ Initialize Current Positions and Sizes CtrlObj.GetPos(&CtrlX, &CtrlY, &CtrlW, &CtrlH) LimitX := AnchorW := GuiW, LimitY := AnchorH := GuiH, OffsetX := OffsetY := 0 ;} ;{ Check for Anchor If CtrlObj.HasProp("Anchor") { If Type(CtrlObj.Anchor) = "Gui.Tab" { CtrlObj.Anchor.GetPos(&AnchorX, &AnchorY, &AnchorW, &AnchorH) OffsetTab(CtrlObj, &TabX, &TabY) CtrlX := CtrlX - TabX, CtrlY := CtrlY - TabY AnchorW := AnchorW + AnchorX - TabX, AnchorH := AnchorH + AnchorY - TabY } Else { CtrlObj.Anchor.GetPos(&AnchorX, &AnchorY, &AnchorW, &AnchorH) If CtrlObj.HasProp("X") or CtrlObj.HasProp("XP") OffsetX := AnchorX If CtrlObj.HasProp("Y") or CtrlObj.HasProp("YP") OffsetY := AnchorY } If CtrlObj.AnchorIn LimitX := AnchorW, LimitY := AnchorH } ;} ;{ OriginX If CtrlObj.HasProp("OriginX") and CtrlObj.HasProp("OriginXP") OriginX := CtrlObj.OriginX + (CtrlW * CtrlObj.OriginXP) Else If CtrlObj.HasProp("OriginX") and !CtrlObj.HasProp("OriginXP") OriginX := CtrlObj.OriginX Else If !CtrlObj.HasProp("OriginX") and CtrlObj.HasProp("OriginXP") OriginX := CtrlW * CtrlObj.OriginXP Else OriginX := 0 ;} ;{ OriginY If CtrlObj.HasProp("OriginY") and CtrlObj.HasProp("OriginYP") OriginY := CtrlObj.OriginY + (CtrlH * CtrlObj.OriginYP) Else If CtrlObj.HasProp("OriginY") and !CtrlObj.HasProp("OriginYP") OriginY := CtrlObj.OriginY Else If !CtrlObj.HasProp("OriginY") and CtrlObj.HasProp("OriginYP") OriginY := CtrlH * CtrlObj.OriginYP Else OriginY := 0 ;} ;{ X If CtrlObj.HasProp("X") and CtrlObj.HasProp("XP") CtrlX := Mod(LimitX + CtrlObj.X + (AnchorW * CtrlObj.XP) - OriginX, LimitX) Else If CtrlObj.HasProp("X") and !CtrlObj.HasProp("XP") CtrlX := Mod(LimitX + CtrlObj.X - OriginX, LimitX) Else If !CtrlObj.HasProp("X") and CtrlObj.HasProp("XP") CtrlX := Mod(LimitX + (AnchorW * CtrlObj.XP) - OriginX, LimitX) ;} ;{ Y If CtrlObj.HasProp("Y") and CtrlObj.HasProp("YP") CtrlY := Mod(LimitY + CtrlObj.Y + (AnchorH * CtrlObj.YP) - OriginY, LimitY) Else If CtrlObj.HasProp("Y") and !CtrlObj.HasProp("YP") CtrlY := Mod(LimitY + CtrlObj.Y - OriginY, LimitY) Else If !CtrlObj.HasProp("Y") and CtrlObj.HasProp("YP") CtrlY := Mod(LimitY + AnchorH * CtrlObj.YP - OriginY, LimitY) ;} ;{ Width If CtrlObj.HasProp("Width") and CtrlObj.HasProp("WidthP") (CtrlObj.Width > 0 and CtrlObj.WidthP > 0 ? CtrlW := CtrlObj.Width + AnchorW * CtrlObj.WidthP : CtrlW := CtrlObj.Width + AnchorW + AnchorW * CtrlObj.WidthP - CtrlX) Else If CtrlObj.HasProp("Width") and !CtrlObj.HasProp("WidthP") (CtrlObj.Width > 0 ? CtrlW := CtrlObj.Width : CtrlW := AnchorW + CtrlObj.Width - CtrlX) Else If !CtrlObj.HasProp("Width") and CtrlObj.HasProp("WidthP") (CtrlObj.WidthP > 0 ? CtrlW := AnchorW * CtrlObj.WidthP : CtrlW := AnchorW + AnchorW * CtrlObj.WidthP - CtrlX) ;} ;{ Height If CtrlObj.HasProp("Height") and CtrlObj.HasProp("HeightP") (CtrlObj.Height > 0 and CtrlObj.HeightP > 0 ? CtrlH := CtrlObj.Height + AnchorH * CtrlObj.HeightP : CtrlH := CtrlObj.Height + AnchorH + AnchorH * CtrlObj.HeightP - CtrlY) Else If CtrlObj.HasProp("Height") and !CtrlObj.HasProp("HeightP") (CtrlObj.Height > 0 ? CtrlH := CtrlObj.Height : CtrlH := AnchorH + CtrlObj.Height - CtrlY) Else If !CtrlObj.HasProp("Height") and CtrlObj.HasProp("HeightP") (CtrlObj.HeightP > 0 ? CtrlH := AnchorH * CtrlObj.HeightP : CtrlH := AnchorH + AnchorH * CtrlObj.HeightP - CtrlY) ;} ;{ Min Max (CtrlObj.HasProp("MinX") ? MinX := CtrlObj.MinX : MinX := -999999) (CtrlObj.HasProp("MaxX") ? MaxX := CtrlObj.MaxX : MaxX := 999999) (CtrlObj.HasProp("MinY") ? MinY := CtrlObj.MinY : MinY := -999999) (CtrlObj.HasProp("MaxY") ? MaxY := CtrlObj.MaxY : MaxY := 999999) (CtrlObj.HasProp("MinWidth") ? MinW := CtrlObj.MinWidth : MinW := 0) (CtrlObj.HasProp("MaxWidth") ? MaxW := CtrlObj.MaxWidth : MaxW := 999999) (CtrlObj.HasProp("MinHeight") ? MinH := CtrlObj.MinHeight : MinH := 0) (CtrlObj.HasProp("MaxHeight") ? MaxH := CtrlObj.MaxHeight : MaxH := 999999) CtrlX := MinMax(CtrlX, MinX, MaxX) CtrlY := MinMax(CtrlY, MinY, MaxY) CtrlW := MinMax(CtrlW, MinW, MaxW) CtrlH := MinMax(CtrlH, MinH, MaxH) ;} ;{ Move and Size CtrlObj.Move(CtrlX + OffsetX, CtrlY + OffsetY, CtrlW, CtrlH) ;} ;{ Redraw on Cleanup or GuiObj.Init If GuiObj.Init or (CtrlObj.HasProp("Cleanup") and CtrlObj.Cleanup = true) CtrlObj.Redraw() ;} ;{ Custom Function Call If CtrlObj.HasProp("Function") CtrlObj.Function(GuiObj) ; CtrlObj is hidden 'this' first parameter ;} } ;} ;{ Reduce GuiObj.Init Counter and Check for Call again If (GuiObj.Init := Max(GuiObj.Init - 1, 0)) { GuiObj.GetClientPos(, , &AnchorW, &AnchorH) GuiReSizer(GuiObj, WindowMinMax, AnchorW, AnchorH) } ;} ;{ Functions: Helpers MinMax(Num, MinNum, MaxNum) => Min(Max(Num, MinNum), MaxNum) OffsetTab(CtrlObj, &OffsetX, &OffsetY) { hParentWnd := DllCall("GetParent", "Ptr", CtrlObj.Hwnd, "Ptr") RECT := Buffer(16, 0) DllCall("GetWindowRect", "Ptr", hParentWnd, "Ptr", RECT) DllCall("MapWindowPoints", "Ptr", 0, "Ptr", DllCall("GetParent", "Ptr", hParentWnd, "Ptr"), "Ptr", RECT, "UInt", 1) OffsetX := NumGet(RECT, 0, "Int"), OffsetY := NumGet(RECT, 4, "Int") } InTab3(CtrlObj) { Try Tab3Obj := GuiCtrlFromHwnd(DllCall('GetWindow', 'Ptr', DllCall('GetParent', 'Ptr', CtrlObj.Hwnd, 'Ptr'), 'UInt', 3, 'Ptr')) Catch Tab3Obj := false Return Tab3Obj } ;} } ;} ;{ Methods: ;{ Options Static Opt(CtrlObj, Options) => GuiReSizer.Options(CtrlObj, Options) Static Options(CtrlObj, Options) { For Option in StrSplit(Options, " ") { For Abbr, Cmd in Map( "xp", "XP", "yp", "YP", "x", "X", "y", "Y", "wp", "WidthP", "hp", "HeightP", "w", "Width", "h", "Height", "minx", "MinX", "maxx", "MaxX", "miny", "MinY", "maxy", "MaxY", "minw", "MinWidth", "maxw", "MaxWidth", "minh", "MinHeight", "maxh", "MaxHeight", "oxp", "OriginXP", "oyp", "OriginYP", "ox", "OriginX", "oy", "OriginY") If RegExMatch(Option, "i)^" Abbr "(\[\\d.-\]*$)", &Match) { CtrlObj.%Cmd% := Match.1 Break } ; Origin letters If SubStr(Option, 1, 1) = "o" { Flags := SubStr(Option, 2) If Flags ~= "i)l" ; left CtrlObj.OriginXP := 0 If Flags ~= "i)c" ; center (left to right) CtrlObj.OriginXP := 0.5 If Flags ~= "i)r" ; right CtrlObj.OriginXP := 1 If Flags ~= "i)t" ; top CtrlObj.OriginYP := 0 If Flags ~= "i)m" ; middle (top to bottom) CtrlObj.OriginYP := 0.5 If Flags ~= "i)b" ; bottom CtrlObj.OriginYP := 1 } } } ;} ;{ Now Static Now(GuiObj, Redraw := true, Init := 2) { If Redraw GuiObj.Init := Init GuiObj.GetClientPos(, , &Width, &Height) GuiReSizer(GuiObj, WindowMinMax := 1, Width, Height) } ;} ;} } ;} ;{ \[Function\] GuiButtonIcon ;{ ; Fanatic Guru ; Version 2019 03 26 ; ; #Requires AutoHotkey v2.0.2+ ; ; FUNCTION to Assign an Icon to a Gui Button ; ;------------------------------------------------ ; ; Method: ; GuiButtonIcon(Handle, File, Index, Options) ; ; Parameters: ; 1) {Handle} HWND handle of Gui button ; 2) {File} File containing icon image ; 3) {Index} Index of icon in file ; Optional: Default = 1 ; 4) {Options} Single letter flag followed by a number with multiple options delimited by a space ; W = Width of Icon (default = 16) ; H = Height of Icon (default = 16) ; S = Size of Icon, Makes Width and Height both equal to Size ; L = Left Margin ; T = Top Margin ; R = Right Margin ; B = Botton Margin ; A = Alignment (0 = left, 1 = right, 2 = top, 3 = bottom, 4 = center; default = 4) ; ; Return: ; 1 = icon found, 0 = icon not found ; ; Example: ; Gui := GuiCreate() ; Button := Gui.Add("Button", "w70 h38", "Save") ; GuiButtonIcon(Button.Hwnd, "shell32.dll", 259, "s32 a1 r2") ; Gui.Show ;} GuiButtonIcon(Handle, File, Index := 1, Options := "") { RegExMatch(Options, "i)w\\K\\d+", &W) ? W := W.0 : W := 16 RegExMatch(Options, "i)h\\K\\d+", &H) ? H := H.0 : H := 16 RegExMatch(Options, "i)s\\K\\d+", &S) ? W := H := S.0 : "" RegExMatch(Options, "i)l\\K\\d+", &L) ? L := L.0 : L := 0 RegExMatch(Options, "i)t\\K\\d+", &T) ? T := T.0 : T := 0 RegExMatch(Options, "i)r\\K\\d+", &R) ? R := R.0 : R := 0 RegExMatch(Options, "i)b\\K\\d+", &B) ? B := B.0 : B := 0 RegExMatch(Options, "i)a\\K\\d+", &A) ? A := A.0 : A := 4 W := W * (A_ScreenDPI / 96), H := H * (A_ScreenDPI / 96) Psz := (A_PtrSize = "" ? 4 : A_PtrSize), DW := "UInt", Ptr := (A_PtrSize = "" ? DW : "Ptr") button_il := Buffer(20 + Psz) normal_il := DllCall("ImageList_Create", DW, W, DW, H, DW, 0x21, DW, 1, DW, 1) NumPut(Ptr, normal_il, button_il, 0) ; Width & Height NumPut(DW, L, button_il, 0 + Psz) ; Left Margin NumPut(DW, T, button_il, 4 + Psz) ; Top Margin NumPut(DW, R, button_il, 8 + Psz) ; Right Margin NumPut(DW, B, button_il, 12 + Psz) ; Bottom Margin NumPut(DW, A, button_il, 16 + Psz) ; Alignment SendMessage(BCM_SETIMAGELIST := 5634, 0, button_il, , "AHK_ID " Handle) Return IL_Add(normal_il, File, Index) } ;} ;} 6 | ## 想法 -------------------------------------------------------------------------------- /AHK_V12V2.md: -------------------------------------------------------------------------------- 1 | | V1 | V2 | 2 | | ---- | ---- | 3 | | VarSetCapacity(GUID,16,0) | GUID:=Buffer(16) | 4 | | 单元格 | 单元格 | 5 | -------------------------------------------------------------------------------- /Chrome_ConvertBookmarks.py: -------------------------------------------------------------------------------- 1 | 2 | import sqlite3 3 | 4 | favicons_file='D:\\SoftX\\Chrome_GenBookmark\\Favicons' 5 | dest_db="D:\\SoftX\\test.db" 6 | 7 | 8 | conn1 = sqlite3.connect(favicons_file) 9 | cursor1 = conn1.cursor() 10 | conn2 = sqlite3.connect(dest_db) 11 | cursor2 = conn2.cursor() 12 | 13 | sql_cmd='select guid, bk_url from bookmarks' 14 | cursor2.execute(sql_cmd) 15 | values = cursor2.fetchall() 16 | for i in range(len(values)): 17 | this_guid=values[i][0] 18 | this_url=values[i][1] 19 | is_file=this_url.startswith('file:///') 20 | is_chrome_setting=this_url.startswith('chrome://') 21 | is_bookmarklet=this_url.startswith('javascript:') 22 | if( is_file or is_chrome_setting or is_bookmarklet): 23 | print (values[i][0]) 24 | else: 25 | # print(this_url) 26 | try: 27 | sql_cmd='select icon_id from icon_mapping where page_url like \'' + this_url +'%\'' 28 | cursor1.execute(sql_cmd) 29 | record = cursor1.fetchone() 30 | icon_id = record[0] 31 | except: 32 | print('can not get icon_id for:' + this_url) 33 | continue # can not get icon_id by url, skip the loop 34 | try: 35 | sql_cmd='select image_data from favicon_bitmaps where icon_id =' + str(icon_id) + ' and width=32' 36 | cursor1.execute(sql_cmd) 37 | except: 38 | sql_cmd='select image_data from favicon_bitmaps where icon_id =' + str(icon_id) + ' and width=16' 39 | cursor1.execute(sql_cmd) 40 | try: 41 | record = cursor1.fetchone()[0] 42 | except: 43 | print('no icon file for:' + str(icon_id) + '; url:' + this_url) 44 | continue 45 | sql_cmd='update bookmarks set bk_icon = ? where guid = ?' 46 | update_tutle=(record, '\'' + this_guid + '\'') 47 | cursor2.execute(sql_cmd,update_tutle) 48 | 49 | conn2.commit() 50 | cursor1.close() 51 | conn1.close() 52 | # conn.commit() 53 | cursor2.close() 54 | conn2.close() 55 | -------------------------------------------------------------------------------- /Chrome_CreateShortcut.ahk: -------------------------------------------------------------------------------- 1 | 2 | GroupAdd "Browser", "ahk_exe chrome.exe" 3 | GroupAdd "Browser", "ahk_exe msedge.exe" 4 | 5 | #HotIf WinActive("ahk_group Browser") 6 | ^d:: 7 | { 8 | BookmarkDir:="D:\SoftX\MyBookmarks\" 9 | url := GetUrl() 10 | if (url) 11 | { 12 | IB := InputBox(url, "BookMarker", "w200 h100") 13 | if IB.Result = "OK" 14 | { 15 | BookmarkName:=BookmarkDir . IB.value . ".url" 16 | IconFileName:=BookmarkDir . "icon\" . IB.value 17 | if(FileExist(IconFile:=IconFileName . ".ico")) 18 | { 19 | IniWrite url, BookmarkName, "InternetShortcut", "URL" 20 | IniWrite IconFile, BookmarkName, "InternetShortcut", "IconFile" 21 | IniWrite 0, BookmarkName, "InternetShortcut", "IconIndex" 22 | Target:=url 23 | LinkFile:=BookmarkName 24 | } 25 | else 26 | IniWrite url, BookmarkName, "InternetShortcut", "URL" 27 | 28 | } 29 | } 30 | } 31 | 32 | 33 | ; Version: 2023.10.05.1 34 | ; https://gist.github.com/7cce378c9dfdaf733cb3ca6df345b140 35 | 36 | GetUrl() { ; Active Window Only 37 | static S_OK := 0, TreeScope_Descendants := 4, UIA_ControlTypePropertyId := 30003, UIA_DocumentControlTypeId := 50030, UIA_EditControlTypeId := 50004, UIA_ValueValuePropertyId := 30045 38 | hWnd := WinGetID("A") 39 | IUIAutomation := ComObject("{FF48DBA4-60EF-4201-AA87-54103EEF594E}", "{30CBE57D-D9D0-452A-AB13-7AC5AC4825EE}") 40 | eRoot := ComValue(13, 0) 41 | HRESULT := ComCall(6, IUIAutomation, "Ptr", hWnd, "Ptr*", eRoot) 42 | if (HRESULT != S_OK) { 43 | throw Error("IUIAutomation::ElementFromHandle()", -1, HRESULT) 44 | } 45 | winClass := WinGetClass("A") 46 | ctrlTypeId := (winClass ~= "Chrome" ? UIA_DocumentControlTypeId : UIA_EditControlTypeId) 47 | value := Buffer(8 + 2 * A_PtrSize, 0) 48 | NumPut("UShort", 3, value, 0) 49 | NumPut("Ptr", ctrlTypeId, value, 8) 50 | condition := ComValue(13, 0) 51 | if (A_PtrSize = 8) { 52 | HRESULT := ComCall(23, IUIAutomation, "UInt", UIA_ControlTypePropertyId, "Ptr", value, "Ptr*", condition) 53 | } else { 54 | HRESULT := ComCall(23, IUIAutomation, "UInt", UIA_ControlTypePropertyId, "UInt64", NumGet(value, 0, "UInt64"), "UInt64", NumGet(value, 8, "UInt64"), "Ptr*", condition) 55 | } 56 | if (HRESULT != S_OK) { 57 | throw Error("IUIAutomation::CreatePropertyCondition()", -1, HRESULT) 58 | } 59 | eFirst := ComValue(13, 0) 60 | HRESULT := ComCall(5, eRoot, "UInt", TreeScope_Descendants, "Ptr", condition, "Ptr*", eFirst) 61 | if (HRESULT != S_OK) { 62 | throw Error("IUIAutomationElement::GetRootElement()", -1, HRESULT) 63 | } 64 | propertyValue := Buffer(8 + 2 * A_PtrSize) 65 | HRESULT := ComCall(10, eFirst, "UInt", UIA_ValueValuePropertyId, "Ptr", propertyValue) 66 | if (HRESULT != S_OK) { 67 | throw Error("IUIAutomationElement::GetCurrentPropertyValue()", -1, HRESULT) 68 | } 69 | ObjRelease(eFirst.Ptr) 70 | ObjRelease(eRoot.Ptr) 71 | try { 72 | pProperty := NumGet(propertyValue, 8, "Ptr") 73 | return StrGet(pProperty, "UTF-16") 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Chrome_Download.ahk: -------------------------------------------------------------------------------- 1 | #Requires Autohotkey 2.0 2 | 3 | #Include .\lib\Class_SQLiteDB.ahk 4 | #Include .\lib\TC_AHK_Lib.ahk 5 | 6 | global db_file, db_here 7 | global ExePath_7Z := IniRead("SQLiteDB.ini", "Main", "7z") 8 | global ExePath_7ZG := IniRead("SQLiteDB.ini", "Main", "7zg") 9 | global ArrFullPath := Array() 10 | Exist_7z := FileExist(ExePath_7Z) 11 | Exist_7zg := FileExist(ExePath_7ZG) 12 | if (!ExePath_7Z or !ExePath_7ZG) 13 | { 14 | MsgBox "No 7z or 7zg file found`nset in SQLiteDB.ini" 15 | return 16 | } 17 | 18 | db_file := IniRead("SQLiteDB.ini", "Main", "db_file") 19 | db_here := A_ScriptDir . "\DownloadHistory.db" 20 | if (!FileExist(db_file)) 21 | { 22 | MsgBox "No History sqlite databse file found`nset in SQLiteDB.ini" 23 | return 24 | } 25 | 26 | MyGui := Gui("+AlwaysOnTop +ToolWindow") 27 | MyGui.SetFont("s14", "Verdana") 28 | CurrentHwnd := MyGui.Hwnd 29 | LVS_SHOWSELALWAYS := 8 ; Seems to have the opposite effect with Explorer theme, at least on Windows 11. 30 | LV_BGColor := Format(' Background{:x}', DllCall("GetSysColor", "int", 15, "int")) ; background color of listview item when get selected by up & down arrow 31 | LV := MyGui.Add("ListView", "r20 w700 -Multi -Hdr " LVS_SHOWSELALWAYS LV_BGColor, ["FileFullPath"]) 32 | OnMessage(WM_KEYDOWN := 0x100, KeyDown) 33 | OnMessage(WM_ACTIVATE := 0x0006, LoseFocus2Close) 34 | #HotIf WinActive("ahk_exe chrome.exe") 35 | !d:: 36 | { 37 | GetDownloadInfo() 38 | ListDownloadFiles() 39 | MyGui.Show("Center") 40 | WinWaitActive("ahk_id " . CurrentHwnd) 41 | IME_To_EN(CurrentHwnd) 42 | 43 | } 44 | return 45 | 46 | GetDownloadInfo() 47 | { 48 | ; global ArrFullPath 49 | if (FileExist(db_here)) 50 | FileDelete(db_here) 51 | FileCopy db_file, db_here 52 | DB := SQLiteDB() 53 | DB.OpenDB(db_here) 54 | sql_cmd := 'SELECT current_path FROM downloads WHERE current_path!="" ORDER BY end_time DESC;' 55 | results := IndexDb(DB, sql_cmd) 56 | If !DB.CloseDB() 57 | MsgBox("Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode, "SQLite Error", 16) 58 | IndexResults := StrSplit(results, '`n') 59 | loop IndexResults.Length 60 | { 61 | ThisFile := Trim(IndexResults[A_Index]) 62 | if (FileExist(ThisFile)) 63 | { 64 | ArrFullPath.Push(ThisFile) 65 | } 66 | if (ArrFullPath.Length = 20) 67 | break 68 | } 69 | IndexDb(DB, sql_cmd) 70 | { 71 | ; global DB 72 | If !DB.Query(sql_cmd, &query_result) 73 | { 74 | MsgBox("SQLite QUERY Error`n`nMessage: " . DB.ErrorMsg . "`nCode: " . DB.ErrorCode . "`nFile: " . db_file . "`nQuery: " . sql_cmd) 75 | return 0 76 | } 77 | 78 | search_result := '' 79 | Loop 80 | { 81 | result := query_result.Next(&row) 82 | If !result 83 | { 84 | MsgBox("SQLite NEXT Error`n`nMessage: " . DB.ErrorMsg . "`nCode: " . DB.ErrorCode) 85 | return 0 86 | } 87 | If result = -1 88 | { 89 | Break 90 | } 91 | Loop query_result.ColumnCount 92 | { 93 | search_result .= row[A_Index] . A_Tab 94 | } 95 | search_result .= '`n' 96 | } 97 | query_result.Free() 98 | search_result := SubStr(search_result, 1, StrLen(search_result) - 1) ; remove last `n 99 | return search_result 100 | } 101 | } 102 | 103 | 104 | ListDownloadFiles() 105 | { 106 | global LV 107 | CountNumber := LV.GetCount() 108 | if (CountNumber >= 1) 109 | { 110 | LV.Delete 111 | try 112 | Success := IL_Destroy(ImageListID) 113 | } 114 | FileNum := ArrFullPath.Length 115 | ImageListID := IL_Create(FileNum) 116 | LV.SetImageList(ImageListID) 117 | 118 | loop FileNum 119 | { 120 | ThisFileFullPath := Trim(ArrFullPath[A_Index]) 121 | 122 | if ( not FileExist(ThisFileFullPath)) 123 | continue 124 | SplitPath ThisFileFullPath, , , &ThisFileExt 125 | ThisFileExt := Trim(ThisFileExt) 126 | IconFile := IconForFile(ThisFileExt) 127 | IL_Add(ImageListID, IconFile) 128 | LV.Add("Icon" . A_Index, ThisFileFullPath) 129 | } 130 | LV.Modify("1", "Select Focus") 131 | } 132 | IME_To_EN(hwnd) 133 | { 134 | ; https://www.cnblogs.com/yf-zhao/p/16018481.html 135 | ; hWnd := CurrentHwnd ;winGetID("A") ; 136 | ; result := SendMessage( 137 | ; 0x283, ; Message : WM_IME_CONTROL 138 | ; 0x001, ; wParam : IMC_GETCONVERSIONMODE 139 | ; 0, ; lParam : (NoArgs) 140 | ; , ; Control : (Window) 141 | ; ; Retrieves the default window handle to the IME class. 142 | ; "ahk_id " DllCall("imm32\ImmGetDefaultIMEWnd", "Uint", hWnd, "Uint") 143 | ; ) 144 | ; if(result!=0) 145 | ; { 146 | WinWaitActive("ahk_id " . CurrentHwnd) 147 | send "{Shift}" 148 | ; } 149 | 150 | } 151 | IconForFile(FileExt) 152 | { 153 | if (FileExt = "exe") 154 | { 155 | return A_ScriptDir . "\icon\exe.ico" 156 | } 157 | else if (FileExt = "") 158 | return A_ScriptDir . "\icon\NoExt.ico" 159 | else 160 | { 161 | iconFile := A_ScriptDir . "\icon\" . FileExt . ".ico" 162 | if (FileExist(iconFile)) 163 | return iconFile 164 | else 165 | return A_ScriptDir . "\icon\General.ico" 166 | } 167 | } 168 | KeyDown(wParam, lParam, nmsg, Hwnd) 169 | { 170 | static VK_ESC := 0x1B 171 | static VK_Enter := 0x0D 172 | static VK_S := 0x53 173 | 174 | gc := GuiCtrlFromHwnd(Hwnd) 175 | 176 | if (wParam = VK_ESC) 177 | { 178 | WinClose("ahk_id " . CurrentHwnd) 179 | } 180 | else if (wParam = VK_S) 181 | { 182 | FileUnderCursor := GetUnderCursor() 183 | SplitPath FileUnderCursor, , , &ThisFileExt 184 | if (ThisFileExt!="" and InStr("zip|rar|7z", ThisFileExt)) 185 | { 186 | SmartUnzip(FileUnderCursor) 187 | MyGui.Hide 188 | } 189 | else 190 | { 191 | MyGui.Hide 192 | TC_FocusOnLeftFile(FileUnderCursor) 193 | Send "{WheelDown 4}" 194 | } 195 | } 196 | else if (gc is Gui.ListView and wParam = VK_Enter) 197 | { 198 | ; press Enter in the ListView to activate corresponding window 199 | FileFullPath := GetUnderCursor() 200 | WinClose() 201 | Run FileFullPath 202 | return true 203 | } 204 | 205 | GetUnderCursor() 206 | { 207 | global LV 208 | RowNumber := 0 ; This causes the first loop iteration to start the search at the top of the list. 209 | Loop 210 | { 211 | RowNumber := LV.GetNext(RowNumber, "F") ; Resume the search at the row after that found by the previous iteration. 212 | if not RowNumber ; The above returned zero, so there are no more selected rows. 213 | break 214 | FileFullPath := LV.GetText(RowNumber, 1) 215 | } 216 | return FileFullPath 217 | } 218 | 219 | } 220 | LoseFocus2Close(wParam, lParam, nmsg, hwnd) 221 | { 222 | if( hwnd && !wParam) 223 | { 224 | MyGui.Hide 225 | try 226 | { 227 | WinClose("ahk_id " . hwnd) 228 | } 229 | } 230 | return true 231 | } 232 | Str_LastCharPos(InputStr, InChar) 233 | { 234 | return InStr(InputStr, InChar, 1, -1) 235 | } 236 | 237 | 238 | SmartUnzip(FileFullPath) 239 | { 240 | 241 | SmartUnzip_MultiFileIndicator := 0 242 | SmartUnzip_HasFolderIndicator := 0 243 | SmartUnzip_Level1FolderName := 244 | SmartUnzip_FolderNameA := 245 | SmartUnzip_FolderNameB := 246 | ZipFileList := A_Temp . "\smartunzip_" . A_Now . ".txt" 247 | global ExePath_7Z 248 | global ExePath_7ZG 249 | SplitPath FileFullPath, , &ZipFileDir, , &ZipFileName 250 | If (InStr(ExePath_7Z, " ") and SubStr(ExePath_7Z, 1, 1) != chr(34)) 251 | ExePath_7Z := chr(34) . ExePath_7Z . chr(34) 252 | qutoed_ZipFileList := chr(34) . ZipFileList . chr(34) 253 | quoted_FileFullPath := chr(34) . FileFullPath . chr(34) 254 | run_cmd := ExePath_7Z . " l " . quoted_FileFullPath . " > " . qutoed_ZipFileList 255 | quoted_run_cmd := chr(34) . run_cmd . chr(34) 256 | 257 | run_cmd := A_ComSpec . " /c " . quoted_run_cmd 258 | ExitCode := RunWait(run_cmd) 259 | ;━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 260 | 261 | IsFirstRowOfFileList := 0 262 | IsLastRowOfFileList := 0 263 | nFolder := 0 264 | nFile := 0 265 | loop read ZipFileList 266 | { 267 | If (RegExMatch(A_LoopReadLine, "^(\-{4}.*\-)$")) ; look for line starts with ---- and ends with - 268 | { 269 | 270 | If (IsFirstRowOfFileList = 0) 271 | { 272 | IsFirstRowOfFileList := 1 273 | Continue 274 | } 275 | Else 276 | { 277 | IsLastRowOfFileList := 1 278 | Break 279 | } 280 | } 281 | if (IsFirstRowOfFileList = 0) ; has not found the starting line, contiune 282 | { 283 | Continue 284 | } 285 | 286 | If (instr(A_LoopReadLine, "\")) ; skip the line which is not the first level 287 | { 288 | Continue 289 | } 290 | If (instr(A_LoopReadLine, "D....")) 291 | { 292 | nFolder := nFolder + 1 293 | SmartUnzip_FolderNameA := SubStr(A_LoopReadLine, 54) 294 | ; StringMid,,A_LoopReadLine,54,InStr(A_loopreadline,"\")-54 295 | } 296 | Else If (instr(A_LoopReadLine, "....A")) 297 | { 298 | nFile := nFile + 1 299 | } 300 | } 301 | ;━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 302 | ; TargetFolder: the foler would be Unzipped to 303 | If (nFile = 1 && nFolder = 0) ;Only ONE single file in Levle1 of the Achrive file 304 | { 305 | run_cmd := ExePath_7ZG . " x " . chr(34) . FileFullPath . chr(34) . " -o" . chr(34) . ZipFileDir . chr(34) 306 | RunWait run_cmd ;user can choose write or rename using 7z if there is any confiliction 307 | ; MsgBox ZipFileDir . "-1" 308 | TC_SetLeftPath(ZipFileDir) 309 | } 310 | Else If (nFile = 0 && nFolder = 1) ;Only ONE single folder in Level1 of the Achrive file 311 | { 312 | If (FileExist(ZipFileDir . "\" . SmartUnzip_FolderNameA)) ;if TargetFolder exists, create new folder named as TargetFolder (n) 313 | { 314 | Loop 315 | { 316 | SmartUnZip_NewFolderName := ZipFileDir . "\" . SmartUnzip_FolderNameA . " (" . A_Index . ")" 317 | If !FileExist(SmartUnZip_NewFolderName) 318 | { 319 | dbq_name := chr(34) . SmartUnZip_NewFolderName . chr(34) 320 | run_cmd := ExePath_7ZG . " x " . chr(34) . FileFullPath . chr(34) . " -o" . dbq_name 321 | RunWait run_cmd 322 | ; MsgBox dbq_name . "-2" 323 | TC_SetLeftPath(SmartUnZip_NewFolderName) 324 | break 325 | } 326 | } 327 | } 328 | Else ; if TargetFolder does NOT exist, directly unzip 329 | { 330 | dbq_name := chr(34) . ZipFileDir . chr(34) 331 | run_cmd := ExePath_7ZG . " x " . chr(34) . FileFullPath . chr(34) . " -o" . dbq_name 332 | RunWait run_cmd 333 | ; MsgBox dbq_name . "-3" 334 | TC_SetLeftPath(ZipFileDir) 335 | 336 | } 337 | } 338 | Else ;at least one folder and one file in Level1 of the Achrive file 339 | { 340 | If (FileExist(ZipFileDir . "\" . ZipFileName)) ; if TargetFolder exists , create new folder named as TargetFolder (n) 341 | { 342 | Loop 343 | { 344 | SmartUnZip_NewFolderName := ZipFileDir . "\" . ZipFileName . " (" . A_Index . ")" 345 | If !FileExist(SmartUnZip_NewFolderName) 346 | { 347 | dbq_name := chr(34) . SmartUnZip_NewFolderName . chr(34) 348 | run_cmd := ExePath_7ZG . " x " . chr(34) . FileFullPath . chr(34) . " -o" . dbq_name 349 | ; MsgBox run_cmd 350 | RunWait run_cmd 351 | ; MsgBox dbq_name . "-4" 352 | TC_SetLeftPath(SmartUnZip_NewFolderName) 353 | 354 | break 355 | } 356 | } 357 | } 358 | Else ; if TargetFolder does NOT exist, directly unzip 359 | { 360 | dbq_name := chr(34) . ZipFileDir . "\" . ZipFileName . chr(34) 361 | run_cmd := ExePath_7ZG . " x " . chr(34) . FileFullPath . chr(34) . " -o" . dbq_name 362 | RunWait run_cmd 363 | ; MsgBox dbq_name . "-5" 364 | TC_SetLeftPath(ZipFileDir . "\" . ZipFileName) 365 | ; break 366 | } 367 | } 368 | Return 369 | } 370 | -------------------------------------------------------------------------------- /Chrome_GenBookmarks.ahk: -------------------------------------------------------------------------------- 1 | #Requires AutoHotkey 2.0 2 | #Include .\lib\_JXON.ahk 3 | 4 | F1:: 5 | { 6 | global bk_dir 7 | bk_dir := DirSelect("D:\", 3, "Saving bookmarks to") 8 | if bk_dir = "" 9 | { 10 | MsgBox "You didn't select a folder." 11 | return 12 | } 13 | 14 | ; Chrome's bookmarks is saved in %Appdata%\Local\Google\Chrome\User Data\xxx\, xxx stands for Default or Profile N 15 | ; the file is named as [Bookmarks] without extension, it is acutally a json file. 16 | ; copy [Bookmarks] file into \temp and rename it as Bookmarks.json 17 | bk_pos1:=StrReplace(A_AppData,"\Roaming") . "\Local\Google\Chrome\User Data\Profile 1\" 18 | bk_pos_d:=StrReplace(A_AppData,"\Roaming") . "\Local\Google\Chrome\User Data\Default\" 19 | chrome_bk_file_dir:=FileExist(bk_pos1 . "Bookmarks")?bk_pos1:bk_pos_d 20 | chrome_bk_file:=chrome_bk_file_dir . "Bookmarks" 21 | json_file:=A_Temp . "\Bookmarks.json" 22 | if(FileExist(chrome_bk_file)) 23 | FileCopy chrome_bk_file,json_file,1 24 | else 25 | { 26 | MsgBox "Can't locate the [Bookmarks] file" 27 | return 28 | } 29 | 30 | ToolTip "Converting urls..." 31 | strAllData:= FileRead(json_file , "UTF-8") 32 | objAllData := jxon_load(&strAllData) 33 | objAllBookmarks:=objAllData["roots"]["bookmark_bar"] 34 | parse_json(objAllBookmarks,"") 35 | ToolTip 36 | } 37 | parse_json(data,ThisDir:="") 38 | { 39 | nOjectType:=OjectType(data) 40 | if(OjectType(data)=1 and data.Has("type") and data["type"]=="folder") 41 | { 42 | ThisDir:=ThisDir . data["name"] . "\" 43 | } 44 | data.Has("url") 45 | 46 | if (OjectType(data)=1) ;map 47 | { 48 | for key, value in data 49 | { 50 | if (OjectType(value)=1 or OjectType(value)=2) 51 | { 52 | parse_json(value,ThisDir) 53 | } 54 | else 55 | { 56 | ; do sth to for the level N elements here 57 | if(data.Has("name") and data.Has("url")) 58 | { 59 | Out_str:= "Dir:" . ThisDir . "`tkey: " . data["name"] . "`tvalue: " . data["url"] . "`r`n" 60 | FileAppend Out_str, "1.txt" 61 | GenShortcut(data["name"],data["url"]) 62 | } 63 | break 64 | } 65 | } 66 | } 67 | else if (OjectType(data)=2) ;array 68 | { 69 | loop data.Length 70 | { 71 | Item:=data[A_Index] 72 | parse_json(Item,ThisDir) 73 | } 74 | } 75 | else 76 | MsgBox "data member " . data.Count 77 | 78 | } 79 | 80 | GenShortcut(bk_name,bk_url) 81 | { 82 | if(Trim(bk_name)="") ;bookmark name is empty 83 | return 84 | bk_full_name:=bk_dir . "\" . bk_name . ".url" 85 | IniWrite bk_url, bk_full_name, "InternetShortcut", "URL" 86 | ; IniWrite , bk_full_name, "InternetShortcut", "IconFile" 87 | ; IniWrite 0, bk_full_name, "InternetShortcut", "IconIndex" 88 | } 89 | OjectType(data) 90 | { 91 | try 92 | { 93 | ObjItemNum:=data.Count 94 | AHKOjbect:=1 ; map 95 | } 96 | catch as e 97 | { 98 | try 99 | { 100 | ObjItemNum:=data.Length 101 | AHKOjbect:=2 ; array 102 | } 103 | catch as e 104 | { 105 | try 106 | { 107 | ObjItemNum:=ObjOwnPropCount(data) 108 | AHKOjbect:=3 ; ojbect 109 | } 110 | catch as e 111 | AHKOjbect:=4 ;string 112 | } 113 | } 114 | return AHKOjbect 115 | } 116 | -------------------------------------------------------------------------------- /Chrome_GetBookmarks.ahk: -------------------------------------------------------------------------------- 1 | #Requires AutoHotkey 2.0 2 | 3 | #Include D:\Downloads\cherry-snippet-v2-master\lib\Class_SQLiteDB.ahk 4 | ; #Include D:\SoftX\AHK_Scripts_V2\Lib\Image_ImagePut.ahk 5 | ; %LocalAppData%\Google\Chrome\ 6 | db_file:="D:\SoftX\AHK_Scripts_V2\Chrome_Bookmarks\Favicons" 7 | 8 | 9 | DB := SQLiteDB() 10 | DB.OpenDB(db_file) 11 | Get_Icon_For_URL(strUrl) 12 | If !DB.CloseDB() 13 | MsgBox("Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode, "SQLite Error", 16) 14 | 15 | Get_Icon_For_URL(URL) 16 | { 17 | ; URL:="https://mail.google.com/mail/" 18 | IconID:=Get_Icon_ID_From_URL(URL) 19 | blob:=Get_Icon_File(IconID) 20 | FileObj := FileOpen('1.ico', "w") 21 | FileObj.RawWrite(blob , blob.Size) 22 | FileObj.Close() 23 | return IconID ;. "`n" . IconFile 24 | ; get icon_id in table "icon_mapping" by url 25 | Get_Icon_ID_From_URL(strURL) 26 | { 27 | sql_cmd := 'SELECT icon_id FROM icon_mapping WHERE page_url IN ("' . strURL . '");' 28 | result:=IndexDb(sql_cmd) 29 | return result 30 | } 31 | 32 | 33 | Get_Icon_File(icon_id_number) 34 | { 35 | sql_cmd := 'SELECT image_data FROM favicon_bitmaps WHERE icon_id =' . icon_id_number . ' AND width = 32;' 36 | If !db.Query(sql_cmd, &query_result) 37 | { 38 | MsgBox("SQLite QUERY Error`n`nMessage: " . db.ErrorMsg . "`nCode: " . db.ErrorCode . "`nFile: " . db_file . "`nQuery: " . sql_cmd) 39 | return 0 40 | } 41 | 42 | search_result := '' 43 | Loop 44 | { 45 | result := query_result.Next(&row) 46 | If !result 47 | { 48 | MsgBox("SQLite NEXT Error`n`nMessage: " . db.ErrorMsg . "`nCode: " . db.ErrorCode) 49 | return 0 50 | } 51 | If result = -1 52 | { 53 | Break 54 | } 55 | search_result := row[1] 56 | query_result.Free() 57 | return search_result 58 | } 59 | } 60 | 61 | IndexDb(sql_cmd) 62 | { 63 | If !db.Query(sql_cmd, &query_result) 64 | { 65 | MsgBox("SQLite QUERY Error`n`nMessage: " . db.ErrorMsg . "`nCode: " . db.ErrorCode . "`nFile: " . db_file . "`nQuery: " . sql_cmd) 66 | return 0 67 | } 68 | 69 | search_result := '' 70 | Loop 71 | { 72 | result := query_result.Next(&row) 73 | If !result 74 | { 75 | MsgBox("SQLite NEXT Error`n`nMessage: " . db.ErrorMsg . "`nCode: " . db.ErrorCode) 76 | return 0 77 | } 78 | If result = -1 79 | { 80 | Break 81 | } 82 | Loop query_result.ColumnCount 83 | { 84 | search_result .= row[A_Index] . A_Tab 85 | } 86 | search_result .= '`n' 87 | } 88 | query_result.Free() 89 | return search_result 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /Chrome_GetIcon.md: -------------------------------------------------------------------------------- 1 | database structure 2 | ![image](https://github.com/valuex/AutohotkeyScripts/assets/3627812/90f4daa0-0962-4b7f-99d4-58441c49bc19) 3 | 4 | error message 5 | ![image](https://github.com/valuex/AutohotkeyScripts/assets/3627812/fc5d4218-439c-403a-85c8-2c26733dee25) 6 | -------------------------------------------------------------------------------- /Chrome_PinToTaskbar.ahk: -------------------------------------------------------------------------------- 1 | #Requires AutoHotkey >=2.0 2 | #Include D:\SoftX\AHK_Scripts_V2\UIA-v2-main\Lib\UIA.ahk 3 | StartTime := A_TickCount 4 | npEl := UIA.ElementFromHandle("ahk_exe chrome.exe") 5 | ; Find the first Document or Edit control (in Notepad there is only one). The type of the edit area depends on your Windows version, in newer ones it's usually Document type. 6 | btnSetting := npEl.FindElement([{Type:"MenuItem",Name:"Chrome"}]) 7 | 8 | btnSetting.Click() 9 | menuSave := npEl.FindElement([{Type:"MenuItem",Name:"保存并分享(S)"}]) 10 | menuSave.Click() 11 | menuItemCreatShortcut := npEl.FindElement([{Type:"MenuItem",Name:"创建快捷方式(S)…"}]) 12 | menuItemCreatShortcut.Click() 13 | ; wait for the appreance of create shortcut window 14 | loop 20 15 | { 16 | try 17 | btnCreatShortcut := npEl.FindElement([{Type:"Button",Name:"创建"}]) 18 | catch as e 19 | Sleep 100 20 | } 21 | btnCreatShortcut.Click() 22 | /* 23 | process the notification window 24 | 1- wait for the appearence by FindWindowEx 25 | */ 26 | loop 40 27 | { 28 | hwnd := DllCall("FindWindowEx", "ptr", 0, "ptr", 0, "str", "Windows.UI.Core.CoreWindow", "str", "新通知") 29 | if(hwnd) 30 | break 31 | Sleep 100 32 | } 33 | ;2- click the OK button 34 | loop 40 35 | { 36 | try 37 | { 38 | npEl := UIA.ElementFromHandle(hwnd) 39 | btnCreatShortcut := npEl.FindElement([{Type:"Button",Name:"是"}]) 40 | btnCreatShortcut.Click() 41 | } 42 | catch as e 43 | Sleep 100 44 | } 45 | ControlSend("{Enter}",,hwnd) ; an extra click is needed 46 | ElapsedTime := A_TickCount - StartTime ; it takes about 3 seconds 47 | -------------------------------------------------------------------------------- /Chrome_SmartClick.md: -------------------------------------------------------------------------------- 1 | # Error 2 | ![image](https://github.com/valuex/AutohotkeyScripts/assets/3627812/2cf326da-73e8-4a8b-b3cb-d82e326cff6a) 3 | 4 | # Correct output 5 | ![image](https://github.com/valuex/AutohotkeyScripts/assets/3627812/dc9f2fef-9009-4c0f-8fd3-323e48f66bd5) 6 | -------------------------------------------------------------------------------- /DownloadInfo.py: -------------------------------------------------------------------------------- 1 | from playwright.sync_api import sync_playwright 2 | from concurrent.futures import ThreadPoolExecutor 3 | import os 4 | def save_mhtml(path:str, text:str): 5 | with open(path, mode='w', encoding='UTF-8',newline='\n') as file: 6 | file.write(text) 7 | 8 | def main(): 9 | # opening the file in read mode 10 | my_file = open("url_list.txt", "r") 11 | data = my_file.read() 12 | item_list = data.split("\n") 13 | my_file.close() 14 | return item_list 15 | def get_fname(str_url): 16 | len_url=len(str_url) 17 | str_1=str_url[len_url-41:] 18 | str_2=str_1[0:len(str_1)-5] 19 | return str_2 20 | 21 | def download_page(str_url): 22 | fname=get_fname(str_url) + '.mhtml' 23 | if(os.path.exists(fname)): 24 | return 25 | else: 26 | print(fname) 27 | with sync_playwright() as playwright: 28 | browser=playwright.chromium.launch(headless=False) 29 | page=browser.new_page() 30 | page.goto(str_url,wait_until="domcontentloaded") 31 | page.wait_for_selector("a[class=exhibitor-name]") 32 | page.wait_for_selector("img") 33 | page.wait_for_timeout(3000) 34 | client=page.context.new_cdp_session(page) 35 | mhtml=client.send('Page.captureSnapshot')['data'] 36 | save_mhtml(fname,mhtml) 37 | browser.close() 38 | 39 | if __name__ == '__main__': 40 | items=main() 41 | with ThreadPoolExecutor(max_workers=10) as executor: 42 | executor.map(download_page , items) 43 | print("All Authors Info Downloaded Successfully") 44 | 45 | -------------------------------------------------------------------------------- /Everything_PasteTo.ahk: -------------------------------------------------------------------------------- 1 | 2 | 3 | ; PasteTo 4 | ; Paste the seclted file content to text editor. 5 | ; In Everything, select one source code file, then press the corresponding hotkey. 6 | ; this script will copy the file content and paste the content to the previous editor. 7 | ; Date: 2024-1-6 8 | ; Author: Valuex 9 | 10 | #Requires AutoHotkey >=2.0 11 | #SingleInstance Ignore ; only one instance is allowed 12 | if(A_Args.Length>1) 13 | ExitApp 14 | FileFullPath:=A_Args[1] 15 | SplitPath FileFullPath,,,&FileExt 16 | TxtExt:=FileRead("TxtExtension.txt") 17 | ArrExt:=StrSplit(TxtExt,"`n","`r") 18 | ThisWinID:=WinGetID("A") 19 | 20 | loop ArrExt.Length 21 | { 22 | ThisExt:=Trim(ArrExt[A_Index]) 23 | if (ThisExt="") 24 | continue 25 | if (ThisExt=FileExt) 26 | { 27 | FileContent:=FileRead(FileFullPath) 28 | Send "{ALT DOWN}{TAB}{ALT UP}" 29 | WaitForAltWin(ThisWinID, 5) 30 | SendStrByPaste(FileContent) 31 | } 32 | } 33 | 34 | WaitForAltWin(CurWinID, iSeconds) 35 | { 36 | N:=iSeconds*10 37 | loop N { 38 | Sleep 100 39 | AcID:=WinGetID("A") 40 | if(AcID!=CurWinID) 41 | return 42 | } 43 | MsgBox "The attempt to switch window failed." 44 | } 45 | 46 | SendStrByPaste(strContent) 47 | { 48 | ClipTemp:=ClipboardAll() 49 | A_Clipboard:="" 50 | A_Clipboard:=strContent 51 | if !ClipWait(2) 52 | { 53 | MsgBox "The attempt to copy text onto the clipboard failed." 54 | return 55 | } 56 | Send "^v" 57 | PasteWait() 58 | Sleep 500 59 | A_Clipboard:=ClipTemp 60 | } 61 | PasteWait(timeout:=1000){ ; (not working yet for at least one user on Win10 x64) 62 | ; https://www.autohotkey.com/boards/viewtopic.php?f=5&t=37209&p=171360#p271287 63 | start_tick := A_TickCount ; time since last reboot in milliseconds 64 | while DllCall("user32\GetOpenClipboardWindow", "Ptr") { 65 | if(A_TickCount - start_tick) > timeout { 66 | Break 67 | } 68 | Sleep 100 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Everything_PasteTo.md: -------------------------------------------------------------------------------- 1 | # 利用Everything 1.5 进行代码管理 2 | ![image](https://github.com/valuex/AutohotkeyScripts/assets/3627812/d19c3712-1600-433a-a524-e3203722723a) 3 | 4 | ## 背景 5 | 代码片段管理软件/服务有很多,包括 cheerysnippet, masscode,gist等。 6 | 个人体验下来,cheerysnippet 比较重,后端需要配置一个cheery note。 7 | masscode 和 visual studio code 配合较好,用其他编辑器时需要来回切换,就比较影响工作流了。 8 | gist 网页分类功能比较差。 9 | 所以个人也在找一些更普世的代码片段管理方案。 10 | 最近试用了Everything 1.5,里面升级的几个功能就非常适合用于代码片段管理了。 11 | ## 实现 12 | 1. 将Everything 1.5 以下的几大功能组合起来,就能很快的定位到特定代码片段文件 13 | 自定义过滤(Filter) ,标题检索,内容检索(content search),内容预览(preview) 14 | 2. 配合下面的Autohotkey 脚本,能够通过快捷键实现代码片段文件内容快速粘贴到正在工作的编辑器中 15 | 具体实现过程: 16 | - AHK 脚本链接: https://github.com/valuex/AutohotkeyScripts/blob/main/Everything_PasteTo.ahk 17 | - 将该脚本用ahk2exe转化为exe文件,放到某个目录下 18 | - 在Everything 中定义Custom Open Commands https://www.voidtools.com/forum/viewtopic.php?t=13720 19 | ` $exec("Your_Path_Here\PasteTo.exe" "%1") ` 20 | ![image](https://github.com/valuex/AutohotkeyScripts/assets/3627812/2642d9e2-09f8-4800-859e-bd107c60e04c) 21 | 22 | - 在Everything 中给上述命令配置一个快捷键 23 | ![image](https://github.com/valuex/AutohotkeyScripts/assets/3627812/7d811ed5-e321-4fb0-b1c7-db52e5256950) 24 | 25 | - 当然,会使用AHK的,也可以把下面的脚本改一下,直接利用`#HotIf`定义一个只作用于Everything 的快捷键。 26 | -------------------------------------------------------------------------------- /HelpFile.ahk: -------------------------------------------------------------------------------- 1 | /** 2 | * Interface for the AutoHotkey v2 help file. 3 | * https://github.com/G33kDude/CodeQuickTester/blob/v2-main/lib/HelpFile.ahk 4 | */ 5 | class HelpFile { 6 | 7 | /** @type {String} Base string of the URL for documentation files */ 8 | ; baseUrl := "ms-its:{}::/docs" 9 | baseUrl := "mk:@MSITStore:{}::/docs" 10 | 11 | /** @type {Map} Cache of known syntax strings by keyword */ 12 | syntaxes := Map(), syntaxes.CaseSense := false 13 | 14 | /** @type {Map} Cache of known command URL fragments by keyword */ 15 | commands := Map(), commands.CaseSense := false 16 | 17 | /** @type {Map} Cache of known variable URL fragments by keyword */ 18 | variables := Map(), variables.CaseSense := false 19 | 20 | /** @type {Map} Cache of known URL fragments by keyword */ 21 | lookup := Map(), lookup.CaseSense := false 22 | 23 | /** 24 | * @param {String} path - Path to the AutoHotkey.chm file 25 | */ 26 | __New(path := A_AhkPath "\..\AutoHotkey.chm") { 27 | if !FileExist(path) 28 | return this 29 | this.baseUrl := Format(this.baseUrl, path) 30 | 31 | ; Get the command reference 32 | page := this.GetPage("lib/index.htm") 33 | rows := unset 34 | if !IsSet(rows) ; Windows 35 | try rows := page.querySelectorAll(".info td:first-child a") 36 | if !IsSet(rows) ; Wine 37 | try rows := page.body.querySelectorAll(".info td:first-child a") 38 | if !IsSet(rows) { ; IE8 39 | rows := this.HTMLCollection() 40 | trows := page.getElementsByTagName("table")[0].children[0].children 41 | loop trows.length 42 | rows.push(trows.Item(A_Index - 1).children[0].children[0]) 43 | } 44 | 45 | ; Pull the keywords 46 | loop rows.length { 47 | row := rows.Item(A_Index - 1) 48 | for text in StrSplit(row.innerText, "/") 49 | if RegExMatch(text, "^[\w#]+", &match) && !this.commands.Has(match.0) 50 | this.commands[match.0] := "lib/" RegExReplace(row.getAttribute("href"), "^about:") 51 | } 52 | 53 | ; Get the variables reference 54 | page := this.GetPage("Variables.htm") 55 | rows := unset 56 | if !IsSet(rows) ; Windows 57 | try rows := page.querySelectorAll(".info td:first-child") 58 | if !IsSet(rows) ; Wine 59 | try rows := page.body.querySelectorAll(".info td:first-child") 60 | if !IsSet(rows) { ; IE8 61 | rows := HelpFile.HTMLCollection() 62 | tables := page.getElementsByTagName("table") 63 | loop tables.length { 64 | trows := tables.Item(A_Index - 1).children[0].children 65 | loop trows.length 66 | rows.push(trows.Item(A_Index - 1).children[0]) 67 | } 68 | } 69 | 70 | ; Pull the keywords 71 | loop rows.length { 72 | row := rows.Item(A_Index - 1) 73 | if RegExMatch(row.innerText, "A_\w+", &match) 74 | this.variables[match.0] := "Variables.htm#" row.parentNode.getAttribute("id") 75 | } 76 | 77 | ; Combine 78 | ; out := "" 79 | for k, v in this.commands { 80 | this.lookup[k] := v 81 | ; out .= "|" k 82 | } 83 | ; A_Clipboard := SubStr(out, 2) 84 | for k, v in this.variables 85 | this.lookup[k] := v 86 | } 87 | 88 | /** 89 | * Gets an HtmlFile object for the given page 90 | * @param {String} path - The given page 91 | */ 92 | GetPage(path) { 93 | ; Strip fragment 94 | path := this.baseUrl "/" RegExReplace(path, "[?#].+") 95 | 96 | ; Request the page 97 | xhr := ComObject("MSXML2.XMLHTTP.3.0") 98 | xhr.open("GET", path, True) 99 | xhr.send() 100 | 101 | ; Load it into HtmlFile 102 | html := ComObject("HtmlFile") 103 | html.open() 104 | html.write(xhr.responseText) 105 | html.close() 106 | 107 | ; Wait for it to finish parsing 108 | while !(html.readyState = "interactive" || html.readyState = "complete") 109 | Sleep 50 110 | 111 | return html 112 | } 113 | 114 | /** 115 | * Opens the help file to the page corresponding to a given keyword 116 | * 117 | * @param {String} keyword - A keyword to open the help file to 118 | */ 119 | Open(keyword := "") { 120 | suffix := this.lookup.has(keyword) ? this.lookup[keyword] : "index.htm" 121 | Run 'hh.exe "' this.baseUrl '/' suffix '"' 122 | } 123 | 124 | /** 125 | * Opens the help file to the page corresponding to a given keyword 126 | * in the existed hh.exe instance or a new one 127 | * @param {String} keyword - A keyword to open the help file to 128 | */ 129 | HH_AHKHelp(UserKeyWords) 130 | { 131 | Win_AHK_Help:="AutoHotkey v2 Help ahk_exe hh.exe" 132 | if (!WinExist(Win_AHK_Help)) 133 | { 134 | run "hh.exe C:\Program Files\AutoHotkey\v2.0.2\AutoHotkey.chm" 135 | Hwnd:=WinWait(Win_AHK_Help,,3) 136 | if(!Hwnd) 137 | return 138 | } 139 | suffix := this.lookup.has(UserKeyWords) 140 | if(suffix) 141 | { 142 | suffix:=this.lookup[UserKeyWords] 143 | ThisKwUrl:=this.baseUrl '/' suffix 144 | this.HH_NavigateTo(ThisKwUrl) 145 | Send "!n" ; activate Index tab 146 | } 147 | else 148 | { 149 | this.HH_SendToUI(UserKeyWords) 150 | } 151 | } 152 | HH_SendToUI(UserKeyWords) 153 | { 154 | Win_AHK_Help:="AutoHotkey v2 Help ahk_exe hh.exe" 155 | if (WinExist(Win_AHK_Help)) 156 | { 157 | WinActivate(Win_AHK_Help) 158 | WinWaitActive(Win_AHK_Help, , 2) 159 | Send "!s" ; Alt+S: activate Search tab 160 | Sleep(500) 161 | Send "^+{Home}" 162 | Sleep(500) 163 | Send "{del}" 164 | ClipSaved :=ClipboardAll() 165 | A_Clipboard:=Trim(UserKeyWords) 166 | Send "^v" 167 | Sleep(500) 168 | Send "{enter}" 169 | A_Clipboard:=ClipSaved 170 | ClipSaved :="" 171 | } 172 | } 173 | HH_NavigateTo(vPath) 174 | { 175 | hWnd:=WinGetID("AutoHotkey v2 Help ahk_class HH Parent") 176 | if hWnd 177 | { 178 | oWB := this.WBGet("ahk_id " hWnd) 179 | oWB.Navigate(vPath) 180 | oWB := "" 181 | } 182 | else 183 | Run "hh.exe " . vPath 184 | } 185 | WBGet(WinTitle:="ahk_class IEFrame", Svr:=1) 186 | { 187 | ; Reference: 188 | ; C:\Program%20Files\AutoHotkey\v2.0.2\AutoHotkey.chm::/docs/lib/ComObjQuery.htm 189 | ; https://www.autohotkey.com/boards/viewtopic.php?f=6&t=39869 190 | static msg := DllCall("RegisterWindowMessage", "str", "WM_HTML_GETOBJECT") 191 | , IID := "{0002DF05-0000-0000-C000-000000000046}" ;// IID_IWebBrowserApp 192 | static VT_UNKNOWN := 13 193 | lResult := SendMessage(msg, 0, 0, "Internet Explorer_Server" Svr, WinTitle) 194 | if (lResult != "") 195 | { 196 | GUID:=Buffer(16) 197 | if DllCall("ole32\CLSIDFromString", "wstr","{332C4425-26CB-11D0-B483-00C04FD90119}", "ptr",GUID) >= 0 { 198 | DllCall("oleacc\ObjectFromLresult", "ptr",lResult, "ptr",GUID, "ptr",0, "ptr*",pdoc := ComValue(VT_UNKNOWN, 0)) 199 | pweb :=ComObjQuery(pdoc,IID,IID) 200 | ObjAddRef(pweb.ptr) 201 | static VT_DISPATCH := 9 202 | return ComValue(VT_DISPATCH, pweb.ptr) 203 | } 204 | } 205 | } 206 | 207 | 208 | /** 209 | * Gets the syntax hints for a given keyword, if available 210 | * 211 | * @param {String} keyword - The keyword to pull the syntax for 212 | * 213 | * @return {String} The syntax, or empty string 214 | */ 215 | GetSyntax(keyword := "") { 216 | ; Only look for Syntax of commands 217 | if !this.commands.Has(keyword) 218 | return "" 219 | path := this.commands[keyword] 220 | 221 | ; Try to find it in the cache 222 | if this.syntaxes.Has(keyword) 223 | return this.syntaxes[keyword] 224 | 225 | ; Get the right DOM to search 226 | page := this.GetPage(path) 227 | root := page ; Keep the page root in memory or it will be garbage collected 228 | if RegExMatch(path, "#\K.+", &id) 229 | page := page.getElementById(id.0) 230 | 231 | ; Search for the syntax-containing element 232 | if !IsSet(nodes) ; Windows 233 | try nodes := page.getElementsByClassName("Syntax") 234 | if !IsSet(nodes) ; Wine 235 | try nodes := page.body.getElementsByClassName("Syntax") 236 | if !IsSet(nodes) ; IE8 237 | nodes := page.getElementsByTagName("pre") 238 | if nodes.Length 239 | element := nodes.Item(0) 240 | else { 241 | try { 242 | loop 4 243 | page := page.nextElementSibling 244 | until page.classList.contains("Syntax") 245 | } 246 | } 247 | 248 | text := "" 249 | if text == "" ; Windows 250 | try text := nodes.Item(0).innerText 251 | if text == "" ; Some versions of Wine 252 | try text := nodes.Item(0).innerHTML 253 | 254 | return this.syntaxes[keyword] := StrReplace(text, "`r") 255 | } 256 | 257 | /** Array wrapper implementing some of the HTMLCollection interface */ 258 | class HTMLCollection extends Array { 259 | Item(i) => this[i + 1] 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /Ini_File_Lib.ahk: -------------------------------------------------------------------------------- 1 | iniSecToMap(iniFile,iniSec) 2 | { 3 | SecContents:=IniRead(iniFile,iniSec) 4 | ArrSecContents:=StrSplit(SecContents,"`n","`r") 5 | KeyValueMap:=Map() 6 | loop ArrSecContents.Length 7 | { 8 | ThisPair:=ArrSecContents[A_Index] 9 | EqualPos:=InStr(ThisPair,"=") 10 | ThisKey:=Trim(SubStr(ThisPair,1,EqualPos-1)) 11 | ThisValue:=Trim(SubStr(ThisPair,EqualPos+1)) 12 | KeyValueMap[ThisKey]:=ThisValue 13 | } 14 | return KeyValueMap 15 | } 16 | 17 | IniSec2Arr(FileName,SecName) 18 | { 19 | SecContents:=IniRead(FileName,SecName) 20 | ArrSecItems:=StrSplit(SecContents,"`r","`n") 21 | ArrKeyValue:=Array() 22 | loop ArrSecItems.Length 23 | { 24 | ThisLine:=ArrSecItems[A_Index] 25 | EqualPos:=InStr(ThisLine,"=") 26 | ThisKey:=SubStr(ThisLine,1,EqualPos-1) 27 | ThisValue:=SubStr(ThisLine,EqualPos+1) 28 | ArrKeyValue.Push(Map("key",ThisKey,"value",ThisValue)) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AutohotkeyScripts 2 | My collection of Autohotkey scripts 3 | -------------------------------------------------------------------------------- /TC_AHK_Lib.ahk: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | TC_Minimum_Mode() 4 | fucntion: hide TC's title bar, menu bar, button bar, etc 5 | agruments: path of WinCMD.ini 6 | return: none 7 | */ 8 | 9 | TF_Minimum_Mode(WinCMD_ini) 10 | { 11 | ; global WinCMD_ini 12 | ; 1-toggle caption 13 | ; https://learn.microsoft.com/en-us/windows/win32/winmsg/window-styles 14 | ; 0x00C00000 WS_CAPTION 15 | ; Style & 0x00C00000 is great than 0, caption exists 16 | TC_Class:="ahk_class TTOTAL_CMD" 17 | Style := WinGetStyle(TC_Class) 18 | if(Style & 0x00C00000) 19 | WinSetStyle("-0xC00000", TC_Class) ;hide caption 20 | 21 | ; 2- toggle meanu bar 22 | ; user_command to hide menu https://www.ghisler.ch/board/viewtopic.php?t=72307 23 | ; define those contents in 24 | /* 25 | [em_hidemenu] 26 | cmd=OPENLANGUAGEFILE 27 | param="%|commander_path|\Language\0.mnu" 28 | [em_showmenu] 29 | cmd=OPENLANGUAGEFILE 30 | param="%|commander_path|\Language\Wcmd_chn.mnu" 31 | */ 32 | 33 | menuName:=IniRead(WinCMD_ini,"Configuration","Mainmenu") 34 | if(InStr(menuName,"Wcmd_chn")) ; use translated menu, then hide it 35 | TC_SendUserCommand("em_hidemenu") 36 | 37 | ;3- toggle other objects by using TC internal command 38 | Check2Hide("ButtonBar", 2901) ;cm_VisButtonBar=2901;Hide button bar 39 | Check2Hide("DriveBar1", 2902) ;cm_VisButtonBar=2902;hide drive button bars 40 | Check2Hide("DriveBar2", 2903) ;cm_VisTwoDriveButtons=2903;hide two drive bars 41 | Check2Hide("ButtonBarVertical", 2944) ;cm_VisButtonBar2=2944;Hide vertical button bar 42 | Check2Hide("DirectoryTabs", 2916) ;hide folder tabs 43 | Check2Hide("DriveCombo", 2906) ;cm_VisDriveCombo=2906; hide drive combobox 44 | Check2Hide("CurDir", 2907) ;Hide current directory 45 | Check2Hide("TabHeader", 2908) ;Hide tab header (sorting) 46 | Check2Hide("CmdLine", 2910) ;Hide Command line 47 | Check2Hide("KeyButtons", 2911) ;cm_VisKeyButtons=2911; hide function key buttons 48 | 49 | ; Check2Hide("DriveBarFlat", 2904) ; cm_VisFlatDriveButtons=2904;Buttons: Flat/normal mode 50 | ; Check2Hide("InterfaceFlat", 2905) ; cm_VisFlatInterface=2905;Interface: Flat/normal mode 51 | ; Check2Hide("BreadCrumbBar", 2911) ; cm_VisBreadCrumbs=2926;Show/hide Breadcrumb bar 52 | ; Check2Hide("StatusBar", 2909) ;cm_VisStatusBar=2909;Show/hide status bar 53 | 54 | 55 | Check2Hide(Item, em_code) 56 | { 57 | ItemShown:=IniRead(WinCMD_ini,"Layout",Item) 58 | if(ItemShown) 59 | SendMessage(1075, em_code, 0, , TC_Class) 60 | } 61 | } 62 | 63 | TF_Toggle_Mode(WinCMD_ini) 64 | { 65 | ; 1-toggle caption 66 | Style := WinGetStyle("ahk_class TTOTAL_CMD") 67 | ; https://learn.microsoft.com/en-us/windows/win32/winmsg/window-styles 68 | ; 0x00C00000 WS_CAPTION 69 | ; Style & 0x00C00000 is 0, there is no caption 70 | if(Style & 0x00C00000) 71 | WinSetStyle("-0xC00000", "ahk_class TTOTAL_CMD") ;hide caption 72 | else 73 | WinSetStyle("+0xC00000", "ahk_class TTOTAL_CMD") ; show caption 74 | 75 | ; 2- toggle meanu bar by user-defined command 76 | ; user_command to hide menu https://www.ghisler.ch/board/viewtopic.php?t=72307 77 | ; define those contents in 78 | /* 79 | [em_hidemenu] 80 | cmd=OPENLANGUAGEFILE 81 | param="%|commander_path|\Language\0.mnu" 82 | [em_showmenu] 83 | cmd=OPENLANGUAGEFILE 84 | param="%|commander_path|\Language\Wcmd_chn.mnu" 85 | */ 86 | ; global WinCMD_ini 87 | ; WinCMD_ini:="D:\SoftX\TotalCommander11\WinCMD.ini" 88 | menuName:=IniRead(WinCMD_ini,"Configuration","Mainmenu") 89 | if(InStr(menuName,"Wcmd_chn")) 90 | TC_SendUserCommand("em_hidemenu") 91 | else 92 | TC_SendUserCommand("em_showmenu") 93 | ;3- toggle other objects by using TC internal command 94 | SendMessage(1075, 2907, 0, , "ahk_class TTOTAL_CMD") ;Show/hide current directory 95 | SendMessage(1075, 2916, 0, , "ahk_class TTOTAL_CMD") ;Show/hide folder tabs 96 | SendMessage(1075, 2908, 0, , "ahk_class TTOTAL_CMD") ;;Show/hide tab header (sorting) 97 | SendMessage(1075, 2909, 0, , "ahk_class TTOTAL_CMD") ;Show/hide status bar 98 | SendMessage(1075, 2901, 0, , "ahk_class TTOTAL_CMD") ;cm_VisButtonBar=2901;Show/hide button bar 99 | SendMessage(1075, 2944, 0, , "ahk_class TTOTAL_CMD") ;cm_VisButtonBar2=2944;Show/hide vertical button bar 100 | } 101 | 102 | TF_Goto1stDownload(FilePath) 103 | { 104 | global g_TCClass:="ahk_class TTOTAL_CMD" 105 | global g_TCEXE:="D:\SoftX\TotalCommander11\TotalCMD64.exe" 106 | TC_AOR(g_TCClass,g_TCEXE) 107 | TC_FocusOnLeftFile(FilePath) 108 | ; SendMessage(0x433,4001,0,,"ahk_class TTOTAL_CMD") ; cm_FocusLeft=4001;Focus on left file list 109 | ; SendMessage(0x433,124,-1,,"ahk_class TTOTAL_CMD") ; cm_LeftByDateTime=124;Left: Sort by date 110 | ; SendMessage(0x433,2050,0,,"ahk_class TTOTAL_CMD") ; cm_GoToFirstFile=2050;Place cursor on first file in list 111 | } 112 | 113 | TC_AOR(WinTitle,WinExe) 114 | { 115 | if(WinExist(WinTitle)) 116 | { 117 | WinActivate(WinTitle) 118 | WinA:=WinWaitClass("TTOTAL_CMD") 119 | return WinA ? true: false 120 | } 121 | else 122 | { 123 | Run WinExe 124 | WinWaitActive(WinTitle,,5) 125 | WinA:=WinWaitClass("TTOTAL_CMD") 126 | return WinA ? true: false 127 | } 128 | WinWaitClass(WinClass) 129 | { 130 | loop(100) 131 | { 132 | aClass:=WinGetClass("A") 133 | if(StrCompare(aClass,WinClass)=0) 134 | return true 135 | else 136 | Sleep(100) 137 | } 138 | return false 139 | } 140 | } 141 | 142 | TC_FocusOnLeftFile(FileFullPath) 143 | { 144 | SplitPath FileFullPath,,&DirPath 145 | TC_LeftNewTab(DirPath) 146 | AcSide:=TC_GetActiveSide1() 147 | If(AcSide:=2) 148 | SendMessage(0x433,4001,0,,"ahk_class TTOTAL_CMD") ;cm_FocusLeft=4001;Focus on left file list 149 | TC_FocusLeftFile(FileFullPath) 150 | WinActivate("ahk_class TTOTAL_CMD") 151 | } 152 | TC_FocusOnRightFile(FileFullPath) 153 | { 154 | SplitPath FileFullPath,,&DirPath 155 | TC_SetRightPath(DirPath) 156 | AcSide:=TC_GetActiveSide1() 157 | If(AcSide:=1) 158 | SendMessage(0x433,4002,0,,"ahk_class TTOTAL_CMD") ;cm_FocusLeft=4002;Focus on right file list 159 | TC_OpenAndSelect(FileFullPath) 160 | WinActivate("ahk_class TTOTAL_CMD") 161 | } 162 | /* 163 | TC_SetLeftPath(inpath) | TC_SetRightPath(inpath) 164 | fucntion: set path in TC's left / right side 165 | agruments: directory path 166 | return: none 167 | */ 168 | 169 | ; https://www.ghisler.ch/board/viewtopic.php?p=277574#256573 170 | /* 171 | The complete syntax is in fact : 172 | `r\0 ; eg: D:\xxx\ `r E:\xxx\ \0 173 | `r\0S ; eg: D:\xxx\ `r E:\xxx\ \0 174 | `r\0T open in new Tab ; eg: D:\xxx\ `r E:\xxx\ \0T 175 | */ 176 | TC_FocusLeftFile(FilePath) 177 | { 178 | newPath:=FilePath . "\:`r" 179 | TC_SetPath(newPath) 180 | } 181 | TC_FocusRightFile(FilePath) 182 | { 183 | newPath:="`r" . FilePath . "\:\0" 184 | TC_SetPath(newPath) 185 | } 186 | 187 | TC_SetLeftPath(DirPath) 188 | { 189 | ; DirPath should be ended with \ 190 | newPath:=DirPath . "`r" 191 | TC_SetPath(newPath) 192 | } 193 | TC_LeftNewTab(DirPath) 194 | { 195 | ; DirPath should be ended with \ 196 | newPath:=DirPath . "`r" . "\0" 197 | SendMessage(0x433,4001,0,,"ahk_class TTOTAL_CMD") ; FocusLeft 198 | SendMessage(0x433,3001,0,,"ahk_class TTOTAL_CMD") ; NewTab 199 | TC_SetPath(newPath) ; CD to DirPath 200 | } 201 | TC_SetRightPath(DirPath) 202 | { 203 | ; DirPath should be ended with \ 204 | newPath:="`r" . DirPath . "\0" 205 | TC_SetPath(newPath) 206 | } 207 | TC_RightNewTab(DirPath) 208 | { 209 | ; DirPath should be ended with \ 210 | newPath:=DirPath . "`r" . "\0" 211 | SendMessage(0x433,4002,0,,"ahk_class TTOTAL_CMD") ; FocusRight 212 | SendMessage(0x433,3001,0,,"ahk_class TTOTAL_CMD") ; NewTab 213 | TC_SetPath(newPath) ; CD to DirPath 214 | } 215 | TC_SetPath(userCommand) 216 | { 217 | ; https://www.autohotkey.com/boards/viewtopic.php?p=538463&sid=4471e03917209854441ac07ebdc70901#p538463 218 | static dwData := 17475 ;;Ord("C") +256*Ord("D") 219 | static WM_COPYDATA := 0x4A 220 | cbData := Buffer(StrPut(userCommand, 'CP0')) 221 | StrPut(userCommand, cbData, 'CP0') 222 | COPYDATASTRUCT := Buffer(A_PtrSize * 3) 223 | NumPut('Ptr', dwData, 'Ptr', cbData.size, 'Ptr', cbData.ptr, COPYDATASTRUCT) 224 | MsgResult:=SendMessage( WM_COPYDATA,, COPYDATASTRUCT,, 'ahk_class TTOTAL_CMD') 225 | return MsgResult 226 | } 227 | 228 | 229 | /* 230 | TC_SendUserCommand() 231 | fucntion: send user defined command in the usercmd.ini to TC 232 | agruments: command name in usercmd.ini 233 | return: none 234 | */ 235 | 236 | TC_SendUserCommand(userCommand) 237 | { 238 | ; https://www.autohotkey.com/boards/viewtopic.php?p=538463&sid=4471e03917209854441ac07ebdc70901#p538463 239 | static dwData := 19781 ;Ord("E") +256*Ord("M") 240 | static WM_COPYDATA := 0x4A 241 | cbData := Buffer(StrPut(userCommand, 'CP0')) 242 | StrPut(userCommand, cbData, 'CP0') 243 | COPYDATASTRUCT := Buffer(A_PtrSize * 3) 244 | NumPut('Ptr', dwData, 'Ptr', cbData.size, 'Ptr', cbData.ptr, COPYDATASTRUCT) 245 | MsgResult:=SendMessage( WM_COPYDATA,, COPYDATASTRUCT,, 'ahk_class TTOTAL_CMD') 246 | return MsgResult 247 | } 248 | 249 | /* 250 | TC_OpenAndSelect() 251 | fucntion: open TC, navigate to the dir and get the file selected 252 | agruments: file full path 253 | return: none 254 | 255 | ; SendMessage with "WM_User+51" WM_User=0x400=1024 +51 == 0x433=1075 ( to send a number) 256 | */ 257 | 258 | TC_OpenAndSelect(FilePath) 259 | { 260 | AcSide:=TC_GetActiveSide1() 261 | If(AcSide=1) 262 | TC_FocusLeftFile(FilePath) 263 | else 264 | TC_FocusRightFile(FilePath) 265 | } 266 | 267 | /* 268 | TC_GetActiveSide() 269 | fucntion: get the active side of TC 270 | return: 1 or 2. 1=L, 2= R 271 | */ 272 | TC_GetActiveSide1() 273 | { 274 | Result := SendMessage(1074, 1000, 0, ," ahk_class TTOTAL_CMD") 275 | return Result 276 | } 277 | 278 | /* 279 | TC_GetActiveSide() 280 | fucntion: get the active side of TC 281 | return: L or R 282 | */ 283 | 284 | TC_GetActiveSide() 285 | { 286 | ;https://wincmd.ru/forum/viewtopic.php?p=110848&sid=0dfde01723b39e508e96d62c00a7a9b5 287 | If WinExist("ahk_class TTOTAL_CMD") ;&& WinActive("ahk_class TTOTAL_CMD") 288 | { 289 | OnMessage(0x4a, TC_Receive_WM_COPYDATA) ; 0x4a is WM_COPYDATA 290 | TC_Send_WM_COPYDATA(cmd:="A") 291 | ; 25.11.11 Added: Send WM_COPYDATA 292 | ; with dwData='G'+256*'A' and lpData pointing to command to get back WM_COPYDATA with various info. 293 | ; % Supported commands: 294 | ; A: Active side (returns L or R), or 295 | ; % Supported two byte command: 296 | ; % first byte: L=left, R=right, S=source, T=target. 297 | ; % Second byte: P=current path, C=list count, I=caret index, N=name of file under caret. 298 | ; % dwData of return is 'R'+256*'A' (32/64) 299 | return retVal 300 | } 301 | else 302 | return "TC does NOT exist" 303 | } 304 | 305 | TC_Send_WM_COPYDATA(cmd){ 306 | 307 | Critical 308 | if(!RegExMatch(cmd, "^(A|[LRST][PCIN]?)$")) 309 | return 310 | static dwData:=Ord("G") + 256 * Ord("W") 311 | static WM_COPYDATA := 0x4A ;WM_COPYDATA=0x4A=74 312 | cbData := Buffer(StrPut(cmd, 'CP0')) 313 | StrPut(cmd, cbData, 'CP0') 314 | CopyDataStruct:=Buffer(A_PtrSize * 3) 315 | NumPut('Ptr', dwData, 'Ptr', cbData.size, 'Ptr', cbData.ptr, COPYDATASTRUCT) 316 | MsgResult:=SendMessage(WM_COPYDATA, A_ScriptHwnd, CopyDataStruct, , "ahk_class TTOTAL_CMD") 317 | return MsgResult 318 | } 319 | 320 | TC_Receive_WM_COPYDATA(wParam, lParam, msg, hwnd) 321 | { 322 | global retVal 323 | PtrPos:=NumGet(lParam + A_PtrSize * 2,0,"Ptr") 324 | retVal:=StrGet(PtrPos) 325 | return 1 326 | } 327 | -------------------------------------------------------------------------------- /TC_Minimal_interface.md: -------------------------------------------------------------------------------- 1 | This is the new version of minimum TC interface 2 | no caption, no menu bar, no button bar 3 | only two panels! 4 | ![image](https://github.com/valuex/AutohotkeyScripts/assets/3627812/42faa132-acd0-4f57-b05c-a484ae0165e7) 5 | 6 | 7 | 8 | ``` autohotkey 9 | ; 1-toggle caption 10 | Style := WinGetStyle("ahk_class TTOTAL_CMD") 11 | ; https://learn.microsoft.com/en-us/windows/win32/winmsg/window-styles 12 | ; 0x00C00000 WS_CAPTION 13 | ; Style & 0x00C00000 is 0, there is no caption 14 | if(Style & 0x00C00000) 15 | WinSetStyle("-0xC00000", "ahk_class TTOTAL_CMD") ;hide caption 16 | else 17 | WinSetStyle("+0xC00000", "ahk_class TTOTAL_CMD") ; show caption 18 | 19 | ; 2- toggle meanu bar by user-defined command 20 | ; user_command to hide menu https://www.ghisler.ch/board/viewtopic.php?t=72307 21 | ; define those contents in 22 | /* 23 | [em_hidemenu] 24 | cmd=OPENLANGUAGEFILE 25 | param="%|commander_path|\Language\0.mnu" 26 | [em_showmenu] 27 | cmd=OPENLANGUAGEFILE 28 | param="%|commander_path|\Language\Wcmd_chn.mnu" 29 | */ 30 | WinCMD_ini:="D:\SoftX\TotalCommander11\WinCMD.ini" 31 | menuName:=IniRead(WinCMD_ini,"Configuration","Mainmenu") 32 | if(InStr(menuName,"Wcmd_chn")) 33 | SendTCUserCommand("em_hidemenu") 34 | else 35 | SendTCUserCommand("em_showmenu") 36 | ;3- toggle other objects by using TC internal command 37 | SendMessage(1075, 2907, 0, , "ahk_class TTOTAL_CMD") ;Show/hide current directory 38 | SendMessage(1075, 2916, 0, , "ahk_class TTOTAL_CMD") ;Show/hide folder tabs 39 | SendMessage(1075, 2908, 0, , "ahk_class TTOTAL_CMD") ;;Show/hide tab header (sorting) 40 | SendMessage(1075, 2909, 0, , "ahk_class TTOTAL_CMD") ;Show/hide status bar 41 | SendMessage(1075, 2901, 0, , "ahk_class TTOTAL_CMD") ;cm_VisButtonBar=2901;Show/hide button bar 42 | SendMessage(1075, 2944, 0, , "ahk_class TTOTAL_CMD") ;cm_VisButtonBar2=2944;Show/hide vertical button bar 43 | 44 | 45 | SendTCUserCommand(userCommand) 46 | { 47 | ; https://www.autohotkey.com/boards/viewtopic.php?p=538463&sid=4471e03917209854441ac07ebdc70901#p538463 48 | static EM := 19781 49 | static WM_COPYDATA := 0x4A 50 | ansiBuf := Buffer(StrPut(userCommand, 'CP0')) 51 | StrPut(userCommand, ansiBuf, 'CP0') 52 | COPYDATASTRUCT := Buffer(A_PtrSize * 3) 53 | NumPut('Ptr', EM, 'Ptr', ansiBuf.size, 'Ptr', ansiBuf.ptr, COPYDATASTRUCT) 54 | MsgResult:=SendMessage( WM_COPYDATA,, COPYDATASTRUCT,, 'ahk_class TTOTAL_CMD') 55 | return MsgResult 56 | } 57 | ``` 58 | -------------------------------------------------------------------------------- /TC_Open.ahk: -------------------------------------------------------------------------------- 1 | ; TC_Open 2 | ; Open file or folder with Total Commander 3 | ; 1. if a folder already open in one of TC's tabs, activate the corresponding tab; else, open a new tab 4 | ; 2. if the input file's directory open in one of TC's tabs, activate the corresponding tab, select the input file; else, open a new tab and select the file 5 | ; 3. for special folders, like Control, My Computer, it will be open use explorer.exe 6 | ; Author: Valuex 7 | ; 2024/2/3 8 | #Requires AutoHotkey >=2.0 9 | #Include C:\Users\wei_x\Desktop\Chrome_Download\lib\TC_AHK_Lib.ahk 10 | 11 | fpath:="" 12 | loop A_Args.Length 13 | { 14 | fpath:=fpath . A_Args[A_Index] . " " 15 | } 16 | fpath:=Trim(fpath) ; remove the last space 17 | SpecialFolder := RegExMatch(fpath, "::\{.*\}") ; ::{26EE0668-A00A-44D7-9371-BEB064C98683} control 18 | DiskDrive:=RegExMatch(fpath, '([A-Z]:)\"',&DrivePath) ; drive 19 | if (SpecialFolder) 20 | Run "explorer.exe " . fpath ; for special folders, open it with default explorer 21 | else if (DiskDrive) 22 | { 23 | fpath:=DrivePath[1] . "\" 24 | TC_Open(fpath) 25 | } 26 | else 27 | { 28 | TC_Open(fpath) 29 | } 30 | return 31 | 32 | TC_Open(InputPath) 33 | { 34 | TC_Path:=IsScriptInTCDir() 35 | InPutType:=IsInputFileOrFolder(InputPath) ; 0- not exist;1 - Folder; 2- File 36 | IsTC_Active:=AOR("ahk_class TTOTAL_CMD",TC_Path) 37 | 38 | if(!TC_Path or !InPutType or !IsTC_Active) 39 | return 40 | 41 | TC_OpenTabsFile:=A_ScriptDir . "\User\SAVETABS2.tab" 42 | ReOutput(TC_OpenTabsFile) 43 | ; get open tabs number in active panel 44 | AcTabs:=IniRead(TC_OpenTabsFile,"activetabs") 45 | AcTabNum:=IniRead(TC_OpenTabsFile,"activetabs","activetab") 46 | AcTabKeyName:=String(AcTabNum) . "_path" 47 | AcTabPath:=IniRead(TC_OpenTabsFile,"activetabs",AcTabKeyName) 48 | iTabExist:=false 49 | if(InPutType=1) ; input is folder 50 | { 51 | iAcTab:=IsFolderInActiveTab(AcTabPath,InputPath,AcTabNum) 52 | if(iAcTab) 53 | iTab:=iAcTab 54 | else 55 | iTab:=IsFolderOpenInTabs(AcTabs,InputPath) 56 | 57 | if(iTab) 58 | { 59 | xsTCCommand:=5200+iTab ; in TotalCMD.inc, left tab id starts from 5201 60 | SendMessage(1075, xsTCCommand, 0, , "ahk_class TTOTAL_CMD") 61 | } 62 | else 63 | { 64 | TC_LeftNewTab(InputPath) 65 | } 66 | } 67 | else ; input is file 68 | { 69 | SplitPath InputPath, , &dir 70 | iAcTab:=IsFolderInActiveTab(AcTabPath,dir,AcTabNum) 71 | if(iAcTab) 72 | iTab:=iAcTab 73 | else 74 | iTab:=IsFolderOpenInTabs(AcTabs,dir) 75 | if(iTab) 76 | { 77 | xsTCCommand:=5201+iTab-1 ; in TotalCMD.inc, left tab id starts from 5201 78 | SendMessage(1075, xsTCCommand, 0, , "ahk_class TTOTAL_CMD") ; go to tab 79 | TC_OpenAndSelect(InputPath) 80 | } 81 | else 82 | { 83 | TC_FocusOnLeftFile(InputPath) 84 | } 85 | } 86 | AOR(WinTitle,WinExe) 87 | { 88 | if(WinExist(WinTitle)) 89 | { 90 | WinActivate(WinTitle) 91 | WinA:=WinWaitClass("TTOTAL_CMD") 92 | return WinA ? true: false 93 | } 94 | else 95 | { 96 | Run WinExe 97 | WinWaitActive(WinTitle,,5) 98 | WinA:=WinWaitClass("TTOTAL_CMD") 99 | return WinA ? true: false 100 | } 101 | } 102 | WinWaitClass(WinClass) 103 | { 104 | loop(100) 105 | { 106 | aClass:=WinGetClass("A") 107 | if(StrCompare(aClass,WinClass)=0) 108 | return true 109 | else 110 | Sleep(100) 111 | } 112 | return false 113 | } 114 | IsInputFileOrFolder(FilePattern) 115 | { 116 | AttributeString := FileExist(FilePattern) 117 | if(InStr(AttributeString,"D")) 118 | return 1 ;"Folder" 119 | else if(AttributeString) 120 | return 2 ;"File" 121 | else 122 | return 0 ;AttributeString: empty means no file exsits 123 | } 124 | IsScriptInTCDir() 125 | { 126 | ; check whether this script in the same directory as Total Commander main program 127 | TC64:=A_ScriptDir . "\Totalcmd64.exe" 128 | TC32:=A_ScriptDir . "\Totalcmd.exe" 129 | if A_Is64bitOS AND FileExist(TC64) 130 | TC:=DoubleQuote(TC64) 131 | else if FileExist(TC32) 132 | TC:=DoubleQuote(TC32) 133 | else 134 | { 135 | MsgBox "This script shall be put in the directory of Totalcmd.exe!" 136 | return "" 137 | } 138 | return TC 139 | } 140 | 141 | IsFolderOpenInTabs(ActiveTabs,InputPath) 142 | { 143 | ; loop to see if there is any tab already exist 144 | if(!SubStr(InputPath,StrLen(InputPath)="\")) 145 | InputPath:=InputPath . "\" 146 | ArrAcTabs:=StrSplit(ActiveTabs,"`n","`r") 147 | AcTabsNum:=ArrAcTabs.Length-1 148 | loop AcTabsNum 149 | { 150 | i:=Floor((A_Index-1)/2) ; in SAVETABS2.tab, tab id starts from 0 151 | iTabIndex:=String(i) . "_path" 152 | ThisLine:=ArrAcTabs[A_Index] 153 | ThisLineID:= GetTabID(ThisLine) 154 | ThisLinePath:= GetTabPath(ThisLine) 155 | if(!InStr(ThisLineID,iTabIndex)) 156 | continue 157 | if(StrCompare(InputPath,ThisLinePath)=0) 158 | { 159 | TabIndex:=StrSplit(ThisLine,"_")[1] 160 | return TabIndex+1 161 | } 162 | } 163 | return false 164 | } 165 | IsFolderInActiveTab(ActiveTabPath,InputPath,AcTabNumber) 166 | { 167 | if(StrCompare(InputPath,ActiveTabPath)=0) 168 | return AcTabNumber 169 | else 170 | return false 171 | } 172 | GetTabID(iniLine) 173 | { 174 | ; to the left of =, like 0_path, 1_path 175 | EqualPos:=InStr(iniLine,"=") 176 | TabID:=SubStr(iniLine,1,EqualPos-1) 177 | return TabID 178 | } 179 | GetTabPath(iniLine) 180 | { 181 | EqualPos:=InStr(iniLine,"=") 182 | TabPath:=SubStr(iniLine,EqualPos+1) 183 | return TabPath 184 | } 185 | ReOutput(TC_OpenTabsFile) 186 | { 187 | if(FileExist(TC_OpenTabsFile)) 188 | FileDelete TC_OpenTabsFile 189 | 190 | ; output open tab list 191 | TC_SendUserCommand("em_savealltabs") 192 | 193 | loop 10 194 | { 195 | Sleep(200) 196 | if(FileExist(TC_OpenTabsFile)) 197 | break 198 | } 199 | } 200 | DoubleQuote(strInput) 201 | { 202 | return Chr(34) . strInput . Chr(34) 203 | } 204 | } 205 | 206 | 207 | 208 | -------------------------------------------------------------------------------- /TC_Open.md: -------------------------------------------------------------------------------- 1 | 1. 将`OpenTCSelected.exe`放到TC主程序所在目录 2 | 下载exe:https://github.com/valuex/AutohotkeyScripts/releases/tag/V0.1 3 | 脚本:https://github.com/valuex/AutohotkeyScripts/blob/main/TC_Open.ahk 4 | 3. 在注册表中进行如下配置: 5 | 注册表位置: `计算机\HKEY_CLASSES_ROOT\Folder\shell\open\command` 6 | 配置内容: `D:\SoftX\TotalCommander11\OpenTCSelected.exe "%1"` 7 | 8 | ![image](https://github.com/valuex/AutohotkeyScripts/assets/3627812/7e454419-604e-4bb2-8a7b-f61850800fe5) 9 | -------------------------------------------------------------------------------- /TC_OpenTCWithFileSelected.ahk: -------------------------------------------------------------------------------- 1 | F1:: 2 | { 3 | tc_exe:="D:\SoftX\TotalCommander11\TotalCMD64.exe" 4 | fpath:="D:\Downloads\yourfile.txt" 5 | if(FileExist(fpath)) 6 | r_cmd:=tc_exe . " /O /T /A /L=" . Chr(34) . fpath . Chr(34) 7 | else 8 | { 9 | SplitPath fpath,,&OutDir 10 | if(FileExist(OutDir)) 11 | r_cmd:=tc_exe . " /O /T /L=" . Chr(34) . OutDir . Chr(34) 12 | else 13 | r_cmd:=tc_exe 14 | } 15 | Run r_cmd 16 | } 17 | 18 | -------------------------------------------------------------------------------- /TC_QuickMove.ahk: -------------------------------------------------------------------------------- 1 | #Requires AutoHotkey >=2.0 2 | ; TC_QuickMove 3 | ; Move files/Folders in the current dir to [destination folder] quickly 4 | ; [destination folder] is in the oppsite panel of Total Commander 5 | ; user can choose the [destination folder] from a menu which list all the tabs open in the oppsite panel of TC. 6 | ; Author: Valuex 7 | ; Date: 2023-12-27 8 | F2:: 9 | { 10 | global TC_Sel 11 | AcWinClass:=WinGetClass("A") 12 | if(AcWinClass!="TTOTAL_CMD") 13 | return 14 | TC_Sel:=TC_GetSelection() 15 | if(!TC_Sel) 16 | return 17 | TC_ListOpenTabs() 18 | } 19 | return 20 | TC_GetSelection(){ 21 | 22 | SendMessage( 1075, 2018, 0, , "ahk_class TTOTAL_CMD") ;cm_CopyFullNamesToClip 23 | SelectedFiles:=StrSplit(A_Clipboard,"`n","`r") 24 | if(SelectedFiles.Length=1) 25 | { 26 | Candy_IsOneFile:=1 27 | return SelectedFiles[1] 28 | } 29 | Else 30 | { 31 | Candy_IsMultiFile:=1 32 | loop SelectedFiles.Length 33 | { 34 | SelectedFilesNames.=SelectedFiles[A_Index] . "`n" 35 | } 36 | return SelectedFilesNames 37 | } 38 | } 39 | TC_ListOpenTabs() 40 | { 41 | MyMenu:=Menu() 42 | global TC_OpenTabsFile 43 | TC_OpenTabsFile:=A_ScriptDir . "\User\SAVETABS2.tab" 44 | ReOutput(TC_OpenTabsFile) 45 | ; get open tabs number in inactive panel 46 | AcTabs:=IniRead(TC_OpenTabsFile,"inactivetabs") 47 | loop 200 48 | { 49 | DirPath:=IniRead(TC_OpenTabsFile, "inactivetabs",String(A_Index-1) . "_path", "error") 50 | if(DirPath="error") 51 | break 52 | PathArr:=StrSplit(DirPath,"\") 53 | if(PathArr.Length=1) 54 | ThisDir:=DirPath 55 | else 56 | ThisDir:=PathArr[PathArr.Length-1] 57 | ThisDir_Pinyin:=zh2py(ThisDir) 58 | FoundPos:=RegExMatch(ThisDir_Pinyin,"(a-zA-Z)",&F1st_Pinyin) 59 | try 60 | MenuItemName:="&" . F1st_Pinyin[1] . "`t" . ThisDir 61 | catch as e 62 | MenuItemName:="&" . A_Index . "`t" . ThisDir 63 | MyMenu.Add MenuItemName, TC_MoveSelection 64 | } 65 | MyMenu.Show() 66 | ReOutput(TC_OpenTabsFile) 67 | { 68 | if(FileExist(TC_OpenTabsFile)) 69 | FileDelete TC_OpenTabsFile 70 | 71 | ; output open tab list 72 | SendTCUserCommand("em_savealltabs") 73 | loop 10 74 | { 75 | Sleep(200) 76 | if(FileExist(TC_OpenTabsFile)) 77 | break 78 | } 79 | } 80 | DoubleQuote(strInput) 81 | { 82 | return Chr(34) . strInput . Chr(34) 83 | } 84 | } 85 | TC_MoveSelection(ItemName,ItemPos,*) 86 | { 87 | DirPath:=IniRead(TC_OpenTabsFile, "inactivetabs",String(ItemPos-1) . "_path", "error") 88 | SelDirArr:=StrSplit(TC_Sel,"`n","`r") 89 | loop SelDirArr.Length 90 | { 91 | FileMove SelDirArr[A_Index],DirPath 92 | } 93 | } 94 | SendTCUserCommand(userCommand) 95 | { 96 | ; https://www.autohotkey.com/boards/viewtopic.php?p=538463&sid=4471e03917209854441ac07ebdc70901#p538463 97 | static EM := 19781 98 | static WM_COPYDATA := 0x4A 99 | ansiBuf := Buffer(StrPut(userCommand, 'CP0')) 100 | StrPut(userCommand, ansiBuf, 'CP0') 101 | COPYDATASTRUCT := Buffer(A_PtrSize * 3) 102 | NumPut('Ptr', EM, 'Ptr', ansiBuf.size, 'Ptr', ansiBuf.ptr, COPYDATASTRUCT) 103 | MsgResult:=SendMessage( WM_COPYDATA,, COPYDATASTRUCT,, 'ahk_class TTOTAL_CMD') 104 | return MsgResult 105 | } 106 | 107 | zh2py(str) 108 | { 109 | ; 从 php 转换而来的 (http://www.sjyhome.com/php/201311170606.html) 110 | ; 根据汉字区位表,(http://www.mytju.com/classcode/tools/QuWeiMa_FullList.asp) 111 | ; 我们可以看到从16-55区之间是按拼音字母排序的,所以我们只需要判断某个汉字的区位码就可以得知它的拼音首字母. 112 | 113 | ; 区位表第一部份,按拼音字母排序的. 114 | ; 16区-55区 115 | /* 116 | 'A'=>0xB0A1, 'B'=>0xB0C5, 'C'=>0xB2C1, 'D'=>0xB4EE, 'E'=>0xB6EA, 'F'=>0xB7A2, 'G'=>0xB8C1,'H'=>0xB9FE, 117 | 'J'=>0xBBF7, 'K'=>0xBFA6, 'L'=>0xC0AC, 'M'=>0xC2E8, 'N'=>0xC4C3, 'O'=>0xC5B6, 'P'=>0xC5BE,'Q'=>0xC6DA, 118 | 'R'=>0xC8BB, 'S'=>0xC8F6, 'T'=>0xCBFA, 'W'=>0xCDDA, 'X'=>0xCEF4, 'Y'=>0xD1B9, 'Z'=>0xD4D1 119 | */ 120 | static FirstTable := [ 0xB0C5, 0xB2C1, 0xB4EE, 0xB6EA, 0xB7A2, 0xB8C1, 0xB9FE, 0xBBF7, 0xBFA6, 0xC0AC, 0xC2E8 121 | , 0xC4C3, 0xC5B6, 0xC5BE, 0xC6DA, 0xC8BB, 0xC8F6, 0xCBFA, 0xCDDA, 0xCEF4, 0xD1B9, 0xD4D1, 0xD7FA ] 122 | static FirstLetter := StrSplit("ABCDEFGHJKLMNOPQRSTWXYZ") 123 | 124 | ; 区位表第二部份,不规则的,下面的字母是每个区里面对应字的拼音首字母.从网上查询整理出来的,可能会有部份错误. 125 | ; 56区-87区 126 | static SecondTable := [ StrSplit("CJWGNSPGCGNEGYPBTYYZDXYKYGTZJNMJQMBSGZSCYJSYYFPGKBZGYDYWJKGKLJSWKPJQHYJWRDZLSYMRYPYWWCCKZNKYYG") 127 | , StrSplit("TTNGJEYKKZYTCJNMCYLQLYPYSFQRPZSLWBTGKJFYXJWZLTBNCXJJJJTXDTTSQZYCDXXHGCKBPHFFSSTYBGMXLPBYLLBHLX") 128 | , StrSplit("SMZMYJHSOJNGHDZQYKLGJHSGQZHXQGKXZZWYSCSCJXYEYXADZPMDSSMZJZQJYZCJJFWQJBDZBXGZNZCPWHWXHQKMWFBPBY") 129 | , StrSplit("DTJZZKXHYLYGXFPTYJYYZPSZLFCHMQSHGMXXSXJYQDCSBBQBEFSJYHWWGZKPYLQBGLDLCDTNMAYDDKSSNGYCSGXLYZAYPN") 130 | , StrSplit("PTSDKDYLHGYMYLCXPYCJNDQJWXQXFYYFJLEJPZRXCCQWQQSBZKYMGPLBMJRQCFLNYMYQMSQYRBCJTHZTQFRXQHXMQJCJLY") 131 | , StrSplit("QGJMSHZKBSWYEMYLTXFSYDXWLYCJQXSJNQBSCTYHBFTDCYZDJWYGHQFRXWCKQKXEBPTLPXJZSRMEBWHJLBJSLYYSMDXLCL") 132 | , StrSplit("QKXLHXJRZJMFQHXHWYWSBHTRXXGLHQHFNMGYKLDYXZPYLGGSMTCFBAJJZYLJTYANJGBJPLQGSZYQYAXBKYSECJSZNSLYZH") 133 | , StrSplit("ZXLZCGHPXZHZNYTDSBCJKDLZAYFFYDLEBBGQYZKXGLDNDNYSKJSHDLYXBCGHXYPKDJMMZNGMMCLGWZSZXZJFZNMLZZTHCS") 134 | , StrSplit("YDBDLLSCDDNLKJYKJSYCJLKWHQASDKNHCSGAGHDAASHTCPLCPQYBSZMPJLPCJOQLCDHJJYSPRCHNWJNLHLYYQYYWZPTCZG") 135 | , StrSplit("WWMZFFJQQQQYXACLBHKDJXDGMMYDJXZLLSYGXGKJRYWZWYCLZMSSJZLDBYDCFCXYHLXCHYZJQSQQAGMNYXPFRKSSBJLYXY") 136 | , StrSplit("SYGLNSCMHCWWMNZJJLXXHCHSYZSTTXRYCYXBYHCSMXJSZNPWGPXXTAYBGAJCXLYXDCCWZOCWKCCSBNHCPDYZNFCYYTYCKX") 137 | , StrSplit("KYBSQKKYTQQXFCMCHCYKELZQBSQYJQCCLMTHSYWHMKTLKJLYCXWHEQQHTQKZPQSQSCFYMMDMGBWHWLGSLLYSDLMLXPTHMJ") 138 | , StrSplit("HWLJZYHZJXKTXJLHXRSWLWZJCBXMHZQXSDZPSGFCSGLSXYMJSHXPJXWMYQKSMYPLRTHBXFTPMHYXLCHLHLZYLXGSSSSTCL") 139 | , StrSplit("SLDCLRPBHZHXYYFHBMGDMYCNQQWLQHJJCYWJZYEJJDHPBLQXTQKWHLCHQXAGTLXLJXMSLJHTZKZJECXJCJNMFBYCSFYWYB") 140 | , StrSplit("JZGNYSDZSQYRSLJPCLPWXSDWEJBJCBCNAYTWGMPAPCLYQPCLZXSBNMSGGFNZJJBZSFZYNTXHPLQKZCZWALSBCZJXSYZGWK") 141 | , StrSplit("YPSGXFZFCDKHJGXTLQFSGDSLQWZKXTMHSBGZMJZRGLYJBPMLMSXLZJQQHZYJCZYDJWFMJKLDDPMJEGXYHYLXHLQYQHKYCW") 142 | , StrSplit("CJMYYXNATJHYCCXZPCQLBZWWYTWBQCMLPMYRJCCCXFPZNZZLJPLXXYZTZLGDLTCKLYRZZGQTTJHHHJLJAXFGFJZSLCFDQZ") 143 | , StrSplit("LCLGJDJZSNZLLJPJQDCCLCJXMYZFTSXGCGSBRZXJQQCTZHGYQTJQQLZXJYLYLBCYAMCSTYLPDJBYREGKLZYZHLYSZQLZNW") 144 | , StrSplit("CZCLLWJQJJJKDGJZOLBBZPPGLGHTGZXYGHZMYCNQSYCYHBHGXKAMTXYXNBSKYZZGJZLQJTFCJXDYGJQJJPMGWGJJJPKQSB") 145 | , StrSplit("GBMMCJSSCLPQPDXCDYYKYPCJDDYYGYWRHJRTGZNYQLDKLJSZZGZQZJGDYKSHPZMTLCPWNJYFYZDJCNMWESCYGLBTZZGMSS") 146 | , StrSplit("LLYXYSXXBSJSBBSGGHFJLYPMZJNLYYWDQSHZXTYYWHMCYHYWDBXBTLMSYYYFSXJCBDXXLHJHFSSXZQHFZMZCZTQCXZXRTT") 147 | , StrSplit("DJHNRYZQQMTQDMMGNYDXMJGDXCDYZBFFALLZTDLTFXMXQZDNGWQDBDCZJDXBZGSQQDDJCMBKZFFXMKDMDSYYSZCMLJDSYN") 148 | , StrSplit("SPRSKMKMPCKLGTBQTFZSWTFGGLYPLLJZHGJJGYPZLTCSMCNBTJBQFKDHBYZGKPBBYMTDSSXTBNPDKLEYCJNYCDYKZTDHQH") 149 | , StrSplit("SYZSCTARLLTKZLGECLLKJLQJAQNBDKKGHPJTZQKSECSHALQFMMGJNLYJBBTMLYZXDXJPLDLPCQDHZYCBZSCZBZMSLJFLKR") 150 | , StrSplit("ZJSNFRGJHXPDHYJYBZGDLQCSEZGXLBLGYXTWMABCHECMWYJYZLLJJYHLGNDJLSLYGKDZPZXJYYZLWCXSZFGWYYDLYHCLJS") 151 | , StrSplit("CMBJHBLYZLYCBLYDPDQYSXQZBYTDKYXJYYCNRJMPDJGKLCLJBCTBJDDBBLBLCZQRPYXJCJLZCSHLTOLJNMDDDLNGKATHQH") 152 | , StrSplit("JHYKHEZNMSHRPHQQJCHGMFPRXHJGDYCHGHLYRZQLCYQJNZSQTKQJYMSZSWLCFQQQXYFGGYPTQWLMCRNFKKFSYYLQBMQAMM") 153 | , StrSplit("MYXCTPSHCPTXXZZSMPHPSHMCLMLDQFYQXSZYJDJJZZHQPDSZGLSTJBCKBXYQZJSGPSXQZQZRQTBDKYXZKHHGFLBCSMDLDG") 154 | , StrSplit("DZDBLZYYCXNNCSYBZBFGLZZXSWMSCCMQNJQSBDQSJTXXMBLTXZCLZSHZCXRQJGJYLXZFJPHYMZQQYDFQJJLZZNZJCDGZYG") 155 | , StrSplit("CTXMZYSCTLKPHTXHTLBJXJLXSCDQXCBBTJFQZFSLTJBTKQBXXJJLJCHCZDBZJDCZJDCPRNPQCJPFCZLCLZXZDMXMPHJSGZ") 156 | , StrSplit("GSZZQLYLWTJPFSYASMCJBTZYYCWMYTZSJJLJCQLWZMALBXYFBPNLSFHTGJWEJJXXGLLJSTGSHJQLZFKCGNNNSZFDEQFHBS") 157 | , StrSplit("AQTGYLBXMMYGSZLDYDQMJJRGBJTKGDHGKBLQKBDMBYLXWCXYTTYBKMRTJZXQJBHLMHMJJZMQASLDCYXYQDLQCAFYWYXQHZ") ] 158 | 159 | 160 | static var := Buffer(2) 161 | 162 | ; 如果不包含中文字符,则直接返回原字符 163 | if !RegExMatch(str, "[^\x{00}-\x{ff}]") 164 | Return str 165 | 166 | Loop Parse str 167 | { 168 | StrPut(A_LoopField, var, "CP936") 169 | H := NumGet(var, 0, "UChar") 170 | L := NumGet(var, 1, "UChar") 171 | 172 | ; 字符集非法 173 | if (H < 0xB0 || L < 0xA1 || H > 0xF7 || L = 0xFF) 174 | { 175 | newStr .= A_LoopField 176 | Continue 177 | } 178 | 179 | if (H < 0xD8) || (H >= 0xB0 && H <=0xD7) ; 查询文字在一级汉字区(16-55) 180 | { 181 | W := (H << 8) | L 182 | For key, value in FirstTable 183 | { 184 | if (W < value) 185 | { 186 | newStr .= FirstLetter[key] 187 | Break 188 | } 189 | } 190 | } 191 | else ; if (H >= 0xD8 && H <= 0xF7) ; 查询中文在二级汉字区(56-87) 192 | newStr .= SecondTable[ H - 0xD8 + 1 ][ L - 0xA1 + 1 ] 193 | } 194 | 195 | Return newStr 196 | } 197 | -------------------------------------------------------------------------------- /TC_Run.ahk: -------------------------------------------------------------------------------- 1 | #Requires Autohotkey >=2.0 2 | #Include .\lib\Ini_File_Lib.ahk 3 | #Include .\lib\TC_AHK_Lib.ahk 4 | 5 | global g_TCDir:="D:\SoftX\TotalCommander11\" 6 | global g_tc_CmdFile:=g_TCDir . "TotalCMD.inc" 7 | global g_CMDGroups 8 | global g_TC_CMDArr 9 | global g_UserCMDGroupName:="UCMD" 10 | global WinCMD_ini:=g_TCDir . "WinCMD.ini" 11 | 12 | 13 | g_TC_CMDArr:=GetCMDArr(&g_CMDGroups) 14 | MyGui := Gui("+AlwaysOnTop +ToolWindow") 15 | MyGui.SetFont("s14", "Verdana") 16 | ; MyGui.Opt("-Caption") 17 | CurrentHwnd := MyGui.Hwnd 18 | CtlInput:=MyGui.AddEdit("w700") 19 | CtlInput.OnEvent("Change",UserInput_Change) 20 | LVS_SHOWSELALWAYS := 8 ; Seems to have the opposite effect with Explorer theme, at least on Windows 11. 21 | LV_BGColor:=Format(' Background{:x}', DllCall("GetSysColor", "int", 15, "int")) ; background color of listview item when get selected by up & down arrow 22 | LV := MyGui.Add("ListView", "r20 w700 -Multi -Hdr " LVS_SHOWSELALWAYS LV_BGColor, ["Group","Command","Description","Code"]) 23 | LV.OnEvent("DoubleClick", LVItemHanlder) 24 | OnMessage(WM_KEYDOWN := 0x100, KeyDown) 25 | #HotIf WinActive("ahk_class TTOTAL_CMD") 26 | !e:: 27 | { 28 | if(FileExist("log.txt")) 29 | FileDelete("log.txt") 30 | Add2List() 31 | ; LV.ModifyCol ; Auto-size each column to fit its contents. 32 | LVColumnWidth() 33 | MyGui.Show() 34 | } 35 | LVColumnWidth() 36 | { 37 | LV.ModifyCol(1,"80") 38 | LV.ModifyCol(2,"200") 39 | LV.ModifyCol(3,"300") 40 | LV.ModifyCol(4,"150") 41 | } 42 | ; excute corrsponding command 43 | LVItemHanlder(LV,RowNum) 44 | { 45 | InputStr:=CtlInput.Value 46 | CMDCode :=LV.GetText(RowNum,1) 47 | CMDName := LV.GetText(RowNum,2) 48 | CMDComment := LV.GetText(RowNum,3) 49 | CMDGroup :=LV.GetText(RowNum,4) 50 | 51 | if(CMDGroup=g_UserCMDGroupName) 52 | { 53 | IniWrite(InputStr,"Setting.ini","commands",CMDName) 54 | ; MsgBox CMDComment 55 | %CMDComment%() 56 | } 57 | else if(CMDCode>0) 58 | { 59 | IniWrite(InputStr,"Setting.ini","commands",CMDName) 60 | try 61 | PostMessage(0x433,CMDCode,0,,"ahk_class TTOTAL_CMD") 62 | catch TimeoutError as err 63 | ToolTip "Time out" 64 | } 65 | else 66 | { 67 | ToolTip "Can NOT excute CMD with negative code now!" 68 | SetTimer () => ToolTip(), -3000 69 | } 70 | WinClose() 71 | } 72 | 73 | 74 | KeyDown(wParam, lParam, nmsg, Hwnd) 75 | { 76 | global LV 77 | static VK_UP := 0x26 78 | static VK_DOWN := 0x28 79 | static VK_Enter := 0x0D 80 | static VK_ESC:=0x1B 81 | static VK_Ctrl:=0x11 82 | static VK_W:=0x57 83 | static VK_CtrlW:=0x1157 84 | 85 | gc := GuiCtrlFromHwnd(Hwnd) 86 | if !(wParam = VK_UP || wParam = VK_DOWN || wParam=VK_Enter || wParam=VK_ESC || wParam=VK_W) ;|| wParam=VK_Ctrl|| wParam=VK_W 87 | return 88 | if (gc is Gui.Edit and (wParam = VK_UP || wParam = VK_DOWN )) 89 | { 90 | ; press up & down in Eidt control to select item in listview 91 | CurRowNumber := LV.GetNext() ;get current selected row number 92 | LastRowNumber := LV.GetCount() 93 | if(CurRowNumber=1 and wParam = VK_UP) 94 | LV.Modify(LastRowNumber, "Select Focus") 95 | else if (CurRowNumber=LastRowNumber and wParam = VK_DOWN) 96 | LV.Modify("1", "Select Focus") 97 | else 98 | PostMessage nmsg, wParam, lParam, LV 99 | return true 100 | } 101 | else if (wParam=VK_ESC or (wParam=VK_W and GetKeyState("Ctrl"))) 102 | { 103 | WinClose("ahk_id " . CurrentHwnd) 104 | } 105 | ; else if ( gc is Gui.ListView and wParam=VK_Enter ) 106 | else if (wParam=VK_Enter ) 107 | { 108 | RowNumber := LV.GetNext() ;get current selected row number 109 | LVItemHanlder(LV,RowNumber) 110 | return true 111 | } 112 | } 113 | Add2List() 114 | { 115 | global LV 116 | i:=0 117 | For CMDName , CMDInfo in g_TC_CMDArr 118 | { 119 | i:=i+1 120 | if(i>50) 121 | break 122 | ThisItem:=g_TC_CMDArr[CMDName] 123 | LV.Add(,ThisItem["Code"],CMDName,ThisItem["Comment"],ThisItem["Group"]) 124 | } 125 | LV.Modify("1", "Select Focus") 126 | } 127 | 128 | UserInput_Change(*) 129 | { 130 | InputStr:=CtlInput.Value 131 | FoundPos1 := RegExMatch(InputStr, "^\/(\w*?)\s(\w*)" , &OutputVar) 132 | FoundPos2 := RegExMatch(Trim(InputStr), "^\/(\w+?)$" , &InGroupNamePat) 133 | FoundPos3 := RegExMatch(Trim(InputStr), "^;([0-9]+|-[0-9]+)$" , &InCMDCodePat) 134 | IsIndexByGroup:=FoundPos2=1 135 | IsIndexByCode:=FoundPos3=1 136 | InputStrLastChar:=SubStr(InputStr,StrLen(InputStr)) 137 | IsAutoExpandToFirstGroup:=IsIndexByGroup and InputStrLastChar=" " 138 | SpacePos:=InStr(InputStr," ") 139 | Keywords:=Trim(SubStr(InputStr,SpacePos+1)) 140 | static AutoExpandedGroup:="" 141 | 142 | if(InputStr="/") ; start to index groups' name only 143 | { 144 | LV.Delete 145 | loop g_CMDGroups.Length 146 | LV.Add(,g_CMDGroups[A_Index],"","","") 147 | AutoExpandedGroup:="" 148 | LV.ModifyCol 149 | } 150 | else if(InputStr="" or InputStr=";") ; input nothing or only input semicolon for code indexing 151 | { 152 | LV.Delete 153 | Add2List() 154 | AutoExpandedGroup:="" 155 | LVColumnWidth() 156 | } 157 | else if(IsIndexByGroup) ; indexing group by "/xxx" 158 | { 159 | LV.Delete 160 | InRegNeedle:=Str2RegChars(InGroupNamePat[1]) 161 | loop g_CMDGroups.Length 162 | { 163 | ThisItem:=g_CMDGroups[A_Index] 164 | FoundPos := RegExMatch(ThisItem, "i)" . InRegNeedle , &OutputVar) 165 | if(FoundPos>=1) 166 | { 167 | LV.Add(,ThisItem,"","","") 168 | } 169 | } 170 | 171 | ; auto expand to the 1st group in the listview when space is input 172 | if(InputStrLastChar=" " and LV.GetCount()>=1) ;if indexing by "/xxx" 173 | { 174 | Row1Text:=LV.GetText(1,1) 175 | AutoExpandedGroup:=Row1Text 176 | LV.Delete 177 | For CMDName , CMDInfo in g_TC_CMDArr 178 | { 179 | ThisItem:=g_TC_CMDArr[CMDName] 180 | if(ThisItem["Group"]=Row1Text) 181 | { 182 | LV.Add(,ThisItem["Code"],CMDName,ThisItem["Comment"],ThisItem["Group"]) 183 | } 184 | } 185 | LVColumnWidth() 186 | } 187 | 188 | } 189 | else if(AutoExpandedGroup) ;indexing command by "/xxxxxx" 190 | { 191 | LV.Delete 192 | InRegNeedle:=Str2RegChars(Keywords) 193 | AllMatchedItems:="" 194 | For CMDName , CMDInfo in g_TC_CMDArr 195 | { 196 | ThisItem:=g_TC_CMDArr[CMDName] 197 | IsTheExpandedGroup:=(ThisItem["Group"]=AutoExpandedGroup) 198 | FoundPos1 := RegExMatch(CMDName, "i)" . InRegNeedle , &OutputVar) 199 | FoundPos2 := RegExMatch(ThisItem["Comment"], "i)" . InRegNeedle , &OutputVar) 200 | 201 | RegMatchX(CMDName,InRegNeedle,&InCMDNamePat,1, &FoundPos1,&MatchScore1:=0) 202 | RegMatchX(ThisItem["Comment"],InRegNeedle,&InCommentPat,1, &FoundPos2,&MatchScore2:=0) 203 | ThisMatchedScore:=GetMatchScore(MatchScore1,MatchScore2) 204 | ThisMatchedItem:=ThisMatchedScore . "|" . CMDName 205 | 206 | if(IsTheExpandedGroup and (FoundPos1 or FoundPos2)) 207 | { 208 | AllMatchedItems:=AllMatchedItems . ThisMatchedItem . "`n" 209 | } 210 | } 211 | SortAndAddToLV(AllMatchedItems) 212 | } 213 | else if(IsIndexByCode) 214 | { 215 | InputCode:=InCMDCodePat[1] 216 | LV.Delete 217 | AllMatchedItems:="" 218 | For CMDName , CMDInfo in g_TC_CMDArr 219 | { 220 | ThisItem:=g_TC_CMDArr[CMDName] 221 | CMDCode:=ThisItem["Code"] 222 | FoundPos := RegExMatch(CMDCode, InputCode) 223 | if(FoundPos=0) 224 | continue 225 | if(CMDCode>0) 226 | { 227 | ThisMatchedItem:=FoundPos . CMDCode . "|" . CMDName 228 | AllMatchedItems:=AllMatchedItems . ThisMatchedItem . "`n" 229 | } 230 | else 231 | { 232 | ; for command with minus code, increase weight to make it appear at the back of the list 233 | ThisMatchedItem:=(FoundPos+1)*10000 . Abs(CMDCode) . "|" . CMDName 234 | AllMatchedItems:=AllMatchedItems . ThisMatchedItem . "`n" 235 | } 236 | } 237 | SortAndAddToLV(AllMatchedItems) 238 | } 239 | else ; indexing command name and description 240 | { 241 | InRegNeedle:=Str2RegChars(InputStr) 242 | LV.Delete 243 | PreCmdsAdded:=LoadPreSaved(InputStr) 244 | AllMatchedItems:="" 245 | For CMDName , CMDInfo in g_TC_CMDArr 246 | { 247 | ThisItem:=g_TC_CMDArr[CMDName] 248 | ThisMatchedScore:=0 249 | RegMatchX(CMDName,InRegNeedle,&InCMDNamePat,1, &FoundPos1,&MatchScore1:=0) 250 | RegMatchX(ThisItem["Comment"],InRegNeedle,&InCommentPat,1, &FoundPos2,&MatchScore2:=0) 251 | 252 | if(FoundPos1 or FoundPos2) 253 | { 254 | if(PreCmdsAdded.Has(CMDName)) 255 | continue 256 | ThisMatchedScore:=GetMatchScore(MatchScore1,MatchScore2) 257 | ThisMatchedItem:=ThisMatchedScore . "|" . CMDName 258 | AllMatchedItems:=AllMatchedItems . ThisMatchedItem . "`n" 259 | } 260 | } 261 | SortAndAddToLV(AllMatchedItems) 262 | } 263 | ; LV.ModifyCol ; Auto-size each column to fit its contents. 264 | 265 | ; regmatchx to get matched results including matched content, position and score. 266 | RegMatchX(Haystack,NeedleRegEx,&OutputVar,StartingPos:=1, &FoundPos:=0,&MatchScore:=0) 267 | { 268 | FoundPos := RegExMatch(Haystack, "i)" . NeedleRegEx , &OutputVar) 269 | MatchScore:=0 270 | if(FoundPos) 271 | { 272 | loop OutputVar.Count 273 | MatchScore:= MatchScore+OutputVar.Pos[A_Index] 274 | } 275 | } 276 | ;get match score for one command from matching results in name and description 277 | GetMatchScore(Score1,Score2) 278 | { 279 | 280 | if(Score1=0 and Score2=0) 281 | MatchScore:=10000 ; large number 282 | else if(Score1=0 or Score2=0) 283 | MatchScore:=Score1=0?Score2:Score1 284 | else 285 | MatchScore:=Min(Score1,Score2+0.5) ; 0.5 makes the 2nd item with a little bit lower priority 286 | return MatchScore 287 | } 288 | ; convert input string into regex pattern 289 | Str2RegChars(InputStr) 290 | { 291 | CharsRegNeedle:="" 292 | ArrChars:=StrSplit(InputStr) 293 | loop ArrChars.Length 294 | { 295 | ThisChar:=ArrChars[A_Index] 296 | if(ThisChar=" ") 297 | continue 298 | CharsRegNeedle:=CharsRegNeedle . "(" . ThisChar . ".*?)" 299 | } 300 | return CharsRegNeedle 301 | } 302 | ; load commands from setting. ini 303 | LoadPreSaved(InputStr:="") 304 | { 305 | global LV 306 | PreCMDMap:=iniSecToMap("Setting.ini","Commands") 307 | PreCMDsAdded:=Map() 308 | AllMatchedItems:="" 309 | InRegNeedle:=Str2RegChars(InputStr) 310 | For CMDName , CMDShortName in PreCMDMap 311 | { 312 | ThisMatchedScore:=0 313 | FoundPos1 := RegExMatch(CMDShortName, "i)" . InRegNeedle , &CMDShortNamePat) 314 | if(FoundPos1) 315 | { 316 | loop CMDShortNamePat.Count 317 | ThisMatchedScore:= ThisMatchedScore+CMDShortNamePat.Pos[A_Index] 318 | ThisItem:=g_TC_CMDArr[CMDName] 319 | ThisMatchedItem:=ThisMatchedScore . "|" . CMDName 320 | AllMatchedItems:=AllMatchedItems . ThisMatchedItem . "`n" 321 | } 322 | } 323 | PreCMDsAdded:=SortAndAddToLV(AllMatchedItems) 324 | 325 | return PreCMDsAdded 326 | } 327 | ; sort commands and load them into listview 328 | SortAndAddToLV(AllMatchedItems) 329 | { 330 | CMDsAdded:=Map() 331 | AllMatchedItems := subStr(AllMatchedItems, 1, strLen(AllMatchedItems) - 1) ; remove trailing `n 332 | SortedItems := Sort(Trim(AllMatchedItems) , , SortByScore) 333 | ArrAllMatchedItems:=StrSplit(SortedItems,"`n") 334 | loop ArrAllMatchedItems.Length 335 | { 336 | ThisLine:=ArrAllMatchedItems[A_Index] 337 | CMDName:=StrSplit(ThisLine,"|")[2] 338 | ThisItem:=g_TC_CMDArr[CMDName] 339 | LV.Add(,ThisItem["Code"],CMDName,ThisItem["Comment"],ThisItem["Group"]) 340 | CMDsAdded[CMDName]:=Map("Group", ThisItem["Group"],"Code",ThisItem["Code"],"Comment",ThisItem["Comment"]) 341 | } 342 | LVColumnWidth() 343 | return CMDsAdded 344 | } 345 | 346 | SortByScore(a1,a2,*) 347 | { 348 | a1:=StrSplit(a1,"|")[1] 349 | a2:=StrSplit(a2,"|")[1] 350 | return a1 > a2 ? 1 : a1 < a2 ? -1 : 0 ; Sorts according to the lengths determined above. 351 | } 352 | } 353 | 354 | 355 | ; read TotalCMD.inc into a MAP object 356 | GetCMDArr(&CMDGroups) 357 | { 358 | tc_CmdFileContent := FileRead(g_tc_CmdFile) 359 | ArrCMDContent:=StrSplit(tc_CmdFileContent,"`n","`r") 360 | ArrCMDs:=Map() 361 | CMDGroups:=Array() 362 | loop ArrCMDContent.Length 363 | { 364 | ThisLine:=Trim(ArrCMDContent[A_Index]) 365 | ThisLineLen:=StrLen(ThisLine) 366 | CMDGroupPos := RegExMatch(ThisLine, "^\[(.*?)=0" , &ThisCMDGroupPat,1) 367 | ; IsCMDLine:=InStr(ThisLine, "cm_") 368 | IsCMDLine:=(ThisLineLen>1) and CMDGroupPos=0 and (not SubStr(ThisLine,1,1)=";") 369 | ;cm_SrcViewModeList=333;Source: View mode menu 370 | if(CMDGroupPos>=1) 371 | { 372 | FoundPos1 := RegExMatch(ThisCMDGroupPat[1], "([a-zA-Z].*?)_" , &ThisNeatCMDGroupName) 373 | ThisGroup:=ThisNeatCMDGroupName[1] 374 | CMDGroups.Push(ThisGroup) 375 | } 376 | else if(IsCMDLine) 377 | { 378 | 379 | EqualPos:=InStr(ThisLine,"=") 380 | SemiPos:=InStr(ThisLine,";") 381 | CMDName := Trim(SubStr(ThisLine,1,EqualPos-1)) 382 | CMDCode := Trim(SubStr(ThisLine,EqualPos+1,SemiPos-EqualPos-1)) 383 | ; MsgBox CMDCode 384 | CMDComment := Trim(SubStr(ThisLine,SemiPos+1)) 385 | if(SubStr(ThisLine,1,3)="cm_") 386 | { 387 | CMDName := Trim(SubStr(ThisLine,4,EqualPos-4)) 388 | } 389 | try 390 | { 391 | ArrCMDs[CMDName]:=Map("Group", ThisGroup,"Code",CMDCode,"Comment",CMDComment) 392 | ; ArrCMDs.Push(Map("Group",ThisGroup,"Name", CMDName,"Code",CMDCode,"Comment",CMDComment)) 393 | } 394 | catch as e 395 | MsgBox "error info`n" . ThisLine 396 | } 397 | } 398 | LoadUserCMD() 399 | return ArrCMDs 400 | LoadUserCMD() 401 | { 402 | UserCMDs:=iniSecToMap("Setting.ini","UserCommands") 403 | for UserCMDName, UserCommand in UserCMDs 404 | { 405 | ArrCMDs[UserCMDName]:=Map("Group", g_UserCMDGroupName,"Code","","Comment",UserCommand) 406 | } 407 | g_CMDGroups.Push(g_UserCMDGroupName) 408 | } 409 | } 410 | -------------------------------------------------------------------------------- /TC_SendMessage.md: -------------------------------------------------------------------------------- 1 | # 1074 2 | vMsg = 1074 ;WM_USER+50 3 | ``` 4 | Result := SendMessage(1074, wparam, 0, ,"ahk_class TTOTAL_CMD") 5 | ``` 6 | ## wparam 取值 7 | * wparam=1~29, returns window handle of control. 8 | * 1=leftlist 9 | * 2=rightlist 10 | * 3=active list 11 | * 4=inactive list 12 | * 5=leftheader 13 | * 6=rightheader 14 | * 7=leftsize 15 | * 8=rightsize 16 | * 9=leftpath 17 | * 10=rightpath 18 | * 11=leftinfo 19 | * 12=rightinfo 20 | * 13=leftdrives 21 | * 14=rightdrives 22 | * 15=leftpanel, 23 | * 16=rightpanel 24 | * 17=bottompanel 25 | * 18=lefttree 26 | * 19=righttree 27 | * 20=cmdline 28 | * 21=curdirpanel 29 | * 22=inplaceedit 30 | * 23=splitpanel, 31 | * 24=leftdrivepanel 32 | * 25=rightdrivepanel 33 | * 26=lefttabs 34 | * 27=righttabs 35 | * 28=buttonbar 36 | * 29=buttonbarvertical 37 | 38 | * 1011/1012 to get index of first file in list (-1 if there are no files) (32/64) 39 | * 1009/1010 to get index of first item (0 if there is no updir, 1 otherwise) (32/64) 40 | * 1007/1008 to get index of current item (caret) (32/64) 41 | * 1005/1006 to get total number of selected items (32/64) 42 | * 1003/1004 to get total number of items (including those hidden by quick filter (32/64) 43 | * 1001/1002 to get number of items in left/right list (32/64) 44 | * 1000 to get active panel: 1=left, 2=right (32/64) 45 | 46 | 47 | 48 | ## Exmaple1--check the active panel 49 | 50 | ``` autohotkey 51 | ; check the active panel 52 | ; 1- left, 2-right 53 | Result := SendMessage(1074, 1000, 0, ,"ahk_class TTOTAL_CMD") 54 | MsgBox Result 55 | ``` 56 | 57 | # 1075 58 | * vMsg = 1075 ;WM_USER+51 59 | * TotalCMD.inc 中对应的command code 都通过1075调用 60 | SendMessage(1075, em_code, 0, , TC_Class) 61 | 62 | ## 可接受参数的命令 63 | ;https://ghisler.ch/board/viewtopic.php?p=310263#p310263 64 | 65 | ```Autohotkey 66 | Result := SendMessage(1075, wParam, lParam, Control, WinTitle, WinText, ExcludeTitle, ExcludeText, Timeout]) 67 | ; 参数通过lParam 进行传递 68 | ; ;Place cursor on 5th item, folder OR file 69 | PostMessage(1075 ,2049,4,,"ahk_class TTOTAL_CMD") 70 | ``` 71 | 15.05.16 Added: The following commands now accept a numeric parameter in the button bar or start menu: 72 | * CM_WAIT 73 | * cm_Select=2936;Select file under cursor, go to next 74 | * CM_UNSELECT 75 | * CM_REVERSE 76 | * cm_GoToFirstEntry=2049;Place cursor on first folder or file 77 | * cm_GoToFirstFile=2050;Place cursor on first file in list 78 | * CM_SWITCHDRIVE 79 | * CM_DELETE 80 | * CM_LEFTSWITCHTOTHISCUSTOMVIEW 81 | * CM_RIGHTSWITCHTOTHISCUSTOMVIEW 82 | * CM_SEARCHFORINCURDIR 83 | * CM_DIRECTORYHOTLIST 84 | 85 | 86 | -------------------------------------------------------------------------------- /TC_SmartOpen.ahk: -------------------------------------------------------------------------------- 1 | ; TC_SmartOpen 2 | ; Open file or folder with Total Commander 3 | ; 1. if a folder already open in one of TC's tabs, activate the corresponding tab; else, open a new tab 4 | ; 2. if the input file's directory open in one of TC's tabs, activate the corresponding tab, select the input file; else, open a new tab and select the file 5 | ; 3. for special folders, like Control, My Computer, it will be open use explorer.exe 6 | ; Author: Valuex 7 | ; 2023/9/24 8 | #Requires AutoHotkey >=2.0 9 | fpath:="" 10 | loop A_Args.Length 11 | { 12 | fpath:=fpath . A_Args[A_Index] . " " 13 | } 14 | fpath:=Trim(fpath) ; remove the last space 15 | SpecialFolder := RegExMatch(fpath, "::\{.*\}") ; ::{26EE0668-A00A-44D7-9371-BEB064C98683} control 16 | DiskDrive:=RegExMatch(fpath, '([A-Z]:)\"',&DrivePath) ; drive 17 | ; MsgBox fpath 18 | if (SpecialFolder) 19 | Run "explorer.exe " . fpath ; for special folders, open it with default explorer 20 | else if (DiskDrive) 21 | { 22 | fpath:=DrivePath[1] . "\" 23 | TC_Open(fpath) 24 | } 25 | else 26 | TC_Open(fpath) 27 | return 28 | 29 | TC_Open(InputPath) 30 | { 31 | TC_Path:=IsScriptInTCDir() 32 | InPutType:=IsInputFileOrFolder(InputPath) ; 0- not exist;1 - Folder; 2- File 33 | IsTC_Active:=AOR("ahk_class TTOTAL_CMD",TC_Path) 34 | 35 | if(!TC_Path or !InPutType or !IsTC_Active) 36 | return 37 | 38 | TC_OpenTabsFile:=A_ScriptDir . "\User\SAVETABS2.tab" 39 | ReOutput(TC_OpenTabsFile) 40 | ; get open tabs number in active panel 41 | AcTabs:=IniRead(TC_OpenTabsFile,"activetabs") 42 | AcTabNum:=IniRead(TC_OpenTabsFile,"activetabs","activetab") 43 | AcTabKeyName:=String(AcTabNum) . "_path" 44 | AcTabPath:=IniRead(TC_OpenTabsFile,"activetabs",AcTabKeyName) 45 | ; MsgBox AcTabPath 46 | iTabExist:=false 47 | if(InPutType=1) ; input is folder 48 | { 49 | iAcTab:=IsFolderInActiveTab(AcTabPath,InputPath,AcTabNum) 50 | if(iAcTab) 51 | iTab:=iAcTab 52 | else 53 | iTab:=IsFolderOpenInTabs(AcTabs,InputPath) 54 | 55 | if(iTab) 56 | { 57 | xsTCCommand:=5000+iTab ; in TotalCMD.inc, source tab id starts from 5001 58 | SendMessage( 1075, xsTCCommand, 0, , "ahk_class TTOTAL_CMD") 59 | } 60 | else 61 | { 62 | ; run tc to open a new tab for input path 63 | tc_cmd:=TC_Path . " /O /T /S /L= " . DoubleQuote(InputPath) 64 | run tc_cmd 65 | } 66 | } 67 | else ; input is file 68 | { 69 | SplitPath InputPath, , &dir 70 | iAcTab:=IsFolderInActiveTab(AcTabPath,dir,AcTabNum) 71 | if(iAcTab) 72 | iTab:=iAcTab 73 | else 74 | iTab:=IsFolderOpenInTabs(AcTabs,dir) 75 | if(iTab) 76 | { 77 | xsTCCommand:=5001+iTab ; in TotalCMD.inc, source tab id starts from 5001 78 | SendMessage( 1075, xsTCCommand, 0, , "ahk_class TTOTAL_CMD") ; go to tab 79 | GotoFile(InputPath) 80 | } 81 | else 82 | { 83 | tc_cmd:=TC_Path . " /O /T /A /S /L= " . DoubleQuote(InputPath) 84 | run tc_cmd 85 | } 86 | } 87 | 88 | GotoFile(path) 89 | { 90 | user_cmd_ini:=A_ScriptDir . "\usercmd.ini" 91 | SecName:="em_focusfile" 92 | IniWrite(path,user_cmd_ini,SecName,"param") 93 | SendTCUserCommand("em_focusfile") 94 | } 95 | 96 | AOR(WinTitle,WinExe) 97 | { 98 | if(WinExist(WinTitle)) 99 | { 100 | WinActivate(WinTitle) 101 | WinA:=WinWaitClass("TTOTAL_CMD") 102 | return WinA ? true: false 103 | } 104 | else 105 | { 106 | Run WinExe 107 | WinWaitActive(WinTitle,,5) 108 | WinA:=WinWaitClass("TTOTAL_CMD") 109 | return WinA ? true: false 110 | } 111 | } 112 | WinWaitClass(WinClass) 113 | { 114 | loop(100) 115 | { 116 | aClass:=WinGetClass("A") 117 | if(StrCompare(aClass,WinClass)=0) 118 | return true 119 | else 120 | Sleep(100) 121 | } 122 | return false 123 | } 124 | IsInputFileOrFolder(FilePattern) 125 | { 126 | AttributeString := FileExist(FilePattern) 127 | if(InStr(AttributeString,"D")) 128 | return 1 ;"Folder" 129 | else if(AttributeString) 130 | return 2 ;"File" 131 | else 132 | return 0 ;AttributeString: empty means no file exsits 133 | } 134 | IsScriptInTCDir() 135 | { 136 | ; check whether this script in the same directory as Total Commander main program 137 | TC64:=A_ScriptDir . "\Totalcmd64.exe" 138 | TC32:=A_ScriptDir . "\Totalcmd.exe" 139 | if A_Is64bitOS AND FileExist(TC64) 140 | TC:=DoubleQuote(TC64) 141 | else if FileExist(TC32) 142 | TC:=DoubleQuote(TC32) 143 | else 144 | { 145 | MsgBox "This script shall be put in the directory of Totalcmd.exe!" 146 | return "" 147 | } 148 | return TC 149 | } 150 | 151 | IsFolderOpenInTabs(ActiveTabs,InputPath) 152 | { 153 | ; loop to see if there is any tab already exist 154 | ArrAcTabs:=StrSplit(ActiveTabs,"`n","`r") 155 | AcTabsNum:=ArrAcTabs.Length-1 156 | loop AcTabsNum 157 | { 158 | i:=Floor((A_Index-1)/2) ; in SAVETABS2.tab, tab id starts from 0 159 | iTabIndex:=String(i) . "_path" 160 | ThisLine:=ArrAcTabs[A_Index] 161 | ThisLineID:= GetTabID(ThisLine) 162 | ThisLinePath:= GetTabPath(ThisLine) 163 | if(!InStr(ThisLineID,iTabIndex)) 164 | continue 165 | if(StrCompare(InputPath,ThisLinePath)=0) 166 | { 167 | TabIndex:=StrSplit(ThisLine,"_")[1] 168 | return TabIndex+1 169 | } 170 | } 171 | return false 172 | } 173 | IsFolderInActiveTab(ActiveTabPath,InputPath,AcTabNumber) 174 | { 175 | if(StrCompare(InputPath,ActiveTabPath)=0) 176 | return AcTabNumber 177 | else 178 | return false 179 | } 180 | GetTabID(iniLine) 181 | { 182 | ; to the left of =, like 0_path, 1_path 183 | EqualPos:=InStr(iniLine,"=") 184 | TabID:=SubStr(iniLine,1,EqualPos-1) 185 | return TabID 186 | } 187 | GetTabPath(iniLine) 188 | { 189 | EqualPos:=InStr(iniLine,"=") 190 | TabPath:=SubStr(iniLine,EqualPos+1) 191 | return TabPath 192 | } 193 | ReOutput(TC_OpenTabsFile) 194 | { 195 | if(FileExist(TC_OpenTabsFile)) 196 | FileDelete TC_OpenTabsFile 197 | 198 | ; output open tab list 199 | SendTCUserCommand("em_savealltabs") 200 | loop 10 201 | { 202 | Sleep(200) 203 | if(FileExist(TC_OpenTabsFile)) 204 | break 205 | } 206 | } 207 | DoubleQuote(strInput) 208 | { 209 | return Chr(34) . strInput . Chr(34) 210 | } 211 | } 212 | 213 | SendTCUserCommand(userCommand) 214 | { 215 | ; https://www.autohotkey.com/boards/viewtopic.php?p=538463&sid=4471e03917209854441ac07ebdc70901#p538463 216 | static EM := 19781, WM_COPYDATA := 0x4A 217 | ansiBuf := Buffer(StrPut(userCommand, 'CP0')) 218 | StrPut(userCommand, ansiBuf, 'CP0') 219 | COPYDATASTRUCT := Buffer(A_PtrSize * 3) 220 | NumPut('Ptr', EM, 'Ptr', ansiBuf.size, 'Ptr', ansiBuf.ptr, COPYDATASTRUCT) 221 | MsgResult:=SendMessage( WM_COPYDATA,, COPYDATASTRUCT,, 'ahk_class TTOTAL_CMD') 222 | return MsgResult 223 | } 224 | -------------------------------------------------------------------------------- /TC_替代Explorer的配置.md: -------------------------------------------------------------------------------- 1 | # Window 系统配置 2 | ## 配置autohotkey 脚本 3 | 1. 用`AHK2EXE`编译`OpenTCSelected.ahk`为`OpenTCSelected.exe` (可自行编译,或下载编译好的版本 https://github.com/valuex/AutohotkeyScripts/releases/tag/V0.1 ) 4 | 2. 将`OpenTCSelected.exe` 放入`TotalCMD64.exe` 或 `TotalCMD.exe`所在目录 5 | 6 | ## 配置注册表 7 | 1. 修改注册表 `计算机\HKEY_CLASSES_ROOT\Folder\shell\open\command` 8 | - `默认`位置处修改为`D:\SoftX\TotalCommander11\OpenTCSelected.exe "%1"` 9 | - `DelegateExecute`修改为 空 10 | 11 | 2. 注册表还原 `计算机\HKEY_CLASSES_ROOT\Folder\shell\open\command` 12 | - `默认`位置处修改为 `%SystemRoot%\Explorer.exe` 13 | - `DelegateExecute`修改为 `{11dbb47c-a525-400b-9e80-a54615a090c0}` 14 | 15 | ## 配置TotalCommander 16 | 在`usercmd.ini`中加入如下配置 17 | ```ini 18 | [em_savealltabs] 19 | button=wcmicons.dll,10 20 | cmd=SAVETABS2 21 | param="%|commander_path|\User\SAVETABS2.tab" 22 | [em_focusfile] 23 | button=wcmicons.dll,10 24 | cmd=CD 25 | param="D:\SoftX\TotalCommander11\TCMatch.ini" 26 | 27 | ``` 28 | # 配置Everything 29 | 30 | 在`工具-选项-上下文菜单`中,分别在这两项内容下配置 31 | - 打开文件夹 32 | - 打开路径 33 | 34 | `$exec("D:\SoftX\TotalCommander11\OpenTCSelected.exe" "%1")` 35 | 36 | # 配置Listary 37 | 托盘图标右键,`选项-常规设置-打开文件夹用` 38 | - 路径:D:\SoftX\TotalCommander11\OpenTCSelected.exe 39 | - 参数: "%1" 40 | 41 | ![image](https://github.com/valuex/AutohotkeyScripts/assets/3627812/9919e447-a708-4a6f-94c1-6c268040efa4) 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /TotalComander/TC_VBA_Interposer.ahk: -------------------------------------------------------------------------------- 1 | #Requires AutoHotkey >=2.0 2 | #Include C:\Users\wei_x\Desktop\Chrome_Download\lib\TC_AHK_Lib.ahk 3 | Persistent 4 | ; global retVal:="" 5 | MyGui:=Gui() 6 | MyGui.Title := "TC-VBA-Interposer" 7 | MyGui.Show("hide w500 h200") 8 | TC_Interposer() 9 | return 10 | TC_Interposer() 11 | { ;https://wincmd.ru/forum/viewtopic.php?p=110848&sid=0dfde01723b39e508e96d62c00a7a9b5 12 | OnMessage(0x4a, TC_Receive_WM_COPYDATA1) ; 0x4a is WM_COPYDATA 13 | } 14 | 15 | TC_Receive_WM_COPYDATA1(wParam, lParam, msg, hwnd) 16 | { 17 | PtrPos:=NumGet(lParam + A_PtrSize * 2,0,"Ptr") 18 | retVal:=StrGet(PtrPos) 19 | if(retVal) 20 | { 21 | ;winTitle:=WinGetTitle("ahk_id " . hwnd) 22 | ; winTitle:=WinGetProcessName("ahk_id " . hwnd) 23 | ; MsgBox winTitle 24 | 25 | If WinExist("ahk_class TTOTAL_CMD") ;&& WinActive("ahk_class TTOTAL_CMD") 26 | ForwardCMD(retVal) 27 | else 28 | MsgBox "TC does NOT exist" 29 | } 30 | } 31 | 32 | ForwardCMD(strCMD) 33 | { 34 | if(InStr(strCMD,"em_SelectFile")=1) 35 | { 36 | NewCMD:=SubStr(strCMD,StrLen("em_SelectFile")+1) 37 | NewCMD:=Trim(NewCMD) 38 | NewCMDArr:=StrSplit(NewCMD, "|") 39 | FilePath:=NewCMDArr[1] 40 | if(FileExist(FilePath)) 41 | { 42 | TC_FocusOnLeftFile(FilePath) 43 | WinActivate(NewCMDArr[2]) 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /TotalComander/TC_VBA_SendData.vbs: -------------------------------------------------------------------------------- 1 | Option Explicit 2 | 3 | Private Declare PtrSafe Function FindWindow Lib "USER32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long 4 | Private Declare PtrSafe Function SendMessage Lib "USER32" Alias "SendMessageA" (ByVal hWnd As LongPtr, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As LongPtr 5 | Private Declare PtrSafe Function GetWindowTextLength Lib "USER32" Alias "GetWindowTextLengthA" (ByVal hWnd As Long) As Long 6 | Private Declare PtrSafe Function GetWindowText Lib "USER32" Alias "GetWindowTextA" (ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long) As Long 7 | Private Declare PtrSafe Function GetWindow Lib "USER32" (ByVal hWnd As Long, ByVal wCmd As Long) As Long 8 | Private Declare PtrSafe Function IsWindowVisible Lib "USER32" (ByVal hWnd As Long) As Boolean 9 | Public Declare PtrSafe Function GetParent Lib "user32.dll" (ByVal hWnd As LongPtr) As LongPtr 10 | Public Declare PtrSafe Function GetWindowThreadProcessId Lib "USER32" (ByVal hWnd As LongPtr, lpdwProcessId As Long) As Long 11 | 12 | Public Type CopyDataStruct 13 | dwData As LongPtr 14 | cbData As Long 15 | lpData As LongPtr 16 | End Type 17 | Private Const WM_COPYDATA = &H4A 18 | Private Const GW_HWNDNEXT = 2 19 | Function GetHiddenWinHwndByTitle(strWinTitle) As Long 20 | Dim lhWndP As Long 21 | If GetHandleFromPartialCaption(lhWndP, strWinTitle) = True Then 22 | GetHiddenWinHwndByTitle = lhWndP 23 | Else 24 | GetHiddenWinHwndByTitle = 0 25 | End If 26 | End Function 27 | 28 | 29 | Sub TC_SendUserCMD(strPath) 30 | Dim UserCMD As String 31 | Dim AcWorkbookName As String 32 | AcWorkbookName = ActiveWorkbook.Name 33 | 34 | UserCMD = "em_SelectFile " & strPath & "|" & AcWorkbookName 35 | 36 | Dim cds As CopyDataStruct, result As LongPtr 37 | Static hwndAHKInterposer As Long 38 | Dim wParam As Long 39 | wParam = 0 40 | If (hwndAHKInterposer > 0) Then 41 | hwndAHKInterposer = hwndAHKInterposer 42 | Else 43 | hwndAHKInterposer = GetHiddenWinHwndByTitle("TC-VBA-Interposer") 44 | Debug.Print 1 45 | End If 46 | 'Debug.Print hwndAHKInterposer 47 | If (hwndAHKInterposer > 0) Then 48 | cds.dwData = Asc("E") + 256 * Asc("M") 49 | cds.cbData = Len(UserCMD) * 2 + 2 'The size, in bytes 50 | cds.lpData = StrPtr(UserCMD) 51 | result = SendMessage(hwndAHKInterposer, WM_COPYDATA, wParam, cds) 52 | 'Debug.Print hwndAHKInterposer 53 | End If 54 | End Sub 55 | 56 | 57 | 58 | Private Function GetHandleFromPartialCaption(ByRef lWnd As Long, ByVal sCaption As String) As Boolean 59 | 'https://copyprogramming.com/howto/how-to-locate-the-window-using-findwindow-function-in-windowapi-using-vba 60 | Dim lhWndP As Long 61 | Dim sStr As String 62 | GetHandleFromPartialCaption = False 63 | lhWndP = FindWindow(vbNullString, vbNullString) 'PARENT WINDOW 64 | Do While lhWndP <> 0 65 | sStr = String(GetWindowTextLength(lhWndP) + 1, Chr$(0)) 66 | GetWindowText lhWndP, sStr, Len(sStr) 67 | sStr = Left$(sStr, Len(sStr) - 1) 68 | If InStr(1, sStr, sCaption) > 0 Then 69 | GetHandleFromPartialCaption = True 70 | lWnd = lhWndP 71 | Debug.Print sStr 72 | Exit Do 73 | End If 74 | lhWndP = GetWindow(lhWndP, GW_HWNDNEXT) 75 | Loop 76 | End Function 77 | 78 | -------------------------------------------------------------------------------- /lib/_JXON.ahk: -------------------------------------------------------------------------------- 1 | ; originally posted by user coco on AutoHotkey.com 2 | ; https://github.com/cocobelgica/AutoHotkey-JSON 3 | ; https://github.com/TheArkive/JXON_ahk2/blob/master/_JXON.ahk 4 | 5 | Jxon_Load(&src, args*) { 6 | key := "", is_key := false 7 | stack := [ tree := [] ] 8 | next := '"{[01234567890-tfn' 9 | pos := 0 10 | 11 | while ( (ch := SubStr(src, ++pos, 1)) != "" ) { 12 | if InStr(" `t`n`r", ch) 13 | continue 14 | if !InStr(next, ch, true) { 15 | testArr := StrSplit(SubStr(src, 1, pos), "`n") 16 | 17 | ln := testArr.Length 18 | col := pos - InStr(src, "`n",, -(StrLen(src)-pos+1)) 19 | 20 | msg := Format("{}: line {} col {} (char {})" 21 | , (next == "") ? ["Extra data", ch := SubStr(src, pos)][1] 22 | : (next == "'") ? "Unterminated string starting at" 23 | : (next == "\") ? "Invalid \escape" 24 | : (next == ":") ? "Expecting ':' delimiter" 25 | : (next == '"') ? "Expecting object key enclosed in double quotes" 26 | : (next == '"}') ? "Expecting object key enclosed in double quotes or object closing '}'" 27 | : (next == ",}") ? "Expecting ',' delimiter or object closing '}'" 28 | : (next == ",]") ? "Expecting ',' delimiter or array closing ']'" 29 | : [ "Expecting JSON value(string, number, [true, false, null], object or array)" 30 | , ch := SubStr(src, pos, (SubStr(src, pos)~="[\]\},\s]|$")-1) ][1] 31 | , ln, col, pos) 32 | 33 | throw Error(msg, -1, ch) 34 | } 35 | 36 | obj := stack[1] 37 | is_array := (obj is Array) 38 | 39 | if i := InStr("{[", ch) { ; start new object / map? 40 | val := (i = 1) ? Map() : Array() ; ahk v2 41 | 42 | is_array ? obj.Push(val) : obj[key] := val 43 | stack.InsertAt(1,val) 44 | 45 | next := '"' ((is_key := (ch == "{")) ? "}" : "{[]0123456789-tfn") 46 | } else if InStr("}]", ch) { 47 | stack.RemoveAt(1) 48 | next := (stack[1]==tree) ? "" : (stack[1] is Array) ? ",]" : ",}" 49 | } else if InStr(",:", ch) { 50 | is_key := (!is_array && ch == ",") 51 | next := is_key ? '"' : '"{[0123456789-tfn' 52 | } else { ; string | number | true | false | null 53 | if (ch == '"') { ; string 54 | i := pos 55 | while i := InStr(src, '"',, i+1) { 56 | val := StrReplace(SubStr(src, pos+1, i-pos-1), "\\", "\u005C") 57 | if (SubStr(val, -1) != "\") 58 | break 59 | } 60 | if !i ? (pos--, next := "'") : 0 61 | continue 62 | 63 | pos := i ; update pos 64 | 65 | val := StrReplace(val, "\/", "/") 66 | val := StrReplace(val, '\"', '"') 67 | , val := StrReplace(val, "\b", "`b") 68 | , val := StrReplace(val, "\f", "`f") 69 | , val := StrReplace(val, "\n", "`n") 70 | , val := StrReplace(val, "\r", "`r") 71 | , val := StrReplace(val, "\t", "`t") 72 | 73 | i := 0 74 | while i := InStr(val, "\",, i+1) { 75 | if (SubStr(val, i+1, 1) != "u") ? (pos -= StrLen(SubStr(val, i)), next := "\") : 0 76 | continue 2 77 | 78 | xxxx := Abs("0x" . SubStr(val, i+2, 4)) ; \uXXXX - JSON unicode escape sequence 79 | if (xxxx < 0x100) 80 | val := SubStr(val, 1, i-1) . Chr(xxxx) . SubStr(val, i+6) 81 | } 82 | 83 | if is_key { 84 | key := val, next := ":" 85 | continue 86 | } 87 | } else { ; number | true | false | null 88 | val := SubStr(src, pos, i := RegExMatch(src, "[\]\},\s]|$",, pos)-pos) 89 | 90 | if IsInteger(val) 91 | val += 0 92 | else if IsFloat(val) 93 | val += 0 94 | else if (val == "true" || val == "false") 95 | val := (val == "true") 96 | else if (val == "null") 97 | val := "" 98 | else if is_key { 99 | pos--, next := "#" 100 | continue 101 | } 102 | 103 | pos += i-1 104 | } 105 | 106 | is_array ? obj.Push(val) : obj[key] := val 107 | next := obj == tree ? "" : is_array ? ",]" : ",}" 108 | } 109 | } 110 | 111 | return tree[1] 112 | } 113 | 114 | Jxon_Dump(obj, indent:="", lvl:=1) { 115 | if IsObject(obj) { 116 | If !(obj is Array || obj is Map || obj is String || obj is Number) 117 | throw Error("Object type not supported.", -1, Format("", ObjPtr(obj))) 118 | 119 | if IsInteger(indent) 120 | { 121 | if (indent < 0) 122 | throw Error("Indent parameter must be a postive integer.", -1, indent) 123 | spaces := indent, indent := "" 124 | 125 | Loop spaces ; ===> changed 126 | indent .= " " 127 | } 128 | indt := "" 129 | 130 | Loop indent ? lvl : 0 131 | indt .= indent 132 | 133 | is_array := (obj is Array) 134 | 135 | lvl += 1, out := "" ; Make #Warn happy 136 | for k, v in obj { 137 | if IsObject(k) || (k == "") 138 | throw Error("Invalid object key.", -1, k ? Format("", ObjPtr(obj)) : "") 139 | 140 | if !is_array ;// key ; ObjGetCapacity([k], 1) 141 | out .= (ObjGetCapacity([k]) ? Jxon_Dump(k) : escape_str(k)) (indent ? ": " : ":") ; token + padding 142 | 143 | out .= Jxon_Dump(v, indent, lvl) ; value 144 | . ( indent ? ",`n" . indt : "," ) ; token + indent 145 | } 146 | 147 | if (out != "") { 148 | out := Trim(out, ",`n" . indent) 149 | if (indent != "") 150 | out := "`n" . indt . out . "`n" . SubStr(indt, StrLen(indent)+1) 151 | } 152 | 153 | return is_array ? "[" . out . "]" : "{" . out . "}" 154 | 155 | } Else If (obj is Number) 156 | return obj 157 | 158 | Else ; String 159 | return escape_str(obj) 160 | 161 | escape_str(obj) { 162 | obj := StrReplace(obj,"\","\\") 163 | obj := StrReplace(obj,"`t","\t") 164 | obj := StrReplace(obj,"`r","\r") 165 | obj := StrReplace(obj,"`n","\n") 166 | obj := StrReplace(obj,"`b","\b") 167 | obj := StrReplace(obj,"`f","\f") 168 | obj := StrReplace(obj,"/","\/") 169 | obj := StrReplace(obj,'"','\"') 170 | 171 | return '"' obj '"' 172 | } 173 | } 174 | --------------------------------------------------------------------------------