Compare commits

..
Author SHA1 Message Date
agrynco be68b706f0 fix(files): use ctrl+8 and activate the open files window 2026-11-14 16:24:47 +02:00
agrynco 23a7c73331 feat(files): list all folder shortcuts with ctrl+f8
Reuse the folder shortcuts dialog and open the selected destination in the active panel.
2026-11-14 16:19:23 +02:00
agrynco 82fe8ce3a1 Merge pull request 'Show specific LAN peer lookup errors in Files' (#22) from codex/files-peer-errors into main 2026-11-14 16:14:28 +02:00
4 changed files with 63 additions and 16 deletions

No files matched your search

+5 -1
View File
@@ -44,7 +44,7 @@ Far Manager є зразком для оформлення файлового м
- Короткий Alt перемикає головне меню Files при відпусканні. F9 також перемикає меню. Після закриття фокус повертається до активної панелі. Alt з літерою верхнього рівня спрацьовує одразу при натисканні літери. Alt+O відкриває Options, а відпускання Alt після комбінації не перемикає меню.
- Коли головне меню відкрите, L, F, C, O та R відкривають Left, Files, Commands, Options та Right. У підменю підсвічена літера викликає відповідну команду. Літери унікальні в межах поточного рівня. Усталені мнемоніки мають пріоритет, зокрема X для Exit.
- Глобальне скорочення **Open KSwitcher Files** можна змінити або очистити в налаштуваннях. Для профілю без цього поля пропонується Ctrl+Alt+F, якщо Windows реєструє комбінацію і вона вільна серед прив’язок KSwitcher.
- Глобальне скорочення повертає до відкритого вікна Files із тієї ж збірки або запускає Files, якщо такого вікна немає. Пункт **Files** у треї відкриває нове вікно.
- Глобальне скорочення повертає до відкритого вікна Files у поточній сесії Windows або запускає Files, якщо такого вікна немає. Пункт **Files** у треї відкриває нове вікно.
- Ctrl+Shift+0–9 відкриває діалог Title і Path із поточною папкою. OK додає запис без дублювання, Escape скасовує. Title необов’язковий, порожнє значення показує шлях. Записи LAN зберігають ID ПК, а редагування Path залишає запис на тому самому ПК.
- Ctrl+0–9 одразу відкриває єдину папку. Для кількох папок відкривається компактний попап Far з одним заголовком Folder shortcuts у подвійній рамці та коротким рядом клавіш у нижній рамці. Ширина залежить від найдовшого запису й обмежується розміром вікна, а висота — кількістю видимих рядків. Нижня рамка показує Ins Del F4 Ctrl+Up Ctrl+Down. Insert додає поточну папку через Title і Path, Delete відв’язує, F4 редагує, Ctrl+Up і Ctrl+Down змінюють і зберігають порядок. Enter відкриває папку. Escape або клік поза попапом закриває його й повертає фокус до панелі. Commands → Folder shortcuts дає вибрати зайняту цифру й відкрити той самий попап навіть для єдиного запису. Brief і Wide доступні в меню Left/Right та Options.
@@ -66,6 +66,10 @@ Far Manager є зразком для оформлення файлового м
## Панелі
- Ctrl+8 відкриває список усіх ярликів папок. Кожен рядок показує групу
й назву або шлях. Enter відкриває папку в активній панелі, F4 редагує
ярлик, а Delete прибирає його зі списку.
- У Change drive повідомлення No paired computers з’являється після
успішної відповіді з порожнім списком. Збої локального запиту до
KSwitcher відображаються окремо.
+1 -1
View File
@@ -150,7 +150,7 @@ bool activateFilesWindow()
{
wchar_t name[32]{};
if(!IsWindowVisible(candidate) || !GetClassNameW(candidate,name,std::size(name)) ||
wcscmp(name,L"KSwitcher.Files") || !configurationPeer(candidate,L"KSwitcher.Files.exe"))
wcscmp(name,L"KSwitcher.Files"))
return TRUE;
*reinterpret_cast<HWND *>(context)=candidate;
return FALSE;
+40 -12
View File
@@ -187,13 +187,21 @@ struct FolderShortcutView
std::vector<int> digits;
int rowHeight{};
Panel *panel{};
bool all{};
std::vector<std::pair<int,size_t>> entries;
};
std::wstring shortcutLabel(const FolderShortcut &entry)
{
return entry.title.empty()?(entry.peerId.empty()?L"":entry.peerName+L" · ")+entry.path.native():entry.title;
}
void layoutQuickFolders(HWND dialog,FolderShortcutView &view,int selection)
{
const auto list=GetDlgItem(dialog,shortcutList);
SendMessageW(list,LB_RESETCONTENT,0,0);
view.digits.clear();
view.entries.clear();
const auto owner=GetWindow(dialog,GW_OWNER);
const auto dc=GetDC(dialog);
const auto font=SelectObject(dc,mono);
@@ -211,14 +219,23 @@ void layoutQuickFolders(HWND dialog,FolderShortcutView &view,int selection)
GetTextExtentPoint32W(dc,label.data(),static_cast<int>(label.size()),&size);
return static_cast<int>(size.cx);
};
int width=std::max(measure(L"Folder shortcuts"),measure(view.digit<0?L"Enter Esc":quickFolderHints))+3*cellWidth;
int width=std::max(measure(L"Folder shortcuts"),measure(view.all?L"Del F4":view.digit<0?L"Enter Esc":quickFolderHints))+3*cellWidth;
const int textInset=dialogRowTextInset(cellWidth);
const auto add=[&](const std::wstring &label)
{
width=std::max(width,measure(label)+2*textInset);
SendMessageW(list,LB_ADDSTRING,0,reinterpret_cast<LPARAM>(label.c_str()));
};
if(view.digit<0)
if(view.all)
{
for(int digit=0;digit<static_cast<int>(folderShortcuts.size());++digit)
for(size_t index=0;index<folderShortcuts[digit].size();++index)
{
view.entries.emplace_back(digit,index);
add(std::to_wstring(digit)+L" "+shortcutLabel(folderShortcuts[digit][index]));
}
}
else if(view.digit<0)
{
for(int digit=0;digit<10;++digit)
if(!folderShortcuts[digit].empty())
@@ -228,7 +245,7 @@ void layoutQuickFolders(HWND dialog,FolderShortcutView &view,int selection)
}
}
else for(const auto &entry:folderShortcuts[view.digit])
add(entry.title.empty()?(entry.peerId.empty()?L"":entry.peerName+L" · ")+entry.path.native():entry.title);
add(shortcutLabel(entry));
SelectObject(dc,font);
ReleaseDC(dialog,dc);
MONITORINFO monitor{sizeof(monitor)};
@@ -304,7 +321,7 @@ INT_PTR CALLBACK quickFolderDialog(HWND dialog,UINT message,WPARAM wp,LPARAM lp)
const auto bounds=paintDialogFrame(dc,client,dialogFrameMetrics(GetDpiForWindow(dialog)),teal,frame);
DeleteObject(frame);
paintDialogFrameCaptions(dc,client,bounds,L"Folder shortcuts",teal,colors[Text],mono,
view->digit<0?L"Enter Esc":quickFolderHints);
view->all?L"Del F4":view->digit<0?L"Enter Esc":quickFolderHints);
EndPaint(dialog,&ps);
return TRUE;
}
@@ -331,7 +348,7 @@ INT_PTR CALLBACK quickFolderDialog(HWND dialog,UINT message,WPARAM wp,LPARAM lp)
if(action!=quickRemove && action!=quickEdit && action!=quickInsert && action!=quickMoveUp &&
action!=quickMoveDown && action!=IDOK && !(action==shortcutList && HIWORD(wp)==LBN_DBLCLK)) return FALSE;
const auto row=SendDlgItemMessageW(dialog,shortcutList,LB_GETCURSEL,0,0);
if(view->digit<0)
if(!view->all && view->digit<0)
{
if((action==IDOK || action==shortcutList) && row>=0 && static_cast<size_t>(row)<view->digits.size())
{
@@ -340,7 +357,17 @@ INT_PTR CALLBACK quickFolderDialog(HWND dialog,UINT message,WPARAM wp,LPARAM lp)
}
return TRUE;
}
const auto &group=folderShortcuts[view->digit];
int digit=view->digit;
size_t index=static_cast<size_t>(row);
if(view->all)
{
if(index>=view->entries.size() || action==quickInsert ||
action==quickMoveUp || action==quickMoveDown) return TRUE;
const auto &entry=view->entries[index];
digit=entry.first;
index=entry.second;
}
const auto &group=folderShortcuts[digit];
if(action==quickInsert)
{
const auto &panel=*view->panel;
@@ -351,7 +378,7 @@ INT_PTR CALLBACK quickFolderDialog(HWND dialog,UINT message,WPARAM wp,LPARAM lp)
SetFocus(GetDlgItem(dialog,shortcutList));
return TRUE;
}
if(row<0 || static_cast<size_t>(row)>=group.size()) return TRUE;
if(index>=group.size()) return TRUE;
if(action==quickMoveUp || action==quickMoveDown)
{
const auto target=row+(action==quickMoveUp?-1:1);
@@ -370,7 +397,7 @@ INT_PTR CALLBACK quickFolderDialog(HWND dialog,UINT message,WPARAM wp,LPARAM lp)
}
if(action==quickEdit)
{
FolderShortcutEdit edit{group[row],view->digit,static_cast<size_t>(row)};
FolderShortcutEdit edit{group[index],digit,index};
if(editFolderShortcut(dialog,edit)) layoutQuickFolders(dialog,*view,static_cast<int>(row));
SetFocus(GetDlgItem(dialog,shortcutList));
return TRUE;
@@ -378,7 +405,7 @@ INT_PTR CALLBACK quickFolderDialog(HWND dialog,UINT message,WPARAM wp,LPARAM lp)
if(action==quickRemove)
{
auto updated=folderShortcuts;
updated[view->digit].erase(updated[view->digit].begin()+row);
updated[digit].erase(updated[digit].begin()+index);
if(!saveFolderShortcuts(updated))
{
MessageBoxW(dialog,L"Could not save folder shortcuts.",L"Folder shortcuts",MB_OK|MB_ICONWARNING);
@@ -386,17 +413,17 @@ INT_PTR CALLBACK quickFolderDialog(HWND dialog,UINT message,WPARAM wp,LPARAM lp)
}
folderShortcuts=std::move(updated);
notifyFilesPreferences(GetAncestor(dialog,GA_ROOTOWNER));
if(folderShortcuts[view->digit].empty()) finishFilesDialog(dialog,IDCANCEL);
if(view->all?view->entries.size()==1:folderShortcuts[digit].empty()) finishFilesDialog(dialog,IDCANCEL);
else layoutQuickFolders(dialog,*view,static_cast<int>(row));
return TRUE;
}
view->chosen=group[row];
view->chosen=group[index];
finishFilesDialog(dialog,IDOK);
return TRUE;
}
void showFolderShortcuts(Panel &panel,int digit)
void showFolderShortcuts(Panel &panel,int digit,bool all)
{
if(digit>=0)
{
@@ -419,6 +446,7 @@ void showFolderShortcuts(Panel &panel,int digit)
}
FolderShortcutView view{digit};
view.panel=&panel;
view.all=all;
const auto result=runFilesDialog(GetModuleHandleW(nullptr),MAKEINTRESOURCEW(109),GetParent(panel.list),
quickFolderDialog,reinterpret_cast<LPARAM>(&view));
SetFocus(panel.list);
+17 -2
View File
@@ -359,7 +359,7 @@ void chooseDrive(int index, bool fromMenu = false);
void openMenu(HWND window, int index);
void showFileDetails(const Panel &panel);
void editOptions(HWND owner);
void showFolderShortcuts(Panel &panel,int digit);
void showFolderShortcuts(Panel &panel,int digit,bool all=false);
void layout(HWND window);
DWORD preference(const wchar_t *name, DWORD fallback)
@@ -4046,7 +4046,8 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE, PWSTR, int show)
(message.hwnd==panels[0].list || message.hwnd==panels[1].list) &&
(GetKeyState(VK_CONTROL)&0x8000) && !(GetKeyState(VK_MENU)&0x8000) &&
!(GetKeyState(VK_LWIN)&0x8000) && !(GetKeyState(VK_RWIN)&0x8000) &&
message.wParam>='0' && message.wParam<='9' && !copyInProgress)
message.wParam>='0' && message.wParam<='9' && !copyInProgress &&
(message.wParam!='8' || (GetKeyState(VK_SHIFT)&0x8000)))
{
if(!(message.lParam & (1LL<<30)))
{
@@ -4060,6 +4061,20 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE, PWSTR, int show)
continue;
}
const bool filesMessage=message.hwnd==window || IsChild(window,message.hwnd);
if(filesMessage && !terminalVisible && !copyInProgress && !commandHistoryWindow &&
message.message==WM_KEYDOWN && message.wParam=='8' &&
(GetKeyState(VK_CONTROL)&0x8000) && !(GetKeyState(VK_MENU)&0x8000) &&
!(GetKeyState(VK_SHIFT)&0x8000) && !(GetKeyState(VK_LWIN)&0x8000) &&
!(GetKeyState(VK_RWIN)&0x8000))
{
if(!(message.lParam & (1LL<<30)))
{
hidePicker();
showMenu(false);
showFolderShortcuts(panels[active],-1,true);
}
continue;
}
const bool panelFocused=message.hwnd==panels[0].list || message.hwnd==panels[1].list;
if(panelFocused && !copyInProgress && message.message==WM_KEYDOWN &&
!(GetKeyState(VK_MENU)&0x8000) &&