├── docs
├── .vuepress
│ ├── styles
│ │ ├── config.scss
│ │ ├── palette.scss
│ │ └── index.scss
│ ├── public
│ │ └── favicon.ico
│ ├── navbar.ts
│ ├── config.ts
│ ├── sidebar.ts
│ └── theme.ts
├── images
│ ├── plugin.jpg
│ ├── plugin-2.jpg
│ ├── setting-1.jpg
│ ├── setting-2.jpg
│ ├── search-box.jpg
│ ├── virustotal.jpg
│ ├── edit-startup-mode.jpg
│ ├── intelligent-mode.jpg
│ └── edit-intelligent-mode.jpg
├── guide
│ ├── boot
│ │ ├── boot.jpg
│ │ └── README.md
│ ├── about
│ │ ├── about.jpg
│ │ └── README.md
│ ├── startup
│ │ ├── edit.jpg
│ │ ├── search.jpg
│ │ └── README.md
│ ├── intelligent
│ │ ├── search.jpg
│ │ ├── usage.jpg
│ │ ├── README.md
│ │ ├── run-with.jpg
│ │ ├── usage.md
│ │ ├── edit.md
│ │ └── concept.md
│ ├── user-data
│ │ ├── export.jpg
│ │ ├── import.jpg
│ │ └── README.md
│ ├── get-started
│ │ ├── README.md
│ │ ├── intro.md
│ │ └── install-usage.md
│ ├── plugin
│ │ └── README.md
│ ├── README.md
│ └── setting
│ │ └── README.md
├── plugin
│ ├── images
│ │ ├── ocr-1.jpg
│ │ ├── ocr-2.jpg
│ │ ├── file-find.jpg
│ │ ├── web-search-1.jpg
│ │ ├── web-search-2.jpg
│ │ ├── timed-reminder-1.jpg
│ │ ├── timed-reminder-2.jpg
│ │ ├── window-switcher-1.jpg
│ │ ├── window-switcher-2.jpg
│ │ ├── window-switcher-3.jpg
│ │ ├── win10-taskbar-transparent.jpg
│ │ ├── file-selection-dialog-nav-1.jpg
│ │ └── file-selection-dialog-nav-2.jpg
│ ├── README.md
│ ├── win10-taskbar-transparent.md
│ ├── timed-reminder.md
│ ├── web-search.md
│ ├── file-selection-dialog-nav.md
│ ├── window-switcher.md
│ ├── file-find.md
│ └── ocr.md
├── dev
│ ├── images
│ │ ├── startup-1.jpg
│ │ ├── startup-2.jpg
│ │ ├── startup-3.jpg
│ │ ├── startup-4.jpg
│ │ ├── startup-5.jpg
│ │ ├── code-prompt.jpg
│ │ ├── intelligent-1.jpg
│ │ ├── intelligent-2.jpg
│ │ ├── intelligent-3.jpg
│ │ ├── intelligent-4.jpg
│ │ ├── intelligent-5.jpg
│ │ ├── intelligent-6.jpg
│ │ ├── myplugin-gui.jpg
│ │ ├── myplugin-menu.jpg
│ │ ├── plugin-mode-1.jpg
│ │ ├── plugin-mode-2.jpg
│ │ ├── plugin-mode-3.jpg
│ │ ├── plugin-mode-4.jpg
│ │ ├── plugin-mode-5.jpg
│ │ ├── plugin-mode-6.jpg
│ │ ├── plugin-mode-7.jpg
│ │ ├── plugin-mode-8.jpg
│ │ ├── plugin-mode-9.jpg
│ │ ├── plugin-mode-10.jpg
│ │ ├── plugin-mode-11.jpg
│ │ └── myplugin-startup-item.jpg
│ ├── others
│ │ ├── README.md
│ │ ├── ahk-gui.md
│ │ └── image-put-doc-1.md
│ ├── plugin-mode
│ │ ├── README.md
│ │ ├── basics.md
│ │ └── advanced.md
│ ├── intelligent
│ │ ├── README.md
│ │ ├── basics.md
│ │ └── advanced.md
│ ├── README.md
│ ├── image-put.md
│ └── startup.md
├── api
│ ├── utils
│ │ ├── README.md
│ │ ├── other.md
│ │ └── ImagePutHelper.md
│ ├── README.md
│ ├── pluginMenu.md
│ ├── searchGuiHwnd.md
│ ├── imgDir.md
│ ├── placeholder.md
│ ├── searchText.md
│ ├── getPluginMode.md
│ ├── pastedContentType.md
│ ├── addEntryFunc.md
│ ├── hideSearchGui.md
│ ├── workWinInfo.md
│ ├── getPluginIconBase64.md
│ ├── getPluginHIcon.md
│ ├── setSearchTextSel.md
│ ├── winInfoMatchFlag.md
│ ├── pastedContent.md
│ ├── addPluginToStartupMode.md
│ ├── addPluginToIntelligentMode.md
│ └── showPluginMode.md
├── README.md
└── history.md
├── 创建快捷方式.bat
├── resource
└── img
│ ├── AI.png
│ ├── add.ico
│ ├── img.png
│ ├── run.ico
│ ├── txt.png
│ ├── copy.ico
│ ├── delete.ico
│ ├── edit.ico
│ ├── error.png
│ ├── folder.ico
│ ├── folder.png
│ ├── help.png
│ ├── info.ico
│ ├── link.ico
│ ├── noImg.png
│ ├── plugin.ico
│ ├── plugin.png
│ ├── reload.ico
│ ├── Starter.ico
│ ├── Starter.png
│ ├── program.png
│ ├── setting.ico
│ └── autohotkey.png
├── src
├── AutoHotkey64.exe
├── Utils
│ ├── 7Zip
│ │ └── 7-zip64.dll
│ ├── LoadIconFromBase64.ah2
│ ├── IME.ah2
│ ├── QuickSort.ah2
│ ├── MapArrClone.ah2
│ ├── DataHelper.ah2
│ ├── Start.ah2
│ ├── GetSelectedText.ah2
│ ├── UrlEncode.ah2
│ ├── ChineseFirstChar.ah2
│ ├── CopyToClipboard.ah2
│ ├── EditCtrlFunc.ah2
│ ├── Class_Loader.ah2
│ ├── HotkeyHelper.ah2
│ ├── GlobalData.ah2
│ └── JXON.ah2
├── Plugin
│ ├── Everything
│ │ ├── Everything32.dll
│ │ └── Everything64.dll
│ ├── win10任务栏透明.ahk
│ ├── 定时提醒.ahk
│ ├── 文件选择对话框导航.ahk
│ ├── 窗口切换.ahk
│ └── demo.ahk
├── Gui
│ ├── AboutGui.ah2
│ ├── BootGui.ah2
│ ├── PluginGui.ah2
│ └── TrayMenu.ah2
└── Starter.ah2
├── .gitignore
├── CreateShortcut.vbs
├── package.json
├── .github
└── workflows
│ ├── sync2gitee.yml
│ └── deploy-docs.yml
└── README.md
/docs/.vuepress/styles/config.scss:
--------------------------------------------------------------------------------
1 | $code-bg-color: #23272e;
2 | $code-color: #ffffff;
--------------------------------------------------------------------------------
/创建快捷方式.bat:
--------------------------------------------------------------------------------
1 | echo Creating...
2 | start CreateShortcut.vbs
3 | echo Finished!
4 |
--------------------------------------------------------------------------------
/resource/img/AI.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/resource/img/AI.png
--------------------------------------------------------------------------------
/resource/img/add.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/resource/img/add.ico
--------------------------------------------------------------------------------
/resource/img/img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/resource/img/img.png
--------------------------------------------------------------------------------
/resource/img/run.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/resource/img/run.ico
--------------------------------------------------------------------------------
/resource/img/txt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/resource/img/txt.png
--------------------------------------------------------------------------------
/src/AutoHotkey64.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/src/AutoHotkey64.exe
--------------------------------------------------------------------------------
/docs/.vuepress/styles/palette.scss:
--------------------------------------------------------------------------------
1 | // you can change colors here
2 | $theme-color: #4daf7c;
3 |
--------------------------------------------------------------------------------
/docs/images/plugin.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/images/plugin.jpg
--------------------------------------------------------------------------------
/resource/img/copy.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/resource/img/copy.ico
--------------------------------------------------------------------------------
/resource/img/delete.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/resource/img/delete.ico
--------------------------------------------------------------------------------
/resource/img/edit.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/resource/img/edit.ico
--------------------------------------------------------------------------------
/resource/img/error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/resource/img/error.png
--------------------------------------------------------------------------------
/resource/img/folder.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/resource/img/folder.ico
--------------------------------------------------------------------------------
/resource/img/folder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/resource/img/folder.png
--------------------------------------------------------------------------------
/resource/img/help.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/resource/img/help.png
--------------------------------------------------------------------------------
/resource/img/info.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/resource/img/info.ico
--------------------------------------------------------------------------------
/resource/img/link.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/resource/img/link.ico
--------------------------------------------------------------------------------
/resource/img/noImg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/resource/img/noImg.png
--------------------------------------------------------------------------------
/resource/img/plugin.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/resource/img/plugin.ico
--------------------------------------------------------------------------------
/resource/img/plugin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/resource/img/plugin.png
--------------------------------------------------------------------------------
/resource/img/reload.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/resource/img/reload.ico
--------------------------------------------------------------------------------
/docs/guide/boot/boot.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/guide/boot/boot.jpg
--------------------------------------------------------------------------------
/docs/images/plugin-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/images/plugin-2.jpg
--------------------------------------------------------------------------------
/docs/images/setting-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/images/setting-1.jpg
--------------------------------------------------------------------------------
/docs/images/setting-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/images/setting-2.jpg
--------------------------------------------------------------------------------
/resource/img/Starter.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/resource/img/Starter.ico
--------------------------------------------------------------------------------
/resource/img/Starter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/resource/img/Starter.png
--------------------------------------------------------------------------------
/resource/img/program.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/resource/img/program.png
--------------------------------------------------------------------------------
/resource/img/setting.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/resource/img/setting.ico
--------------------------------------------------------------------------------
/docs/guide/about/about.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/guide/about/about.jpg
--------------------------------------------------------------------------------
/docs/guide/startup/edit.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/guide/startup/edit.jpg
--------------------------------------------------------------------------------
/docs/images/search-box.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/images/search-box.jpg
--------------------------------------------------------------------------------
/docs/images/virustotal.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/images/virustotal.jpg
--------------------------------------------------------------------------------
/docs/plugin/images/ocr-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/plugin/images/ocr-1.jpg
--------------------------------------------------------------------------------
/docs/plugin/images/ocr-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/plugin/images/ocr-2.jpg
--------------------------------------------------------------------------------
/resource/img/autohotkey.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/resource/img/autohotkey.png
--------------------------------------------------------------------------------
/src/Utils/7Zip/7-zip64.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/src/Utils/7Zip/7-zip64.dll
--------------------------------------------------------------------------------
/docs/dev/images/startup-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/dev/images/startup-1.jpg
--------------------------------------------------------------------------------
/docs/dev/images/startup-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/dev/images/startup-2.jpg
--------------------------------------------------------------------------------
/docs/dev/images/startup-3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/dev/images/startup-3.jpg
--------------------------------------------------------------------------------
/docs/dev/images/startup-4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/dev/images/startup-4.jpg
--------------------------------------------------------------------------------
/docs/dev/images/startup-5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/dev/images/startup-5.jpg
--------------------------------------------------------------------------------
/docs/dev/others/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 其他内容
3 | icon: ellipsis
4 | index: false
5 | ---
6 |
7 |
--------------------------------------------------------------------------------
/docs/guide/startup/search.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/guide/startup/search.jpg
--------------------------------------------------------------------------------
/docs/.vuepress/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/.vuepress/public/favicon.ico
--------------------------------------------------------------------------------
/docs/dev/images/code-prompt.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/dev/images/code-prompt.jpg
--------------------------------------------------------------------------------
/docs/dev/images/intelligent-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/dev/images/intelligent-1.jpg
--------------------------------------------------------------------------------
/docs/dev/images/intelligent-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/dev/images/intelligent-2.jpg
--------------------------------------------------------------------------------
/docs/dev/images/intelligent-3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/dev/images/intelligent-3.jpg
--------------------------------------------------------------------------------
/docs/dev/images/intelligent-4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/dev/images/intelligent-4.jpg
--------------------------------------------------------------------------------
/docs/dev/images/intelligent-5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/dev/images/intelligent-5.jpg
--------------------------------------------------------------------------------
/docs/dev/images/intelligent-6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/dev/images/intelligent-6.jpg
--------------------------------------------------------------------------------
/docs/dev/images/myplugin-gui.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/dev/images/myplugin-gui.jpg
--------------------------------------------------------------------------------
/docs/dev/images/myplugin-menu.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/dev/images/myplugin-menu.jpg
--------------------------------------------------------------------------------
/docs/dev/images/plugin-mode-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/dev/images/plugin-mode-1.jpg
--------------------------------------------------------------------------------
/docs/dev/images/plugin-mode-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/dev/images/plugin-mode-2.jpg
--------------------------------------------------------------------------------
/docs/dev/images/plugin-mode-3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/dev/images/plugin-mode-3.jpg
--------------------------------------------------------------------------------
/docs/dev/images/plugin-mode-4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/dev/images/plugin-mode-4.jpg
--------------------------------------------------------------------------------
/docs/dev/images/plugin-mode-5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/dev/images/plugin-mode-5.jpg
--------------------------------------------------------------------------------
/docs/dev/images/plugin-mode-6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/dev/images/plugin-mode-6.jpg
--------------------------------------------------------------------------------
/docs/dev/images/plugin-mode-7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/dev/images/plugin-mode-7.jpg
--------------------------------------------------------------------------------
/docs/dev/images/plugin-mode-8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/dev/images/plugin-mode-8.jpg
--------------------------------------------------------------------------------
/docs/dev/images/plugin-mode-9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/dev/images/plugin-mode-9.jpg
--------------------------------------------------------------------------------
/docs/dev/plugin-mode/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 插件模式
3 | icon: list-ul
4 | index: false
5 | ---
6 |
7 |
--------------------------------------------------------------------------------
/docs/guide/intelligent/search.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/guide/intelligent/search.jpg
--------------------------------------------------------------------------------
/docs/guide/intelligent/usage.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/guide/intelligent/usage.jpg
--------------------------------------------------------------------------------
/docs/guide/user-data/export.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/guide/user-data/export.jpg
--------------------------------------------------------------------------------
/docs/guide/user-data/import.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/guide/user-data/import.jpg
--------------------------------------------------------------------------------
/docs/images/edit-startup-mode.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/images/edit-startup-mode.jpg
--------------------------------------------------------------------------------
/docs/images/intelligent-mode.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/images/intelligent-mode.jpg
--------------------------------------------------------------------------------
/docs/plugin/images/file-find.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/plugin/images/file-find.jpg
--------------------------------------------------------------------------------
/docs/dev/images/plugin-mode-10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/dev/images/plugin-mode-10.jpg
--------------------------------------------------------------------------------
/docs/dev/images/plugin-mode-11.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/dev/images/plugin-mode-11.jpg
--------------------------------------------------------------------------------
/docs/dev/intelligent/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 插件智能项
3 | icon: face-laugh
4 | index: false
5 | ---
6 |
7 |
--------------------------------------------------------------------------------
/docs/guide/get-started/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 快速上手
3 | icon: lightbulb
4 | index: false
5 | ---
6 |
7 |
--------------------------------------------------------------------------------
/docs/guide/intelligent/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 智能模式
3 | icon: face-laugh
4 | index: false
5 | ---
6 |
7 |
--------------------------------------------------------------------------------
/docs/guide/intelligent/run-with.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/guide/intelligent/run-with.jpg
--------------------------------------------------------------------------------
/docs/plugin/images/web-search-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/plugin/images/web-search-1.jpg
--------------------------------------------------------------------------------
/docs/plugin/images/web-search-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/plugin/images/web-search-2.jpg
--------------------------------------------------------------------------------
/docs/images/edit-intelligent-mode.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/images/edit-intelligent-mode.jpg
--------------------------------------------------------------------------------
/src/Plugin/Everything/Everything32.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/src/Plugin/Everything/Everything32.dll
--------------------------------------------------------------------------------
/src/Plugin/Everything/Everything64.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/src/Plugin/Everything/Everything64.dll
--------------------------------------------------------------------------------
/docs/plugin/images/timed-reminder-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/plugin/images/timed-reminder-1.jpg
--------------------------------------------------------------------------------
/docs/plugin/images/timed-reminder-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/plugin/images/timed-reminder-2.jpg
--------------------------------------------------------------------------------
/docs/plugin/images/window-switcher-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/plugin/images/window-switcher-1.jpg
--------------------------------------------------------------------------------
/docs/plugin/images/window-switcher-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/plugin/images/window-switcher-2.jpg
--------------------------------------------------------------------------------
/docs/plugin/images/window-switcher-3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/plugin/images/window-switcher-3.jpg
--------------------------------------------------------------------------------
/docs/dev/images/myplugin-startup-item.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/dev/images/myplugin-startup-item.jpg
--------------------------------------------------------------------------------
/docs/.vuepress/styles/index.scss:
--------------------------------------------------------------------------------
1 | .shields {
2 | text-align: center !important;
3 |
4 | img {
5 | margin: 0.1rem;
6 | }
7 | }
--------------------------------------------------------------------------------
/docs/plugin/images/win10-taskbar-transparent.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/plugin/images/win10-taskbar-transparent.jpg
--------------------------------------------------------------------------------
/docs/plugin/images/file-selection-dialog-nav-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/plugin/images/file-selection-dialog-nav-1.jpg
--------------------------------------------------------------------------------
/docs/plugin/images/file-selection-dialog-nav-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AkiChase/Starter/HEAD/docs/plugin/images/file-selection-dialog-nav-2.jpg
--------------------------------------------------------------------------------
/docs/api/utils/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Utils
3 | author: AkiChase
4 | index: false
5 | ---
6 |
7 | `PluginHelper.Utils` 纯工具类
8 |
9 |
--------------------------------------------------------------------------------
/docs/api/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: PluginHelper
3 | author: AkiChase
4 | index: false
5 | ---
6 |
7 | 插件开发工具模块 `PluginHelper` 中的所有API参数及说明
8 |
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode/
2 | resource/data/
3 | Starter.lnk
4 | src/Plugin/*.txt
5 |
6 | node_modules/
7 | docs/.vuepress/.cache/
8 | docs/.vuepress/.temp/
9 | docs/.vuepress/dist/
10 |
--------------------------------------------------------------------------------
/docs/plugin/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 插件指南
3 | icon: list-ul
4 | index: false
5 | ---
6 |
7 | 插件指南为用户提供各种插件的**使用帮助**。
8 |
9 | 插件是 **Starter** 最有创造性✨也是最强大的一部分💪
10 |
11 |
--------------------------------------------------------------------------------
/docs/api/pluginMenu.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: pluginMenu
3 | author: AkiChase
4 | order: 1
5 | date: 2023-04-14
6 | ---
7 |
8 | ## 定义
9 |
10 | ```ahk
11 | static pluginMenu
12 | ```
13 |
14 | ## 类型
15 |
16 | 静态属性 \{Menu\}
17 |
18 | ## 说明
19 |
20 | **插件菜单**对象,菜单位于:**托盘菜单** > **插件功能**
21 |
--------------------------------------------------------------------------------
/docs/dev/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 插件开发
3 | icon: code
4 | ---
5 |
6 | 开发者,欢迎你。
7 |
8 | 创建一个 `Starter` 插件非常简单,只需要了解一些AHK的基本知识并使用 `Starter` 提供的接口和工具函数。实际上,创建插件与编写普通的AHK程序类似,你也可以把自己常用的脚本转化为 `Starter` 插件,通过 `Starter` 实现更加强大的功能。
9 |
10 | ::: tip
11 | 阅读[快速上手](./get-started/),创建你的第一个专属插件。
12 | :::
--------------------------------------------------------------------------------
/docs/api/searchGuiHwnd.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: searchText
3 | author: AkiChase
4 | order: 1
5 | date: 2023-04-15
6 | ---
7 |
8 | ## 定义
9 |
10 | ```ahk
11 | static searchText {
12 | get => SearchGui.gui.Hwnd
13 | }
14 | ```
15 |
16 | ## 类型
17 |
18 | 动态属性 \{Int\}
19 |
20 | ## 说明
21 |
22 | **获取**搜索界面hwnd。
--------------------------------------------------------------------------------
/docs/api/imgDir.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: imgDir
3 | author: AkiChase
4 | order: 1
5 | date: 2023-04-15
6 | ---
7 |
8 | ## 定义
9 |
10 | ```ahk
11 | static imgDir => GlobalData.imgDir
12 | ```
13 |
14 | ## 类型
15 |
16 | 动态属性 \{String\}
17 |
18 | ## 说明
19 |
20 | 返回图片资源的目录路径。
21 |
22 | ## 返回值 {String}
23 |
24 | 返回字符串类型,代表 **Starter** 图片资源的目录路径。
--------------------------------------------------------------------------------
/docs/plugin/win10-taskbar-transparent.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Win10任务栏透明
3 | author: AkiChase
4 | date: 2023-04-11
5 | ---
6 |
7 | 将Win10任务栏透明化,仅此而已
8 |
9 | ::: warning
10 | 打开开始菜单后透明状态会暂时消失,**且仅支持Win10**
11 | :::
12 |
13 | 右键Starter右下角托盘图标:**Starter菜单** > **插件功能** > **Win10任务栏透明** > **开启**
14 |
15 | 
--------------------------------------------------------------------------------
/docs/plugin/timed-reminder.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 定时提醒
3 | author: AkiChase
4 | date: 2023-04-11
5 | ---
6 |
7 | ## 介绍
8 |
9 | 隔一段时间提醒一下坐在电脑前的你,该喝水\起身\休息啦!
10 |
11 | 
12 |
13 | ### 1.2 配置
14 |
15 | 右键Starter右下角托盘图标:**Starter菜单** > **插件功能** > **定时提醒** > **设置 | 开启**
16 |
17 | 
--------------------------------------------------------------------------------
/docs/api/placeholder.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: placeholder
3 | author: AkiChase
4 | order: 1
5 | date: 2023-04-15
6 | ---
7 |
8 | ## 定义
9 |
10 | ```ahk
11 | static placeholder {
12 | get => SearchGui.placeholder
13 | set => SearchGui.placeholder := Value
14 | }
15 | ```
16 |
17 | ## 类型
18 |
19 | 动态属性 \{String\}
20 |
21 | ## 说明
22 |
23 | **获取**、**设置**搜索框的占位符。占位符是搜索框未输入搜索内容时的显示内容。
--------------------------------------------------------------------------------
/docs/api/searchText.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: searchText
3 | author: AkiChase
4 | order: 1
5 | date: 2023-04-15
6 | ---
7 |
8 | ## 定义
9 |
10 | ```ahk
11 | static searchText {
12 | get => SearchGui.searchText
13 | set => SearchGui.edit.Value := SearchGui.searchText := value
14 | }
15 | ```
16 |
17 | ## 类型
18 |
19 | 动态属性 \{String\}
20 |
21 | ## 说明
22 |
23 | **获取**、**设置**搜索框当前的文本内容。
--------------------------------------------------------------------------------
/docs/.vuepress/navbar.ts:
--------------------------------------------------------------------------------
1 | import { navbar } from "vuepress-theme-hope";
2 |
3 | export const zhNavbar = navbar([
4 | { text: "使用指南", icon: "lightbulb", link: "/guide/" },
5 | { text: "插件指南", icon: "list-ul", link: "/plugin/" },
6 | { text: "插件开发", icon: "code", link: "/dev/" },
7 | { text: "API", icon: "screwdriver-wrench", link: "/api/" },
8 | { text: "更新日志", icon: "clock", link: "/history" }
9 | ]);
10 |
--------------------------------------------------------------------------------
/docs/api/getPluginMode.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: getPluginMode
3 | author: AkiChase
4 | order: 1
5 | date: 2023-04-15
6 | ---
7 |
8 | ## 定义
9 |
10 | ```ahk
11 | static getPluginMode(*)
12 | ```
13 |
14 | ## 类型
15 |
16 | 静态函数
17 |
18 | ## 说明
19 |
20 | 返回 `PluginMode` 类
21 |
22 | 特定情况下需要提前获取到PluginMode,即所谓的that。
23 |
24 | ## 参数
25 |
26 | - `*`: 具体使用时可以传入任何参数,此参数在该函数中没有任何用途。
27 |
28 | ## 返回值 \{PluginMode\}
29 |
30 | 返回 `PluginMode` 类
--------------------------------------------------------------------------------
/docs/api/pastedContentType.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: pastedContentType
3 | author: AkiChase
4 | order: 1
5 | date: 2023-04-15
6 | ---
7 |
8 | ## 定义
9 |
10 | ```ahk
11 | static pastedContentType => SearchGui._pastedContentType
12 | ```
13 |
14 | ## 类型
15 |
16 | 动态属性 \{String\}
17 |
18 | ## 说明
19 |
20 | 返回**当前搜索框**粘贴的内容的**类型**,或者按下**智能搜索框**时选中的内容的**类型**。可返回 "file", "bitmap", "text"。
21 |
22 | ## 返回值 \{String\}
23 |
24 | 返回字符串类型,代表粘贴的内容类型。可返回 "file", "bitmap", "text"。
--------------------------------------------------------------------------------
/docs/api/addEntryFunc.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: addEntryFunc
3 | author: AkiChase
4 | order: 1
5 | date: 2023-04-14
6 | ---
7 | ## 定义
8 |
9 | ```ahk
10 | static PluginHelper.addEntryFunc(f)
11 | ```
12 |
13 | ## 类型
14 |
15 | 静态方法
16 |
17 | ## 说明
18 |
19 | 添加插件入口函数到执行队列,等待基本功能初始化后,函数将被执行
20 |
21 | ## 参数
22 |
23 | - ### f \{[Closure](https://orz707.gitee.io/v2/docs/Functions.htm#closures)\}
24 |
25 | ```ahk
26 | (*) => Any
27 | ```
28 |
29 | 插件**入口函数**,也可以称为插件的**初始化函数**
--------------------------------------------------------------------------------
/docs/api/hideSearchGui.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: hideSearchGui
3 | author: AkiChase
4 | order: 1
5 | date: 2023-04-15
6 | ---
7 |
8 | ## 定义
9 |
10 | ```ahk
11 | static hideSearchGui(recordHideTime:=false)
12 | ```
13 |
14 | ## 类型
15 |
16 | 静态方法
17 |
18 | ## 说明
19 |
20 | 隐藏搜索框。
21 |
22 | 如果 recordHideTime 值为 true,则会记录隐藏时间,15s内按**呼出搜索框**快捷键可恢复窗口。
23 |
24 | ## 参数
25 |
26 | - ### recordHideTime \{Bool\}
27 |
28 | 默认为 `false`。如果设置为 `true`,则会记录隐藏时间,15s内按**呼出搜索框**快捷键可恢复搜索框内容。
--------------------------------------------------------------------------------
/docs/api/workWinInfo.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: workWinInfo
3 | author: AkiChase
4 | order: 1
5 | date: 2023-04-15
6 | ---
7 |
8 | ## 定义
9 |
10 | ```ahk
11 | static workWinInfo => SearchGui.workWinInfo
12 | ```
13 |
14 | ## 类型
15 |
16 | 动态属性 \{Object\}
17 |
18 | ## 说明
19 |
20 | 返回当前活动窗口的相关信息。
21 |
22 | ## 返回值 \{Object\}
23 |
24 | 返回一个包含活动窗口信息的对象。对象包含以下属性:
25 |
26 | - `hwnd`: 窗口句柄
27 | - `title`: 窗口标题
28 | - `class`: 窗口类名
29 | - `processPath`: 程序路径
30 | - `processName`: 程序名称
--------------------------------------------------------------------------------
/src/Utils/LoadIconFromBase64.ah2:
--------------------------------------------------------------------------------
1 | LoadIconFromBase64(base64, W := 0, H := 0)
2 | {
3 | nBytes := Floor((B64Len := StrLen(base64 := RTrim(base64, "="))) * 3 / 4)
4 | buf := Buffer(nBytes)
5 |
6 | DllCall("Crypt32.dll\CryptStringToBinary", "str", base64, "int", B64Len, "int", 1, "ptr", buf, "uintp", nBytes, "Int", 0, "Int", 0)
7 | Return DllCall("User32.dll\CreateIconFromResourceEx", "ptr", buf, "int", nBytes, "int", 1, "int", 0x30000, "Int", W, "Int", H, "Int", 0, "ptr")
8 | }
--------------------------------------------------------------------------------
/docs/guide/plugin/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 插件界面
3 | icon: list-ul
4 | author: AkiChase
5 | date: 2023-04-11
6 | ---
7 |
8 | 运行 **Starter** 后,右键右下角托盘图标打开菜单,点击**插件界面**。
9 |
10 | 
11 |
12 | - **双击**列表项可以启用/禁用插件
13 | - 点击**保存重载**,可以保存当前启用/禁用状态,然后重启软件以加载启用的插件
14 | - 点击**刷新列表**,可以重新读取插件目录内的插件信息,刷新插件界面列表
15 | - 插件使用帮助,请移步[插件指南](../../plugin/)
16 | - 自定义插件开发,请移步[插件开发](../../dev/)
17 |
18 | ::: tip
19 | 请不要过分贪图 `ALL IN ONE`, 加载到`Starter`内的插件过多必然会影响程序的运行速度。
20 | :::
--------------------------------------------------------------------------------
/docs/plugin/web-search.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 网页搜索
3 | author: AkiChase
4 | date: 2023-04-11
5 | order: 1
6 | ---
7 |
8 | ## 介绍
9 |
10 | 进行百度、必应、谷歌网页搜索,输入搜索内容时显示搜索联想词。
11 |
12 | 
13 |
14 | ## 配置
15 |
16 | 右键 **Starter** 右下角托盘图标 > **Starter菜单** > **插件功能** > **网页搜索** > **设置**
17 |
18 | **谷歌搜索**国内需要使用代理,通过本地socket代理的方式连通网络。
19 |
20 | 如果有需要可以考虑[蓝色海洋](https://abcloud365.xyz/index.php#/register?code=lyUxxqMu),配合Clash使用
21 |
22 | 
--------------------------------------------------------------------------------
/docs/api/getPluginIconBase64.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: getPluginIconBase64
3 | author: AkiChase
4 | order: 1
5 | date: 2023-04-15
6 | ---
7 |
8 | ## 定义
9 |
10 | ```ahk
11 | static getPluginIconBase64(pluginName)
12 | ```
13 |
14 | ## 类型
15 |
16 | 静态方法
17 |
18 | ## 说明
19 |
20 | 获取指定插件的图标的无头部 `Base64`
21 |
22 | 如果插件存在图标则返回无头部 `Base64`,如果插件不存在图标则返回 0。
23 |
24 | ## 参数
25 |
26 | - ### pluginName \{String\}
27 |
28 | 插件名称,即插件文件名。
29 |
30 | ## 返回值 \{(String|Int)\}
31 |
32 | 如果插件存在图标则返回无头部 `Base64`,如果插件不存在图标则返回 0。
--------------------------------------------------------------------------------
/docs/guide/about/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 关于界面
3 | icon: circle-info
4 | author: AkiChase
5 | date: 2023-04-11
6 | ---
7 |
8 | ## 关于界面
9 |
10 | 
11 |
12 | 运行 **Starter** 后,右键右下角托盘图标打开菜单,点击**关于界面**。
13 |
14 | - 显示当前版本号
15 | - 显示项目主页
16 | - 检查更新按钮
17 |
18 | ## 检查更新
19 |
20 | 软件启动时会进行一次检查更新,也可以通过自启界面的检查更新按钮来手动检查。
21 |
22 | 更新需要前往项目主页,或者其他版本发布地址手动下载最新版本。
23 |
24 | 更新版本前记得导出旧版的数据文件,以导入新版本中。
25 |
26 | ::: tip
27 | 考虑到很多人无法访问GitHub,所以检查更新基于同步的Gitee仓库的Tags
28 |
29 | 效果一般,仅仅能检测版本号
30 | :::
--------------------------------------------------------------------------------
/docs/api/getPluginHIcon.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: getPluginHIcon
3 | author: AkiChase
4 | order: 1
5 | date: 2023-04-15
6 | ---
7 |
8 | ## 定义
9 |
10 | ```ahk
11 | static PluginHelper.getPluginHIcon(pluginName)
12 | ```
13 |
14 | ## 类型
15 |
16 | 静态方法
17 |
18 | ## 说明
19 |
20 | 获取指定插件的图标 `hIcon`
21 |
22 | :::warning
23 | 使用 `hIcon` 时请加 `*` 以使用副本,如 `hIcon:* 123456`,避免原图标句柄用后销毁
24 | :::
25 |
26 | ## 参数
27 |
28 | - ### pluginName \{String\}
29 |
30 | 插件名称,即插件文件名、插件id
31 |
32 | ## 返回值 \{Int\}
33 |
34 | 如果插件有图标,则返回hIcon,否则返回0
--------------------------------------------------------------------------------
/CreateShortcut.vbs:
--------------------------------------------------------------------------------
1 | set WshShell=WScript.CreateObject("WScript.Shell")
2 | Set Ws = CreateObject("Scripting.FileSystemObject")
3 | '获取当前脚本路径
4 | currentpath = Ws.GetFile(Wscript.ScriptFullName).ParentFolder.Path
5 | set oShellLink=WshShell.CreateShortcut(currentpath & "\Starter.lnk")
6 | oShellLink.TargetPath= currentpath & "\src\AutoHotkey64.exe"
7 | oShellLink.Arguments = "Starter.ah2"
8 | oShellLink.IconLocation= currentpath & "\resource\img\Starter.ico"
9 | oShellLink.WorkingDirectory=currentpath & "\src"
10 | oShellLink.Save
--------------------------------------------------------------------------------
/docs/guide/user-data/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 用户数据
3 | icon: user
4 | author: AkiChase
5 | date: 2023-04-11
6 | ---
7 |
8 | 右键右下角托盘图标打开软件菜单,点击**用户数据**进入**子菜单**
9 |
10 | ## 打开数据目录
11 |
12 | 打开用户数据所在目录
13 |
14 | ## 导出用户数据
15 |
16 | 
17 |
18 | 进入导出用户数据界面,选择保存目录、导出选项,将相关内容导出为 **zip** 文件
19 |
20 | ## 导入用户数据
21 |
22 | 
23 |
24 | 进入导入用户数据界面,选择数据路径、导入选项,将相关内容导入至 **Starter**
25 |
26 | ::: warning
27 | 导入的内容会直接覆盖同名文件,担心误操作请提前导出数据作为备份。
28 |
29 | 目前导出时请不要覆盖插件,而是手动复制插件的配置文件,粘贴到新版本插件目录内。
30 | :::
--------------------------------------------------------------------------------
/docs/api/setSearchTextSel.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: setSearchTextSel
3 | author: AkiChase
4 | order: 1
5 | date: 2023-04-15
6 | ---
7 |
8 | ## 定义
9 |
10 | ```ahk
11 | static setSearchTextSel(start := 0, end := -1)
12 | ```
13 |
14 | ## 类型
15 |
16 | 静态方法
17 |
18 | ## 说明
19 |
20 | 设置搜索框的选中文本区域。
21 |
22 | ## 参数
23 |
24 | - `start`: 选中文本区域的开始位置,默认值为 `0`,表示从第一个文本之前开始选中。
25 | - `end`: 选中文本区域的结束位置,默认值为 `-1`,表示选中最后一个文本。
26 |
27 | :::tip
28 | 当 `start` 和 `end` 的值相同时,表示将游标移动到指定位置。
29 |
30 | 使用 `setSearchTextSel(StrLen(searchText), -1)` 将游标移动到最后
31 | :::
--------------------------------------------------------------------------------
/docs/api/winInfoMatchFlag.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: winInfoMatchFlag
3 | author: AkiChase
4 | order: 1
5 | date: 2023-04-15
6 | ---
7 |
8 | ## 定义
9 |
10 | ```ahk
11 | static winInfoMatchFlag => SearchGui.winInfoMatchFlag
12 | ```
13 |
14 | ## 类型
15 |
16 | 动态属性 \{Bool\}
17 |
18 | ## 说明
19 |
20 | 返回一个布尔值,表示当前是否处于工作窗口模式。
21 |
22 | :::tip
23 | 工作窗口模式是按下**智能搜索**快捷键时,若当前**没有选中任何内容**,则**Starter**将获取工作窗口信息,进入工作窗口模式下的智能模式搜索框。
24 |
25 | 搜索框会短暂显示工作窗口的信息,插件可以根据此时的工作窗口信息进行匹配
26 | :::
27 |
28 | ## 返回值 \{Bool\}
29 |
30 | 返回一个布尔值,表示当前是否处于工作窗口模式。如果处于工作窗口模式,则返回 `true`,否则返回 `false`。
--------------------------------------------------------------------------------
/docs/api/pastedContent.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: pastedContent
3 | author: AkiChase
4 | order: 1
5 | date: 2023-04-15
6 | ---
7 |
8 | ## 定义
9 |
10 | ```ahk
11 | static pastedContent => SearchGui._pastedContent
12 | ```
13 |
14 | ## 类型
15 |
16 | 动态属性 \{(Array|ImagePutBuffer|String)\}
17 |
18 | ## 说明
19 |
20 | 返回**当前搜索框**粘贴的内容,或者按下**智能搜索框**时选中的内容。
21 |
22 | 根据[pastedContentType](./pastedContentType.md)的不同,可返回文件路径数组,ImagePut缓冲对象ImagePutBuffer、字符串。
23 |
24 |
25 | ## 返回值 \{(Array|Int|String)\}
26 |
27 | 根据[pastedContentType](./pastedContentType.md)的不同,可返回文件路径数组,ImagePutBuffer、字符串。
--------------------------------------------------------------------------------
/docs/guide/intelligent/usage.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 使用
3 | icon: keyboard
4 | order: 3
5 | author: AkiChase
6 | date: 2023-04-11
7 | ---
8 |
9 | 
10 |
11 | ## 进入智能模式
12 |
13 | 进入智能模式有几种方式
14 |
15 | 1. 按下 `呼出搜索框` 快捷键,呼出**启动模式搜索框**,按 `Tab` 键切换到智能模式。
16 |
17 | 2. 选中任意内容,按下 `智能搜索框` 快捷键,将获取选中内容,切换到智能模式,将选中内容输入搜索框。
18 |
19 | 3. 当剪切板中复制有文件、位图时,呼出**启动模式搜索框**,粘贴后,将切换到智能模式。
20 |
21 | ::: warning
22 | 只有仅输入文本时,才可能匹配到**原生智能项**,可以通过 `Esc`键,清除其他输入内容。
23 |
24 | 第2种,第3种方式一般都是用于快速匹配相关的**插件智能项**的。
25 | :::
26 |
27 | ## 启动智能项
28 |
29 | 在搜索界面中,操作方式和启动模式下基本相同,只是没有了双击 `Right` 在文件夹中打开的功能。
--------------------------------------------------------------------------------
/src/Utils/IME.ah2:
--------------------------------------------------------------------------------
1 | ; IME_GET 获取输入法状态
2 | ; 返回 0 英文
3 | ; 返回 1 中文
4 | IME_GET() {
5 | return DllCall("SendMessage"
6 | , "UInt", DllCall("imm32\ImmGetDefaultIMEWnd", "Uint", WinActive("A"))
7 | , "UInt", 0x0283 ;Message : WM_IME_CONTROL
8 | , "Int", 0x0005 ;wParam : IMC_GETOPENSTATUS
9 | , "Int", 0)
10 | }
11 |
12 | ; IME_SET 设置输入法状态
13 | ; state := 0 英文
14 | ; state := 1 中文
15 | IME_SET(state := 0) {
16 | return DllCall("SendMessage"
17 | , "UInt", DllCall("imm32\ImmGetDefaultIMEWnd", "Uint", WinActive("A"))
18 | , "UInt", 0x0283 ;Message : WM_IME_CONTROL
19 | , "Int", 0x006 ;wParam : IMC_SETOPENSTATUS
20 | , "Int", state) ;lParam : 0 or 1
21 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "starter",
3 | "version": "0.4.0",
4 | "description": "starter docs",
5 | "license": "GPL-3.0",
6 | "type": "module",
7 | "scripts": {
8 | "docs:build": "vuepress build docs",
9 | "docs:clean-dev": "vuepress dev docs --clean-cache",
10 | "docs:dev": "vuepress dev docs",
11 | "docs:update-package": "pnpm dlx vp-update"
12 | },
13 | "devDependencies": {
14 | "@vuepress/client": "2.0.0-beta.61",
15 | "@vuepress/plugin-shiki": "2.0.0-beta.61",
16 | "vue": "^3.2.47",
17 | "vuepress": "2.0.0-beta.61",
18 | "vuepress-plugin-auto-catalog": "2.0.0-beta.202",
19 | "vuepress-plugin-search-pro": "2.0.0-beta.202",
20 | "vuepress-theme-hope": "2.0.0-beta.202"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/docs/plugin/file-selection-dialog-nav.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 文件选择对话框导航
3 | author: AkiChase
4 | date: 2023-04-12
5 | ---
6 |
7 | ## 介绍
8 |
9 | 文件对话框中路径导航功能,模仿Listary的 `Ctrl+G` 功能
10 |
11 | 让文件对话框导航到**资源管理器**中正在浏览的文件夹。
12 |
13 | 
14 |
15 | ## 使用方式
16 |
17 | 当你正处于某个文件选择对话框时,按下 `智能搜索框` 快捷键(不能选中任何内容),进入**工作窗口模式**的智能搜索框
18 |
19 | 在搜索结果中可以看到**文件选择对话框路径导航**,启动此**插件智能项**即可进入插件界面
20 |
21 | 插件界面的列表中会列举所有正在运行的**资源管理器**中正在浏览的文件夹,**输入内容到搜索框可以对其进行筛选**
22 |
23 | 筛选依据为:输入的内容是否为列表项**标题**或者**将标题内中文转拼音首字母后的标题**的一部分
24 |
25 | 最后,启动某列表项即可完成导航到指定路径。
26 |
27 | 
28 |
29 | ::: warning
30 | 按下 `智能搜索框` 快捷键之前,请不要选中任何文件或者文本,否则插件智能项不会出现在列表中(因为无法进入工作窗口模式)
31 | :::
32 |
--------------------------------------------------------------------------------
/docs/guide/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 使用指南
3 | icon: lightbulb
4 | ---
5 |
6 | ## 从这里开始
7 |
8 | 在开始使用 Starter 之前,建议先阅读[快速上手](./get-started/intro),以便快速了解软件的基本功能和操作。
9 |
10 | 若想深入了解软件的**所有功能**,可以查阅使用指南的其他内容,其中包含了详细的介绍和操作说明。
11 |
12 | ::: tip
13 | 若在使用 Starter 过程中遇到无法解决的问题,欢迎前往 [Issues](https://github.com/AkiChase/Starter/issues) 提交问题报告。
14 |
15 | 在提交问题报告时,请尽可能提供详细的信息,例如出错时的错误提示、错误复现流程和软件版本等,以便更好地解决问题。感谢你的支持和理解!
16 | :::
17 |
18 | ## 万能搜索框 ✨
19 |
20 | 
21 |
22 | 通过搜索和情景匹配,回应符合要求的内容
23 | ## 轻量 & 绿色 ✨
24 |
25 | 
26 |
27 | Starter 使用AHK编写,绿色免安装,体积 < 2M
28 | ## 简洁 & 颜值在线 ✨
29 |
30 | 
31 |
32 | Starter 设计简洁美观,UI的「颜值即正义」
33 | ## 插件化 ✨
34 |
35 | 
36 |
37 | 自由装载插件,打造个人专属效率工具
--------------------------------------------------------------------------------
/docs/guide/boot/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 自启界面
3 | icon: desktop
4 | author: AkiChase
5 | date: 2023-04-11
6 | ---
7 |
8 | ## 开机自启动
9 |
10 | 运行 **Starter** 后,右键右下角托盘图标打开菜单,点击**开机启动**,即可切换开机自启状态。
11 |
12 | ::: tip
13 | **Starter** 开机自启通过写入注册表实现
14 | :::
15 |
16 | ## 自启界面
17 |
18 | 
19 |
20 | 运行 **Starter** 后,右键右下角托盘图标打开菜单,点击**自启界面**。
21 |
22 | - Starter**开机自启时**会自动运行自启界面列表中的所有项,**按名称顺序**。
23 | ::: warning
24 | **开启**开机自启时,Starter才会在**开机自启动**时运行自启界面列表中的所有项。
25 |
26 | 因为写入开机自启注册表时为启动 **Starter** 程序附加了 `"the_startup"` 命令行参数
27 | :::
28 |
29 | - **右键**点击列表打开**菜单**进行添加、刷新、删除操作。
30 | - **拖动文件**到自启界面中可以**批量添加**自启项。
31 | - **双击**列表项可以直接启动对应项。
32 |
33 | ::: tip
34 | 添加的自启项将会创建快捷方式到**用户数据目录**的 `boot` 文件夹下
35 |
36 | 如果有需要改变自启顺序,可以通过修改`boot` 文件夹对应**快捷方式的文件名**来修改顺序
37 |
38 | 比如为快捷方式文件名加上 `01`,`02` 等前缀
39 | :::
--------------------------------------------------------------------------------
/docs/plugin/window-switcher.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 窗口切换
3 | author: AkiChase
4 | date: 2023-05-12
5 | ---
6 |
7 | ## 介绍
8 |
9 | 窗口切换功能,模仿Switcheroo
10 |
11 | 显示当前窗口列表,输入内容对列表进行检索,支持拼音首字母。
12 |
13 | 
14 |
15 | 
16 |
17 |
18 | ## 使用方式
19 |
20 | 插件入口在启动模式中,其他关键词为`["CKQH"]`。
21 |
22 | 启动该插件启动项,进入窗口切换插件。
23 |
24 | 当未输入任何内容时,在搜索结果中可以看到当前所有窗口的标题列表,即介绍中的第一张图片。
25 |
26 | 输入任意文本,即可对窗口标题进行检索,**支持拼音首字母**。
27 |
28 | 最后,启动某列表项即可完成切换到指定窗口。
29 |
30 | ## 进阶技巧
31 |
32 | 添加对应的[关键词快捷键](https://AkiChase.github.io/Starter/guide/setting/#控制),可以通过快捷键**快速启动插件**。
33 |
34 | 
35 |
36 | 参考设置如上图,可以通过按下`Alt` + `CapsLK`快捷键来启动该插件。
37 |
38 | :::tip
39 | 如果需要用来代替`Alt` + `Tab`功能,请将**按键类型**设置为**自定义**,**按键内容**设置为`!Tab`
40 | :::
--------------------------------------------------------------------------------
/docs/plugin/file-find.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 文件搜索
3 | author: AkiChase
4 | date: 2023-04-11
5 | order: 2
6 | ---
7 |
8 | ## 介绍
9 |
10 | 调用Everything进行文件搜索。
11 |
12 | 
13 |
14 | ## 插件项入口
15 |
16 | ### 1.启动模式
17 |
18 | 关键词为`["WJSS", "Everything"]`
19 |
20 | ### 2. 智能模式
21 |
22 | - 输入任意内容,进入插件时保留输入内容 (优先级为 **1**)
23 | - 搜索框带有**单个文件夹**时,进入插件时保留输入内容和文件夹信息 (优先级为 **1**)
24 | - 搜索框带有**单个文件夹**时且输入 `Everything`, `WJSS` 开头或全部的文本, 进入插件时**不保留输入内容**但**保留文件夹信息** (优先级为 **2**)
25 |
26 | ::: tip
27 | 优先级越高,在搜索结果中排序越靠前,且**插件智能项**优先级高于**原生智能项**。
28 | :::
29 |
30 | ## 使用方式
31 |
32 | 1. 搜索语法见: [Searching - voidtools](https://www.voidtools.com/zh-cn/support/everything/searching/)
33 | 2. 右键任意搜索结果打开功能菜单,进行文件夹中显示、复制、删除、设置等操作
34 | 3. 双击`Right`键也可以打开功能菜单
35 | 4. 搜索框可以拖入、粘贴**单个文件夹**,此时将在该文件夹内搜索
36 |
37 | ::: tip
38 | 相当于加入前缀 `"文件夹路径xxx"` + `空格`
39 | :::
40 |
--------------------------------------------------------------------------------
/src/Utils/QuickSort.ah2:
--------------------------------------------------------------------------------
1 | QuickSort(arr, function) {
2 | if 2 > len := arr.Length
3 | return arr
4 | ranges := [1 | (len << 32)], ranges.Length := len, i := 2
5 | while i > 1 {
6 | range := ranges[--i]
7 | if (start := range & 0xffffffff) >= (end := range >> 32)
8 | continue
9 | mid := arr[(start + end) / 2], left := start, right := end
10 | loop {
11 | while function(arr[left], mid) < 0
12 | ++left
13 | while function(arr[right], mid) > 0
14 | --right
15 | if left <= right
16 | temp := arr[left], arr[left] := arr[right], arr[right] := temp, left++, right--
17 | } until left > right
18 | if start < right
19 | ranges[i++] := start | right << 32
20 | if end > left
21 | ranges[i++] := left | end << 32
22 | }
23 | return arr
24 | }
--------------------------------------------------------------------------------
/src/Utils/MapArrClone.ah2:
--------------------------------------------------------------------------------
1 | /**
2 | * MapArrClone(obj)
3 | * AHK v2.x
4 | * Created by AkiChase on 2023.2.17
5 | * 深拷贝 支持值类型和Map、Array引用类型
6 | */
7 |
8 | MapArrClone(obj) {
9 | m := Map()
10 | _deep(target) {
11 | if (!isObject(target)) ; 非对象直接返回
12 | return target
13 |
14 | if !(target is Array or obj is Map) ; 对象类型仅支持Map和Array
15 | throw Format("Only Array and Map are supported: {}", Type(obj))
16 |
17 | if (m.Has(target)) ; 存在已递归过的对象,直接返回上次的值,避免循环递归溢出
18 | return m[target]
19 |
20 | if (target is Array) { ; 创建新对象
21 | result := Array()
22 | result.Capacity := target.Capacity
23 | } else
24 | result := Map()
25 |
26 | m[target] := result ; 记录已递归
27 |
28 | for k, v in target
29 | (target is Array) ? result.Push(v) : result[k] := _deep(v) ; 递归
30 | return result
31 | }
32 | return _deep(obj)
33 | }
--------------------------------------------------------------------------------
/docs/plugin/ocr.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: OCR识别文字
3 | author: AkiChase
4 | date: 2023-04-13
5 | ---
6 |
7 | ## 介绍
8 |
9 | 调用百度OCR在线识别文字,需要自行申请API密钥
10 |
11 | 
12 |
13 |
14 | ## 配置
15 |
16 | 请先申请百度OCR,方法自行上网搜索。
17 |
18 | 右键 **Starter** 右下角托盘图标 > **Starter菜单** > **插件功能** > **OCR识别文字** > **设置**
19 |
20 | 设置界面分别填入申请到的 `id` 和 `secret` ,点击**保存**
21 |
22 | ## 使用
23 |
24 | - ### 方式一
25 |
26 | 使用任意截图工具截取图片到**剪切板**,呼出**搜索框**,粘贴,转到**智能模式搜索框**
27 |
28 | 
29 |
30 | 启动对应**插件智能项**进入识别界面,并识别图片
31 |
32 | - ### 方式二
33 |
34 | 启动模式搜索框中关键词为`["OCR识别文字", "OCRSBWZ"]`
35 |
36 | 启动对应**插件启动项**进入识别界面
37 |
38 | - ### 方式三
39 |
40 | 右键 **Starter** 右下角托盘图标 > **Starter菜单** > **插件功能** > **OCR识别文字** > **显示**,进入识别界面
41 |
42 | ## 识别界面
43 |
44 | 左侧为正在识别的图片,**不用在意显示的图片变形,仅仅是控件显示问题**
45 |
46 | 右侧为识别结果
47 |
48 | :::tip
49 | **直接粘贴图片**就可以进行图片识别
50 |
51 | **点击左侧图片**位置可以通过文件选择进行图片识别
52 | :::
53 |
54 | ::: warning
55 | 修改识别结果**连接方式**或者**自动复制**选项时,打开**设置界面**并点击保存,
56 |
57 | **下次启动时才会使用保存的选择**
58 | :::
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | home: true
3 | icon: home
4 | title: 主页
5 | heroImage: /logo.svg
6 | heroImageDark: /logo-tp.svg
7 | heroText: Starter
8 | tagline: 智能、快捷地启动文件和插件应用,提供便利与高效的使用体验✨
9 | actions:
10 | - text: 使用指南 💡
11 | link: /guide/
12 | type: primary
13 |
14 | - text: 插件开发 🔧
15 | link: /dev/
16 |
17 | features:
18 | - title: 万能搜索框
19 | icon: magnifying-glass
20 | details: Starter 通过搜索和情景匹配,回应符合要求的多种内容。
21 |
22 | - title: 轻量 & 绿色
23 | icon: feather-pointed
24 | details: Starter 使用AHK编写,绿色免安装,体积 < 2M 。
25 |
26 | - title: 简洁 & 颜值在线
27 | icon: heart
28 | details: Starter 设计简洁美观,UI的「颜值即正义」。
29 |
30 | - title: 插件化
31 | icon: list-ul
32 | details: Starter 可以自由装载插件,打造个人专属效率工具。
33 |
34 | - title: 插件 - 文件搜索
35 | icon: folder-closed
36 | details: 基于Everything而更便捷的文件秒搜
37 |
38 | - title: 插件 - 网页搜索
39 | icon: cloud
40 | details: 带有联想词的搜索框,支持百度、必应、谷歌搜索
41 |
42 | - title: 更多插件开发中
43 | icon: ellipsis
44 | details: 提供插件开发模板与实例,欢迎参与开源,提交PR
45 | ---
46 |
47 |
--------------------------------------------------------------------------------
/docs/.vuepress/config.ts:
--------------------------------------------------------------------------------
1 | import { defineUserConfig } from "vuepress";
2 | import theme from "./theme.js";
3 | // 搜索插件
4 | import { searchProPlugin } from "vuepress-plugin-search-pro";
5 | // 自定义代码高亮
6 | import { shikiPlugin } from "@vuepress/plugin-shiki";
7 |
8 |
9 | import { readFileSync } from 'fs';
10 | import { join } from 'path';
11 |
12 | export default defineUserConfig({
13 | base: "/Starter/",
14 |
15 | locales: {
16 | "/": {
17 | lang: "zh-CN",
18 | title: "Starter文档",
19 | description: "Starter - 极简效率工具",
20 | },
21 | },
22 | theme,
23 | plugins: [
24 | searchProPlugin({
25 | indexContent: true,
26 | }),
27 | shikiPlugin({
28 | theme: "one-dark-pro",
29 | langs: [{
30 | id: "autohotkey",
31 | scopeName: 'source.ahk2',
32 | grammar: JSON.parse(readFileSync(join(__dirname, 'ahk2.tmLanguage.json'), "utf-8")),
33 | aliases: ['ahk', 'ahk2', 'ah2'],
34 | path: join(__dirname, 'ahk2.tmLanguage.json')
35 | }]
36 | }),
37 | ],
38 | });
39 |
40 |
41 |
--------------------------------------------------------------------------------
/.github/workflows/sync2gitee.yml:
--------------------------------------------------------------------------------
1 | # This is a basic workflow to help you get started with Actions
2 |
3 | name: sync2gitee
4 |
5 | # Controls when the workflow will run
6 | on:
7 | push:
8 | branches: [ "master" ]
9 | release:
10 | types: [published]
11 |
12 | # Allows you to run this workflow manually from the Actions tab
13 | workflow_dispatch:
14 |
15 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel
16 | jobs:
17 | # This workflow contains a single job called "repo-sync"
18 | repo-sync:
19 | # The type of runner that the job will run on
20 | runs-on: ubuntu-latest
21 |
22 | # Steps represent a sequence of tasks that will be executed as part of the job
23 | steps:
24 | - name: sync-gitee-mirror
25 | uses: abersheeran/sync-gitee-mirror@v1-beta
26 | with:
27 | # Gitee 仓库,例如 abersheeran/gitee-mirror
28 | repository: ${{ github.repository }}
29 | # Gitee 用户名,用于登录。
30 | username: AkiChase
31 | # Gitee 密码,用于登录。
32 | password: ${{ secrets.GITEE_PASSWORD }}
33 |
--------------------------------------------------------------------------------
/src/Utils/DataHelper.ah2:
--------------------------------------------------------------------------------
1 | class DataHelper {
2 | static Join(sep, arr) {
3 | for item in arr
4 | str .= item . sep
5 | return SubStr(str, 1, -StrLen(sep))
6 | }
7 |
8 | ;加载数据
9 | static loadData(path) {
10 | out := []
11 | Loop read, path ;不使用StrSplit
12 | {
13 | if (StrLen(A_LoopReadLine))
14 | out.Push(StrSplit(A_LoopReadLine, "¢"))
15 | }
16 | return out
17 | }
18 |
19 | ;保存数据到文件
20 | static storeData(data, path) {
21 | content := ""
22 | for item in data {
23 | row := this.Join("¢", item)
24 | content .= row "`n"
25 | }
26 | f := FileOpen(path, "w", "UTF-8-RAW")
27 | f.Write(SubStr(content, 1, -1))
28 | f.Close()
29 | }
30 |
31 | static loadJSONFile(path) {
32 | json := FileRead(path)
33 | return Jxon_Load(&json)
34 | }
35 |
36 | static storeJSONFile(json, path) {
37 | f := FileOpen(path, "w")
38 | f.Write(Jxon_Dump(json, 2))
39 | f.Close()
40 | }
41 | }
--------------------------------------------------------------------------------
/src/Utils/Start.ah2:
--------------------------------------------------------------------------------
1 | class Start {
2 | /**
3 | * @description: 运行文件
4 | */
5 | static startFile(path, workingDir := "", options := "", beforeRun?) {
6 | if !(FileExist(path)) { ;文件不存在
7 | res := MsgBox("文件不存在:" path "`n是否尝试打开原文件夹?", "文件不存在", 0x40041)
8 | if (res = "OK") {
9 | SplitPath(path, , &outDir)
10 | try Run(outDir)
11 | }
12 | } else {
13 | if !(workingDir) ;默认使用文件所在文件夹作为工作目录
14 | SplitPath(path, , &workingDir)
15 |
16 | if (IsSet(beforeRun))
17 | beforeRun()
18 | try {
19 | Run(path, workingDir, options, &outPID)
20 | return outPID
21 | }
22 | }
23 | }
24 |
25 | /**
26 | * @description: 在文件夹中打开
27 | */
28 | static openFileInFolder(path) {
29 | if (FileExist(path)) {
30 | try Run('explorer.exe /select,"' path '"')
31 | } else {
32 | SplitPath(path, , &outDir)
33 | try Run(outDir)
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/.github/workflows/deploy-docs.yml:
--------------------------------------------------------------------------------
1 |
2 | name: 部署文档
3 |
4 | on:
5 | push:
6 | branches:
7 | # 确保这是你正在使用的分支名称
8 | - master
9 |
10 | jobs:
11 | deploy-gh-pages:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - name: Checkout
15 | uses: actions/checkout@v3
16 | with:
17 | fetch-depth: 0
18 | # 如果你文档需要 Git 子模块,取消注释下一行
19 | # submodules: true
20 |
21 | - name: 安装 pnpm
22 | uses: pnpm/action-setup@v2
23 | with:
24 | version: 8
25 | run_install: true
26 |
27 |
28 | - name: 设置 Node.js
29 | uses: actions/setup-node@v3
30 | with:
31 | node-version: 18
32 | cache: pnpm
33 |
34 |
35 | - name: 构建文档
36 | env:
37 | NODE_OPTIONS: --max_old_space_size=8192
38 | run: |-
39 | pnpm run docs:build
40 | > docs/.vuepress/dist/.nojekyll
41 |
42 | - name: 部署文档
43 | uses: JamesIves/github-pages-deploy-action@v4
44 | with:
45 | # 这是文档部署到的分支名称
46 | branch: gh-pages
47 | folder: docs/.vuepress/dist
48 |
--------------------------------------------------------------------------------
/src/Utils/GetSelectedText.ah2:
--------------------------------------------------------------------------------
1 | /**
2 | * @Name: GetSelectedText
3 | * @Version: 0.0.1
4 | * @Author: AkiChase
5 | * @LastEditors: AkiChase
6 | * @LastEditTime: 2023-04-07
7 | * @Description: 获取选中内容的文本和内容类型
8 | */
9 |
10 | /**
11 | * 获取选中内容的文本和内容类型
12 | * @param clipWaitSec 剪切板等待选中内容的时间
13 | * @param &outType 返回选中内容的类型, bitmap:位图, file:文件, text:文本, unknow:未知类型, timeout:剪切板等待超时
14 | */
15 | GetSelectedText(clipWaitSec := 0.5, &outType := unset) {
16 | seleted := ""
17 | ClipSaved := ClipboardAll()
18 |
19 | A_Clipboard := ""
20 | Send("^c")
21 | if (ClipWait(clipWaitSec)) {
22 | if (DllCall("IsClipboardFormatAvailable", "uint", 2)) { ; 位图
23 | outType := "bitmap"
24 | return ; 位图情况下不还原剪切板,直接返回
25 | }
26 | else if (DllCall("IsClipboardFormatAvailable", "uint", 15)) ; 文件
27 | outType := "file"
28 | else ; 文本或未知
29 | outType := DllCall("IsClipboardFormatAvailable", "uint", 1) ? "text" : "unknow"
30 | seleted := A_Clipboard
31 | } else
32 | outType := "timeout" ; 超时
33 |
34 | A_Clipboard := ClipSaved
35 | return seleted
36 | }
--------------------------------------------------------------------------------
/src/Utils/UrlEncode.ah2:
--------------------------------------------------------------------------------
1 | UrlEncode(str, sExcepts := "-_.", enc := "UTF-8")
2 | {
3 | hex := "00", func := "msvcrt\swprintf"
4 | buff := Buffer(StrPut(str, enc)), StrPut(str, buff, enc) ;转码
5 | encoded := ""
6 | Loop {
7 | if (!b := NumGet(buff, A_Index - 1, "UChar"))
8 | break
9 | ch := Chr(b)
10 | ; "is alnum" is not used because it is locale dependent.
11 | if (b >= 0x41 && b <= 0x5A ; A-Z
12 | || b >= 0x61 && b <= 0x7A ; a-z
13 | || b >= 0x30 && b <= 0x39 ; 0-9
14 | || InStr(sExcepts, Chr(b), true))
15 | encoded .= Chr(b)
16 | else {
17 | DllCall(func, "Str", hex, "Str", "%%%02X", "UChar", b, "Cdecl")
18 | encoded .= hex
19 | }
20 | }
21 | return encoded
22 | }
23 |
24 |
25 | ; Decode precent encoding
26 | UrlDecode(Url, Enc := "UTF-8")
27 | {
28 | Pos := 1
29 | Loop {
30 | Pos := RegExMatch(Url, "i)(?:%[\da-f]{2})+", &code, Pos++)
31 | If (Pos = 0)
32 | Break
33 | code := code[0]
34 | var := Buffer(StrLen(code) // 3, 0)
35 | code := SubStr(code, 2)
36 | loop Parse code, "`%"
37 | NumPut("UChar", Integer("0x" . A_LoopField), var, A_Index - 1)
38 | Url := StrReplace(Url, "`%" code, StrGet(var, Enc))
39 | }
40 | Return Url
41 | }
--------------------------------------------------------------------------------
/src/Utils/ChineseFirstChar.ah2:
--------------------------------------------------------------------------------
1 | ChineseFirstChar(str)
2 | {
3 | static bufferObj := Buffer(2)
4 | VarSetStrCapacity(&var, 2)
5 | static array := [[-20319, -20284, "A"], [-20283, -19776, "B"], [-19775, -19219, "C"], [-19218, -18711, "D"], [-18710, -18527, "E"], [-18526, -18240, "F"], [-18239, -17923, "G"], [-17922, -17418, "H"], [-17417, -16475, "J"], [-16474, -16213, "K"], [-16212, -15641, "L"], [-15640, -15166, "M"], [-15165, -14923, "N"], [-14922, -14915, "O"], [-14914, -14631, "P"], [-14630, -14150, "Q"], [-14149, -14091, "R"], [-14090, -13319, "S"], [-13318, -12839, "T"], [-12838, -12557, "W"], [-12556, -11848, "X"], [-11847, -11056, "Y"], [-11055, -10247, "Z"]]
6 |
7 | ; 如果不包含中文字符,则直接返回原字符
8 | if !RegExMatch(str, "[^\x{00}-\x{ff}]")
9 | return str
10 |
11 | loop parse, str
12 | {
13 | if (Ord(A_LoopField) >= 0x2E80 and Ord(A_LoopField) <= 0x9FFF)
14 | {
15 | StrPut(A_LoopField, bufferObj, "CP936")
16 | nGBKCode := (NumGet(bufferObj, 0, "UChar") << 8) + NumGet(bufferObj, 1, "UChar") - 65536
17 | for item in array {
18 | if (nGBKCode >= item[1] and nGBKCode <= item[2]) {
19 | out .= item[3]
20 | Break
21 | }
22 | }
23 | }
24 | else
25 | out .= A_LoopField
26 | }
27 |
28 | return out
29 | }
--------------------------------------------------------------------------------
/docs/dev/others/ahk-gui.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: AHK Gui编程范式
3 | icon: code
4 | date: 2023-04-11
5 | ---
6 |
7 | 介绍 **Starter** 中AHK Gui的编程范式,为使用Gui控件提供一个思路。
8 |
9 | ## 驱动方式
10 |
11 | ### 1. 事件驱动
12 |
13 | 传统的Gui编程是基于事件驱动
14 |
15 | 比如用户点击按钮、输入内容等事件触发回调,在回调中我们对需要改变的数据直接进行修改、对要需要改变的UI控件进行操作。
16 |
17 | 好处是简单粗暴,缺点也很明显,当某事件与很多控件、数据相关时,这个直接修改的代码写起来会非常痛苦,又臭又长。
18 |
19 | ### 2. 数据驱动
20 |
21 | 而数据驱动则是另一种思想:一切皆数据,我们的UI控件表现如此是因为我们的数据如此,当我们的数据修改后,UI界面就应该根据数据表现为新的状态。
22 |
23 | 缺点是代码写起来比较复杂,优点是对于复杂的事件回调,代码反而简洁许多。
24 |
25 | ahk v2版本的新语法中支持了比较现代的`class`、`getter`、`setter`,因此我们可以方便地使用数据驱动(相对v1版本)
26 |
27 | 数据驱动的关键是定义好数据(MVC中的`Model`)与视图(MVC中的`View`)的交互层(`MVC`中的`Controller`)
28 |
29 | ::: note
30 | 由于 **Starter** 一开始也是使用事件驱动,后来才尝试改用数据驱动,因此没有很好的使用MVC规范,仅供参考
31 | :::
32 |
33 | ## 实现思路
34 |
35 | - 数据 -> UI:
36 |
37 | 用抽象的数据(AHK中称为动态属性)来实现。对抽象的数据进行修改可以触发抽象数据的`setter`,在其`setter`中修改真实数据(若关联到其他数据,也可以修改其他数据的抽象数据,进一步套娃触发),并且对当前数据直接关联的UI控件进行修改。如此,实现了改变数据后UI也随之变动。
38 |
39 | - UI -> 数据:
40 |
41 | 为UI控件设置事件回调`OnEvent`。用户的交互信息,如点击、输入内容等可以触发相应的事件回调,事件回调中修改对应抽象数据的值为当前控件的值(或其他值)。
42 |
43 | - 注意事项
44 |
45 | 因为代码层面上对AHK控件修改不会触发其`OnEvent`,所以用户操作引起**UI -> 数据 -> UI**就终止,并不会造成死循环。其他语言环境则需要考虑在**数据->UI**环节中鉴别是否需要中断(比如判断对应值无变化则中断)。
46 |
47 | ::: tip
48 | 具体用法可以参考**Starter**源码
49 | :::
--------------------------------------------------------------------------------
/docs/api/addPluginToStartupMode.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: addPluginToStartupMode
3 | author: AkiChase
4 | order: 1
5 | date: 2023-04-15
6 | ---
7 |
8 | ## 定义
9 |
10 | ```ahk
11 | static addPluginToStartupMode(
12 | name,
13 | title,
14 | keywords,
15 | startHandler,
16 | doubleRightHandler?,
17 | contextHandler?,
18 | hIcon?
19 | )
20 | ```
21 |
22 | ## 类型
23 |
24 | 静态方法
25 |
26 | ## 说明
27 |
28 | 添加**插件启动项**,应用方式见[插件启动项](../dev/startup/)
29 |
30 | ## 参数
31 |
32 | - ### name \{String\}
33 |
34 | 插件id,即插件文件名
35 |
36 | - ### title \{String\}
37 |
38 | 插件启动项显示标题
39 |
40 | - ### keywords \{Array\}
41 |
42 | 插件启动项其他关键字,比如 `["其他","QTGJZ"]`
43 |
44 | - ### startHandler \{[Closure](https://orz707.gitee.io/v2/docs/Functions.htm#closures)\}
45 |
46 | ```ahk
47 | (obj, searchText) => Any
48 | ```
49 |
50 | - 接收参数
51 | - `obj`:指向添加的插件启动项对象。
52 | - `searchText`:当前搜索内容。
53 |
54 | 运行(鼠标双击或回车)该插件启动项时执行的函数。
55 |
56 | - ### doubleRightHandler \{[Closure](https://orz707.gitee.io/v2/docs/Functions.htm#closures)\} (可选)
57 |
58 | ```ahk
59 | (obj, searchText) => Any
60 | ```
61 |
62 | - 接收参数
63 | - `obj`:指向添加的插件启动项对象。
64 | - `searchText`:当前搜索内容。
65 |
66 | 选填,选中该插件启动项后,双击 `Right` 按键时执行的函数。
67 |
68 | - ### contextHandler \{[Closure](https://orz707.gitee.io/v2/docs/Functions.htm#closures)\} (可选)
69 |
70 | ```ahk
71 | (obj) => Any
72 | ```
73 |
74 | - 接收参数
75 | - `obj`:指向添加的插件启动项对象。
76 |
77 | 选填,右键该插件启动项时的处理函数。
78 |
79 | - ### hIcon \{Int\} (可选)
80 |
81 | 插件启动项显示的图标hIcon,忽略则使用插件的图标。
--------------------------------------------------------------------------------
/docs/guide/get-started/intro.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 项目介绍
3 | icon: circle-info
4 | order: 1
5 | author: AkiChase
6 | date: 2023-04-09
7 | ---
8 |
9 | ## 项目初衷
10 |
11 | **Starter** 的初衷源于我没有找到一个**真正让自己满意的**启动工具或效率工具。
12 |
13 | 我只是想要一个搜索框,输入内容,就能启动我想要的东西,最好还能有一些支持扩展的功能。
14 |
15 | 在启动软件的设计上,我比较喜欢 [uTools](https://u.tools/) 或者其开源替代品 [rubick](https://github.com/rubickCenter/rubick)。
16 |
17 | 然而,它们都存在一些问题:
18 |
19 | - 基于 Electron(相当于一个浏览器),对于启动工具来说过于臃肿了。
20 | - 不能自由设置**双击、长按、任意**快捷键呼出搜索框,而其他快捷键或是不方便或是易误触。
21 | - 搜索结果不能完全自定义。虽然能通过插件曲线救国,但是终究不太方便。
22 |
23 | 总之,虽然各种快速启动工具很多,但它们总会有不符合我个人习惯的地方,
24 | 或是 UI 太丑,或是操作逻辑不适应,或是匹配方式无法完全自定义,或是捆绑太多内容,或是体积庞大、性能有限...
25 |
26 | 因此,我决定自己开发一个启动工具,以满足自己的需求,并分享给其他需要的人使用。
27 |
28 | 这就是 **Starter** 的初衷。
29 |
30 | ## 项目特点
31 |
32 | - ### 编程语言
33 |
34 | [Autohotkey](https://www.autohotkey.com/)是一门小众而冷门的脚本语言,但它确实是我的编程启蒙语言。
35 | 尽管我曾一度嫌弃 `AHK` 那些不规范的语法,但 `AHK` 的 **V2** 版本已经规范了代码格式,并且支持了更多现代化语法。
36 |
37 | 这门语言语法简单、开发快速、无需安装运行环境,因此,完全可以作为 **Starter** 的开发语言。
38 |
39 | 作为我掌握时间最久,却没有产出任何开源作品的编程语言,我决定用它来开发 **Starter**。
40 |
41 | 虽然 `AHK` 可以使用基于 `WebView` 的 UI界面,而且使用 **Web 开发** 的方式可以获得更加精美的界面,
42 | 但为了确保开源项目能被更多 **AHKer** 接受,我决定采用 `AHK` 自带的 `Gui` 控件,即 **Win32 Gui** 控件。
43 |
44 | 这样也能为 **AHKer** 提供一个使用 `AHK` 开发的实例。
45 |
46 | - ### 小巧精美
47 |
48 | **Starter** 将贯彻**轻量**、**绿色**、**简洁**和**美观**的理念,为用户提供更好的使用体验。
49 |
50 | - ### 可扩展
51 |
52 | 每个 **AHKer** 都能够使用 **Starter** 提供的 `API` 接口来[开发](../../dev/)和加载自己的插件扩展,从而打造专属于自己的工具。
53 |
54 | 非开发者也可以在 **Starter** 日渐丰富的[插件库](../../plugin/)中挑选自己心仪的插件进行装载,扩展 **Starter** 的能力
55 |
56 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Starter
2 |
3 |

4 |
5 | Starter
6 | 智能、快捷地启动文件和插件应用,提供便利和高效的使用体验。
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | ## 特性
17 |
18 | - 万能搜索框 —— 通过搜索和情景匹配,回应符合要求的多种内容。
19 | - 轻量 & 绿色 —— 使用AHK编写,绿色免安装,体积 < 2M 。
20 | - 简洁 & 颜值在线 —— 设计简洁美观,UI的「颜值即正义」。
21 | - 插件化 —— 自由装载插件,打造个人专属效率工具。
22 |
23 | ## 文档
24 |
25 | [Starter文档 - GitHub Pages](https://AkiChase.github.io/Starter/)
26 |
27 | [Starter文档 - Gitee Pages](https://AkiChase.gitee.io/Starter/)
28 |
29 | ## 下载
30 |
31 | - Github下载:[Github Releases](https://github.com/AkiChase/Starter/releases)
32 |
33 | - 蓝奏云下载:[蓝奏云](https://wwi.lanzoup.com/b01kb1g4j) 密码: 9vge
34 |
35 | **Starter 优先使用** `雅痞-简` 字体,可在上方蓝奏云链接内下载安装。
36 |
37 | ## 运行
38 |
39 | 将下载的压缩包**解压**,运行文件夹中的 `创建快捷方式.bat` ,将在文件夹内创建 `Starter.lnk` 快捷方式,双击即可运行软件。
40 |
41 | 刚刚安装好的 **Starter** 就像一张白纸,但在添加各种配置之后,它将成为你最得心应手的启动工具。
42 |
--------------------------------------------------------------------------------
/docs/dev/image-put.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: ImagePut
3 | icon: image
4 | author: AkiChase
5 | date: 2023-04-14
6 | ---
7 |
8 | > ImagePut 是 iseahound 写的一个图片操作库,大部分常见图片操作都可以用极为简单的方式实现。
9 |
10 | - [简单、高效、实用的图片操作库 —— ImagePut 轻松实现截图、转换、缩放、裁剪等各种功能 - AutoAHK](https://www.autoahk.com/archives/37246)
11 | - [ImagePut —— 裁剪、缩放 & 其他选项](./others/image-put-doc-1.md)
12 | - [ImagePut —— 输入类型 & 输出函数](./others/image-put-doc-2.md)
13 |
14 | **Starter** 也引入了这个强大的图片操作库,并将其主要API访问方式添加到了 `PluginHelper.Utils.ImagePutHelper` 工具类中,参考[ImagePutHelper](../api/utils/ImagePutHelper.md)
15 |
16 | 可以通过这个工具类调用 `ImagePut`,完成你需要的图片相关操作。
17 |
18 | 在此给出[OCR识别文字](../plugin/ocr.md)插件中的部分代码作为示例:
19 |
20 | ```ahk {14,15}
21 | ; ocr识别 image为ImagePut类型
22 | static ocr(image) {
23 | oldTitle := this.gui.Title
24 | this.gui.Title := "正在进行文字识别..."
25 | ; accessToken是否过期判断
26 | if (!this.accessToken)
27 | if (this.accessToken := this.genAccessToken()) {
28 | this.storeData()
29 | } else {
30 | this.gui.Title := oldTitle
31 | return
32 | }
33 |
34 | ; 使用 ImagePutURI 将图片直接转化为 base64 用于上传图片
35 | base64 := PluginHelper.Utils.ImagePutHelper.ImagePutURI(image, "jpg", 100)
36 |
37 | if (res := this.baiduOcr(base64)) {
38 | out := []
39 | ; 根据模式选择拼接方式 目前使用换行符拼接
40 | for words in res["words_result"]
41 | out.Push(words["words"])
42 | this.ocrRes := out
43 | this.gui.Title := oldTitle
44 | return true
45 | }
46 | this.gui.Title := oldTitle
47 | return false
48 | }
49 | ```
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/docs/guide/intelligent/edit.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 配置
3 | icon: gear
4 | order: 2
5 | author: AkiChase
6 | date: 2023-04-11
7 | ---
8 |
9 | 在理解了智能模式的相关概念之后,你就可以正确地配置**原生智能项**了
10 |
11 | ## 智能项示例
12 |
13 | 右键右下角托盘图标打开菜单,点击**编辑智能模式**,进入**智能模式编辑界面**
14 |
15 | 
16 |
17 | 默认情况下,**Starter** 带有三个**原生智能项**作为你配置智能项的参考。你可以根据需要添加、编辑或删除智能项,以便根据个人习惯打开应用程序、网站等。
18 |
19 | 打开网址位于**启动分组**,百度搜索和谷歌搜索位于**搜索分组**。匹配模式都是 `reg`,即使用正则表达式进行匹配和替换。
20 |
21 | 接下来依次解释这三个实例的具体功能与含义,可以与[基本概念](./concept.md)相互对照。
22 |
23 | ### 1. 打开网址
24 |
25 | 该智能项带有两对正则表达式
26 |
27 | 1. `[^\s]*(\.[a-zA-z]{2}[^\s]*){2}`,`$0`
28 |
29 | 匹配带有两个以上"."的文本,不替换任何内容(实际上是将原始文本替换成原始文本)
30 |
31 | 2. `https?:/{2}(.+)`,`$0`
32 |
33 | 匹配以 `http://` 或者 `https://` 开头的文本,不替换任何内容(同上)
34 |
35 | 脚本模式为 `none`,启动处理程序直接执行输入的内容
36 |
37 | **实现的效果就是如果输入文本是网址链接,那么将使用默认浏览器打开这个链接**
38 |
39 | ### 2. 百度搜索 {#baidu-search-example}
40 |
41 | 该智能项带有一对正则表达式
42 |
43 | `(bd|baidu|百度)\s+(?.*)`, `${query}`
44 |
45 | 匹配以 `bd`、`baidu`、`百度` 开头 + `空格` + `搜索词` 的文本,将原始文本替换为`搜索词`
46 |
47 | 示例:`bd xxx` 将被替换为 `xxx`,作为**传递的内容**。
48 |
49 | **实现的效果就是如果输入文本是 `bd xxx`,那么将使用默认浏览器进行百度搜索 `xxx`**
50 |
51 | ### 3. 谷歌搜索
52 |
53 | 该智能项带有一对正则表达式
54 |
55 | `(gg|谷歌)\s+(?.*)`, `${query}`
56 |
57 | 与 [2. 百度搜索](#baidu-search-example) 一样,除了开头是 `gg` 或 `谷歌`
58 |
59 | **实现的效果就是如果输入文本是 `gg xxx`,那么将使用默认浏览器进行百度搜索 `xxx`**
60 |
61 | ## 更多配置
62 |
63 | 1. 在 `reg` 匹配模式时,右键**正则匹配替换模式列表**可以打开菜单,进行添加、修改、删除等操作。
64 | 2. 在**图标文件**一栏中,点击**选择**按钮,可以选择带有图片资源的文件作为智能项的图标,储存至用户数据。
65 | 3. 在**搜索分组**时,点击**获取**按钮,可以尝试获取**搜索URL**对应的网站图标,下载至用户数据。
66 |
--------------------------------------------------------------------------------
/docs/guide/startup/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 启动模式
3 | icon: bolt
4 | author: AkiChase
5 | date: 2023-04-11
6 | ---
7 |
8 | 
9 |
10 | 启动模式的使用,在 [快速上手 - 下载与使用](../get-started/install-usage.md) 已经描述了一遍,在此作为一个补充。
11 |
12 | ::: warning
13 | 此处的启动项指的是**非插件添加的**启动项,也就是**原生启动项**,可以在启动模式编辑界面中添加、修改等。
14 | :::
15 |
16 | ## 匹配
17 |
18 | **Starter** 根据**显示名称**和**其他关键字**来识别原生启动项。
19 |
20 | 在**启动模式搜索框**中搜索时,只要搜索内容是 **显示名称的一部分** 或 **某关键字的一部分**,该启动项就会出现在搜索结果中。
21 |
22 | ## 配置
23 |
24 | 
25 |
26 | ### 1. 编辑界面
27 |
28 | 运行 **Starter** 后,右键右下角托盘图标打开菜单,点击**编辑启动模式**。
29 |
30 | 没有配置任何启动项,会弹窗提示“启动列表内无可编辑项,请添加文件”,在弹窗后出现的文件选择框中选择任意文件添加为启动项即可。
31 |
32 | ### 2. 添加启动项
33 |
34 | 你可以通过3种方式来添加启动项:
35 |
36 | 1. 点击**启动模式编辑界面**上的**添加**按钮,在文件选择框中选择要添加的文件
37 | 2. 将所需添加的文件拖拽到**启动模式编辑界面**窗口中,这种方式既快速又方便,可以一次性添加多个启动项。
38 | 3. 将所需添加的文件拖拽到**启动模式搜索框**中,这种方式类似于第二种,但由于**搜索框会自动隐藏**,需要一定的手速。
39 |
40 | ### 3. 编辑启动项
41 |
42 | 在启动项编辑界面,你可以直接在编辑框中输入和修改启动项的内容。
43 |
44 | - **图标路径**可以指向任意含有图像资源的文件,若图标加载失败,**Starter**会使用默认图标代替。
45 | - **文件路径**指向的文件不存在时,该启动项在搜索结果的图标将变成警告图标。
46 | - **优先级**指的是启动项在启动模式搜索结果中排序的优先级,数字越大排序越靠前。
47 |
48 | ::: tip
49 | 启动项带有**动态优先级**,**每次**启动、在文件夹中打开,都会**增加**启动项的优先级,范围 0-999。
50 |
51 | **原生启动项**的优先级 < **插件启动项**的优先级
52 | :::
53 |
54 | - 右键点击**其他关键字列表**,可以打开菜单进行增加、删除或修改操作。
55 |
56 | ## 使用
57 |
58 | - 呼出搜索框
59 |
60 | 按下 `呼出搜索框` 快捷键,呼出**启动模式搜索框**,输入任意内容,可以看到搜索结果列表。
61 |
62 | - 切换选中项
63 |
64 | `Up`、`Down` 按键可在列表中**上下切换**选中的条目。
65 |
66 | `Alt` + `数字` 按键可以快速选中**当前视图**中的第n个条目 (`Alt` + `0` 代表选中第10个)。
67 |
68 | - 启动选中项
69 |
70 | `回车` 可以启动当前选中项。
71 |
72 | - 文件夹中显示
73 |
74 | 双击 `Right`按键可以在文件夹中显示当前选中的**原生启动项**的文件路径。
75 |
76 | - 清空与关闭
77 |
78 | `Esc`按键将**清空** 输入内容,或者**隐藏**搜索界面。
79 |
80 | 搜索界面失去焦点一段时间后**自动隐藏**,自动隐藏后15s内**保留搜索结果**。
81 |
82 | - 右键菜单
83 |
84 | 右键点击任意结果条目,将会打开菜单以进行更多操作。
85 |
86 |
--------------------------------------------------------------------------------
/docs/api/addPluginToIntelligentMode.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: addPluginToIntelligentMode
3 | author: AkiChase
4 | order: 1
5 | date: 2023-04-15
6 | ---
7 |
8 | ## 定义
9 |
10 | ```ahk
11 | static addPluginToIntelligentMode(
12 | name, title, matchHandler, runHandler, contextHandler?, hIcon?
13 | )
14 | ```
15 |
16 | ## 类型
17 |
18 | 静态方法
19 |
20 | ## 说明
21 |
22 | 添加**插件智能项**,应用方式见[插件智能项](../dev/intelligent/)
23 |
24 | ## 参数
25 |
26 | - ### name \{String\}
27 |
28 | 插件id,即插件文件名
29 |
30 | - ### title \{String\}
31 |
32 | 插件智能项显示标题
33 |
34 | - ### matchHandler \{[Closure](https://orz707.gitee.io/v2/docs/Functions.htm#closures)\}
35 |
36 | ```ahk
37 | (
38 | obj,
39 | searchText,
40 | pastedContentType,
41 | pastedContent,
42 | workWinInfo,
43 | winInfoMatchFlag
44 | ) => Number
45 | ```
46 | - 接收参数
47 | - `obj`:指向添加的插件智能项对象。
48 | - `searchText`:当前搜索内容。
49 | - `pastedContentType`:粘贴内容类型。
50 | - `pastedContent`:粘贴内容。
51 | - `workWinInfo`:工作窗口信息对象
52 | - `winInfoMatchFlag`:是否开启工作窗口模式
53 | - 返回值
54 | - 1:显示该插件智能项
55 | - 0:不显示该插件智能项
56 |
57 | 智能插件项的自定义匹配函数,返回值决定当前插件项是否显示
58 |
59 | :::tip
60 | 工作窗口模式是按下**智能搜索**快捷键时,若当前**没有选中任何内容**,则**Starter**将获取工作窗口信息,进入工作窗口模式下的智能模式搜索框。
61 |
62 | 搜索框会短暂显示工作窗口的信息,插件可以根据此时的工作窗口信息进行匹配
63 | :::
64 |
65 | - ### runHandler \{[Closure](https://orz707.gitee.io/v2/docs/Functions.htm#closures)\}
66 |
67 | ```ahk
68 | (obj, searchText) => Any
69 | ```
70 |
71 | - 接收参数
72 | - `obj`:指向添加的插件智能项对象。
73 | - `searchText`:当前搜索内容。
74 |
75 | 运行(鼠标双击或回车)该插件智能项时执行的函数。
76 |
77 | - ### contextHandler \{[Closure](https://orz707.gitee.io/v2/docs/Functions.htm#closures)\} (可选)
78 |
79 | ```ahk
80 | (obj) => Any
81 | ```
82 | - 接收参数
83 | - `obj`:指向添加的插件智能项对象。
84 |
85 | 选填,右键该插件智能项时执行的函数。
86 |
87 | - ### hIcon \{Int\} (可选)
88 |
89 | 选填,插件智能项显示的图标hIcon,忽略则使用插件的图标。
--------------------------------------------------------------------------------
/docs/guide/setting/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 设置界面
3 | icon: gear
4 | author: AkiChase
5 | date: 2023-04-13
6 | ---
7 |
8 | 运行 **Starter** 后,右键右下角托盘图标打开菜单,点击**设置界面**。
9 |
10 | ## 常规
11 |
12 | 
13 |
14 | 可通过勾选**开机自启**,修改软件是否开启自启动。
15 |
16 | 对于其他快捷键类型的设置项目,点击**修改**按钮可以修改对应的功能快捷键。
17 |
18 | 显示了每个快捷键的**具体内容**,若按键**无效**也会有对应显示。
19 |
20 | 快捷键设置,点击**修改**按钮可以修改对应的功能快捷键。
21 |
22 | 显示每个快捷键的**具体内容**,若按键**无效**也会有对应显示。
23 |
24 | ### 1. 按键类型 - 普通
25 |
26 | 普通按键类型仅仅支持 `Ctrl`, `Alt`, `Shift` 作为修饰的组合按键,或者单独按键。
27 |
28 | 可勾选**是否屏蔽原按键功能**,勾选后快捷键原功能将被屏蔽。
29 |
30 | 点击按键内容**热键输入框**,按下指定按键即可显示输入的按键内容,点击**确定**进行保存。
31 |
32 | ### 2. 按键类型 - 自定义
33 |
34 | **自定义**按键类型可以**自由填写**热键内容,包括鼠标按键等,
35 |
36 | 参考[热键 - 定义 & 使用 | AutoHotkey v2](https://orz707.gitee.io/v2/docs/Hotkeys.htm#toc)
37 |
38 | :::warning
39 | 热键内容的填写需要有一定AHK经验,否则建议使用其他类型
40 | :::
41 |
42 | ### 3. 按键类型 - 双击
43 |
44 | **双击**按键类型必须填写**单个**按键名,
45 |
46 | 参考[按键列表(键盘, 鼠标和操纵杆) | AutoHotkey v2](https://orz707.gitee.io/v2/docs/KeyList.htm)
47 |
48 | 可勾选**是否屏蔽原按键功能**,勾选后快捷键原功能将被屏蔽。
49 |
50 | :::tip
51 | 双击要求第一次键击**按住**时间小于500ms,且第一次键击**松开**到第二次键击**按下**的时间间隔小于500ms
52 | :::
53 |
54 | ### 4. 按键类型 - 长按
55 |
56 | **双击**按键类型必须填写**单个**按键名,
57 |
58 | 参考[按键列表(键盘, 鼠标和操纵杆) | AutoHotkey v2](https://orz707.gitee.io/v2/docs/KeyList.htm)
59 |
60 | 可勾选**是否屏蔽原按键功能**,勾选后快捷键原功能将被屏蔽。
61 |
62 | :::tip
63 | 长按要求第一次键击**按住**时间超过500ms
64 | :::
65 |
66 |
67 | ## 控制
68 |
69 | 
70 |
71 | - 可以在此处点击按钮来添加、删除**关键词快捷键**
72 | - 双击列表中任意项可以修改对应**关键词快捷键**
73 |
74 | 按下关键词快捷键可以快速*以指定模式*搜索*既定的关键词*,并可选**是否启动搜索结果的第一项**。
75 |
76 | :::tip
77 | 以截图中的关键词快捷键内容为例:
78 |
79 | 1. 快捷键为 `CapsLock & O`,即按下`CapsLock` + `O` 快捷键触发
80 | 2. 搜索模式为启动模式
81 | 3. 关键词为“OCR识别文字”
82 | 4. 勾选了启动搜索结果
83 |
84 | 添加上述关键词快捷键后,就可以通过按下`CapsLock` + `O`快速启动搜索“OCR识别文字”,并启动搜索结果。
85 |
86 | 由于搜索到的首个结果是**插件启动项**`OCR识别文字`,因此可以实现快捷键启动该插件。
87 | :::
88 |
--------------------------------------------------------------------------------
/src/Utils/CopyToClipboard.ah2:
--------------------------------------------------------------------------------
1 | ; CopyToClipboard(".\test.png", 1)
2 |
3 | CopyToClipboard(filePath, cut := false) {
4 | FileCount := 0
5 | PathLength := 0
6 | ;Count files and total string length
7 |
8 | pid := DllCall("GetCurrentProcessId", "Uint")
9 | hwnd := WinExist("ahk_pid " . pid)
10 | DllCall("OpenClipboard", "Ptr", hwnd)
11 | hPath := DllCall("GlobalAlloc", "uint", 0x42, "uint", 20 + (StrLen(filePath) + 2) * 2, "Ptr") ; 0x42 = GMEM_MOVEABLE(0x2) | GMEM_ZEROINIT(0x40)
12 | pPath := DllCall("GlobalLock", "Ptr", hPath) ; Lock the moveable memory, retrieving a pointer to it.
13 | NumPut("uint", 20, pPath + 0), pPath += 16 ; DROPFILES.pFiles = offset of file list
14 | NumPut("uint", 1, pPath + 0), pPath += 4 ;fWide = 0 -->ANSI, fWide = 1 -->Unicode
15 | StrPut(filePath, pPath, StrLen(filePath) + 1, "UTF-16")
16 |
17 | DllCall("GlobalUnlock", "Ptr", hPath)
18 | ;hPath must not be freed! ->http://msdn.microsoft.com/en-us/library/ms649051(VS.85).aspx
19 |
20 | DllCall("EmptyClipboard") ; Empty the clipboard, otherwise SetClipboardData may fail.
21 | result := DllCall("SetClipboardData", "uint", 0xF, "Ptr", hPath) ; Place the data on the clipboard. CF_HDROP=0xF
22 |
23 | ;Write Preferred DropEffect structure to clipboard to switch between copy/cut operations
24 | mem := DllCall("GlobalAlloc", "UInt", 0x42, "UInt", 4, "Ptr") ; 0x42 = GMEM_MOVEABLE(0x2) | GMEM_ZEROINIT(0x40)
25 | str := DllCall("GlobalLock", "Ptr", mem)
26 | if (!cut)
27 | DllCall("RtlFillMemory", "UInt", str, "UInt", 1, "UChar", 0x05)
28 | else
29 | DllCall("RtlFillMemory", "UInt", str, "UInt", 1, "UChar", 0x02)
30 | DllCall("GlobalUnlock", "Ptr", mem)
31 | cfFormat := DllCall("RegisterClipboardFormat", "Str", "Preferred DropEffect")
32 | result := DllCall("SetClipboardData", "UInt", cfFormat, "Ptr", mem)
33 | DllCall("CloseClipboard")
34 | ;mem must not be freed! ->http://msdn.microsoft.com/en-us/library/ms649051(VS.85).aspx
35 | }
--------------------------------------------------------------------------------
/src/Utils/EditCtrlFunc.ah2:
--------------------------------------------------------------------------------
1 | /**
2 | * @Name: 名称
3 | * @Version: 0.0.1
4 | * @Author: AkiChase
5 | * @LastEditors: AkiChase
6 | * @LastEditTime: 2023-04-07
7 | * @Description: 介绍
8 | */
9 | class EditCtrlFunc {
10 | ; Set placeholder
11 | static setPlaceholder(ctrl, placeholder) {
12 | DllCall("User32.dll\SendMessageW", "Ptr", ctrl.Hwnd, "Uint", (0x1500 + 1), "Ptr", True, "WStr", placeholder)
13 | }
14 |
15 | ; Gets the start and end offset of the current selection.
16 | static getSelection(&start, &end, ctrl) {
17 | s := Buffer(4, 0), e := Buffer(4, 0)
18 | SendMessage(0xB0, s.Ptr, e.Ptr, ctrl) ;EM_GETSEL
19 | start := NumGet(s, 0, "UInt"), end := NumGet(e, 0, "UInt")
20 | }
21 |
22 | ; Selects text in a edit box, given absolute character positions (starting at 0.)
23 | ;
24 | ; start: Starting character offset, or -1 to deselect.
25 | ; end: Ending character offset, or -1 for "end of text."
26 | static editSelect(ctrl, start := 0, end := -1) {
27 | SendMessage(0xB1, start, end, ctrl) ;EM_SETSEL
28 | }
29 |
30 | ; Selects a line of text.
31 | ;
32 | ; line: One-based line number, or 0 to select the current line.
33 | ; include_newline: Whether to also select the line terminator (`r`n).
34 | ;
35 | static editSelectline(ctrl, line := 0, include_newline := false)
36 | {
37 | if (line < 1)
38 | line := EditGetCurrentLine(ctrl)
39 |
40 | offset := SendMessage(0xBB, line - 1, 0, ctrl) ; EM_LINEINDEX
41 | lineLen := SendMessage(0xC1, offset, 0, ctrl) ; EM_LINELENGTH
42 |
43 | if (include_newline) {
44 | lineLen += (ctrl.ClassNN = "Edit" || ctrl.ClassNN = "Edit1") ? 2 : 1 ; `r`n : `n
45 | }
46 |
47 | ; Select the line.
48 | SendMessage(0xB1, offset, offset + lineLen, ctrl) ; EM_SETSEL
49 | }
50 |
51 | ; Deletes a line of text.
52 | ;
53 | ; line: One-based line number, or 0 to delete current line.
54 | ;
55 | static editDeleteline(ctrl, line := 0) {
56 | ; Select the line.
57 | this.editSelectline(ctrl, line, true)
58 | ControlSend("{Delete}", ctrl)
59 | }
60 | }
--------------------------------------------------------------------------------
/docs/.vuepress/sidebar.ts:
--------------------------------------------------------------------------------
1 | import { sidebar } from "vuepress-theme-hope";
2 |
3 | export const zhSidebar = sidebar({
4 | "/guide/": [
5 | {
6 | text: "快速上手",
7 | icon: "lightbulb",
8 | link: "/guide/get-started/intro",
9 | prefix: "get-started/",
10 | children: "structure" // structure生成会包括README, README定义index:false将其隐藏
11 | },
12 | {
13 | text: "启动模式",
14 | icon: "bolt",
15 | link: "/guide/startup/",
16 | },
17 | {
18 | text: "智能模式",
19 | icon: "face-laugh",
20 | collapsible: true,
21 | link: "/guide/intelligent/",
22 | prefix: "intelligent/",
23 | children: "structure"
24 | },
25 | {
26 | text: "插件界面",
27 | icon: "list-ul",
28 | link: "/guide/plugin/",
29 | },
30 | {
31 | text: "设置界面",
32 | icon: "gear",
33 | link: "/guide/setting/",
34 | },
35 | {
36 | text: "自启界面",
37 | icon: "desktop",
38 | link: "/guide/boot/",
39 | },
40 | {
41 | text: "关于界面",
42 | icon: "circle-info",
43 | link: "/guide/about/",
44 | },
45 | {
46 | text: "用户数据",
47 | icon: "user",
48 | link: "/guide/user-data/",
49 | }
50 | ],
51 | "/plugin/": "structure",
52 | "/api/": "structure",
53 | "/dev/": [
54 | {
55 | text: "快速上手",
56 | icon: "lightbulb",
57 | link: "/dev/get-started",
58 | },
59 | {
60 | text: "插件启动项",
61 | icon: "bolt",
62 | link: "/dev/startup",
63 | },
64 | {
65 | text: "插件智能项",
66 | icon: "face-laugh",
67 | link: "/dev/intelligent/",
68 | prefix: "intelligent/",
69 | children: "structure"
70 | },
71 | {
72 | text: "插件模式",
73 | icon: "list-ul",
74 | link: "/dev/plugin-mode/",
75 | prefix: "plugin-mode/",
76 | children: "structure"
77 | },
78 | {
79 | text: "ImagePut",
80 | icon: "image",
81 | link: "/dev/image-put",
82 | },
83 | {
84 | text: "其他内容",
85 | icon: "ellipsis",
86 | link: "/dev/others/",
87 | collapsible: true,
88 | prefix: "others/",
89 | children: "structure"
90 | },
91 | ],
92 | "/history": []
93 | });
94 |
--------------------------------------------------------------------------------
/docs/api/showPluginMode.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: showPluginMode
3 | author: AkiChase
4 | order: 1
5 | date: 2023-04-15
6 | ---
7 |
8 | ## 定义
9 |
10 | ```ahk
11 | static showPluginMode(pluginSearchData, searchHandler, runHandler, options := {})
12 | ```
13 |
14 | ## 类型
15 |
16 | 静态方法
17 |
18 | ## 说明
19 |
20 | 启动插件模式。参考[插件模式](../dev/plugin-mode/)。
21 |
22 | ## 参数
23 |
24 | - \{Array\} `pluginSearchData`: **必填参数**,用于插件模式搜索的数据。
25 | - \{(that, searchText) => any\} `searchHandler`: **必填参数**,插件模式搜索处理函数,**额外说明见下方**。
26 | - \{(that, searchText) => any\} `runHandler`: **必填参数**,插件模式回车、双击任意项时的处理函数。
27 | - \{Object\} `options`: 可选参数,**具体使用见下方说明**。
28 |
29 | ### options 中可选参数的说明
30 |
31 | - `doubleRightHandler`(可选)\{(that, rowNum) => void\}
32 | - 插件模式双击 Right 键时的处理函数,`rowNum` 为当前选中项的行号。
33 |
34 | - `loadImgsHandler`(可选)\{(that) => void\}
35 | - 加载插件模式图片的处理函数,若需要显示图标一定要带有此参数。
36 |
37 | - `toBottomHandler`(可选)\{(that) => void\}
38 | - 列表最后一行可见(触底)处理函数。
39 |
40 | - `pasteContentHandler`(可选)\{(that, typeName, content?) => bool\}
41 | - `Ctrl + V` 粘贴内容时的处理函数,如果粘贴的是 bitmap 或者 file 类型,需要额外特殊处理,**具体使用见下方说明**。
42 |
43 | - `dropFilesHandler`(可选)\{(that, fileList, pre) => bool\}
44 | - 拖入文件到搜索框的处理函数,**具体使用见下方说明**。
45 |
46 | - `initHandler`(可选)\{(that) => void\}
47 | - 初始化处理函数,在进入插件模式后被调用。
48 |
49 | - `searchText`(可选): 启动时设置搜索框文本。
50 | - `placeholder`(可选): 设置搜索框占位符。
51 | - `thumb`(可选): hICON,设置插件模式搜索框图标。
52 |
53 | ### searchHandler 处理函数说明{#searchHandler}
54 |
55 | ```ahk
56 | (that, searchText) => any
57 | ```
58 |
59 | 为规范使用,请将搜索结果存放至 that.pluginSearchResult 然后对其进行渲染(添加到 listview)。
60 |
61 | ### pasteContentHandler 处理函数说明{#pastecontenthandler}
62 |
63 | - 函数形式:
64 | 1. `(that, typeName) => bool`
65 | 2. `(that, typeName, content) => any`
66 |
67 | - 函数返回值:
68 | 1. 在粘贴**bitmap/file**内容前会以形式一调用,则需要返回一个布尔值,表示是否允许进行粘贴操作(一般可以通过 typeName 判断是否是需要支持的粘贴内容)。
69 | 2. 在粘贴**bitmap/file**内容后还会以形式二调用,作为粘贴完成的通知
70 |
71 | :::tip
72 | typeName: file 则 content为文件路径数组 \{Array\}
73 |
74 | typeName: bitmap 则 content为位图句柄 hBitmap \{Int\}
75 | :::
76 |
77 | ### dropFilesHandler 处理函数说明{#dropFilesHandler}
78 |
79 | - 函数形式:
80 | 1. `(that, fileList, true) => bool`
81 | 2. `(that, fileList, false) => any`
82 |
83 | - 函数返回值:
84 | 1. 在拖入文件后会以形式一触发,则需要返回一个布尔值,表示是否允许拖入操作生效。
85 | 2. 拖入生效后还会以形式二触发,作为拖入生效的通知。
--------------------------------------------------------------------------------
/docs/.vuepress/theme.ts:
--------------------------------------------------------------------------------
1 | import { hopeTheme } from "vuepress-theme-hope";
2 | import { zhNavbar } from "./navbar.js";
3 | import { zhSidebar } from "./sidebar.js";
4 |
5 |
6 |
7 | export default hopeTheme({
8 | hostname: "https://AkiChase.github.io/Starter/",
9 |
10 | author: {
11 | name: "AkiChase",
12 | url: "https://github.com/AkiChase",
13 | email: "xiangyangxiao@outlook.com"
14 | },
15 |
16 |
17 | iconAssets: [
18 | "https://cdn.bootcdn.net/ajax/libs/font-awesome/6.4.0/css/solid.min.css",
19 | "https://cdn.bootcdn.net/ajax/libs/font-awesome/6.4.0/css/fontawesome.min.css"
20 | ],
21 | iconPrefix: "fas fa-",
22 |
23 | favicon: "/favicon.ico",
24 | logo: "/logo.svg",
25 | logoDark: "/logo-tp.svg",
26 |
27 |
28 | repo: "AkiChase/Starter",
29 | docsDir: "/docs",
30 | docsBranch: "master",
31 |
32 | navbarLayout: {
33 | start: ["Brand"],
34 | center: [],
35 | end: ["Links", "Language", "Repo", "Outlook", "Search"]
36 | },
37 |
38 | // 禁用打印
39 | print: false,
40 |
41 | locales: {
42 | // Chinese locale config
43 | "/": {
44 | // navbar
45 | navbar: zhNavbar,
46 | // sidebar
47 | sidebar: zhSidebar,
48 | footer: 'This site is served by GitHub Pages',
49 | displayFooter: true,
50 | // 页面元数据
51 | metaLocales: {
52 | editLink: "在 GitHub 上编辑此页",
53 | },
54 | },
55 | },
56 |
57 | plugins: {
58 | prismjs: false,
59 | comment: {
60 | provider: "Giscus",
61 | repo: "AkiChase/giscusRepo",
62 | repoId: "R_kgDOJUjnlw",
63 | category: "Announcements",
64 | categoryId: "DIC_kwDOJUjnl84CVpfq",
65 | },
66 |
67 | mdEnhance: {
68 | // 提示、注释、警告等自定义容器
69 | container: true,
70 | // 选项卡
71 | tabs: true,
72 | // 附加属性
73 | attrs: true,
74 | // 自定义对齐
75 | align: true,
76 | // 上下标
77 | sub: true,
78 | sup: true,
79 | // 底部注释引用
80 | footnote: true,
81 | // 高亮标记
82 | mark: true,
83 | // 启用图片懒加载
84 | imgLazyload: true,
85 | // 启用图片标记
86 | imgMark: true,
87 | // 启用图片大小
88 | imgSize: true,
89 | // 任务列表
90 | tasklist: true,
91 | // 导入md文件
92 | include: true,
93 | // 流程图支持
94 | flowchart: true,
95 | },
96 | },
97 | });
98 |
--------------------------------------------------------------------------------
/src/Gui/AboutGui.ah2:
--------------------------------------------------------------------------------
1 | /**
2 | * @Name: 关于界面
3 | * @Version: 0.0.3
4 | * @Author: AkiChase
5 | * @LastEditors: AkiChase
6 | * @LastEditTime: 2023-05-12
7 | * @Description: 关于界面显示版本信息、项目主页、检查更新
8 | */
9 | class AboutGui {
10 | static version := "0.5.3"
11 | ; static gui:=unset
12 |
13 | static init() {
14 | this.gui := Gui("-Resize", "关于界面")
15 | this.gui.SetFont("s14 q5 c333333", "NSimSun")
16 | this.gui.SetFont(, "雅痞-简") ;优先使用更好看的字体
17 |
18 | this.gui.AddPicture("w75 h75", GlobalData.imgDir "\Starter.png")
19 | this.gui.AddText("x160 yp h50 w200", "Starter").SetFont("bold s30")
20 | this.gui.AddText("x160 yp+50", "当前版本: " this.version)
21 |
22 | this.gui.AddText("x140 yp+50", "开发者:")
23 | this.gui.AddText("xp+90 yp w200", "AkiChase").SetFont("bold")
24 | this.gui.AddLink("x120 yp+35", '项目主页: Github Starter')
25 | this.gui.AddLink(, '项目主页: Gitee Starter')
26 |
27 | this.gui.AddButton("x175 yp+50", "检查更新").OnEvent("Click", (*) => this.checkUpdates())
28 |
29 | this.gui.OnEvent("Close", (guiObj) => guiObj.Hide())
30 | this.checkUpdates(true)
31 | }
32 |
33 | static showGui() {
34 | this.gui.Show()
35 | }
36 |
37 | static versionCompare(v1, v2) {
38 | v1 := StrSplit(v1, ".")
39 | v2 := StrSplit(v2, ".")
40 | loop 3 {
41 | if (v1[A_Index] == v2[A_Index])
42 | continue
43 | return StrCompare(v1[A_Index], v2[A_Index])
44 | }
45 | return 0
46 | }
47 |
48 | ; 检查最新版本
49 | static checkUpdates(silent := false) {
50 | this.gui.Title := "正在检查更新..."
51 | try {
52 | res := WinHttp().Download("https://gitee.com/api/v5/repos/AkiChase/Starter/tags?access_token=14eff4e12ee77cfd7ea5410727cb1526")
53 | res_json := Jxon_Load(&res)
54 | latest := SubStr(res_json[1]["name"], 2)
55 | if (this.versionCompare(latest, this.version) > 0) {
56 | Tip.show("检测到新版本: " latest
57 | , "请自行前往项目主页下载, 右键右下角托盘图标导出用户数据后可以导入新版本中", , , true)
58 | } else if (!silent)
59 | Tip.show("更新提示", "无需更新,已更新至最新版本: " latest)
60 | } catch
61 | Tip.show("错误", "检查更新失败")
62 | this.gui.Title := "关于界面"
63 | }
64 | }
--------------------------------------------------------------------------------
/src/Starter.ah2:
--------------------------------------------------------------------------------
1 | /**
2 | * @Name: Starter
3 | * @Version: 0.5.2
4 | * @Author: AkiChase
5 | * @LastEditors: AkiChase
6 | * @LastEditTime: 2023-05-12
7 | * @Description: 介绍Starter 是一款AHK编写的快速启动工具,旨在方便快捷地启动文件、文件夹,提高电脑的使用效率。
8 | */
9 | #NoTrayIcon ; 先隐藏图标
10 |
11 | ListLines False
12 | #SingleInstance Force
13 | InstallKeybdHook(true, true)
14 | InstallMouseHook(true, true)
15 | KeyHistory(3) ; 为了双击验证
16 | FileEncoding("UTF-8-RAW")
17 | SetWinDelay(0)
18 |
19 |
20 | ; 调试模式下,退出时不保存用户数据,不会动态载入插件
21 | ; 手动#inclide 需要调试的插件
22 | ; DEBUG := true
23 | ; #Include .\Plugin\窗口切换.ahk
24 | ; #Include .\Plugin\文件搜索.ahk
25 | ; #Include .\Plugin\文件选择对话框导航.ahk
26 | ; #Include .\Plugin\网页搜索.ahk
27 | ; #Include .\Plugin\demo.ahk
28 |
29 | #Include .\Utils\GlobalData.ah2
30 | GlobalData.init()
31 | TraySetIcon(GlobalData.imgDir "\Starter.ico", , true) ; 设置图标
32 |
33 | #Include .\Utils\Class_Loader.ah2
34 | #Include .\Utils\LoadIconFromBase64.ah2
35 | #Include .\Gui\PluginGui.ah2
36 | PluginGui.init() ;同时重启以加载插件
37 |
38 | #Include .\Utils\ChineseFirstChar.ah2
39 | #Include .\Utils\MapArrClone.ah2
40 | #Include .\Utils\GetSelectedText.ah2
41 | #Include .\Utils\HotkeyHelper.ah2
42 | #Include .\Utils\JXON.ah2
43 | #Include .\Utils\WinHttp.ah2
44 | #Include .\Utils\IME.ah2
45 | #Include .\Utils\QuickSort.ah2
46 | #Include .\Utils\DataHelper.ah2
47 | #Include .\Utils\Start.ah2
48 | #Include .\Utils\WiseGuiHelper.ah2
49 | #Include .\Utils\UrlEncode.ah2
50 | #Include .\Utils\EditCtrlFunc.ah2
51 | #Include .\Utils\CopyToClipboard.ah2
52 | #Include .\Utils\7Zip\SevenZip.ahk
53 | #Include .\Utils\ImagePut.ah2
54 |
55 | Tip := WiseGuiHelper("tooltip")
56 | Tip.setOpt(, , "s14 Bold, 雅痞-简", "s12, 雅痞-简", 225
57 | , "0x805D6B, 0xFFFFFF, 0xF5F5DC, *" LoadPicture(GlobalData.imgDir "\Starter.ico", , &_) ;加*使用副本
58 | , , , "4,1,1,3", "1", , "SlideWest@150")
59 |
60 | #Include .\Gui\BootGui.ah2
61 | BootGui.init()
62 |
63 | #Include .\Gui\SearchGui\SearchGui.ah2
64 | #Include .\Gui\SearchGui\StartupMode.ah2
65 | #Include .\Gui\SearchGui\IntelligentMode.ah2
66 | #Include .\Gui\SearchGui\PluginMode.ah2
67 | SearchGui.init()
68 |
69 | #Include .\Gui\StartupEditGui.ah2
70 | StartupEditGui.init()
71 |
72 | #Include .\Gui\IntelligentEditGui.ah2
73 | IntelligentEditGui.init()
74 |
75 | #Include .\Gui\AboutGui.ah2
76 | AboutGui.init()
77 |
78 | #Include .\Gui\TrayMenu.ah2
79 | TrayMenu.init()
80 |
81 | #Include .\Utils\PluginHelper.ah2
82 | PluginHelper.init() ;同时执行所有插件的入口函数
83 |
84 | #Include .\Gui\SettingGui.ah2
85 | SettingGui.init()
86 |
87 | if (!IsSet(DEBUG) || !DEBUG)
88 | OnExit((*) => GlobalData.onExitHandler()) ;退出时保存数据
89 |
90 | if (IsSet(DEBUG) && DEBUG)
91 | Hotkey("^!q", (*) => (Send("^s"), Reload()))
--------------------------------------------------------------------------------
/docs/dev/others/image-put-doc-1.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: ImagePut —— 裁剪、缩放 & 其他选项
3 | icon: image
4 | author: AkiChase
5 | date: 2023-04-16
6 | ---
7 |
8 | :::warning
9 | 本文仅仅翻译[Crop, Scale, & Other Flags · iseahound/ImagePut Wiki (github.com)](https://github.com/iseahound/ImagePut/wiki/Crop,-Scale,-&-Other-Flags),可能存在不准确的地方,仅供参考,请以原 wiki 文档为准。
10 | :::
11 |
12 | # 剪裁、缩放和其他标志
13 |
14 | ### 用法
15 |
16 | 指定为对象键以覆盖所有可能的输入。`image`
17 |
18 | ```
19 | ImagePutWindow({image: "cats.jpg", scale: 2})
20 | ```
21 |
22 | 或使用 [特定的数据类型](./image-put-doc-2.md#输入类型),例如:`file`
23 |
24 | ```
25 | ImagePutWindow({file: "cats.jpg", scale: 2})
26 | ```
27 |
28 | ### 剪裁 Crop
29 |
30 | 传递一个 [x、y、w、h] 数组。所有四个成员都是必需的。
31 |
32 | ```
33 | ; 剪裁到从 (100, 100) 处开始的 250 x 250 像素的图像。
34 | ImagePutWindow({image: "cats.jpg", crop: [100, 100, 250, 250]})
35 | ```
36 |
37 | 任何负值都会被解释为“从边缘开始”。宽度和高度分别对应右边和下边。
38 |
39 | ```
40 | ; 从每个边缘裁剪 10 像素。
41 | ImagePutWindow({image: "cats.jpg", crop: [-10, -10, -10, -10]})
42 | ```
43 |
44 | 如果这些值中有任何一个是百分比,它们应该作为字符串输入。
45 |
46 | ```
47 | ; 从每个边缘裁剪 10%。
48 | ImagePutWindow({image: "cats.jpg", crop: ["-10%", "-10%", "-10%", "-10%"]})
49 | ```
50 |
51 | 指定的剪裁数组比原始文件大不会发生什么。将忽略超出边界的值。
52 |
53 | ### 缩放 Scale
54 |
55 | 传递一个正实数。缩放算法使用 GDI+ HighQualityBicubic。
56 |
57 | ```
58 | ; 缩放倍数为2.5倍。
59 | ImagePutWindow({image: "cats.jpg", scale: 2.5})
60 | ```
61 |
62 | 要缩放到特定的宽度和高度,请使用 2 成员数组。宽度和高度必须是整数值。
63 |
64 | ```
65 | ; 调整大小为640 x 480。
66 | ImagePutWindow({image: "cats.jpg", scale: [640, 480]})
67 | ```
68 |
69 | 要计算缺失的边,请使用大小数组,并将参数替换为任何字符串。这将保持原始纵横比。
70 |
71 | ```
72 | ; 缩放高度为480像素。
73 | ImagePutWindow({image: "cats.jpg", scale: ["", 480]})
74 | ImagePutWindow({image: "cats.jpg", scale: ["auto", 480]}) ; 更易于理解。
75 | ```
76 |
77 | ### 解码 Decode
78 |
79 | 当设置为 true 时,禁用快速流转换。影响:pdf、url、file、stream、randomaccessstream、base64 和 hex。默认值为 false。
80 |
81 | 启用此标志将删除原始文件编码,包括原始文件格式的任何压缩增益。这可能有助于验证像素数据的内容,否则将保持未检查状态。会降低转换速度。
82 |
83 | ```
84 | ; 图像将解码为像素数据并重新编码为 PNG。
85 | str := ImagePutBase64({image: "cats.jpg", decode: True})
86 |
87 | ; 设置全局解码标志。
88 | ImagePut.decode := True ; 默认值为 false。
89 | ```
90 |
91 | ### 验证 Validate
92 |
93 | 立即通过将位图加载到内存中检查像素数据。将来,这可能会检查流数据的标头。
94 |
95 | 如果调用:`ImagePutBitmap`
96 |
97 | - 如果启用,则对位图调用:`GdipValidateImage`。
98 | - 强制将图像加载到内存中。(糟糕:增加了峰值内存使用量。)
99 | - 避免返回对图像数据的引用。(好:防止多个引用导致数据竞争。)
100 | - 避免通过读取时复制或写入时复制实现延迟渲染。(好:立即加载图像数据可防止将意外修改复制。)
101 | - 附带的一项副作用是立即将图像加载到内存中,意味着对原始图像数据的任何修改都不会被复制过来。
102 | - 修复了一种罕见的错误,即位图克隆的位图克隆(2 层引用)在从流中解码图像时可能会导致数据竞争。
103 | - 当返回 GDI+ 位图时,建议将此标志设置为 true,因为在位图的立即创建之后的任何时候调用都会导致秘密失败。`validate``GdipValidateImage``GdipValidateImage`
104 |
105 | 默认值为 false,这意味着在需要时拉取像素数据,以节省内存并加快速度。除非满足上述条件,否则不需要将此标志设置为 true。
106 |
107 | ```
108 | ; 立即将 cats.jpg 加载到内存中。
109 | pBitmap := ImagePutBitmap({image: "cats.jpg", validate: true})
110 |
111 | ; 设置全局验证标志。
112 | ImagePut.validate := True ; 默认值为 false。
113 | ```
114 |
--------------------------------------------------------------------------------
/src/Plugin/win10任务栏透明.ahk:
--------------------------------------------------------------------------------
1 | /**
2 | * @Name: win10任务栏透明.ahk
3 | * @Version: 0.0.1
4 | * @Author: AkiChase
5 | * @LastEditors: AkiChase
6 | * @LastEditTime: 2023-03-29
7 | * @Description: win10任务栏透明功能
8 | */
9 |
10 | /*
11 | ===Starter Plugin Info==>
12 | {
13 | "author": "AkiChase",
14 | "version": "0.0.1",
15 | "introduction": "任务栏透明化,仅支持win10,打开开始菜单透明化会消失",
16 | "icon": "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAKtJREFUWEdjZBhgwDjA9jMMOgfMxBEiZxkYGGbhkPPBIf6cgYEBpA8vQA8BkAOMsegAWY7LAWl4HD3qgNEQIDkEcCUoPQYGhh14Ujs2KREGBoZLhPQQWw6AspovDsPScYhLMjAwSGGR+8zAwHALJj7qgNEQGHQhMFoXjIbAaAiMVka4GpCjteFoCIBCQB1HAunF0yLixSFHcouIUAeHbHliq2OyLSCkccAdAADLclshWioLowAAAABJRU5ErkJggg=="
17 | }
18 | <==Starter Plugin Info===
19 | */
20 |
21 | PluginHelper.addEntryFunc((*) => Plugin_win10任务栏透明.main()) ; 添加入口函数等待执行
22 |
23 | class Plugin_win10任务栏透明 {
24 | static menu := Menu()
25 | static state := false
26 | ; static f:=unset
27 |
28 | static TaskBar_SetAttr(accent_state := 0, gradient_color := "0x01000000")
29 | {
30 | static init := 0
31 | static hTrayWnd := 0
32 | static ver := DllCall("GetVersion") & 0xff < 10
33 | static pad := A_PtrSize = 8 ? 4 : 0, WCA_ACCENT_POLICY := 19
34 |
35 | if !(init) {
36 | if (ver)
37 | throw Error("Minimum support client: Windows 10", -1)
38 | if !(hTrayWnd := DllCall("user32\FindWindow", "str", "Shell_TrayWnd", "ptr", 0, "ptr"))
39 | throw Error("Failed to get the handle", -1)
40 | init := 1
41 | }
42 |
43 | ACCENT_POLICY := Buffer(16, 0)
44 | accent_size := ACCENT_POLICY.Size
45 | NumPut("int", (accent_state > 0 && accent_state < 4) ? accent_state : 0, ACCENT_POLICY, 0)
46 |
47 | if (accent_state >= 1) && (accent_state <= 2) && (RegExMatch(gradient_color, "0x[[:xdigit:]]{8}"))
48 | NumPut("int", gradient_color, ACCENT_POLICY, 8)
49 |
50 | WINCOMPATTRDATA := Buffer(4 + pad + A_PtrSize + 4 + pad, 0)
51 | NumPut("int", WCA_ACCENT_POLICY, WINCOMPATTRDATA, 0,)
52 | NumPut("ptr", ACCENT_POLICY.Ptr, WINCOMPATTRDATA, 4 + pad)
53 | NumPut("uint", accent_size, WINCOMPATTRDATA, 4 + pad + A_PtrSize)
54 | if !(DllCall("user32\SetWindowCompositionAttribute", "ptr", hTrayWnd, "ptr", WINCOMPATTRDATA.Ptr))
55 | throw Error("Failed to set transparency / blur", -1)
56 | return 0
57 | }
58 |
59 | static toggleState() {
60 | if (this.state) {
61 | SetTimer(this.f, 0) ;关闭计时器
62 | this.menu.Uncheck("开启")
63 | } else {
64 | SetTimer(this.f, 8000) ;开启计时器
65 | this.TaskBar_SetAttr(2) ; 透明化
66 | this.menu.check("开启")
67 | }
68 | this.state := !this.state
69 | }
70 |
71 | static main() {
72 | this.f := this.TaskBar_SetAttr.Bind(this, 2)
73 | this.menu.Add("开启", (*) => this.toggleState())
74 | PluginHelper.pluginMenu.Add("win10任务栏透明", this.menu)
75 | this.toggleState()
76 | }
77 | }
--------------------------------------------------------------------------------
/docs/guide/intelligent/concept.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 基本概念
3 | icon: list
4 | order: 1
5 | author: AkiChase
6 | date: 2023-04-11
7 | ---
8 |
9 | 智能模式的功能比较特殊,有一些相关概念需要你提前了解,以便更好地理解如何使用智能模式。
10 |
11 | ## 智能项
12 |
13 | **原生智能项**是指你在智能模式编辑界面中手动添加、删除或修改的智能项,与插件无关。
14 |
15 | **插件智能项**是指通过插件添加的智能项。插件智能项只能通过插件的编写者更新或修改,有的插件可能会为用户提供**增删改**智能项的方式。
16 |
17 | ::: tip
18 | 本章提到的内容都针对**原生智能项**,非开发者只需要了解**原生智能项**即可,若有兴趣请移步[插件开发 - 插件智能项](../../dev/intelligent/basics.md)
19 | :::
20 |
21 | **原生智能项**的功能或许很强大,或许很鸡肋,因人而异。
22 |
23 | - 它可以根据你的文本输入,快速打开某个网页的搜索页面,并搜索输入的内容。
24 |
25 | - 它可以根据你的文本输入,启动某个程序,并传递输入的命令行参数。
26 |
27 | ::: warning
28 | 接下来的内容比较复杂、繁琐,如果你没有上诉需求或者不喜欢折腾,可以停止阅读本章。
29 | :::
30 |
31 | ## 匹配模式
32 |
33 | **匹配**指的是当前智能项会出现在搜索结果中,设定不同匹配模式可以灵活的匹配不同的输入内容
34 |
35 | ::: warning
36 | 目前,**原生智能项**仅支持匹配**文本**输入类型的内容,暂时不支持**工作窗口信息、文件、位图**等输入类型的匹配。
37 |
38 | 这是为了避免**原生智能项**的相关概念变得更加复杂,同时也降低了**智能模式编辑界面**的复杂程度。
39 |
40 | **工作窗口信息、文件、位图**等输入类型,只有**插件智能项**才可以设定相关的匹配条件,相关内容请移步[插件开发 - 插件智能项](../../dev/intelligent/basics.md)
41 | :::
42 |
43 | ### 1. 字符串模式(str)
44 |
45 | **智能模式搜索框**输入内容为**任意字符串**时匹配,输入内容**原封不动地传递**给启动处理程序。
46 |
47 | ::: tip
48 | 启动处理程序具体做什么在后续会有解释,此时你只要知道它会接收**传递的内容**作为参数进行后续处理
49 | :::
50 |
51 | ### 2. 正则匹配替换模式(reg)
52 |
53 | 在**正则匹配替换模式**下,原生智能项会有一个正则表达式二元列表,列表的每项包含一对表达式:**匹配表达式**,**替换表达式**
54 |
55 | 在智能模式搜索框输入文本时,对于每个原生智能项,**Starter** 依次使用该项中所有**匹配表达式**进行正则匹配,直到有一个表达式与输入文本匹配为止。如果所有表达式都无法匹配,则该智能项不会出现在搜索结果中。
56 |
57 | ::: tip
58 | 对某个智能项的**匹配表达式**的匹配顺序是**从上到下**,也就是排在越前面的表达式优先级越高。
59 | :::
60 |
61 | 对于这一类智能项,**Starter** 将使用该项的替换表达式对输入内容进行替换,替换后的结果就是所谓的**传递的内容**。
62 |
63 | 正则匹配与替换参考:
64 |
65 | 1. [正则表达式30分钟入门教程 (deerchao.cn)](https://deerchao.cn/tutorials/regex/regex.htm#mission)
66 | 2. [RegExReplace - 语法 & 使用 | AutoHotkey v2](https://orz707.gitee.io/v2/docs/commands/RegExReplace.htm)
67 |
68 | ### 3. 匹配优先级
69 |
70 | 搜索结果展示的优先级取决于匹配规则的优先级,匹配规则的优先级越高在搜索结果越靠前。在**原生智能项**中,所有 `reg` 匹配的规则优先级都高于 `str` 匹配的规则,而**插件智能项**的规则优先级更高。
71 |
72 | ## 智能项分组
73 |
74 | **原生启动项**有两个分组,**启动分组**和**搜索分组**,不同分组中的**启动处理程序**略有区别
75 |
76 | 启动处理接下来介绍不同分组、不同条件下**启动处理程序**的具体功能
77 |
78 | ### 1. 启动分组(run-with)
79 |
80 | 
81 |
82 | **启动处理程序**将收到的**传递内容**按当前原生智能项的**脚本模式**执行启动。
83 |
84 | ::: tip
85 | 脚本模式是**启动分组**内原生智能项**特有**的选项,**搜索分组**内原生智能项不具有该选项
86 | :::
87 |
88 | - 空模式(none)
89 |
90 | 启动处理程序**直接执行传递的内容**,即直接执行 `Run(传递的内容)`,此时程序路径无效。
91 |
92 | `Run()` 函数细节可参考[Run / RunWait - 语法 & 使用 ](https://orz707.gitee.io/v2/docs/commands/Run.htm)中的 `Target` 参数。
93 |
94 | - 单参数模式(arg)
95 |
96 | 启动处理程序将**传递的内容**视为**一个**命令行参数(对**传递的内容**中的双引号进行转义,再用双引号包裹),然后用此参数启动填写的**程序路径**
97 |
98 | 即执行 `Run(程序路径 "传递的内容")`
99 |
100 | - 多参数模式(args)
101 |
102 | 启动处理程序将**传递的内容**视为**完整的**命令行参数(对**传递的内容**不做任何处理),用此参数启动填写的**程序路径**。
103 |
104 | 即执行 `Run(程序路径 传递的内容)`
105 |
106 | ### 2. 搜索分组(search)
107 |
108 | 
109 |
110 | **启动处理程序**将收到的内容填充到**搜索URL**中"{}"所在位置,启动填充后的URL。
111 |
112 | ::: tip
113 | 启动处理程序的根本功能就是 `Run(Target)` 参考[Run / RunWait - 语法 & 使用 ](https://orz707.gitee.io/v2/docs/commands/Run.htm)
114 | :::
--------------------------------------------------------------------------------
/docs/guide/get-started/install-usage.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 下载与使用
3 | icon: download
4 | order: 2
5 | author: AkiChase
6 | date: 2023-04-09
7 | ---
8 |
9 | ::: center
10 |
11 | Starter
12 | 智能、快捷地启动文件、文件夹,执行操作,提高电脑的使用效率
13 | :::
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | ## 下载
23 |
24 | - Github下载:[Github Releases](https://github.com/AkiChase/Starter/releases)
25 |
26 | - 蓝奏云下载:[蓝奏云](https://wwi.lanzoup.com/b01kb1g4j) 密码: 9vge
27 |
28 | **Starter 优先使用** `雅痞-简` 字体,可在上方蓝奏云链接内下载安装。
29 |
30 | ## 运行
31 |
32 | 将下载的压缩包**解压**,运行文件夹中的 `创建快捷方式.bat` ,将在文件夹内创建 `Starter.lnk` 快捷方式,双击即可运行软件。
33 |
34 |
35 | :::tip
36 | 刚刚安装好的 **Starter** 就像一张白纸,但在添加各种配置之后,它将成为你最得心应手的启动工具。
37 | :::
38 |
39 | ## 配置启动项
40 |
41 | 运行 **Starter** 后,右键右下角托盘图标打开菜单,点击**编辑启动模式**。
42 |
43 | ::: tip
44 | 由于初次运行,没有配置任何启动项,会弹窗提示“启动列表内无可编辑项,请添加文件”。
45 |
46 | 点击确认,在随后出现的文件选择框中随意选择一个文件,比如QQ,以添加到启动列表。
47 |
48 | 然后就可以打开编辑界面,开始个性化设置启动项了。
49 | :::
50 |
51 | 
52 |
53 | - ### 添加启动项
54 |
55 | 在启动模式编辑界面中,你可以通过两种方式来添加启动项:
56 |
57 | 1. 你可以点击界面上的**添加**按钮,在文件选择框中选择要添加的文件
58 | 2. 你也可以将所需添加的文件拖拽到窗口中,这种方式既快速又方便,可以一次性添加多个启动项。
59 |
60 | ::: tip
61 | 此处的启动项指的是非插件添加的启动项,也就是**原生启动项**,可以在启动模式编辑界面中添加、修改等。
62 | :::
63 |
64 | - ### 编辑启动项
65 |
66 | **Starter** 根据**显示名称**和**其他关键字**来识别启动项。在搜索框中搜索时,只要搜索内容是 **显示名称的一部分** 或 **某行关键字的一部分**,该启动项就会出现在搜索结果中。
67 |
68 | 在启动项编辑界面,你可以直接在编辑框中输入和修改启动项的内容。此外,如果你需要增加、删除或修改其他关键字,可以右键点击其他关键字列表,打开菜单进行相应操作。最后,点击保存按钮进行保存。
69 |
70 | ## 启用插件
71 |
72 | 运行 **Starter** 后,右键右下角托盘图标打开菜单,点击**插件界面**。
73 |
74 | 
75 |
76 | 在插件列表中双击任意一行,即可启用或禁用该插件。在修改完所需的插件状态后,点击**保存重载**按钮,软件会重启且只会载入所有已启用的插件。
77 |
78 | 插件的使用请参考[插件指南](../../plugin/)
79 |
80 | ## 开始使用
81 |
82 | - 呼出搜索框
83 |
84 | 按下 `呼出搜索框` 快捷键,呼出**启动模式搜索框**,输入任意内容,可以看到搜索结果列表。
85 |
86 | - 切换选中项
87 |
88 | `Up`、`Down` 按键可在列表中**上下切换**选中的条目。
89 |
90 | `Alt` + `数字` 按键可以快速选中**当前视图**中的第n个条目 (`Alt` + `0` 代表选中第10个)。
91 |
92 | - 启动选中项
93 |
94 | `回车` 可以启动当前选中项。
95 |
96 | - 文件夹中显示
97 |
98 | 双击 `Right`按键可以在文件夹中显示当前选中的**原生启动项**。
99 |
100 | ::: tip
101 | 如果该启动项来自于某个插件,即**插件启动项**,则执行相应的插件设定。
102 | :::
103 |
104 | - 清空与关闭
105 |
106 | `Esc`按键将**清空** 输入内容,或者**隐藏**搜索界面。
107 |
108 | 搜索界面失去焦点一段时间后**自动隐藏**,自动隐藏后15s内**保留搜索结果**。
109 |
110 | - 右键菜单
111 |
112 | 右键点击任意结果条目,将会打开菜单以进行更多操作。
113 |
114 | ## 更多
115 |
116 | ::: tip
117 | 以上是 **Starter** 中最简单、常用的搜索与启动功能,是你快速上手 **Starter** 的最好方式。
118 | :::
119 |
120 | **Starter** 还具备其他更丰富的功能,比如[插件](../../plugin/)、[智能模式](../intelligent/)、[开机启动](../boot/)等等
121 | ,建议你细读本文档的其他章节,探索其他功能。
122 |
123 |
124 |
125 |
126 |
--------------------------------------------------------------------------------
/docs/dev/startup.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 插件启动项
3 | icon: bolt
4 | author: AkiChase
5 | date: 2023-04-14
6 | ---
7 |
8 | 插件启动项类似于原生启动项,但是更加**自由**、**强大**。
9 |
10 | ## API
11 |
12 | 添加**插件启动项**需要使用 `PluginHelper.addPluginToStartupMode()` API
13 |
14 | 参数及说明:[PluginHelper.addPluginToStartupMode](../api/addPluginToStartupMode.md)
15 |
16 | ## 简单应用
17 |
18 | 在启动该插件项时触发某个功能,参考[快速上手 - 添加插件启动项](./get-started.md#add-plugin-to-startup-mode)
19 |
20 | ## 进阶应用
21 |
22 | 主要通过ahk**闭包特性**进行更多操作,和 `js` 中的闭包一样,用起来非常灵活。
23 | ### 1. 同时添加多个插件项
24 |
25 | 批量添加多个插件项,通过 `obj` 对象的属性、ahk**闭包特性**执行预期的内容。
26 |
27 | ```ahk
28 | ; 添加插件启动项
29 | static addStartupItem() {
30 | demoData := Map(
31 | "明月几时有", "把酒问青天",
32 | "不知天上宫阙", "今夕是何年",
33 | "我欲乘风归去", "又恐琼楼玉宇"
34 | )
35 |
36 | ; 利用闭包特性,可以访问到demoData
37 | startHandler(obj, searchText) {
38 | PluginHelper.Utils.tip(this.name, demoData[obj.title])
39 | }
40 |
41 | for k, v in demoData {
42 | ; 如果startHandler闭包在此处,甚至可以直接访问到k,v
43 |
44 | PluginHelper.addPluginToStartupMode(
45 | this.name,
46 | k,
47 | ; 使用工具函数将其转换为拼音首字母作为关键词
48 | [PluginHelper.Utils.chineseFirstChar(k)],
49 | startHandler
50 | )
51 | }
52 | }
53 | ```
54 |
55 | 批量添加结果
56 |
57 | 
58 |
59 | 搜索拼音首字母 `wy` 得到唯一匹配启动项
60 |
61 | 
62 |
63 | 启动结果如下图
64 |
65 | 
66 |
67 |
68 | ### 2. 右键菜单
69 |
70 | 右键当前项时可以通过 `contextHandler` 显示菜单,而通过**闭包**或者为函数*bind参数*可以区分出具体是哪一项
71 |
72 | - 纯闭包实现
73 | ```ahk
74 | ; 添加插件启动项
75 | static addStartupItem() {
76 | demoData := Map(
77 | "明月几时有", "把酒问青天",
78 | "不知天上宫阙", "今夕是何年",
79 | "我欲乘风归去", "又恐琼楼玉宇"
80 | )
81 |
82 | ; 利用闭包
83 | curContextObj := 0
84 | m := Menu()
85 | m.Add("显示后半句", (*) => PluginHelper.Utils.tip(this.name, demoData[curContextObj.title]))
86 | contextHandler(obj){
87 | ; 利用闭包,在显示菜单时将 curContextObj 赋值,从而能在外访问到符合预期的后半句
88 | curContextObj:=obj
89 | m.Show() ; 显示菜单
90 | }
91 |
92 | for k, v in demoData {
93 | PluginHelper.addPluginToStartupMode(
94 | this.name,
95 | k,
96 | [PluginHelper.Utils.chineseFirstChar(k)],
97 | (*) => 0,,
98 | contextHandler
99 | )
100 | }
101 | }
102 | ```
103 |
104 | - 闭包 + Bind 实现
105 | ```ahk
106 | static addStartupItem() {
107 | demoData := Map(
108 | "明月几时有", "把酒问青天",
109 | "不知天上宫阙", "今夕是何年",
110 | "我欲乘风归去", "又恐琼楼玉宇"
111 | )
112 |
113 | ; 利用闭包
114 | words := 0
115 | m := Menu()
116 | m.Add("显示后半句", (*) => PluginHelper.Utils.tip(this.name, words))
117 | contextHandler(bindParam, obj) {
118 | ; 利用闭包,在显示菜单时将 words 赋值,从而能在外访问到符合预期的后半句
119 | words := bindParam
120 | m.Show() ; 显示菜单
121 | }
122 |
123 | for k, v in demoData {
124 | PluginHelper.addPluginToStartupMode(
125 | this.name,
126 | k,
127 | [PluginHelper.Utils.chineseFirstChar(k)],
128 | (*) => 0, ,
129 | contextHandler.Bind(v)
130 | )
131 | }
132 | }
133 | ```
134 |
135 | 效果相同,只是思路上有细微的区别。
136 |
137 | 
138 |
139 | 
140 |
141 |
--------------------------------------------------------------------------------
/docs/dev/intelligent/basics.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 基础
3 | icon: square-caret-up
4 | author: AkiChase
5 | date: 2023-04-14
6 | order: 1
7 | ---
8 |
9 | **插件智能项**的功能非常强大,可以通过自定义匹配函数,根据当前输入内容的类型,具体内容,工作窗口等信息判断是否匹配当前插件智能项。
10 |
11 | 具体来说,比如,将图片粘贴到智能模式搜索框中,就可以根据输入内容的类型是图片,而匹配到**OCR图片识别**插件添加的智能项。
12 |
13 | 比如,将单个文件夹粘贴到搜索框中,就可以根据输入内容的类型是文件,再根据当前文件是文件夹,而匹配到通过**文件搜索**插件添加的智能项。
14 |
15 | 而其他方面的操作类似于**插件启动项**,在此不多赘述。
16 |
17 | :::tip
18 | 与**插件启动项**不同,**智能启动项**没有 `doubleRightHandler` 参数,其他用法类似。
19 | :::
20 |
21 | 主要内容集中在**自定义匹配**函数
22 |
23 | ## API
24 |
25 | 添加**插件智能项**需要使用 `PluginHelper.addPluginToIntelligentMode()` API
26 |
27 | 参数及说明:[PluginHelper.addPluginToIntelligentMode](../../api/addPluginToIntelligentMode.md)
28 |
29 | ## 简单应用
30 |
31 | 自定义匹配函数的应用,即 `matchHandler` 参数
32 |
33 | ### 1. 文本匹配
34 |
35 | 自由组合文本匹配,matchHandler返回0则不匹配,返回非0则匹配
36 |
37 | ```ahk
38 | ; 添加插件智能项
39 | static addIntelligentItem() {
40 | ; 自定义匹配函数
41 | matchHandler(obj, searchText, pastedContentType, *) { ; 使用*忽略多余参数
42 | ; 带有非文本类型的都不匹配
43 | if (pastedContentType != 'text')
44 | return 0
45 | ; 若searchText为"PPWB"开头部分
46 | if (PluginHelper.Utils.strStartWith("PPWB", searchText)
47 | || searchText == '1234' ;或者searchText为1234
48 | || InStr(searchText, "6") ; 或者searchText包含6
49 | )
50 | return 1 ;则匹配
51 |
52 | return 0 ; 其他情况也不匹配
53 | }
54 |
55 | PluginHelper.addPluginToIntelligentMode(this.name,
56 | "匹配文本",
57 | matchHandler,
58 | (obj, *) => PluginHelper.Utils.tip(this.name, obj.title)
59 | )
60 | }
61 | ```
62 |
63 | 如图,符合`InStr(searchText, "6")`而匹配
64 |
65 | 
66 |
67 | ### 2. 输入类型匹配
68 |
69 | ```ahk
70 | ; 添加插件智能项
71 | static addIntelligentItem() {
72 | ; 自定义匹配函数
73 | matchHandler(obj, searchText, pastedContentType, pastedContent, *) { ; 使用*忽略多余参数
74 | if (pastedContentType == 'file' && ; 文件类型 且
75 | pastedContent.Length == 1 && ; 文件数量为1 且
76 | InStr(FileExist(pastedContent[1]), "D") ; 文件为文件夹
77 | )
78 | return 1 ; 符合则匹配
79 | return 0 ; 否则不匹配
80 | }
81 |
82 | PluginHelper.addPluginToIntelligentMode(this.name,
83 | "匹配单个文件夹",
84 | matchHandler,
85 | (obj, *) => PluginHelper.Utils.tip(this.name, obj.title)
86 | )
87 | }
88 | ```
89 |
90 | 如图,符合单个文件夹而匹配
91 |
92 | 
93 |
94 | ### 3. 工作窗口匹配
95 |
96 | :::tip
97 | 工作窗口模式是按下**智能搜索**快捷键时,若当前**没有选中任何内容**,则**Starter**将获取工作窗口信息,进入工作窗口模式下的智能模式搜索框。
98 |
99 | 搜索框会短暂显示工作窗口的信息,插件可以根据此时的工作窗口信息进行匹配
100 | :::
101 |
102 | 通过工作窗口信息,匹配资源管理器
103 |
104 | ```ahk
105 | static addIntelligentItem() {
106 | ; 自定义匹配函数
107 | matchHandler(obj, searchText, pastedContentType, pastedContent, workWinInfo, winInfoMatchFlag) {
108 | ; 非工作窗口模式不匹配
109 | ; 只有工作窗口模式下,窗口信息才是有效的
110 | ; 否则可能是上次工作窗口模式的信息
111 | if (!winInfoMatchFlag)
112 | return 0
113 |
114 | pName := workWinInfo.processName
115 | cName := workWinInfo.class
116 | ; 返回是否满足资源管理器窗口特征 (用或连接)
117 | return (pName == 'explorer.exe' || cName == "CabinetWClass" || cName == "ExploreWClass")
118 | }
119 |
120 | PluginHelper.addPluginToIntelligentMode(this.name,
121 | "匹配资源管理器",
122 | matchHandler,
123 | (obj, *) => PluginHelper.Utils.tip(this.name, obj.title)
124 | )
125 | }
126 | ```
127 |
128 | 
129 |
--------------------------------------------------------------------------------
/src/Utils/Class_Loader.ah2:
--------------------------------------------------------------------------------
1 | /**
2 | * @Name: Class_Loader
3 | * @Version: 0.0.1
4 | * @Author: AkiChase
5 | * @LastEditors: AkiChase
6 | * @LastEditTime: 2023-03-29
7 | * @Description: Loading files(or code) dynamically. But it needs to be loaded all in one call(loadFromFiles() or loadFromText()).
8 | */
9 |
10 | #Requires AutoHotkey v2.0
11 |
12 | #Include "*i \\.\pipe\3a9e1e44-8c0b-4e18-a0d3-63d1cadc4000"
13 | class Loader {
14 | static _loaded := false
15 |
16 | /**
17 | * @description: loading files dynamically
18 | * @param fileList The file Path(Absolute or Relative) Array
19 | */
20 | static loadFromFiles(fileList) {
21 | includeText := ""
22 | for f in fileList {
23 | includeText .= "`n#Include " this._getFullPathName(f)
24 | }
25 | this.loadFromText(includeText)
26 | }
27 |
28 | /**
29 | * @description: loading code dynamically
30 | * @param text Code to load
31 | */
32 | static loadFromText(text) {
33 | if (this._loaded) ; Prevent dead cycle
34 | return
35 |
36 | text := "Loader._loaded := true`n" text
37 | ;// Create named pipes
38 | pipe := [0, 0]
39 | Loop 2
40 | {
41 | if ((pipe[A_Index] := DllCall(
42 | "CreateNamedPipe", ; http://goo.gl/3aJQg7
43 | "Str", "\\.\pipe\3a9e1e44-8c0b-4e18-a0d3-63d1cadc4000", ; lpName
44 | "UInt", 2, ; dwOpenMode = PIPE_ACCESS_OUTBOUND
45 | "UInt", 0, ; dwPipeMode = PIPE_TYPE_BYTE
46 | "UInt", 255, ; nMaxInstances
47 | "UInt", 0, ; nOutBufferSize
48 | "UInt", 0, ; nInBufferSize
49 | "Ptr", 0, ; nDefaultTimeOut
50 | "Ptr", 0 ; lpSecurityAttributes
51 | )) == -1) ; INVALID_HANDLE_VALUE = -1
52 | throw A_ThisFunc . "() - Failed to create named pipe.`nGetLastError: " . A_LastError
53 | }
54 |
55 | ;// Process command line argument(s)
56 | q := Chr(34) ;// double quote for v1.1 and v2.0-a compatibility
57 | params := ""
58 | for arg in A_Args
59 | {
60 | i := 0
61 | while (i := InStr(arg, q, , i + 1)) ;// escape '"' with '\'
62 | if (SubStr(arg, i - 1, 1) != "\")
63 | arg := SubStr(arg, 1, i - 1) . "\" . SubStr(arg, i++)
64 | params .= (A_Index > 1 ? " " : "") . (InStr(arg, " ") ? q . arg . q : arg)
65 | }
66 |
67 | ;// Reload script passing args(if any)
68 | Run(Format('"{}" /restart "{}" {}', A_AhkPath, A_ScriptFullPath, params))
69 |
70 | DllCall("ConnectNamedPipe", "Ptr", pipe[1], "Ptr", 0) ;// http://goo.gl/pwTnxj
71 | DllCall("CloseHandle", "Ptr", pipe[1])
72 |
73 | ; The second pipe is for the actual file contents.
74 | DllCall("ConnectNamedPipe", "Ptr", pipe[2], "Ptr", 0)
75 | ;// Write dynamic code into pipe
76 | if !(f := FileOpen(pipe[2], "h", "UTF-8")) ;// works on both Unicode and ANSI
77 | return A_LastError
78 | f.Write(text)
79 | f.Close(), DllCall("CloseHandle", "Ptr", pipe[2]) ;// close pipe handle
80 | ExitApp()
81 | }
82 |
83 | static _getFullPathName(path) {
84 | cc := DllCall("GetFullPathNameW", "str", path, "uint", 0, "ptr", 0, "ptr", 0, "uint")
85 | buf := Buffer(cc * 2, 0)
86 | DllCall("GetFullPathNameW", "str", path, "uint", cc, "ptr", buf, "ptr", 0, "uint")
87 | return StrGet(buf)
88 | }
89 | }
--------------------------------------------------------------------------------
/src/Utils/HotkeyHelper.ah2:
--------------------------------------------------------------------------------
1 | /**
2 | * @Name: HotkeyHelper
3 | * @Version: 0.0.1
4 | * @Author: AkiChase
5 | * @LastEditors: AkiChase
6 | * @LastEditTime: 2023-04-16
7 | * @Description: Hotkey Settings Tool Functions
8 | */
9 |
10 | class HotkeyHelper {
11 | /**
12 | * @description:
13 | * @param key the hotkey without modifier symbols
14 | * @param time The longest interval from first release to second press
15 | * @param CB Long press callback
16 | * @param block set false to add '~' for hotkey
17 | * @param physical set true to add '$' for hotkey
18 | * @return total hotkey string
19 | */
20 | static longPressHotKey(key, time, CB, block := false, physical := true) {
21 | totalKey := Format("{}{}{}", block ? "" : "~", physical ? "$" : "", key)
22 | time := String(Round(time, 1))
23 | handler(*) {
24 | if (!KeyWait(key, "T" time)) {
25 | CB()
26 | ; Endless waiting for release to avoid repeated calls
27 | KeyWait(key)
28 | }
29 | }
30 | Hotkey(totalKey, handler, "On")
31 | return totalKey
32 | }
33 |
34 | /**
35 | * @description:
36 | * @param key the hotkey without modifier symbols
37 | * @param time The longest interval from first release to second press
38 | * @param doubleCB double press callback
39 | * @param singleCB single press callback
40 | * @param block set false to add '~' for hotkey
41 | * @param physical set true to add '$' for hotkey
42 | * @return total hotkey string
43 | */
44 | static doubleAndSingleHotKey(key, time, doubleCB, singleCB := (*) => 0, block := false, physical := true) {
45 | totalKey := Format("{}{}{}", block ? "" : "~", physical ? "$" : "", key)
46 | time := String(Round(time, 1))
47 | handler(*) {
48 | ; Wait for release
49 | if (KeyWait(key)) {
50 | if (KeyWait(key, "DT" time) && A_PriorKey = key) {
51 | doubleCB()
52 | KeyWait(key)
53 | } else
54 | singleCB()
55 | }
56 | }
57 | Hotkey(totalKey, handler, "On")
58 | return totalKey
59 | }
60 |
61 | /**
62 | * @description: example of double and long press for the same key.
63 | * @param key the hotkey without modifier symbols
64 | * @param time1 Press for more than this time, it means long press
65 | * @param time2 The longest interval from first release to second press
66 | * @param longCB Long press callback
67 | * @param doubleCB double press callback
68 | * @param block set false to add '~' for hotkey
69 | * @param physical set true to add '$' for hotkey
70 | * @return total hotkey string
71 | */
72 | static doubleAndLongHotkey(key, time1, time2, longCB, doubleCB, block := false, physical := true) {
73 | ; Construct key string
74 | totalKey := Format("{}{}{}", block ? "" : "~", physical ? "$" : "", key)
75 | ; Round the time and convert it to string
76 | time1 := String(Round(time1, 1))
77 | time2 := String(Round(time2, 1))
78 | handler(*) {
79 | if (KeyWait(key, "T" time1)) {
80 | ; Released within time1, waiting for the second press
81 | if (KeyWait(key, "DT" time2) && A_PriorKey = key) {
82 | ; Second Press within time2
83 | doubleCB()
84 | ; Endless waiting for release to avoid repeated calls
85 | KeyWait(key)
86 | ; if you like, you can add 'KeyWait(key, "DT" time2)' for triple key, uadruple key...
87 | }
88 | } else {
89 | ; Press over the time1
90 | longCB()
91 | ; Endless waiting for release to avoid repeated calls
92 | KeyWait(key)
93 | ; Finally, the long press released.
94 | }
95 | }
96 | Hotkey(totalKey, handler, "On")
97 | return totalKey
98 | }
99 | }
--------------------------------------------------------------------------------
/src/Gui/BootGui.ah2:
--------------------------------------------------------------------------------
1 | class BootGui {
2 | ; static gui := unset
3 | ; static listView := unset
4 | ; static itemList := unset
5 | ; static menu := unset
6 | static menuRow := 0
7 |
8 | static init() {
9 | this.gui := Gui("-Resize", "自启界面")
10 | this.gui.BackColor := "FFFFFF"
11 | this.gui.SetFont("s14 q5 c333333", "NSimSun")
12 | this.gui.SetFont(, "雅痞-简") ;优先使用更好看的字体
13 |
14 | this.gui.OnEvent("Close", (guiObj) => this.gui.Hide())
15 | this.gui.OnEvent("DropFiles", this.addItem)
16 |
17 | this.listView := this.gui.Add("ListView", "x0 y0 w300 h300 -Multi -hdr Grid", [""])
18 | this.listView.SetFont("s12")
19 | this.listView.OnEvent("ContextMenu", (_lv, rowNum, *) => this.showMenu(rowNum))
20 | this.listView.OnEvent("DoubleClick", (_lv, rowNum) => this.startSelectedItem(rowNum))
21 |
22 |
23 | this.gui.Show("Hide w300 h300")
24 | this.menuInit()
25 |
26 | ; 判断是否刚开机
27 | for arg in A_Args {
28 | if (arg = "the_Startup") {
29 | this.boot()
30 | break
31 | }
32 | }
33 | }
34 |
35 | static menuInit() {
36 | this.menu := Menu()
37 | this.menu.Add("添加`t(&A)", (*) => this.choseAddItem())
38 | this.menu.Add("刷新`t(&R)", (*) => this.loadItems())
39 | this.menu.Add("删除`t(&X)", (*) => this.delItem(this.menuRow))
40 | this.menu.Add("目录`t(&X)", (*) => Run(GlobalData.bootDir))
41 |
42 | this.menu.SetIcon("1&", GlobalData.imgDir "\add.ico")
43 | this.menu.SetIcon("2&", GlobalData.imgDir "\reload.ico")
44 | this.menu.SetIcon("3&", GlobalData.imgDir "\delete.ico")
45 | this.menu.SetIcon("4&", GlobalData.imgDir "\folder.ico")
46 | }
47 |
48 | static showGui() {
49 | this.loadItems()
50 | this.gui.Show()
51 | }
52 |
53 | ; 显示菜单
54 | static showMenu(rowNum) {
55 | if (rowNum) {
56 | this.menuRow := rowNum
57 | this.menu.Enable("3&")
58 | } else {
59 | this.menu.Disable("3&")
60 | }
61 | this.menu.Show()
62 | }
63 |
64 | ; 加载boot项
65 | static loadItems() {
66 | this.itemList := []
67 | this.listView.Delete()
68 | loop files GlobalData.bootDir "\*.*" {
69 | this.itemList.Push(A_LoopFileFullPath)
70 | this.listView.Add(, A_LoopFileName)
71 | }
72 | }
73 |
74 | ; 启动点击项
75 | static startSelectedItem(rowNum) {
76 | if (rowNum) {
77 | Start.startFile(this.itemList[rowNum])
78 | }
79 | }
80 |
81 | ; 选择文件路径
82 | static choseAddItem() {
83 | res := FileSelect("M35", , "请选择文件")
84 | if (res.Length) {
85 | this.addItem(res)
86 | }
87 | }
88 |
89 | ; 添加回调
90 | static addItem(args*) {
91 | fileList := args.Length == 1 ? args[1] : args[2]
92 | if (fileList.Length) {
93 | for filePath in fileList {
94 | if (SubStr(filePath, -4) == ".lnk") ; 快捷方式直接复制
95 | FileCopy(filePath, GlobalData.bootDir)
96 | else { ; 创建快捷方式到boot文件夹
97 | SplitPath(filePath, , &outDir, , &fileNameNoExt)
98 | FileCreateShortcut(filePath, GlobalData.bootDir "\" fileNameNoExt ".lnk", outDir)
99 | }
100 | }
101 | BootGui.loadItems() ; 重载列表项
102 | ; 此处this不一定是BootGui
103 | }
104 | }
105 |
106 | ; 删除
107 | static delItem(rowNum) {
108 | fileName := this.listView.GetText(rowNum)
109 | if (MsgBox("当前操作不可恢复,是否将当前项删除?", "提示", 0x2044) = "Yes") {
110 | FileDelete(GlobalData.bootDir "\" fileName)
111 | this.itemList.RemoveAt(rowNum)
112 | this.listView.Delete(rowNum)
113 | }
114 | }
115 |
116 | ; 启动
117 | static boot() {
118 | loop files GlobalData.bootDir "\*.*"
119 | Run(A_LoopFileFullPath)
120 | }
121 | }
--------------------------------------------------------------------------------
/docs/history.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 更新日志
3 | icon: clock
4 | ---
5 |
6 | ## [Starter v0.5.3](https://github.com/AkiChase/Starter/releases/tag/v0.5.3) (2023-05-12)
7 | 1. 新增: 窗口切换插件 - [相关文档](https://AkiChase.github.io/Starter/plugin/window-switcher)
8 | 2. 修复: PluginHelper模块注释内容错误
9 |
10 | ## [Starter v0.5.2](https://github.com/AkiChase/Starter/releases/tag/v0.5.2) (2023-05-11)
11 |
12 | 1. 新增: 关键词快捷键 - [相关文档](https://AkiChase.github.io/Starter/guide/setting/#控制)
13 | 2. 优化: 稳定搜索框自动隐藏的时间
14 | 3. 修复: 文件选择对话框导航在某些窗口不生效的问题
15 | 4. 修复: 智能模式下打开文件搜索插件的错误
16 |
17 | ## [Starter v0.5.1](https://github.com/AkiChase/Starter/releases/tag/v0.5.1) (2023-04-16)
18 |
19 | 1. 新增: 完善文档内容 - [插件开发](https://AkiChase.github.io/Starter/dev/)
20 | 2. 新增: 完善文档内容 - [API](https://AkiChase.github.io/Starter/api/)
21 | 3. 新增: pluginHelper插件工具模块完整注释
22 | 4. 修复: 修复双击类型快捷键,双击期间按下其他按键仍会触发的问题
23 | 5. 修复: 导入数据界面按钮失效
24 | 6. 修复:显示插件模式切换错误
25 |
26 | ## [Starter v0.5.0](https://github.com/AkiChase/Starter/releases/tag/v0.5.0) (2023-04-14)
27 |
28 | 1. 新增:添加工作窗口信息作为插件智能模式匹配条件
29 | 2. 新增:文件搜索插件,新增explorer工作窗口下在当前文件夹搜索
30 | 3. 新增:文件选择对话框导航插件,效果类似于Listary的Ctrl+G功能
31 | 4. 新增:使用ImagePut作为图片相关处理工具,添加相关PluginHelper API
32 | 5. 新增:新增OCR识别文字插件,调用百度OCR进行图片识别
33 | 6. 新增:设置界面,添加快捷键修改功能,丰富快捷键选择
34 | 7. 新增:更新相关插件文档,设置界面文档
35 | 8. 优化:提升使用体验,修复快捷键卡顿问题
36 | 9. 修复:修复已知问题
37 |
38 | ## [Starter v0.4.1](https://github.com/AkiChase/Starter/releases/tag/v0.4.1) (2023-04-11)
39 |
40 | 1. 新增: 导入用户数据插件前,询问是否导入,避免误操作覆盖插件
41 | 2. 新增: [Starter 文档](https://AkiChase.github.io/Starter/)✨
42 | 3. 新增: 自启界面添加打开自启目录菜单项
43 | 4. 修复: 文件搜索插件错误
44 |
45 | ## [Starter v0.4.0](https://github.com/AkiChase/Starter/releases/tag/v0.4.0) (2023-04-08)
46 |
47 | 1. 新增: 长按获取选中内容,并粘贴到智能模式搜索框中。若未选中任何内容则获取工作窗口信息,进入窗口匹配模式
48 | 2. 新增: 可粘贴文件、位图(图片)到智能、插件模式搜索框中
49 | 3. 新增: 可拖拽文件到智能、插件模式搜索框中
50 | 4. 新增: 点击粘贴的文件图标,显示文件信息
51 | 5. 新增: 窗口匹配模式下点击智能模式图标,显示工作窗口信息
52 | 6. 新增: 文件搜索插件支持粘贴单文件夹,快速在文件夹内搜索
53 | 7. 新增: 搜索界面中使用Alt+N (N为0-9, 0表示第10行) 快速选中第N行
54 | 8. 调整: 修改插件智能模式匹配条件为自定义函数匹配
55 | 9. 修复: 修复已知问题,优化使用细节
56 |
57 | ## [Starter v0.3.3](https://github.com/AkiChase/Starter/releases/tag/v0.3.3) (2023-04-06)
58 |
59 | 1. 新增: "文件搜索"插件,可调用Everything进行文件搜索
60 | 2. 调整: 将“双击Left”快捷键调整为“双击Right”
61 | 3. 调整: 增加软件搜索界面尺寸,显示更多内容
62 | 4. 调整: 更新“demo”插件示例,修复问题
63 | 5. 优化: 优化细节使用体验
64 | 6. 修复: 修复已知问题
65 |
66 | ## [Starter v0.3.2](https://github.com/AkiChase/Starter/releases/tag/v0.3.2) (2023-04-04)
67 |
68 | 1. 新增: "网页搜索"插件新增必应搜索
69 | 2. 修复: 删除、编辑选中项错位等bug
70 | 3. 修复: 网页搜索插件bug
71 |
72 | ## [Starter v0.3.1](https://github.com/AkiChase/Starter/releases/tag/v0.3.1) (2023-04-04)
73 |
74 | 1. 调整: 调整图标尺寸
75 | 2. 修复: 修复bugs
76 |
77 | ## [Starter v0.3.0](https://github.com/AkiChase/Starter/releases/tag/v0.3.0) (2023-04-04)
78 |
79 | 1. 新增: 插件模式及相关插件API
80 | 2. 新增: "网页搜索"插件,支持百度、谷歌搜索,可使用代理
81 | 3. 调整: 更新demo.ahk插件示例
82 | 4. 调整: 搜索界面自动隐藏后15s内保留搜索结果
83 | 5. 调整: 热键"Shift+Esc" 改为 "Esc"
84 | 6. 调整: 使用更具统一风格的图标
85 | 7. 修复: 修复小bug
86 |
87 | ## [Starter v0.2.2](https://github.com/AkiChase/Starter/releases/tag/v0.2.2) (2023-04-02)
88 |
89 | 1. 新增: 定时提醒插件
90 | 2. 新增: 使用更美观的消息通知组件
91 | 3. 调整: 更新demo插件示例至v0.0.2
92 | 4. 修复: 添加检查更新无响应的消息反馈
93 | 5. 修复: 修复快捷方式图标不正确问题
94 | 6. 优化: 使用更简单的插件图标加载方式
95 |
96 | ## [Starter v0.2.1](https://github.com/AkiChase/Starter/releases/tag/v0.2.1) (2023-04-01)
97 |
98 | 1. 调整: 修改软件图标
99 |
100 | ## [Starter v0.2.0](https://github.com/AkiChase/Starter/releases/tag/v0.2.0) (2023-04-01)
101 |
102 | 1. 新增: 插件界面
103 | 2. 新增: 长按“CapsLK”以智能模式搜索选中内容
104 | 3. 优化: 用户数据导入导出优化,使用7zip进行压缩、解压,支持导入/导出数据、插件
105 | 4. 调整: 取消文件编译,使用AutoHotkey64.exe直接运行源码
106 | 5. 调整: 移动"自启目录"到“用户数据”目录下
107 | 6. 调整: reg匹配模式下搜索结果排序微调
108 |
109 | ## [Starter v0.1.1](https://github.com/AkiChase/Starter/releases/tag/v0.1.1) (2023-02-20)
110 |
111 | 1. 修复: 错误修复
112 |
113 | ## [Starter v0.1.0](https://github.com/AkiChase/Starter/releases/tag/v0.1.0) (2023-02-20)
114 |
115 | 1. 新增: 智能模式
116 | 2. 新增: 关于界面,检查更新
117 | 3. 新增: 用户数据导入、导出
118 | 4. 调整: 完善README
119 | 5. 优化: UI细节
120 |
121 | ## [Starter v0.0.5](https://github.com/AkiChase/Starter/releases/tag/v0.0.5) (2023-02-08)
122 |
123 | 1. 修复: 一些小bug,细节优化
124 | 2. 新增: 双击自启界面列表项可以启动对应项
125 |
126 | ## [Starter v0.0.4](https://github.com/AkiChase/Starter/releases/tag/v0.0.4) (2023-01-17)
127 |
128 | 1. 调整: 添加搜索框50ms防抖
129 | 2. 修复: 解决无启动项时无法打开编辑界面的问题
130 | 3. 修复: 添加启动项目失败的异常处理
131 |
132 | ## [Starter v0.0.3](https://github.com/AkiChase/Starter/releases/tag/v0.0.3) (2023-01-09)
133 |
134 | 1. 调整: 移除搜索框防抖
135 | 2. 修复: lnk文件图标问题
136 |
137 | ## [Starter v0.0.2](https://github.com/AkiChase/Starter/releases/tag/v0.0.2) (2023-01-05)
138 |
139 | 1. 修复:一些小bug
140 |
141 | ## [Starter v0.0.1](https://github.com/AkiChase/Starter/releases/tag/v0.0.1) (2023-01-04)
142 |
143 | 1. 发布: 第一个版本
144 |
--------------------------------------------------------------------------------
/src/Plugin/定时提醒.ahk:
--------------------------------------------------------------------------------
1 | /**
2 | * @Name: 定时提醒.ahk
3 | * @Version: 0.0.1
4 | * @Author: AkiChase
5 | * @LastEditors: AkiChase
6 | * @LastEditTime: 2023-04-06
7 | * @Description: 定时提醒 可设置定时时间和提示语
8 | */
9 |
10 | /*
11 | ===Starter Plugin Info==>
12 | {
13 | "author": "AkiChase",
14 | "version": "0.0.1",
15 | "introduction": "定时提醒, 可设置定时时间和提示语",
16 | "icon": "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAABXJJREFUWEfNVwtsU2UU/s7fhQUYEGAbDw0D5CGi8wEhPBKdQduuBcNYr0YUAoqIkJigYAQlYJwQohgjykvi2FQI3tuBQm97K2QEGApmTkMcTweyBcSMgYypY9x7zN+u2K3tVh4J3KRJe//zn/Od7//+c04Jt/mh2xwfdx6A3FzlPousBQByQNTAjKAl6KOdO9TT18PW+Ly8nimNKevA1igmSifgOIj3COvv+X6/vzHiqwUDdrdnLDHKWgciUC2I5wR8mpoMCIdD6QEb7wTwcBz7ckPXRsYAyMlR0lI74ygsToXgzWSS17JRvbCsWUwkPy/TVWgsOJeAmSDuC1CfsCM+C6YzIHzFNtolmpqYha2UiGQyJWTRXhassAUFhBzpK+hT18ud1xhwupUXmXkDwBsN3TsjGrnTmZ8NoqlMmAqgV3ssEPN6S4j1QZ9aHm3ryFUKQPwWQNsMXc1rAcDh8nwNQAHYY+heb2Sj0+VZyMCyKEclTPSTMK0KZq64mppqiaamB0kgm5gl0Dww0pqdLwro2vJrvpyT+rNIOQngoqFr3VsByC8EaDoxVgX82qty0e7yLCVgSbODI8y0OOhXtbYYaNbR+wDGhg4HeCeoa0vld6dr8nSGKARzteH39msBIDqYoWvknKCMYYv3x8skBM5u70y2rrPJxocDO7x6a1BOl/Iag1eG9hOelgK2uxUfMbsA8hq66mkBQP5w5HpKIZDR2IlGpzbwHqliJpoT9KlrYgI4PTksUArGbsOvPR6PlYJZj32+tyYjpCcmGklsrQEo5Wqq+eSurVvPxwCQL2QdMImfJ2BhNNIbAcBFmdkFZcN+2VeTASlMQSkrTdOqNQy1LuYaRl64XM8MMWEeBeiCSWLcTt+Ww/GycybBAG/K7HX6fMc/5u16xGq4YhM22Ibq+pZj0f5iSrEj1/M6CB8AvMnQvc8lElwyAELUF2Xwih+GofT3TKnI+YZfC+kiIQMhHRByCFgc0LWCmwHAhRkPQaBiU2UWig/1lwBi9BLLgCtf0j+EgYlBXdtxkwCmQ6DwwJmeWLL3fsnHMUP3Dm2bAZfnEoAuMK2+hlFyNhkArW0IOCRrCRenrwDTG3X/dMCUb8dIs3pD17reEgDhrsm/JgIoEwg8u28tiJ+q+7cDpnyTNIDwEZDF7kAgtsBEB7S7lRHC5C6tQXAHqgnkl94L0Ha59uPZHli854Ekj6BZhEz0dtCnvpcwwzYW+ONBqej2Vw2AdGm2ubIfig4NSFaEnpkAPpNt1NC1/BsCUJQhm9nkyN53y4ajrCaE5SVD1za0qQH7RGUAmVwVLpPWjIBesvF6QHBRejFAsm2Hnu9O9sbKg2Hhs40GBrershsmrgNyxe7yLJOl2Ea4pPu0bskA4OKMuWDI1ttCE8rWcai/kiK74vKgri2Kc2Ni3ecoSlqkGWV1baheZz8wjl6oq44R25c97oZlk/KeAMa01utv7s7Gz+dCbb+isTM9ultVLycFQBo5ncoYFrwNQOb4rHPmgtFHjoNwCowTYHQE8WiAhidiZ1X5YPhO9JXLf5JFkwIB9ft4tm2O5U63R2GGnJSQ3rER80Ydw4je1xpZ3NhVF9PwSflgVNaG601kFkgENCEAhyt/NkDhOUBmTRgkv469qxZZ3RowqPtlDO1ZDwHG8Qtd8NvFNFRf6oT9NelmoylsDFQRMDAcmF8xdO/apBloOYrRNENXv7C7PBMImCNHhnZEeZDZ+jDoL9nicClTAS4O5/D/aJbMLfhUBotHn8Od/wRbGEyC7pEZMhOB+BQxn7RAVa0bWOQYGVgd1LW5SYnQ4ZjcRwhbd79frUzmCrZnE+oblnkhXnO78/4btpfNrV7/D4b1gz/RPr0sAAAAAElFTkSuQmCC"
17 | }
18 | <==Starter Plugin Info===
19 | */
20 | #Include ..\Utils\PluginHelper.ah2
21 | PluginHelper.addEntryFunc((*) => Plugin_定时提醒.main()) ; 添加入口函数等待执行
22 |
23 | class Plugin_定时提醒 {
24 | static time := 30
25 | static words := "起来走走, 休息一下眼睛!`n记得要喝水, 保持身体 hydrated!"
26 | static state := false
27 | static menu := Menu()
28 |
29 |
30 | static toggleState() {
31 | if (this.state) {
32 | SetTimer(this.f, 0) ;关闭计时器
33 | this.menu.Uncheck("开启")
34 | } else {
35 | SetTimer(this.f, this.time * 60 * 1000) ;开启计时器
36 | PluginHelper.Utils.tip("定时提醒已开启", "提醒间隔时间: " this.time "分钟", 2500)
37 | this.menu.check("开启")
38 | }
39 | this.state := !this.state
40 | }
41 |
42 | static setting() {
43 | g := Gui(, "定时提醒设置")
44 | g.BackColor := "FFFFFF"
45 | g.SetFont("s14 q5 c333333", "NSimSun")
46 | g.SetFont(, "雅痞-简") ;优先使用更好看的字体
47 | g.AddText(, "提醒间隔时间(min)")
48 | timeEdit := g.AddEdit("w300 ", this.time)
49 | g.AddText(, "提醒内容")
50 | wordsEdit := g.AddEdit("w300 h100", this.words)
51 | f(*) {
52 | this.time := timeEdit.Value, this.words := wordsEdit.Value, this.state := false
53 | this.storeData()
54 | g.Destroy()
55 | this.toggleState()
56 | }
57 | g.AddButton("x135", "保存").OnEvent("Click", f)
58 | g.OnEvent("Close", (*) => g.Destroy())
59 | g.Show()
60 | }
61 |
62 | static storeData() {
63 | SplitPath(A_LineFile, , &dir)
64 | dataPath := dir "\定时提醒配置.txt"
65 | f := FileOpen(dataPath, "w")
66 | f.Write(this.time "`r`n" this.words)
67 | f.Close()
68 | }
69 |
70 | static loadDataAndStart() {
71 | SplitPath(A_LineFile, , &dir)
72 | dataPath := dir "\定时提醒配置.txt"
73 | if (FileExist(dataPath)) {
74 | content := FileRead(dataPath)
75 | sep := "`r`n"
76 | i := InStr(content, sep)
77 | this.time := Float(SubStr(content, 1, i - 1))
78 | this.words := SubStr(content, i + StrLen(sep))
79 | this.toggleState()
80 | } else {
81 | this.setting()
82 | }
83 | }
84 |
85 | static main() {
86 | FileEncoding("UTF-8-RAW")
87 | this.menu.Add("开启", (*) => this.toggleState())
88 | this.menu.Add("设置", (*) => this.setting())
89 | PluginHelper.pluginMenu.Add("定时提醒", this.menu)
90 | this.f := (*) => PluginHelper.Utils.tip(Format("定时提醒: {}min", this.time), this.words)
91 | this.loadDataAndStart()
92 | }
93 | }
--------------------------------------------------------------------------------
/docs/api/utils/other.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 其他
3 | author: AkiChase
4 | order: 1
5 | date: 2023-04-14
6 | ---
7 |
8 | ## chineseFirstChar(str){#chineseFirstChar}
9 |
10 | 将文本的中文部分转换为拼音首字母,多音字转换不准确
11 |
12 | - 参数
13 | - \{String\} `str`: 要进行转换的文本
14 |
15 | - 返回值
16 | - \{String\} 将中文部分转为拼音首字母后的字符串
17 |
18 | ## strStartWith(ori, sub, caseSense := false){#strStartWith}
19 |
20 | ori是否以sub开头
21 |
22 | - 参数
23 | - \{String\} `ori`: 进行判断的文本
24 | - \{String\} `sub`: 开头的文本
25 | - \{Bool\} `caseSense`: 是否大小写敏感
26 |
27 | - 返回值
28 | - \{Bool\} `true` 则 ori 以 sub 开头
29 |
30 | ## pathStrCompact(fullPath, maxChars){#pathStrCompact}
31 |
32 | 压缩文件路径文本,使其不超过最大字符数
33 |
34 | - 参数
35 | - \{String\} `fullPath`: 文件完整路径
36 | - \{Number\} `maxChars`: 压缩后最大字符数
37 |
38 | - 返回值
39 | - \{String\} 压缩后的文件路径文本
40 |
41 | ## copyToClipboard(filePath, cut := false){#copyToClipboard}
42 |
43 | 复制指向文件的路径到剪切板,可选择进行剪切而不是复制
44 |
45 | - 参数
46 | - \{String\} `filePath`: 指向文件的路径
47 | - \{Bool\} `cut`: 是否剪切,默认为 `false`
48 |
49 | - 返回值
50 | - 无
51 |
52 | ## startFile(path, workingDir := "", options := "", beforeRun?){#startFile}
53 |
54 | 运行指定路径的文件
55 |
56 | - 参数
57 | - \{String\} `path`: 文件路径
58 | - \{String\} `workingDir`: 工作目录,见[Run / RunWait - 语法 & 使用 | AutoHotkey v2](https://orz707.gitee.io/v2/docs/commands/Run.htm)
59 | - \{String\} `options`: 见[Run / RunWait - 语法 & 使用 | AutoHotkey v2](https://orz707.gitee.io/v2/docs/commands/Run.htm)
60 | - \{[Closure](https://orz707.gitee.io/v2/docs/Functions.htm#closures)\} `beforeRun`: 运行文件前执行的处理函数
61 |
62 | - 返回值 \{String\}
63 | - PID 如果无法确定 PID, 返回空字符串
64 |
65 | ## openFileInFolder(path){#openFileInFolder}
66 |
67 | 在资源管理器中显示指定路径的文件
68 |
69 | - 参数
70 | - \{String\} `path`: 文件路径
71 |
72 | - 返回值
73 | - 无
74 |
75 | ## UrlEncode(str){#UrlEncode}
76 |
77 | 对给定字符串进行 URL 编码
78 |
79 | - 参数
80 | - \{String\} `str`: 需要编码的字符串
81 |
82 | - 返回值
83 | - \{String\} URL 编码后的字符串
84 |
85 | ## UrlDecode(str){#UrlDecode}
86 |
87 | 对给定字符串进行 URL 解码
88 |
89 | - 参数
90 | - \{String\} `str`: 需要解码的字符串
91 |
92 | - 返回值
93 | - \{String\} URL 解码后的字符串
94 |
95 | ## globalMatch(Haystack, NeedleRegEx, StartingPos := 1){#globalMatch}
96 |
97 | 从给定字符串的指定起始位置处查找符合正则表达式的所有子字符串,即正则全局模式
98 |
99 | 参数可以参考[RegExMatch - 语法 & 使用 | AutoHotkey v2](https://orz707.gitee.io/v2/docs/commands/RegExMatch.htm)
100 |
101 | - 参数
102 | - \{String\} `Haystack`: 给定字符串
103 | - \{RegExp\} `NeedleRegEx`: 正则表达式对象
104 | - \{Number\} `StartingPos`: 起始位置,默认为 1
105 |
106 | - 返回值
107 | - \{Array\} 匹配对象数组,参考[匹配对象 - MatchObject](https://orz707.gitee.io/v2/docs/commands/RegExMatch.htm#MatchObject)
108 |
109 | ## Jxon_Load(src, args*){#Jxon_Load}
110 |
111 | 将给定 JSON 文本数据加载成为 AutoHotkey 变量
112 |
113 | :::warning
114 | 对象转换后都会变成 Map 类型
115 | :::
116 |
117 | - 参数
118 | - \{String\} `src`: JSON 文本的引用(因为 AHK 中没有传递引用的概念)
119 | - `args`:额外参数列表,需要则查看 `src\Utils\JXON.ah2` 源码
120 |
121 | - 返回值
122 | - AutoHotkey 变量
123 |
124 | ## Jxon_Dump(obj, indent := "", lvl := 1){#Jxon_Dump}
125 |
126 | 将给定的 AutoHotkey 变量转换为 JSON 文本
127 |
128 | :::warning
129 | 不支持 Object 类型,请使用 Map 类型代替
130 | :::
131 |
132 | - 参数
133 | - \{*\} `obj`:需要转换的 AutoHotkey 变量
134 | - \{String\} `indent`:缩进用的字符串,默认为空字符串
135 | - \{Number\} `lvl`:当前递归的深度,默认为 1
136 |
137 | - 返回值
138 | - \{String\} 转换后的 JSON 文本
139 |
140 | ## WinHttp(args*){#WinHttp}
141 |
142 | 参考 WinHttp 库函数源码,`src\Utils\WinHttp.ah2`
143 |
144 | - 参数
145 | - `args`:参数列表,根据不同的请求类型和参数,具体参数需要参考文档说明
146 |
147 | - 返回值
148 | - \{WinHttp\} WinHttp 对象
149 |
150 | ## associatedHIcon(filePath){#associatedHIcon}
151 |
152 | 获取 Windows 中与指定文件关联的图标,并返回一个 hIcon 句柄
153 |
154 | - 参数
155 | - \{String\} `filePath`:需要获取关联图标的文件路径
156 |
157 | - 返回值
158 | - \{Int\} 获取到的关联图标的 HICON 句柄
159 |
160 | # base64ToHICON(base64){#base64ToHICON}
161 |
162 | 载入无头部的图片base64文本,返回 hIcon 句柄
163 |
164 | ## 参数
165 |
166 | - \{String\} `base64`:无头部的图片base64文本
167 |
168 | ## 返回值
169 |
170 | - \{Int\} 载入后图标的 HICON 句柄
171 |
172 | ## tip(title, content, time?, unique := false){#tip}
173 |
174 | 在右下角弹出一条 `WiseGui` 通知,可设置标题、内容、计时消失时间、是否唯一,返回该通知的 id
175 |
176 | - 参数
177 | - \{String\} `title`:通知标题
178 | - \{String\} `content`:通知内容
179 | - \{Number\} `time`:计时消失时间(单位为毫秒),选填,默认为 0,表示不消失
180 | - \{Boolean\} `unique`:是否保证唯一(不会被覆盖),选填,默认为 false
181 |
182 | - 返回值
183 | - \{String\} 该通知窗口的 id(如果 `unique` 为 true,则返回 A_TickCount 值作为 id)
184 |
185 | ## quickSort(arr, fn){#quickSort}
186 |
187 | 对给定的数组进行**快速排序**(不生成副本),并返回排序后的数组
188 |
189 | ```ahk
190 | ; 升序排序示例
191 | arr:=[1,9,2,8,3,7]
192 | QuickSort(arr, (a,b)=>a-b)
193 | ```
194 |
195 | - 参数
196 | - `arr`:待排序数组
197 | - `fn`:比较函数,接受两个参数 itemA 和 itemB,返回值为数字类型,表示 itemA 和 itemB 的大小关系。如果 itemA 大于 itemB,返回正数;如果 itemA 小于 itemB,返回负数;如果 itemA 等于 itemB,返回 0。
198 |
199 | - 返回值
200 | - 排序后的数组
--------------------------------------------------------------------------------
/src/Gui/PluginGui.ah2:
--------------------------------------------------------------------------------
1 | /**
2 | * @Name: PluginGui
3 | * @Version: 0.0.1
4 | * @Author: AkiChase
5 | * @LastEditors: AkiChase
6 | * @LastEditTime: 2023-04-13
7 | * @Description: 插件界面
8 | */
9 |
10 | class PluginGui {
11 | ; static gui:=unset
12 | ; static LV:=unset
13 | static pluginList := []
14 | static IL := 0
15 |
16 | static init() {
17 | if (!IsSet(DEBUG) || !DEBUG)
18 | this.loadPlugins()
19 | this.gui := Gui("-Resize", "插件界面")
20 | this.gui.SetFont("s12 q5 c333333", "NSimSun")
21 | this.gui.SetFont(, "雅痞-简") ;优先使用更好看的字体
22 | this.gui.BackColor := "FFFFFF"
23 |
24 | this.LV := this.gui.Add("ListView", "x0 y0 w500 h320 -E0x200 Grid", ["名称", "启用", "作者", "版本", "介绍"])
25 | this.LV.OnEvent("DoubleClick", (_LV, rowNum) => this.togglePluginEnabled(rowNum))
26 |
27 | this.gui.AddButton("x120 y330", "刷新列表").OnEvent("Click", (*) => this.refreshPluginsList())
28 | this.gui.AddButton("x280 y330", "保存重载").OnEvent("Click", (*) => this.storeAndReload())
29 |
30 | this.gui.OnEvent("Close", (guiObj) => guiObj.Hide())
31 | this.gui.Show("w500 h380 Hide")
32 |
33 | this.refreshPluginsList()
34 | }
35 |
36 | static loadPlugins() {
37 | fList := []
38 | pluginList := []
39 | for name in GlobalData.config["plugin"] {
40 | path := GlobalData.pluginDir "\" name
41 | if (FileExist(path)) ; 仅添加有效的文件
42 | fList.Push(GlobalData.pluginDir "\" name), pluginList.Push(name)
43 | }
44 |
45 | ; 如果插件列表出现变动
46 | if (pluginList.Length != GlobalData.config["plugin"].Length) {
47 | GlobalData.config["plugin"] := pluginList
48 | GlobalData.storeConfig()
49 | }
50 | Loader.loadFromFiles(fList)
51 | }
52 |
53 | static storeAndReload() {
54 | plugin := []
55 | for info in this.pluginList {
56 | if (info["enabled"]) {
57 | plugin.Push(info["name"])
58 | }
59 | }
60 | GlobalData.config["plugin"] := plugin
61 | Reload()
62 | }
63 |
64 | static togglePluginEnabled(rowNum) {
65 | if (rowNum > 0) {
66 | flag := this.pluginList[rowNum]["enabled"]
67 | this.pluginList[rowNum]["enabled"] := !flag
68 | this.LV.Modify(rowNum, , , flag ? "" : "是")
69 | this.gui.Title := "插件界面 *未保存"
70 | }
71 | }
72 |
73 | static refreshPluginsList() {
74 | this.LV.Opt("-Redraw")
75 | this.LV.Delete()
76 | if (this.IL)
77 | IL_Destroy(this.IL)
78 | this.IL := IL_Create()
79 | this.LV.SetImageList(this.IL)
80 |
81 |
82 | ; 插件文件后缀判断
83 | fList := []
84 | Loop Files, GlobalData.pluginDir "\*.*" {
85 | if (InStr(A_LoopFileExt, "ahk") || InStr(A_LoopFileExt, "ah2"))
86 | fList.Push(A_LoopFileFullPath)
87 | }
88 |
89 | this.pluginList := []
90 |
91 | if (!fList.Length) {
92 | this.LV.Opt("Redraw")
93 | return
94 | }
95 |
96 | s := "===Starter Plugin Info==>", e := "<==Starter Plugin Info===", len := StrLen(s)
97 | pluginCopy := GlobalData.config["plugin"].Clone()
98 |
99 |
100 | for f in fList {
101 | content := FileRead(f)
102 | l := InStr(content, s) + len, r := InStr(content, e)
103 | if (r <= l || l == len) ;未解析到插件信息,跳过
104 | continue
105 |
106 | content := SubStr(content, l, r - l)
107 | info := Jxon_Load(&content)
108 |
109 | ; 插件信息格式不正确,跳过
110 | if (Type(info) != "Map")
111 | continue
112 |
113 | SplitPath(f, &name)
114 | info["name"] := name
115 |
116 | ; 默认值
117 | for name in ["author", "version", "introduction", "icon"] {
118 | if (!info.Has(name))
119 | info[name] := ""
120 | }
121 |
122 | info["filePath"] := f
123 |
124 | ; 加载图标至图像列表
125 | base64 := info["icon"]
126 | info["iconBase64"] := base64
127 | if (base64) {
128 | hIcon := LoadIconFromBase64(base64, 32, 32)
129 | info["icon"] := IL_Add(this.IL, "HICON:*" hIcon)
130 | info["iconHIcon"] := hIcon
131 | } else
132 | info["icon"] := 0
133 |
134 | info["enabled"] := this._isPluginEnabled(pluginCopy, info["name"]) ? 1 : 0
135 | this.pluginList.Push(info)
136 | }
137 |
138 | this.LV.SetImageList(this.IL)
139 | for info in this.pluginList {
140 | this.LV.Add("Icon" info["icon"], A_Space info["name"],
141 | info["enabled"] ? "是" : "",
142 | info["author"], info["version"], info["introduction"])
143 | }
144 |
145 |
146 | this.LV.ModifyCol()
147 | this.LV.ModifyCol(2, "AutoHdr Center")
148 |
149 | this.LV.Opt("Redraw")
150 |
151 | this.gui.Title := "插件界面"
152 | }
153 |
154 | static _isPluginEnabled(arr, name) {
155 | for i, v in arr {
156 | if (name == v) {
157 | arr.RemoveAt(i)
158 | return true
159 | }
160 | }
161 | return false
162 | }
163 |
164 | static showGui() {
165 | this.gui.Show()
166 | }
167 | }
--------------------------------------------------------------------------------
/src/Gui/TrayMenu.ah2:
--------------------------------------------------------------------------------
1 | /**
2 | * @Name: TrayMenu
3 | * @Version: 0.0.2
4 | * @Author: AkiChase
5 | * @LastEditors: AkiChase
6 | * @LastEditTime: 2023-04-14
7 | * @Description: 菜单栏
8 | */
9 |
10 | class TrayMenu {
11 | ; static menu := unset
12 | ; static 7z:=unset
13 | ; static gui:=unset
14 |
15 | static init() {
16 | A_IconTip := "Starter"
17 |
18 | this.menu := A_TrayMenu
19 | this.menu.Delete()
20 |
21 | this.menu.Add("搜索界面`t双击CapsLock", (*) => StartupMode.showGui())
22 | this.menu.Add("编辑启动模式`t(&2)", (*) => StartupEditGui.showGui())
23 | this.menu.Add("编辑智能模式`t(&3)", (*) => IntelligentEditGui.showGui())
24 | this.menu.Add("自启界面`t(&4)", (*) => BootGui.showGui())
25 | this.menu.Add("插件界面`t(&5)", (*) => PluginGui.showGui())
26 | this.menu.Add("设置界面`t(&6)", (*) => SettingGui.showGui())
27 | this.menu.Add("关于界面`t(&7)", (*) => AboutGui.showGui())
28 | this.menu.Add()
29 | this.menu.Add("开机启动", (*) => this.toggleStartupState())
30 |
31 | userDataMenu := Menu()
32 | userDataMenu.Add("打开数据目录`t(&1)", (*) => Start.startFile(GlobalData.dataDir))
33 | userDataMenu.Add("导出用户数据`t(&2)", (*) => this.guideGui(0))
34 | userDataMenu.Add("导入用户数据`t(&3)", (*) => this.guideGui(1))
35 | this.menu.Add("用户数据`t(&D)", userDataMenu)
36 |
37 | this.menu.Add("退出`t(&X)", (*) => ExitApp())
38 |
39 | this.menu.SetIcon("1&", GlobalData.imgDir "\Starter.png")
40 | this.menu.SetIcon("2&", GlobalData.imgDir "\edit.ico")
41 | this.menu.SetIcon("3&", GlobalData.imgDir "\edit.ico")
42 | this.menu.SetIcon("4&", GlobalData.imgDir "\run.ico")
43 | this.menu.SetIcon("5&", GlobalData.imgDir "\plugin.ico")
44 | this.menu.SetIcon("6&", GlobalData.imgDir "\setting.ico")
45 | this.menu.SetIcon("7&", GlobalData.imgDir "\info.ico")
46 |
47 | if (this.getStartupState())
48 | this.menu.Check("开机启动")
49 |
50 | this.menu.Default := "1&"
51 |
52 | A_IconHidden := false ; 重载结束后显示图标
53 | }
54 |
55 | /**
56 | * @param mode 0: 导出用户数据; 1: 导入用户数据
57 | */
58 | static guideGui(mode := 0) {
59 | g := Gui(, mode ? "导入用户数据" : "导出用户数据")
60 | g.BackColor := "FFFFFF"
61 | g.SetFont("s12 q5 c333333", "NSimSun")
62 | g.SetFont(, "雅痞-简") ;优先使用更好看的字体
63 |
64 | g.AddText("x10 y15", mode ? "数据路径" : "保存目录")
65 | pathEdit := g.AddEdit("xp+80 yp-5 w200 ReadOnly")
66 |
67 | g.AddButton("xp+220 yp-5", "选择").OnEvent("Click",
68 | (*) => mode ?
69 | pathEdit.Value := FileSelect(3, A_Desktop, "请选择用户数据文件", "zip (*.zip)") :
70 | pathEdit.Value := DirSelect("*" A_Desktop, , "请选择保存目录")
71 | )
72 |
73 | g.AddText("x10 yp+50", mode ? "导入内容选项:" : "导出内容选项:")
74 |
75 | checkboxList := [
76 | g.AddCheckbox("x75 yp+30 Checked", "用户数据"),
77 | g.AddCheckbox("xp+150 yp", "插件"),
78 | ]
79 |
80 | options() {
81 | out := []
82 | for c in checkboxList
83 | out.Push(c.Value)
84 | return out
85 | }
86 |
87 | g.AddButton("x130 yp+40 h27 w100", mode ? "导 入" : "导 出").OnEvent("Click",
88 | (*) => mode ? this.importUserData(pathEdit.Value, options()) : this.backupUserData(pathEdit.Value, options(), g)
89 | )
90 |
91 | g.OnEvent("Close", (*) => g.Destroy())
92 | g.Show()
93 | }
94 |
95 | ; 导出用户数据
96 | static backupUserData(path, options, g) {
97 | if (!this.HasOwnProp("7z"))
98 | this.zipper := SevenZip()
99 | fList := []
100 | if (options[1])
101 | fList.Push(GlobalData.dataDir)
102 | if (options[2])
103 | fList.Push(GlobalData.pluginDir)
104 |
105 | if (!fList.Length) {
106 | Tip.show("提示", "至少选择一项内容", 1500)
107 | return
108 | }
109 | if (!StrLen(path)) {
110 | Tip.show("提示", "请选择保存目录", 1500)
111 | return
112 | }
113 |
114 | newPath := path "\Starter_Data_" A_Now ".zip"
115 |
116 | _files := ""
117 | for v in fList
118 | _files .= v "`n"
119 | this.zipper.Add(newPath, _files, "-tzip -r -mx5 -mmt=2")
120 | g.Destroy()
121 | Tip.show("提示", "用户数据已导出: " newPath, 2500)
122 | }
123 |
124 | ; 导入用户数据
125 | static importUserData(path, options) {
126 | if (!this.HasOwnProp("7z"))
127 | this.zipper := SevenZip()
128 | if !(options[1] || options[2]) {
129 | Tip.show("提示", "至少选择一项内容", 1500)
130 | return
131 | }
132 | if (!StrLen(path)) {
133 | Tip.show("提示", "请选择保存目录", 1500)
134 | return
135 | }
136 |
137 | ; 若勾选插件且未确认则返回
138 | if (options[2] && MsgBox("导入插件时将用导入的数据覆盖所有同名文件,`n请勿在更新导入旧数据时使用, 避免旧版本插件覆盖新版本插件`n是否继续导入?", "提示", 0x2044) != "Yes") {
139 | return
140 | }
141 |
142 | tmpDir := A_Temp "\" A_TickCount "_starter"
143 | this.zipper.Extract(path, tmpDir, , "-aoa")
144 |
145 | res := ""
146 | if (options[1]) {
147 | if (FileExist(dir := tmpDir "\data"))
148 | DirCopy(dir, GlobalData.dataDir, true), res .= "用户数据导入成功`n"
149 | }
150 | if (options[2]) {
151 | if (FileExist(dir := tmpDir "\Plugin")) {
152 | DirCopy(dir, GlobalData.pluginDir, true), res .= "插件导入成功`n"
153 | }
154 | }
155 | DirDelete(tmpDir, true)
156 | if (StrLen(res)) {
157 | GlobalData.onExitHandler := (*) => 0
158 | Tip.show("提示", res "1s后软件重启")
159 | Sleep(1000)
160 | Reload()
161 | ;清除退出保存重启
162 | } else {
163 | Tip.show("提示", "导入失败")
164 | }
165 | }
166 |
167 | ; 获取加入注册表状态
168 | static getStartupState() {
169 | try
170 | return !!RegRead("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run", "Starter")
171 | catch
172 | return false
173 | }
174 |
175 | ; 切换开机启动
176 | static toggleStartupState() {
177 | if (this.getStartupState()) {
178 | RegDelete("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run", "Starter")
179 | this.menu.Uncheck("开机启动")
180 | } else {
181 | cmd := Format('"{}" "{}" "the_Startup"', GlobalData.rootDir "\src\AutoHotkey64.exe", GlobalData.rootDir "\src\Starter.ah2")
182 | RegWrite(cmd, "REG_SZ", "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run", "Starter")
183 | this.menu.check("开机启动")
184 | }
185 | }
186 | }
--------------------------------------------------------------------------------
/docs/dev/intelligent/advanced.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 进阶
3 | icon: circle-right
4 | author: AkiChase
5 | date: 2023-04-14
6 | order: 2
7 | ---
8 |
9 | 自定义匹配函数的进阶应用自然是各种匹配条件**混合使用**,此外还有一个排序优先级的概念。
10 |
11 | ## 匹配优先级
12 |
13 | `matchHandler` 自定义匹配函数返回的值 `!= 0` 则匹配,而返回值越大,当前插件智能项在搜索结果中越靠前
14 |
15 | :::tip
16 | 优先级约定俗成:
17 |
18 | - ` 1 ` - 当前匹配条件比较广泛,所以设为基础的优先级
19 | - ` 2 ` - 当前匹配条件稍微严格,设为更高的优先级
20 | - `>=3` - 当前匹配条件苛刻,必须排序靠前、置顶
21 | - `< 0` - 当前匹配条件下不需要优先,置于最后
22 | :::
23 |
24 | 给出一个常用的文本匹配的优先级示例
25 |
26 | ```ahk
27 | ; 添加插件智能项
28 | static addIntelligentItem() {
29 | ; 添加参照物
30 | PluginHelper.addPluginToIntelligentMode(this.name,
31 | "必定匹配且优先级为1.5的参照", ; 虽然可以使用浮点数,但是一般情况下都是用整数作为优先级
32 | (*) => 1.5, ; 无论如何都返回1.5
33 | (obj, *) => PluginHelper.Utils.tip(this.name, obj.title)
34 | )
35 |
36 | ; 自定义匹配函数
37 | matchHandler(obj, searchText, pastedContentType, *) { ; 使用*忽略多余参数
38 | ; 带有非文本类型的都不匹配
39 | if (pastedContentType != 'text')
40 | return 0
41 |
42 | if (PluginHelper.Utils.strStartWith("PPYXJ", searchText)) {
43 | ; 搜索文本PPYXJ的开头
44 | return 2 ; 更高优先级
45 | } else ; 否则优先级为1
46 | return 1 ; 基本优先级
47 |
48 | ; 注意,当未输入任何内容时,智能模式不会进行匹配,所以输入框为空时没有任何智能项
49 | }
50 |
51 | PluginHelper.addPluginToIntelligentMode(this.name,
52 | "匹配优先级",
53 | matchHandler,
54 | (obj, *) => PluginHelper.Utils.tip(this.name, obj.title)
55 | )
56 | }
57 | ```
58 |
59 | 上述代码效果如图
60 |
61 | 
62 |
63 | 
64 |
65 | 
66 |
67 |
68 | :::warning
69 | 当**未输入任何内容**(文件、图片也是输入内容的一种)时,智能模式不会进行匹配,所以输入框为空时**没有任何**智能项
70 | :::
71 |
72 | ## 混合匹配条件
73 |
74 | 混合匹配条件相对比较简单,是为之后**动态修改插件智能项**做铺垫
75 |
76 | 这里以[文件搜索](../../plugin/file-find.md)插件源码中的 `matchHandler` 稍作修改后作为例子
77 |
78 | ```ahk
79 | static addIntelligentItem() {
80 | ; 混合匹配条件
81 | matchHandler(obj, searchText, pastedContentType, pastedContent, workWinInfo, winInfoMatchFlag) {
82 | ; 是否为窗口匹配模式
83 | if (winInfoMatchFlag) {
84 | pName := workWinInfo.processName
85 | cName := workWinInfo.class
86 | path := workWinInfo.title ; 资源管理器的标题一般为当前文件夹路径
87 |
88 | ; 匹配资源管理器 且 标题指向的文件夹存在
89 | if ((pName == 'explorer.exe' || cName == "CabinetWClass" || cName == "ExploreWClass")
90 | && InStr(FileExist(path), "D")
91 | ) {
92 | if (PluginHelper.Utils.strStartWith("Everything", searchText)
93 | || PluginHelper.Utils.strStartWith("WJSS", searchText)) {
94 | ; 搜索文本为Everything或者WJSS的开头
95 | return 2 ; 更高优先级
96 | } else
97 | return 1 ; 基本优先级
98 | }
99 | } else {
100 | if (pastedContentType == 'text' && searchText) {
101 | return 1 ; 基本优先级
102 | } else if (pastedContentType == 'file' && pastedContent.Length = 1 && InStr(FileExist(pastedContent[1]), "D")) {
103 | if (PluginHelper.Utils.strStartWith("Everything", searchText)
104 | || PluginHelper.Utils.strStartWith("WJSS", searchText)) {
105 | ; 搜索文本为Everything或者WJSS的开头
106 | return 2 ; 更高优先级
107 | } else
108 | return 1 ; 基本优先级
109 | }
110 | }
111 | return 0 ; 其他情况不匹配
112 | }
113 |
114 | PluginHelper.addPluginToIntelligentMode(this.name,
115 | "混合匹配条件",
116 | matchHandler,
117 | (obj, *) => PluginHelper.Utils.tip(this.name, obj.title)
118 | )
119 | }
120 | ```
121 | 这个自定义匹配函数的处理方式看起来可能会让人有点疑惑,但匹配函数确确实实用了很多**混合匹配条件**。
122 |
123 | ## 动态修改插件智能项对象
124 |
125 | 自定义匹配函数在执行过程中能够直接访问到插件智能项对象 `obj`
126 |
127 | 所以,可以在匹配时中动态的修改 `obj` 属性,来达到存储数据、修改匹配表现的目的
128 |
129 | 续接之前的[混合匹配条件](#混合匹配条件)代码例子:
130 |
131 | ```ahk
132 | ; 添加插件智能项
133 | static addIntelligentItem() {
134 | ; 混合匹配条件
135 | matchHandler(obj, searchText, pastedContentType, pastedContent, workWinInfo, winInfoMatchFlag) {
136 | if (winInfoMatchFlag) {
137 | pName := workWinInfo.processName
138 | cName := workWinInfo.class
139 | path := workWinInfo.title ; 资源管理器的标题一般为当前文件夹路径
140 | ; 匹配资源管理器 且 标题指向的文件夹存在
141 | if ((pName == 'explorer.exe' || cName == "CabinetWClass" || cName == "ExploreWClass")
142 | && InStr(FileExist(path), "D")
143 | ) {
144 | if (PluginHelper.Utils.strStartWith("Everything", searchText)
145 | || PluginHelper.Utils.strStartWith("WJSS", searchText)) {
146 | ; 搜索文本为Everything或者WJSS的开头
147 | obj.matchData := { type: "window", searchTextFlag: false, path: path }
148 | obj.title := "在工作窗口目录内搜索" ; 修改显示标题
149 | return 2 ; 更高优先级
150 | } else {
151 | obj.matchData := { type: "window", searchTextFlag: true, path: path }
152 | obj.title := "在工作窗口目录内搜索输入内容" ; 修改显示标题
153 | return 1 ; 基本优先级
154 | }
155 | }
156 | } else {
157 | if (pastedContentType == 'text' && searchText) {
158 | obj.matchData := { type: "text" } ; 标记匹配类型,方便进入插件模式前区分进入方式
159 | obj.title := "使用Everything搜索输入内容" ; 修改显示标题
160 | return 1 ; 基本优先级
161 | } else if (pastedContentType == 'file' && pastedContent.Length = 1 && InStr(FileExist(pastedContent[1]), "D")) {
162 | if (PluginHelper.Utils.strStartWith("Everything", searchText)
163 | || PluginHelper.Utils.strStartWith("WJSS", searchText)) {
164 | ; 搜索文本为Everything或者WJSS的开头
165 | obj.matchData := { type: "file", searchTextFlag: false } ; 标记最后不要传入searchText
166 | obj.title := "使用Everything在文件夹内搜索" ; 修改显示标题
167 | return 2 ; 更高优先级
168 | } else {
169 | obj.matchData := { type: "file", searchTextFlag: true }
170 | obj.title := "使用Everything在文件夹内搜索输入内容" ; 修改显示标题
171 | return 1 ; 基本优先级
172 | }
173 | }
174 | }
175 | return 0 ; 不匹配
176 | }
177 |
178 | PluginHelper.addPluginToIntelligentMode(this.name,
179 | "匹配优先级",
180 | matchHandler,
181 | (obj, *) => PluginHelper.Utils.tip(this.name, obj.title)
182 | )
183 | }
184 | ```
185 | 上述代码中,有通过 `obj.matchData := { type: "xxx", searchTextFlag: false, path: "xxx" }` 来动态添加额外数据到 `obj` 对象中,
186 | 从而在 `runHandler(obj, searchText)` 运行函数中可以根据这些额外数据执行相应的操作。
187 |
188 | 当然,`matchData`这个键名不是固定的,你可以使用任意不与原 `obj` 属性冲突的键名。
189 |
190 | 此外,还有通过 `obj.title := "xxx"` 可以动态修改插件智能项的标题
191 |
192 | 如此,**只添加一个插件智能项,却能发挥出n个智能项的效果**
193 |
194 | :::warning
195 | 智能模式搜索框中的内容每次发生变动,Starter都会依次调用一遍每个插件智能项的自定义匹配函数,以判断插件智能项是否匹配。
196 |
197 | 所以匹配函数尽快返回结果,避免调用进度因此卡顿
198 | :::
--------------------------------------------------------------------------------
/src/Plugin/文件选择对话框导航.ahk:
--------------------------------------------------------------------------------
1 | /**
2 | * @Name: 文件选择对话框导航
3 | * @Version: 0.0.3
4 | * @Author: AkiChase
5 | * @LastEditors: AkiChase
6 | * @LastEditTime: 2023-05-13
7 | * @Description: 文件选择对话框路径导航
8 | */
9 |
10 | /*
11 | ===Starter Plugin Info==>
12 | {
13 | "author": "AkiChase",
14 | "version": "0.0.3",
15 | "introduction": "文件选择对话框路径导航",
16 | "icon": "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsTAAALEwEAmpwYAAAG9ElEQVRYhe2XaXRU5RnH52NdWm21otXiUitStVUpFYEQQmayzUzmzkxm5s7c2e6sSZAtQaJIFiVIilQRoT2np4rEgAZ6IIsLS+gCJCCYDbJobf3aD7InJAGCf5/3nXtvZsh8yAe+tXPO/8w9c07O7/e873Of941O9/8PfUQxPM3mDdkpQRZBCgZYCt1+vxqj08uT73C5HA7HLTcNbvMFc0U5fkmUY3AGo3AEInD4wyii2H0hWKUgBBZPABa3H2bRhwKndMRg8N52UwQI/OXGulKMDi4D/qPk30uUvEBZnMjXJTzfHInCLfuQX+Q+fFMkXHLsekfLUpzpWobNG+P4Qx1LDBvXR/HG6xFKGBvWhbChNoT3t4ZJIo5vDkcgBiXk28X+HJurOcfqbGIxWBxN+sKipmyzfW+W2cqz0Gjdm1kg7MnIt+zJyDXzzMsx1z+vL3CrK4BjHy/Bt90TAgy+cX1kQoDgv6+VSSA0IRCQULpYwroaL9ZVS6it8mBtlRtrK0W8VunCq2tcqHnFgZrVDlSvLkL1y3ZUvWxDZYUV5csFzM8zYa6+4BVNILH0Sycv/9el2vKrcDdVX7HKizMnZVzpk4F/kdhXLPT8VZASoPiBL31KJCUeYNDNs22TFXP0xv+yLUhpPtZ4Nq+c0nyF1His+UwuL0xOCSvLJXxL8EtdAQx1B3C1X06CKwIa3DshoMAxKOLQTjtoG8AFtm2Jo20XSwxtjSxRSgSHGsOUED1TPpIpQfxjdxBnGbw7yOFDPQEM9/pxbSAw5eox6OICc/T50LHqO1oXY6T/BZz5Io6znTFKFOfo+3xXFOc7w7jQRekO42J3iMAqPKjAA7hMAiOn/LQS/hsE0levCjyXrQq0LOb7PtpfygU0eFdEgUeS4DKBZQz3BBV4gMNZRk95aSV8aZY/tfqEgC0hwPZeFWCNN9pfQuCEgAbvCRM4NBl+KkjggAL3YYxy5bQX4wPe1Oo1AVETaNthxe8W5ZEANV5HS2lK54/2xwkeUeCRJHiI4CTQG7wB7tfgV/q8tBUSrg+k23tVwJlOIHnqlWKsvzgBV6qfDE8IcPhpP8F9uKrAr/Z5cK3fg+8G01evCWTlQlfEBUrSvvdXBmJcgMN7WWSCy5PhfX4FnhC4RhkngesD7rTVY8CRKtDeXJJSPYPv+ksY/oifv/dGhwcFRR7k2UXk2VzItbpAoxd6iwPZhUUUOxaZbcgy2ZBpFJBZYMGCfAsy8gphcZpRv9mWUn1CQMDsrBzo2ODRBBT44T1RmEQ/nqvbgt/8qQG//mMDnqI8ufUDPEGZuaUej79TjxnvbMdjm7fjl2+/j0cpv9i0DY9QHn7rPTxImf7mu3i0cgPm5pqxr96qwVWB3y7UBIpTBDbVyVhYthqPfPY5HqY89OnnmP7pcfz8k+N4gHI/5WcfH8O9lGmtx3BPawd+SrmrpQM/aWnHjyl3NrfjDsoPm47iqfAS1FSYMdxlVwSK0NZgSQiwsTshkNj7urVBZFbUaPAHkwRU+H1JAgx+d5KACv9R81Eu8KvicrxUZsS54xaMdNu4wEESmJVpgI7N/PbmeErz1a0NYMGqCYHZr76RsvcGYfLe07GbsvczXqrl8Nu5QBkXuHBCwEXKWI81nYB64hVrAmr1c1dWYtlyD/Y1UD7wYH+Dm55F+mZx4cAOJw40OHFwJ2WHA7G4BU+WrtQEZsaZgAkXT1px6aSA4U4B+7ab8ewCPXTsxGtviqccuetfCyDjxWpN4PnyStRW07s9KOPsCS/OnfDg/Ek3LnR6cIky1OXG5R43RnpEjPWKWFMhcAEGvy1JQIWPdAn4LL1AsSYw/8Uqbe9VAXbkslPvwhfSZHivm+BuGkgurFllwRMl5ZrA4/EVqKAtGO60cvhYj4D9200kkE0CdN4fbYolCcRIwK8JsMabU7aG33jUM398wE+noURwD8E9SXCRBpKLbj0CbzwGv3XvEU1AhV89JeBAvQnPZJAAXblHDu6KaNWrAvNWVmmdzwTYdSv5wjFOp95Irwr3ENzN4eN9Il8BVeAWEpgRW0FbUMCbj8HHTwvY+2cjnpmfPaQzOb2tkZIADnwUwZE9YUoIK8q8msADisDSpSIO/9WHf+6WlHjw90YRbR+yo9WJQx868Dcl0Vgh73xWvSoQlPOwv76QKjcT3ASjYMDT8xc16syiOM3okFqNTumyOnbpys07Xx08TODGsctfuxvG7rxcE+bl0GXTYOQCDP4DymPR5XzsssHDGu/ZDP0QLX/jrMzMu9Ne1fPtrt1s7qe89xbbrqle9ecY8ney6xa7cLAjNwE37Jjy/wqZFtdDBPVSxRILDRoP+22qfz9Lb5pOcBfL7KxcJwv7bcoC/1Of7wFq0S6lwML8QQAAAABJRU5ErkJggg=="
17 | }
18 | <==Starter Plugin Info===
19 | */
20 |
21 |
22 | #Include ..\Utils\PluginHelper.ah2
23 |
24 | PluginHelper.addEntryFunc((*) => Plugin_文件选择对话框导航.main()) ; 添加入口函数等待执行
25 |
26 | class Plugin_文件选择对话框导航 {
27 |
28 | static main() {
29 | SplitPath(A_LineFile, &name) ; 获取插件id即文件名
30 | this.name := name
31 |
32 | this.addToIntelligentMode()
33 | }
34 |
35 | static addToIntelligentMode() {
36 | ; 仅匹配窗口
37 | matchHandler(obj, searchText, pastedContentType, pastedContent, workWinInfo, winInfoMatchFlag) {
38 | hwnd := workWinInfo.hwnd
39 | cName := workWinInfo.class
40 | ; 匹配文件选择对话框 winInfoMatchFlag开启,才能保证cName是最新的
41 | if (winInfoMatchFlag && cName == "#32770") {
42 | obj.matchData := { hwnd: hwnd }
43 | return PluginHelper.Utils.strStartWith("WJXZDHK", searchText) ? 3 : 2 ; 优先级
44 | }
45 | return 0
46 | }
47 |
48 | ; 插件模式初始化
49 | init(hwnd, that) {
50 | that.pluginSearchData := this.getExplorerPathList()
51 | that.pluginOtherData := { hwnd: hwnd }
52 | }
53 |
54 | ; 插件模式下搜索
55 | searchHandler(that, searchText) {
56 | that.pluginSearchResult := []
57 | if (searchText) {
58 | ; 搜索结果
59 | for item in that.pluginSearchData {
60 | if (InStr(item.title, searchText) || InStr(item.titlePY, searchText)) ; 原文匹配或者拼音首字母部分匹配
61 | that.pluginSearchResult.Push(item)
62 | }
63 | } else ; 搜索内容为空时显示所有
64 | that.pluginSearchResult := that.pluginSearchData
65 |
66 | ; 搜索结果按标题排序
67 | PluginHelper.Utils.QuickSort(that.pluginSearchResult, (itemA, tiemB) => StrCompare(itemA.title, tiemB.title))
68 | ;重置列表
69 | that.listView.Opt("-Redraw") ;禁用重绘
70 | that.listView.Delete()
71 | ; 添加搜索结果到列表
72 | for item in that.pluginSearchResult {
73 | that.listView.Add(, " " item.title)
74 | }
75 |
76 | that.resizeGui() ;根据搜索结果数量调整gui尺寸 并启用重绘
77 | }
78 |
79 | ;定义插件模式下回车、双击处理函数
80 | runHandler(that, rowNum) {
81 | if (rowNum) {
82 | ; hwnd在ini函数中赋值到了pluginOtherData.hwnd
83 | PluginHelper.hideSearchGui()
84 | this.jumpToPath(that.pluginOtherData.hwnd, that.pluginSearchResult[rowNum].path)
85 | }
86 | }
87 |
88 | ; 添加插件项到智能模式搜索界面
89 | PluginHelper.addPluginToIntelligentMode(
90 | this.name,
91 | "文件选择对话框路径导航",
92 | matchHandler,
93 | (obj, searchText) => (
94 | PluginHelper.showPluginMode( ; 启动插件模式
95 | [], ; 在ini函数中中动态设定
96 | searchHandler,
97 | runHandler, {
98 | initHandler: init.Bind(obj.matchData.hwnd),
99 | placeholder: "选择导航路径",
100 | thumb: PluginHelper.getPluginHIcon(this.name)
101 | }
102 | )
103 | ), , PluginHelper.getPluginHIcon(this.name)
104 | )
105 | }
106 |
107 |
108 | ; 获取当前运行的资源管理器路径
109 | static getExplorerPathList() {
110 | pathList := Map()
111 | for item in ComObject("Shell.Application").Windows {
112 | try folder := item.Document.Folder.Self.Path
113 | if (!folder || pathList.Has(folder))
114 | Continue
115 | pathList[folder] := true
116 | }
117 | out := []
118 | out.Capacity := pathList.Count
119 | for k, v in pathList {
120 | title := PluginHelper.Utils.pathStrCompact(k, 50)
121 | out.Push({ title: title, path: k, titlePY: PluginHelper.Utils.chineseFirstChar(title) }) ; 压缩到50字符内
122 | }
123 | return out
124 | }
125 |
126 | ; 指定对话框导航到指定路径
127 | static jumpToPath(hwnd, path) {
128 | if (WinExist("ahk_id " hwnd)) {
129 | ctrls := WinGetControls("A")
130 |
131 | ControlSend("{F4}")
132 | ctrlNN := ""
133 | for i, ctrl in ctrls {
134 | if (InStr(ctrl, "Edit"))
135 | ctrlNN := ctrl
136 | }
137 | Sleep(150)
138 | ControlFocus(ctrlNN)
139 | ControlSetText(path, ctrlNN)
140 | ControlSend("{Enter}", ctrlNN)
141 | PluginHelper.Utils.tip("文件选择对话框路径导航", "路径已导航至:`n`n" path, 2000)
142 | } else
143 | PluginHelper.Utils.tip("文件选择对话框路径导航", "对话框窗口不存在,导航失败", 2000)
144 |
145 | }
146 | }
--------------------------------------------------------------------------------
/docs/dev/plugin-mode/basics.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 基础
3 | icon: square-caret-up
4 | author: AkiChase
5 | date: 2023-04-14
6 | order: 1
7 | ---
8 |
9 | **插件模式**类似于启动模式、智能模式,但更加自由、强大,**Starter** 仅仅提供一个搜索框,其他内容全部由插件定义。
10 |
11 | 可以定义的内容包括:
12 |
13 | 1. 待搜索数据
14 | 2. 搜索处理函数
15 | 3. 运行处理函数
16 | 4. (可选)双击Right处理函数
17 | 5. (可选)加载图标处理函数
18 | 6. (可选)触底处理函数
19 | 7. (可选)粘贴内容处理函数
20 | 8. (可选)拖入文件处理函数
21 | 9. (可选)初始化函数
22 | 10. (可选)初始搜索框文本
23 | 11. (可选)搜索框占位符
24 | 12. (可选)搜索框图标
25 |
26 | ## API
27 |
28 | 进入**插件模式**需要使用 `PluginHelper.showPluginMode()` API
29 |
30 | 参数及说明:[PluginHelper.showPluginMode](../../api/showPluginMode.md)
31 |
32 | 除此之外还需要了解一下 `PluginMode` 模块的几个成员。
33 |
34 | `PluginMode` 是使用插件模式时处理函数中 `that` 参数指向的类,我们一般只需要了解下面几个数据存储位置即可。
35 |
36 | - `that.pluginSearchData`
37 |
38 | `showPluginMode()`函数中第一个参数传递的数据会被储存在当前位置,意义是**可能**出现在插件模式**搜索结果**的全部静态内容
39 |
40 | 当然这个全部内容只是针对**静态内容**,[进阶](./advanced.md)中有动态获取数据的情况,就不依赖此静态内容。
41 |
42 | - `that.pluginSearchResult`
43 |
44 | 插件应当在 `searchHandler` 即搜索处理函数中,将要显示的搜索结果储存在当前位置,方便 `runHandler` 访问。
45 |
46 | - `that.pluginOtherData`
47 |
48 | 插件如果有额外的数据,可以存放到当前位置
49 |
50 | ::: danger
51 | 插件应用在使用**插件模式**时禁止将任何数据存储在 `PluginMode`或者说 `that` 的其他位置。
52 |
53 | 若数据较多,请嵌套至对象后存储。
54 | :::
55 |
56 | - `that.listView`
57 |
58 | 指向插件模式的搜索框下方列表,可以通过相关的函数对其进行操作,参考[ListView (GUI) - 语法 & 使用](https://orz707.gitee.io/v2/docs/commands/ListView.htm)
59 |
60 | - `that.resizeGui()`
61 |
62 | 重新计算并调整列表、窗口大小,一般在修改`listView`的内容之后调用
63 |
64 | :::tip
65 | `resizeGui()` 方法中会调用 `that.listView.Opt("Redraw")`,所以无需再启用重绘
66 | :::
67 |
68 |
69 | ## 最简示例
70 |
71 | 最简示例直接上**相关部分**代码,看注释
72 |
73 | ```ahk
74 | class Plugin_MyPlugin {
75 | static main() {
76 | SplitPath(A_LineFile, &name)
77 | this.name := name
78 |
79 | ; 添加 进入插件模式 菜单项
80 | m := Menu()
81 | m.Add("进入插件模式", (*) => this.showPluginMode())
82 | PluginHelper.pluginMenu.Add(this.name, m)
83 | }
84 |
85 | ; 进入插件模式
86 | static showPluginMode() {
87 | ; 临时数据
88 | tmpData := [
89 | ["明月几时有", "把酒问青天"],
90 | ["不知天上宫阙", "今夕是何年"],
91 | ["我欲乘风归去", "又恐琼楼玉宇"]
92 | ]
93 | ; 构造出我们真正需要的数据,方便在searchHandler中使用
94 | searchData := []
95 | for data in tmpData {
96 | searchData.Push({
97 | title: data[1],
98 | keywords: PluginHelper.Utils.chineseFirstChar(data[1]), ; 拼音首字母作为关键词
99 | answer: data[2]
100 | })
101 | }
102 | ; 释放不必要的占用,虽然不多,但要有这个意识
103 | tmpData := 0
104 |
105 | ; 此处that指的是 pluginMode 模块,即插件模式
106 | searchHandler(that, searchText) {
107 | ; 如果有搜索内容则进行匹配
108 | if (StrLen(searchText)) {
109 | that.pluginSearchResult:=[] ; 重置 pluginSearchResult
110 | for data in that.pluginSearchData {
111 | ; 如果搜索内容是title或者keywords的一部分则添加到搜索结果
112 | if (InStr(data.title, searchText) || InStr(data.keywords, searchText))
113 | that.pluginSearchResult.Push(data)
114 | }
115 | } else ; 否则显示全部
116 | that.pluginSearchResult := that.pluginSearchData
117 |
118 | ; 对搜索结果进行渲染,即添加到listview中
119 | ;重置列表
120 | that.listView.Opt("-Redraw") ;禁用重绘
121 | that.listView.Delete()
122 | for data in that.pluginSearchResult {
123 | ; 这里使用title作为内容
124 | that.listView.Add(, data.title)
125 | }
126 | ; 调整gui尺寸 并启用重绘,该函数包含了Opt("Redraw")
127 | that.resizeGui()
128 | }
129 |
130 | runHandler(that, rowNum) {
131 | ; 通过pluginSearchResult和当前启动的行号访问到当前数据
132 | curData := that.pluginSearchResult[rowNum]
133 | ; 显示当前项的诗词后半句
134 | ; 此处的this指的是当前插件,不要和that混淆
135 | PluginHelper.Utils.tip(this.name, curData.answer, 1000)
136 | }
137 |
138 | PluginHelper.showPluginMode(
139 | searchData,
140 | searchHandler,
141 | runHandler
142 | )
143 | }
144 | }
145 | ```
146 |
147 | 效果如图:
148 |
149 | 
150 |
151 | 
152 |
153 | 
154 |
155 | ## 从启动项进入
156 |
157 | 虽然可以像最简示例中一样,通过菜单而进入**插件模式**。
158 |
159 | 但是最常用的方式还是通过**插件启动项**的运行处理函数进入。
160 |
161 | ```ahk
162 | ; 添加 进入MyPlugin插件模式 启动项
163 | PluginHelper.addPluginToStartupMode(
164 | this.name,
165 | "进入MyPlugin插件模式",
166 | ["进入MyPlugin插件模式", PluginHelper.Utils.chineseFirstChar("进入MyPlugin插件模式")],
167 | (obj, searchText) => this.showPluginMode(), ; 运行则进入插件模式
168 | )
169 | ```
170 | 
171 |
172 | ## 简易文件夹示例
173 |
174 | 这个示例中,可以通过**启动项**进入**插件模式**,显示软件图片资源文件夹内的所有文件。
175 |
176 | 可以通过文件名或者拼音首字母转换后的文件名进行**搜索筛选**,运行则**在文件夹中打开**指定项
177 |
178 | 具体如何上代码,看注释
179 |
180 | ```ahk
181 | class Plugin_MyPlugin {
182 | static main() {
183 | SplitPath(A_LineFile, &name)
184 | this.name := name
185 |
186 | ; 添加 进入MyPlugin插件模式 启动项
187 | PluginHelper.addPluginToStartupMode(
188 | this.name,
189 | "简易文件夹",
190 | ["简易文件夹", PluginHelper.Utils.chineseFirstChar("简易文件夹")],
191 | (obj, searchText) => this.showPluginMode(), ; 启动则进入插件模式
192 | )
193 | }
194 |
195 | ; 进入插件模式
196 | static showPluginMode() {
197 | ; 构造文件夹相关数据
198 | searchData := []
199 | ; PluginHelper.imgDir 为Starter存放图片资源的目录
200 | loop files PluginHelper.imgDir "\*.*" {
201 | searchData.Push({
202 | title: A_LoopFileName,
203 | keywords: PluginHelper.Utils.chineseFirstChar(A_LoopFileName),
204 | path: A_LoopFileFullPath
205 | })
206 | }
207 |
208 | ; 此处that指的是 pluginMode 模块,即插件模式
209 | searchHandler(that, searchText) {
210 | ; 如果有搜索内容则进行匹配
211 | if (StrLen(searchText)) {
212 | that.pluginSearchResult := [] ; 重置 pluginSearchResult
213 | for data in that.pluginSearchData {
214 | ; 如果搜索内容是title或者keywords的一部分则添加到搜索结果
215 | if (InStr(data.title, searchText) || InStr(data.keywords, searchText))
216 | that.pluginSearchResult.Push(data)
217 | }
218 | } else ; 否则显示全部
219 | that.pluginSearchResult := that.pluginSearchData
220 |
221 | ;重置列表
222 | that.listView.Opt("-Redraw") ;禁用重绘
223 | that.listView.Delete()
224 | for data in that.pluginSearchResult
225 | that.listView.Add(, data.title)
226 | ; 调整gui尺寸 并启用重绘
227 | that.resizeGui()
228 | }
229 |
230 | runHandler(that, rowNum) {
231 | ; 通过pluginSearchResult和当前启动的行号访问到当前数据
232 | curData := that.pluginSearchResult[rowNum]
233 | ; 此处的this指的是当前插件,不要和that混淆
234 | PluginHelper.hideSearchGui() ; 隐藏搜索框
235 | PluginHelper.Utils.tip(this.name, "在文件夹中显示:`n" curData.path)
236 | PluginHelper.Utils.openFileInFolder(curData.path) ; 在文件夹中显示当前文件
237 | }
238 |
239 | PluginHelper.showPluginMode(
240 | searchData,
241 | searchHandler,
242 | runHandler, {
243 | thumb: PluginHelper.getPluginHIcon(this.name) ; 搜索框图标
244 | }
245 | )
246 | }
247 | }
248 | ```
249 |
250 | 效果如图:
251 |
252 | 
253 |
254 | 
255 |
256 | 
257 |
258 | 
259 |
260 | 
261 |
--------------------------------------------------------------------------------
/docs/api/utils/ImagePutHelper.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: ImagePutHelper
3 | author: AkiChase
4 | order: 2
5 | date: 2023-04-14
6 | ---
7 |
8 | ::: warning
9 | 本文内容列举翻译API内容,仅供参考。
10 | :::
11 |
12 | 具体使用请参考:
13 |
14 | - [简单、高效、实用的图片操作库 - AutoAHK](https://www.autoahk.com/archives/37246)
15 | - [ImagePut —— 裁剪、缩放 & 其他选项](../../dev/others/image-put-doc-1.md)
16 | - [ImagePut —— 输入类型 & 输出函数](../../dev/others/image-put-doc-2.md)
17 |
18 | ## ImagePutBase64(image, extension := "", quality := "")
19 |
20 | 将图像转换为指定格式的文件并且返回一个Base64编码的字符串。
21 |
22 | - 参数
23 | - \{Image\} `image`: 需要被转换的图像
24 | - \{String\} `extension`: 文件格式, 选项为: `bmp`, `gif`, `jpg`, `png`, `tiff`
25 | - \{String\} `quality`: `jpg`文件质量的等级,整数类型,0-100
26 |
27 | - 返回值
28 | - \{String\} Base64编码的字符串
29 |
30 | ## ImagePutBitmap(image)
31 |
32 | 将图像转换为一个GDI+位图并且返回一个指针。
33 |
34 | - 参数
35 | - \{Image\} `image`: 需要被转换的图像
36 |
37 | - 返回值
38 | - \{Pointer\} GDI+位图的指针
39 |
40 | ## ImagePutBuffer(image)
41 |
42 | 将图像转换为一个GDI+位图并且返回一个包含GDI+作用域的缓冲区对象。
43 |
44 | - 参数
45 | - \{Image\} `image`: 需要被转换的图像
46 |
47 | - 返回值
48 | - \{BitmapBuffer\} 包含GDI+作用域的缓冲区对象
49 |
50 | ## ImagePutClipboard(image)
51 |
52 | 将图像复制到剪贴板并且返回剪贴板的所有内容。
53 |
54 | - 参数
55 | - \{Image\} `image`: 需要被复制的图像
56 |
57 | - 返回值
58 | - \{String\} 包含剪贴板的所有内容的字符串
59 |
60 | ## ImagePutCursor(image, xHotspot := "", yHotspot := "")
61 |
62 | 将图像设为光标并且返回变量A_Cursor。
63 |
64 | - 参数
65 | - \{Image\} `image`: 需要被设为光标的图像
66 | - \{String\} `xHotspot`: X点击点,范围为0-width。
67 | - \{String\} `yHotspot`: Y点击点,范围为0-height。
68 |
69 | - 返回值
70 | - \{Variable\} 变量A_Cursor
71 |
72 | ## ImagePutDC(image, alpha := "")
73 |
74 | 将图像放到设备上下文并且返回句柄。
75 |
76 | - 参数
77 | - \{Image\} `image`: 需要被放到设备上下文的图像
78 | - \{String\} `alpha`: Alpha通道的颜色,RGB格式,例如 0xFFFFFF。
79 |
80 | - 返回值
81 | - \{Handle\} 句柄
82 |
83 | ## ImagePutDesktop(image)
84 |
85 | 将图像放在桌面图标后面并且返回字符串"desktop"。
86 |
87 | - 参数
88 | - \{Image\} `image`: 需要被放在桌面图标后面的图像
89 |
90 | - 返回值
91 | - \{String\} "desktop"
92 |
93 | ## ImagePutExplorer(image, default := "")
94 |
95 | 将图像保存在最近活动的文件浏览器窗口中。
96 |
97 | - 参数
98 | - \{Image\} `image`: 需要被保存最近活动的文件浏览器窗口中的图像
99 | - \{String\} `default`: 默认路径选项。
100 |
101 | ## ImagePutFile(image, filepath := "", quality := "")
102 |
103 | 将图像保存为文件并返回文件路径。
104 |
105 | - 参数
106 | - \{Object\} `image`: 要保存的图像对象。
107 | - \{String\} `filepath`: 文件路径和扩展名,默认为空字符串 | string -> *.bmp, *.gif, *.jpg, *.png, *.tiff
108 | - \{Number\} `quality`: JPEG 图像质量等级,默认为空字符串 | integer -> 0 - 100
109 |
110 | - 返回值
111 | - \{String\} 文件路径字符串。
112 |
113 | ## ImagePutFormData(image, boundary := "ImagePut-abcdef")
114 |
115 | 将图像以多部分表单数据的形式返回二进制 SafeArray COM 对象。
116 |
117 | - 参数
118 | - \{Object\} `image`: 图像对象。
119 | - \{String\} `boundary`: 内容类型,默认为 "ImagePut-abcdef"。
120 |
121 | - 返回值
122 | - \{Object\} 返回图像的二进制 SafeArray COM 对象。
123 |
124 | ## ImagePutHBitmap(image, alpha := "")
125 |
126 | 将图像保存为设备无关位图,并返回句柄。
127 |
128 | - 参数
129 | - \{Object\} `image`: 要保存的图像对象。
130 | - \{String\} `alpha`: 在 Alpha 通道中的颜色(rgb 值),默认为空字符串。 | RGB -> 0xFFFFFF
131 |
132 | - 返回值
133 | - \{Number\} 设备无关位图处理后的句柄。
134 |
135 | ## ImagePutHex(image, extension := "", quality := "")
136 |
137 | 将图像保存为文件格式,并返回十六进制编码字符串。
138 |
139 | - 参数
140 | - \{Object\} `image`: 要保存的图像对象。
141 | - \{String\} `extension`: 文件格式编码,默认为空字符串。 | string -> bmp, gif, jpg, png, tiff
142 | - \{Number\} `quality`: JPEG 图像质量等级,默认为空字符串。 | integer -> 0 - 100
143 |
144 | - 返回值
145 | - \{String\} 十六进制编码字符串。
146 |
147 | ## ImagePutHIcon(image)
148 |
149 | 将图像处理为图标,并返回句柄。
150 |
151 | - 参数
152 | - \{Object\} `image`: 要进行处理的图像对象。
153 |
154 | - 返回值
155 | - \{Number\} 图标处理成功后的句柄。
156 |
157 | ## ImagePutRandomAccessStream(image, extension := "", quality := "")
158 |
159 | 将图像保存为文件格式,并返回指向 RandomAccessStream 的指针。
160 |
161 | - 参数
162 | - \{Object\} `image`: 要进行处理的图像对象。
163 | - \{String\} `extension`: 文件格式编码,默认为空字符串。 | string -> bmp, gif, jpg, png, tiff
164 | - \{Number\} `quality`: JPEG 图像质量等级,默认为空字符串。 | integer -> 0 - 100
165 |
166 | - 返回值
167 | - \{Object\} RandomAccessStream 指针。
168 |
169 | ## ImagePutSafeArray(image, extension := "", quality := "")
170 |
171 | 将图像保存为文件格式,并返回 SafeArray COM 对象。
172 |
173 | - 参数
174 | - \{Object\} `image`: 要进行处理的图像对象。
175 | - \{String\} `extension`: 文件格式编码,默认为空字符串。 | string -> bmp, gif, jpg, png, tiff
176 | - \{Number\} `quality`: JPEG 图像质量等级,默认为空字符串。 | integer -> 0 - 100
177 |
178 | - 返回值
179 | - \{Object\} SafeArray COM 对象。
180 |
181 | ## ImagePutScreenshot(image, screenshot := "", alpha := "")
182 |
183 | 将图像放置在共享屏幕设备上,并返回坐标数组。
184 |
185 | - 参数
186 | - \{Object\} `image`: 要进行处理的图像对象。
187 | - \{String\} `screenshot`: 屏幕坐标数组,默认为空字符串。 | array -> [x,y,w,h] or [0,0]
188 | - \{String\} `alpha`: 在 Alpha 通道中的颜色(rgb 值),默认为空字符串。 | RGB -> 0xFFFFFF
189 |
190 | - 返回值
191 | - \{Array\} 坐标数组。
192 |
193 | ## ImagePutStream(image, extension := "", quality := "")
194 |
195 | 将图像保存为文件格式,并返回指向 stream 的指针。
196 |
197 | - 参数
198 | - \{Object\} `image`: 要进行处理的图像对象。
199 | - \{String\} `extension`: 文件格式编码,默认为空字符串。 | string -> bmp, gif, jpg, png, tiff
200 | - \{Number\} `quality`: JPEG 图像质量等级,默认为空字符串。 | integer -> 0 - 100
201 |
202 | - 返回值
203 | - \{Object\} stream 指针。
204 |
205 | ## ImagePutURI(image, extension := "", quality := "")
206 |
207 | 将图像保存为文件格式,并返回 URI 字符串。
208 |
209 | - 参数
210 | - \{Object\} `image`: 要进行处理的图像对象。
211 | - \{String\} `extension`: 文件格式编码,默认为空字符串。 | string -> bmp, gif, jpg, png, tiff
212 | - \{Number\} `quality`: JPEG 图像质量等级,默认为空字符串。 | integer -> 0 - 100
213 |
214 | - 返回值
215 | - \{String\} URI 字符串。
216 |
217 | ## ImagePutWallpaper(image)
218 |
219 | 将图像作为桌面壁纸,并返回字符串 "wallpaper"。
220 |
221 | - 参数
222 | - \{Object\} `image`: 要进行处理的图像对象。
223 |
224 | - 返回值
225 | - \{String\} "wallpaper" 字符串。
226 |
227 | ## ImagePutWICBitmap(image)
228 |
229 | 将图像处理为 WICBitmap,并返回接口指针。
230 |
231 | - 参数
232 | - \{Object\} `image`: 要进行处理的图像对象。
233 |
234 | - 返回值
235 | - \{Object\} WICBitmap 接口指针。
236 |
237 | ## ImagePutWindow(image, title := "", pos := "", style := 0x82C80000, styleEx := 0x9, parent := "")
238 |
239 | 将图像放置在窗口中并返回窗口句柄。
240 |
241 | - 参数
242 | - \{Object\} `image`: 要进行处理的图像对象。
243 | - \{String\} `title`: 窗口标题,默认为空字符串。
244 | - \{String\} `pos`: 窗口坐标数组,默认为空字符串。 | array -> [x,y,w,h] or [0,0]
245 | - \{Number\} `style`: 窗口样式,默认为 0x82C80000。
246 | - \{Number\} `styleEx`: 窗口附加样式,默认为 0x9.
247 | - \{Object\} `parent`: 窗口父对象,默认为空字符串。
248 |
249 | - 返回值
250 | - \{Number\} 窗口句柄。
251 |
252 | ## ImageShow(image, title := "", pos := "", style := 0x90000000, styleEx := 0x80088, parent := "")
253 |
254 | 在窗口中显示图像,并返回窗口句柄。
255 |
256 | - 参数
257 | - \{Object\} `image`: 要进行处理的图像对象。
258 | - \{String\} `title`: 窗口标题,默认为空字符串。
259 | - \{String\} `pos`: 窗口坐标数组,默认为空字符串。 | array -> [x,y,w,h] or [0,0]
260 | - \{Number\} `style`: 窗口样式,默认为 0x90000000。
261 | - \{Number\} `styleEx`: 窗口附加样式,默认为 0x80088.
262 | - \{Object\} `parent`: 窗口父对象,默认为空字符串。
263 |
264 | - 返回值
265 | - \{Number\} 窗口句柄。
266 |
267 | ## ImageDestroy(image)
268 |
269 | 销毁图像对象。
270 |
271 | - 参数
272 | - \{Object\} `image`: 要进行销毁的图像对象。
273 |
274 | - 返回值
275 | - 无返回值。
276 |
277 | ## ImageWidth(image)
278 |
279 | 获取图像的宽度。
280 |
281 | - 参数
282 | - \{Object\} `image`: 要获取宽度的图像对象。
283 |
284 | - 返回值
285 | - \{Number\} 图像的宽度。
286 |
287 | ## ImageHeight(image)
288 |
289 | 获取图像的高度。
290 |
291 | - 参数
292 | - \{Object\} `image`: 要获取高度的图像对象。
293 |
294 | - 返回值
295 | - \{Number\} 图像的高度。
--------------------------------------------------------------------------------
/src/Utils/GlobalData.ah2:
--------------------------------------------------------------------------------
1 | class GlobalData {
2 | ; static rootDir := unset
3 | ; static imgDir := unset
4 | ; static bootDir := unset
5 | ; static dataDir := unset
6 | ; static pluginDir := unset
7 | ; static customImgDir := unset
8 |
9 | ; static startupData := unset
10 | ; static startupDataPath := unset
11 | ; static config := unset
12 | ; static configPath := unset
13 |
14 | ; static intelligentData := unset
15 | ; static intelligentDataPath := unset
16 |
17 | static startupSearchResult := []
18 | static intelligentSearchResult := []
19 | static intelligentRegMap := Map()
20 |
21 | static intelligentGroups := ["run-with", "search"]
22 | static intelligentMatchPriority := Map("str", 1, "reg", 2)
23 |
24 | static hotkeyList := []
25 | ; static onExitHandler := unset
26 |
27 | static init() {
28 | SplitPath(A_ScriptDir, , &tmp)
29 | this.rootDir := tmp
30 |
31 | this.imgDir := this.rootDir "\resource\img"
32 | this.pluginDir := this.rootDir "\src\plugin"
33 | this.dataDir := this.rootDir "\resource\data"
34 | this.customImgDir := this.dataDir "\customImg"
35 | this.bootDir := this.dataDir "\boot"
36 |
37 |
38 | for dirPath in [this.dataDir, this.bootDir, this.customImgDir, this.pluginDir]
39 | if (!FileExist(dirPath))
40 | DirCreate(dirPath)
41 |
42 | this.startupDataPath := this.dataDir "\startupData.txt"
43 | this.configPath := this.dataDir "\config.json"
44 | this.intelligentDataPath := this.dataDir "\intelligentData.json"
45 |
46 | this.refreshStartupData()
47 | this.refreshConfig()
48 | this.refreshIntelligentData()
49 |
50 | ; 退出前执行
51 | onExitHandler(*) {
52 | this.storeStartupData()
53 | this.storeConfig()
54 | this.storeIntelligentData()
55 | }
56 | this.onExitHandler := onExitHandler
57 | }
58 |
59 | ; 重新读取智能模式数据
60 | static refreshIntelligentData() {
61 | static defaultData := "
62 | (Join
63 | {
64 | "run-with": [
65 | {
66 | "enabled": 1,
67 | "group": "run-with",
68 | "match": {
69 | "exp": [
70 | "[^\\s]*(\\.[a-zA-z]{2}[^\\s]*){2}",
71 | "https?:\/{2}(.+)"
72 | ],
73 | "mode": "reg",
74 | "replace": [
75 | "$0",
76 | "$0"
77 | ]
78 | },
79 | "notes": "使用默认浏览器打开网址链接",
80 | "removable": 0,
81 | "script": {
82 | "mode": "none"
83 | },
84 | "thumb": "打开网址.png",
85 | "title": "打开网址"
86 | }
87 | ],
88 | "search": [
89 | {
90 | "enabled": 1,
91 | "group": "search",
92 | "match": {
93 | "exp": [
94 | "(bd|baidu|百度)\\s+(?.*)"
95 | ],
96 | "mode": "reg",
97 | "replace": [
98 | "${query}"
99 | ]
100 | },
101 | "notes": "使用默认浏览器百度搜索",
102 | "removable": 1,
103 | "thumb": "百度搜索.ico",
104 | "title": "百度搜索",
105 | "url": "https:\/\/www.baidu.com\/s?word={}"
106 | },
107 | {
108 | "enabled": 1,
109 | "group": "search",
110 | "match": {
111 | "exp": [
112 | "(gg|谷歌)\\s+(?.*)"
113 | ],
114 | "mode": "reg",
115 | "replace": [
116 | "${query}"
117 | ]
118 | },
119 | "notes": "使用默认浏览器谷歌搜索",
120 | "removable": 0,
121 | "thumb": "谷歌搜索.ico",
122 | "title": "谷歌搜索",
123 | "url": "https:\/\/www.google.com\/search?q={}"
124 | }
125 | ]
126 | }
127 | )"
128 | ; 加载默认值
129 | default := Jxon_Load(&defaultData)
130 | if (FileExist(this.intelligentDataPath)) {
131 | this.intelligentData := DataHelper.loadJSONFile(this.intelligentDataPath)
132 | for group, itemList in default {
133 | if !(this.intelligentData.Has(group) and (this.intelligentData[group] is Array) this.intelligentData[group].Length)
134 | this.intelligentData[group] := itemList ; 当前组不存在、非数组、为空则置默认值
135 | }
136 | }
137 | else
138 | this.intelligentData := default
139 | }
140 |
141 | ; 保存智能模式数据文件至本地
142 | static storeIntelligentData() {
143 | DataHelper.storeJSONFile(this.intelligentData, this.intelligentDataPath)
144 | }
145 |
146 | ; 重新读取startupData
147 | static refreshStartupData() {
148 | if (FileExist(this.startupDataPath))
149 | this.startupData := DataHelper.loadData(this.startupDataPath)
150 | else
151 | {
152 | FileAppend("", this.startupDataPath)
153 | this.startupData := []
154 | }
155 | }
156 |
157 | ; 保存startupDataPath至本地
158 | static storeStartupData() {
159 | DataHelper.storeData(this.startupData, this.startupDataPath)
160 | }
161 |
162 | ; 生成默认配置
163 | static newDefaultConfig(key?) {
164 | if (IsSet(key)) {
165 | switch key {
166 | case "plugin":
167 | return []
168 | case "hotkey":
169 | return [Map(
170 | "index", 3,
171 | "key", "CapsLock",
172 | "block", false
173 | ), Map(
174 | "index", 4,
175 | "key", "CapsLock",
176 | "block", false
177 | )]
178 | case "keywordsHK":
179 | return []
180 | }
181 | } else {
182 | config := Map()
183 | config["plugin"] := []
184 | config["hotkey"] := [Map(
185 | "index", 3,
186 | "key", "CapsLock",
187 | "block", false
188 | ), Map(
189 | "index", 4,
190 | "key", "CapsLock",
191 | "block", false
192 | )]
193 | config["keywordsHK"] := []
194 | return config
195 | }
196 | }
197 |
198 | ; 重新读取配置文件
199 | static refreshConfig() {
200 | if (FileExist(this.configPath)) {
201 | try {
202 | this.config := DataHelper.loadJSONFile(this.configPath)
203 | if (Type(this.config) != "Map") {
204 | this.config := this.newDefaultConfig()
205 | }
206 |
207 | for name in ["plugin", "hotkey", "keywordsHK"] {
208 | if (!this.config.Has(name))
209 | this.config[name] := this.newDefaultConfig(name)
210 | }
211 | hotkeyDefault := this.newDefaultConfig("hotkey")
212 | ; 热键数量变化则重置为默认热键
213 | if (this.config["hotkey"].Length < hotkeyDefault.Length)
214 | this.config["hotkey"] := hotkeyDefault
215 |
216 | return
217 | }
218 | }
219 |
220 | ; 配置文件不存在或读取失败则重置为默认配置
221 | this.config := this.newDefaultConfig()
222 | this.storeConfig()
223 | }
224 |
225 | ; 保存配置文件至本地
226 | static storeConfig() {
227 | DataHelper.storeJSONFile(this.config, this.configPath)
228 | }
229 | }
--------------------------------------------------------------------------------
/src/Utils/JXON.ah2:
--------------------------------------------------------------------------------
1 | ;;;; AHK v2
2 | ; Example ===================================================================================
3 | ; ===========================================================================================
4 |
5 | ; Msgbox "The idea here is to create several nested arrays, save to text with jxon_dump(), and then reload the array with jxon_load(). The resulting array should be the same.`r`n`r`nThis is what this example shows."
6 | ; a := Map(), b := Map(), c := Map(), d := Map(), e := Map(), f := Map() ; Object() is more technically correct than {} but both will work.
7 |
8 | ; d["g"] := 1, d["h"] := 2, d["i"] := ["purple","pink","pippy red"]
9 | ; e["g"] := 1, e["h"] := 2, e["i"] := Map("1","test1","2","test2","3","test3")
10 | ; f["g"] := 1, f["h"] := 2, f["i"] := [1,2,Map("a",1.0009,"b",2.0003,"c",3.0001)]
11 |
12 | ; a["test1"] := "test11", a["d"] := d
13 | ; b["test3"] := "test33", b["e"] := e
14 | ; c["test5"] := "test55", c["f"] := f
15 |
16 | ; myObj := Map()
17 | ; myObj["a"] := a, myObj["b"] := b, myObj["c"] := c, myObj["test7"] := "test77", myObj["test8"] := "test88"
18 |
19 | ; g := ["blue","green","red"], myObj["h"] := g ; add linear array for testing
20 |
21 | ; q := Chr(34)
22 | ; textData2 := Jxon_dump(myObj,4) ; ===> convert array to JSON
23 | ; msgbox "JSON output text:`r`n===========================================`r`n(Should match second output.)`r`n`r`n" textData2
24 |
25 | ; newObj := Jxon_load(&textData2) ; ===> convert json back to array
26 |
27 | ; textData3 := Jxon_dump(newObj,4) ; ===> break down array into 2D layout again, should be identical
28 | ; msgbox "Second output text:`r`n===========================================`r`n(should be identical to first output)`r`n`r`n" textData3
29 |
30 | ; msgbox "textData2 = textData3: " ((textData2=textData3) ? "true" : "false")
31 |
32 | ; ===========================================================================================
33 | ; End Example ; =============================================================================
34 | ; ===========================================================================================
35 |
36 | ; originally posted by user coco on AutoHotkey.com
37 | ; https://github.com/cocobelgica/AutoHotkey-JSON
38 |
39 | Jxon_Load(&src, args*) {
40 | key := "", is_key := false
41 | stack := [ tree := [] ]
42 | next := '"{[01234567890-tfn'
43 | pos := 0
44 |
45 | while ( (ch := SubStr(src, ++pos, 1)) != "" ) {
46 | if InStr(" `t`n`r", ch)
47 | continue
48 | if !InStr(next, ch, true) {
49 | testArr := StrSplit(SubStr(src, 1, pos), "`n")
50 |
51 | ln := testArr.Length
52 | col := pos - InStr(src, "`n",, -(StrLen(src)-pos+1))
53 |
54 | msg := Format("{}: line {} col {} (char {})"
55 | , (next == "") ? ["Extra data", ch := SubStr(src, pos)][1]
56 | : (next == "'") ? "Unterminated string starting at"
57 | : (next == "\") ? "Invalid \escape"
58 | : (next == ":") ? "Expecting ':' delimiter"
59 | : (next == '"') ? "Expecting object key enclosed in double quotes"
60 | : (next == '"}') ? "Expecting object key enclosed in double quotes or object closing '}'"
61 | : (next == ",}") ? "Expecting ',' delimiter or object closing '}'"
62 | : (next == ",]") ? "Expecting ',' delimiter or array closing ']'"
63 | : [ "Expecting JSON value(string, number, [true, false, null], object or array)"
64 | , ch := SubStr(src, pos, (SubStr(src, pos)~="[\]\},\s]|$")-1) ][1]
65 | , ln, col, pos)
66 |
67 | throw Error(msg, -1, ch)
68 | }
69 |
70 | obj := stack[1]
71 | is_array := (obj is Array)
72 |
73 | if i := InStr("{[", ch) { ; start new object / map?
74 | val := (i = 1) ? Map() : Array() ; ahk v2
75 |
76 | is_array ? obj.Push(val) : obj[key] := val
77 | stack.InsertAt(1,val)
78 |
79 | next := '"' ((is_key := (ch == "{")) ? "}" : "{[]0123456789-tfn")
80 | } else if InStr("}]", ch) {
81 | stack.RemoveAt(1)
82 | next := (stack[1]==tree) ? "" : (stack[1] is Array) ? ",]" : ",}"
83 | } else if InStr(",:", ch) {
84 | is_key := (!is_array && ch == ",")
85 | next := is_key ? '"' : '"{[0123456789-tfn'
86 | } else { ; string | number | true | false | null
87 | if (ch == '"') { ; string
88 | i := pos
89 | while i := InStr(src, '"',, i+1) {
90 | val := StrReplace(SubStr(src, pos+1, i-pos-1), "\\", "\u005C")
91 | if (SubStr(val, -1) != "\")
92 | break
93 | }
94 | if !i ? (pos--, next := "'") : 0
95 | continue
96 |
97 | pos := i ; update pos
98 |
99 | val := StrReplace(val, "\/", "/")
100 | val := StrReplace(val, '\"', '"')
101 | , val := StrReplace(val, "\b", "`b")
102 | , val := StrReplace(val, "\f", "`f")
103 | , val := StrReplace(val, "\n", "`n")
104 | , val := StrReplace(val, "\r", "`r")
105 | , val := StrReplace(val, "\t", "`t")
106 |
107 | i := 0
108 | while i := InStr(val, "\",, i+1) {
109 | if (SubStr(val, i+1, 1) != "u") ? (pos -= StrLen(SubStr(val, i)), next := "\") : 0
110 | continue 2
111 |
112 | xxxx := Abs("0x" . SubStr(val, i+2, 4)) ; \uXXXX - JSON unicode escape sequence
113 | if (xxxx < 0x100)
114 | val := SubStr(val, 1, i-1) . Chr(xxxx) . SubStr(val, i+6)
115 | }
116 |
117 | if is_key {
118 | key := val, next := ":"
119 | continue
120 | }
121 | } else { ; number | true | false | null
122 | val := SubStr(src, pos, i := RegExMatch(src, "[\]\},\s]|$",, pos)-pos)
123 |
124 | if IsInteger(val)
125 | val += 0
126 | else if IsFloat(val)
127 | val += 0
128 | else if (val == "true" || val == "false")
129 | val := (val == "true")
130 | else if (val == "null")
131 | val := ""
132 | else if is_key {
133 | pos--, next := "#"
134 | continue
135 | }
136 |
137 | pos += i-1
138 | }
139 |
140 | is_array ? obj.Push(val) : obj[key] := val
141 | next := obj == tree ? "" : is_array ? ",]" : ",}"
142 | }
143 | }
144 |
145 | return tree[1]
146 | }
147 |
148 | Jxon_Dump(obj, indent:="", lvl:=1) {
149 | if IsObject(obj) {
150 | If !(obj is Array || obj is Map || obj is String || obj is Number)
151 | throw Error("Object type not supported.", -1, Format("