From 4783263fbc26c7bc2d845abe00f818cecef424b9 Mon Sep 17 00:00:00 2001 From: Chaoses Ib Date: Thu, 31 Mar 2022 02:20:29 +0800 Subject: [PATCH] Quick select: Add terminal hotkeys --- README.md | 14 ++++++-- source/config.cpp | 19 ++++++++++- source/config.hpp | 2 ++ source/quick_select.cpp | 74 +++++++++++++++++++++++++++++++++++++---- 4 files changed, 100 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 1cdaee6..97af15a 100644 --- a/README.md +++ b/README.md @@ -108,10 +108,13 @@ Edit 模式详见 [Edit 模式](docs/pinyin_search/edit_mode.md)。 `Shift+F10` / `Menu` | 打开右键菜单\* `Alt+Enter` | 查看文件属性\* `Esc` / `Ctrl+W` | 关闭窗口\* +`$ (Shift+4)` | 复制文件名,在文件所属目录下启动终端 (v1.5a) +`# (Shift+3)` | 复制文件名,以管理员身份在文件所属目录下启动终端 (v1.5a) 注: * 操作之后是否关闭窗口可以通过配置进行控制。 * 标 \* 的热键为 Everything 默认热键,不是扩展增加的,在这里列出是为了完整性。 +* “(v1.5a)”表示相应热键仅在 Everything v1.5a 中可用。 ### 键列表 键列表支持高 DPI,但只在 Everything v1.5a 上支持缩放(热键为 `Ctrl+=` 和 `Ctrl+-`),在 Everything v1.4 上则不支持。 @@ -139,11 +142,18 @@ quick_select: # 结果列表 result_list: - # [0-9A-Z] 选中项目 - select: true # 同上 alt: 0 + # [0-9A-Z] 选中项目 + select: true + + # 终端 (v1.5a) + # Windows Terminal:"wt -d ${fileDirname}" + # Windows Console:"conhost"(不支持以管理员身份启动) + # 禁用:"" + terminal: "wt -d ${fileDirname}" + # 打开或定位文件后关闭窗口(不对 Everything 默认热键生效) # 如果想要默认 Enter 热键也关闭窗口,可在 Everything 快捷键选项中将“打开选中对象,并退出 Everything”设置为 Enter close_everything: true diff --git a/source/config.cpp b/source/config.cpp index e159039..cef1681 100644 --- a/source/config.cpp +++ b/source/config.cpp @@ -1,6 +1,7 @@ #include "common.hpp" #include "config.hpp" #include +#include #include #include @@ -8,6 +9,13 @@ Config config{}; +std::wstring u8_to_u16(const std::string& u8) { + std::wstring u16; + u16.resize(MultiByteToWideChar(CP_UTF8, 0, u8.c_str(), u8.size(), nullptr, 0)); + MultiByteToWideChar(CP_UTF8, 0, u8.c_str(), u8.size(), u16.data(), u16.size()); + return u16; +} + bool config_init() { using namespace std::literals; @@ -77,10 +85,19 @@ bool config_init() { }(node["search_edit"]), .result_list = [](const YAML::Node& node) { - return decltype(config.quick_select.result_list) { + decltype(config.quick_select.result_list) result_list { .select = node["select"].as(), .alt = node["alt"].as() }; + std::wstring terminal = u8_to_u16(node["terminal"].as()); + if (terminal.size()) { + std::wregex reg(LR"__((?:"([^"]*)"|([^ ]*)) ?(.*))__"); + std::wsmatch match; + std::regex_match(terminal, match, reg); + result_list.terminal_file = match[1].str() + match[2].str(); + result_list.terminal_parameter = match[3].str(); + } + return result_list; }(node["result_list"]), .close_everything = node["close_everything"].as(), diff --git a/source/config.hpp b/source/config.hpp index 8031d60..e13ce83 100644 --- a/source/config.hpp +++ b/source/config.hpp @@ -22,6 +22,8 @@ struct Config { struct { bool select; uint8_t alt; + std::wstring terminal_file; + std::wstring terminal_parameter; } result_list; bool close_everything; diff --git a/source/quick_select.cpp b/source/quick_select.cpp index 2b994e0..77dab35 100644 --- a/source/quick_select.cpp +++ b/source/quick_select.cpp @@ -1,5 +1,6 @@ #include "quick_select.hpp" #include +#include #include "config.hpp" #include "helper.hpp" #include "ipc.hpp" @@ -48,7 +49,7 @@ LRESULT CALLBACK keyboard_proc( _In_ WPARAM wParam, _In_ LPARAM lParam) { - static bool filter = false; + static int filter = -1; static WPARAM filter_wparam; static LPARAM filter_lparam; @@ -59,7 +60,7 @@ LRESULT CALLBACK keyboard_proc( << (GetKeyState(VK_SHIFT) & 0x8000 ? L"Shift " : L"") << (GetKeyState(VK_MENU) & 0x8000 ? L"Alt " : L"") << (GetKeyState(VK_LWIN) & 0x8000 || GetKeyState(VK_RWIN) & 0x8000 ? L"Win " : L"") - << (filter ? L"may filter " : L"") + << (filter != -1 ? L"may filter " : L"") << L'\n'; /* Ctrl+Alt+A: @@ -98,11 +99,11 @@ LRESULT CALLBACK keyboard_proc( if (disable_keyboard_hook) goto call_next; - if (filter) - if (code == HC_NOREMOVE && wParam == filter_wparam && lParam == filter_lparam) + if (filter != -1) + if (code == filter && wParam == filter_wparam && lParam == filter_lparam) return true; else - filter = false; + filter = -1; if (become_down) { int num; @@ -157,7 +158,7 @@ LRESULT CALLBACK keyboard_proc( switch (config.quick_select.input_mode) { case quick::InputMode::WmKey: { // do not change this if you don't know why it's needed - filter = true; + filter = HC_NOREMOVE; filter_wparam = wParam; filter_lparam = lParam; @@ -275,6 +276,65 @@ LRESULT CALLBACK keyboard_proc( break; } } + else if (quick_select.result_list.terminal_file.size() && shift && !(ctrl || alt)) { + if (code == HC_ACTION // do not change this if you don't know why it's needed + && (wParam == '4' || wParam == '3') // `$` or `#` + ) { + debug_output(); + HWND list_item = FindWindowExW(GetParent(list), nullptr, L"EVERYTHING_RESULT_LIST_FOCUS", nullptr); + if (list_item) { + wchar_t item_path[MAX_PATH]; + GetWindowTextW(list_item, item_path, std::size(item_path)); + if constexpr (debug) + DebugOStream() << L"EVERYTHING_RESULT_LIST_FOCUS: " << item_path << L'\n'; + + // copy the filename to the clipboard + std::wstring_view filename = PathFindFileNameW(item_path); + if (OpenClipboard(GetParent(list))) { + if (HGLOBAL h = GlobalAlloc(GMEM_MOVEABLE, (2 + filename.size() + 2) * sizeof(wchar_t))) { + wchar_t* p = (wchar_t*)GlobalLock(h); + + memcpy(p, L".\\", 2 * sizeof(wchar_t)); + p += 2; + + filename.copy(p, filename.size()); + p[filename.size()] = L' '; + p[filename.size() + 1] = L'\0'; + + GlobalUnlock(h); + + EmptyClipboard(); + SetClipboardData(CF_UNICODETEXT, h); + } + CloseClipboard(); + } + + // or `item_path[filename.size()] = L'\0';` ? + PathRemoveFileSpecW(item_path); + + std::wstring parameter = quick_select.result_list.terminal_parameter; + if (size_t pos = parameter.find(L"${fileDirname}"); pos != parameter.npos) { + parameter.replace(pos, std::size(L"${fileDirname}") - 1, std::wstring(L"\"") + item_path + L'"'); + } + + SHELLEXECUTEINFOW execute_info{ + .cbSize = sizeof(execute_info), + .fMask = 0, + .hwnd = GetParent(list), + .lpVerb = wParam == '4' ? L"" : L"runas", + .lpFile = quick_select.result_list.terminal_file.c_str(), + .lpParameters = parameter.c_str(), + .lpDirectory = item_path, + .nShow = SW_SHOW + }; + ShellExecuteExW(&execute_info); + + if (quick_select.close_everything) + PostMessageW(GetParent(list), WM_CLOSE, 0, 0); + break; + } + } + } goto call_next; } } @@ -359,6 +419,8 @@ void quick::init() { if (config.quick_select.input_mode == InputMode::Auto) config.quick_select.input_mode = InputMode::SendInput; + config.quick_select.result_list.terminal_file = {}; + IbDetourAttach(&SetWindowPos_real, SetWindowPos_detour); }