Merge pull request #5880 from RaiKoHoff/dev_master

feat: open hyperlink in background via Ctrl+Shift+LClick
This commit is contained in:
Rainer Kottenhoff 2026-05-16 12:07:12 +02:00 committed by GitHub
commit 97c14a9e45
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 44 additions and 7 deletions

View File

@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.4.33403.182
# Visual Studio Version 18
VisualStudioVersion = 18.6.11806.211 stable
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{D32CB10B-1891-471D-B780-5445BC67C1E2}"
ProjectSection(SolutionItems) = preProject

View File

@ -777,6 +777,21 @@ static VOID CALLBACK TinyExprCopyTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEven
// ----------------------------------------------------------------------------
// Ends the temporary always-on-top window opened around a background URL launch
// (Ctrl+Shift+Click). Restores Notepad3's normal z-order from Settings.AlwaysOnTop.
static VOID CALLBACK _ForegroundLockReleaseTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
UNREFERENCED_PARAMETER(uMsg);
UNREFERENCED_PARAMETER(dwTime);
KillTimer(hwnd, idEvent); // one-shot
LockSetForegroundWindow(LSFW_UNLOCK);
SetWindowPos(hwnd, Settings.AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
SetForegroundWindow(hwnd);
}
// ----------------------------------------------------------------------------
//=============================================================================
//
// InvalidateStyleRedraw
@ -8899,7 +8914,18 @@ bool HandleHotSpotURLClicked(const DocPos position, const HYPERLINK_OPS operatio
Path_Release(hfile_pth);
} else if (operation & OPEN_WITH_BROWSER) { // open in web browser or associated application
bool const bBackground = (operation & OPEN_BACKGROUND) != 0;
int const nShowFlag = bBackground ? SW_SHOWNOACTIVATE : SW_SHOWNORMAL;
if (bBackground) {
// Pin Notepad3 above the about-to-launch browser; SWP_NOACTIVATE keeps focus.
// The lock prevents the browser's async SetForegroundWindow from winning.
SetWindowPos(Globals.hwndMain, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
LockSetForegroundWindow(LSFW_LOCK);
}
HPATHL hDirectory = Path_Allocate(NULL);
if (UrlIsFileUrl(szTextW)) {
@ -8929,7 +8955,7 @@ bool HandleHotSpotURLClicked(const DocPos position, const HYPERLINK_OPS operatio
sei.lpFile = StrgGet(Settings2.HyperlinkShellExURLWithApp);
sei.lpParameters = StrgIsNotEmpty(hstr_params) ? StrgGet(hstr_params) : szUnEscW;
sei.lpDirectory = Path_Get(hDirectory);
sei.nShow = SW_SHOWNORMAL;
sei.nShow = nShowFlag;
bHandled = ShellExecuteExW(&sei);
StrgDestroy(hstr_params);
@ -8945,10 +8971,16 @@ bool HandleHotSpotURLClicked(const DocPos position, const HYPERLINK_OPS operatio
sei.lpFile = szUnEscW;
sei.lpParameters = NULL;
sei.lpDirectory = Path_Get(hDirectory);
sei.nShow = SW_SHOWNORMAL;
sei.nShow = nShowFlag;
bHandled = ShellExecuteExW(&sei);
}
if (bBackground) {
// 600 ms covers the typical browser async-activation window with margin.
SetForegroundWindow(Globals.hwndMain);
SetTimer(Globals.hwndMain, ID_FGLOCKRELEASETIMER, 600, _ForegroundLockReleaseTimerProc);
}
Path_Release(hDirectory);
}
}
@ -9659,7 +9691,11 @@ static LRESULT _MsgNotifyFromEdit(HWND hwnd, const SCNotification* const scn)
HandleHotSpotURLClicked(scn->position, OPEN_IN_NOTEPAD3);
}
} else if (_s_indic_click_modifiers & SCMOD_CTRL) {
HandleHotSpotURLClicked(scn->position, OPEN_WITH_BROWSER); // if applicable (file://)
// Ctrl+Shift+Click → open in background (browser behind, Notepad3 stays active)
HYPERLINK_OPS const op = (_s_indic_click_modifiers & SCMOD_SHIFT)
? (HYPERLINK_OPS)(OPEN_WITH_BROWSER | OPEN_BACKGROUND)
: OPEN_WITH_BROWSER;
HandleHotSpotURLClicked(scn->position, op); // if applicable (file://)
}
} else if (SciCall_IndicatorValueAt(INDIC_NP3_COLOR_DEF, scn->position) > 0) {
if (_s_indic_click_modifiers & SCMOD_CTRL) {

View File

@ -72,6 +72,7 @@ np3params, *LPnp3params;
#define ID_ATOMICSAVETIMER (0xA005) // Atomic Save Detection
#define ID_DEFERMINIMIZETIMER (0xA006) // Deferred minimize on /B + /I startup
#define ID_TINYEXPRCOPYTIMER (0xA007) // TinyExpr status-bar single-click copy debounce
#define ID_FGLOCKRELEASETIMER (0xA008) // Release LockSetForegroundWindow after background URL launch
//==== Reuse Window Lock Timeout ==============================================

View File

@ -180,7 +180,7 @@ typedef COLORREF COLORALPHAREF;
// ----------------------------------------------------------------------------
typedef enum COLOR_LAYER { BACKGROUND_LAYER = 0, FOREGROUND_LAYER = 1 } COLOR_LAYER; // Style_GetColor()
typedef enum HYPERLINK_OPS { OPEN_WITH_BROWSER = 1, OPEN_IN_NOTEPAD3 = (1<<1), OPEN_NEW_NOTEPAD3 = (1<<2), COPY_HYPERLINK = (1<<3), SELECT_HYPERLINK = (1<<4) } HYPERLINK_OPS; // Hyperlink Operations
typedef enum HYPERLINK_OPS { OPEN_WITH_BROWSER = 1, OPEN_IN_NOTEPAD3 = (1<<1), OPEN_NEW_NOTEPAD3 = (1<<2), COPY_HYPERLINK = (1<<3), SELECT_HYPERLINK = (1<<4), OPEN_BACKGROUND = (1<<5) } HYPERLINK_OPS; // Hyperlink Operations
typedef enum FILE_WATCHING_MODE { FWM_NO_INIT = -1, FWM_DONT_CARE = 0, FWM_INDICATORSILENT = 1, FWM_MSGBOX = 2, FWM_AUTORELOAD = 3, FWM_EXCLUSIVELOCK = 4 } FILE_WATCHING_MODE;
typedef enum FILE_WATCHING_METHOD { FWMTH_BOTH = 0, FWMTH_POLL = 1, FWMTH_PUSH = 2 } FILE_WATCHING_METHOD;
typedef enum FOCUSVIEW_MARKER_MODE { FVMM_MARGIN = 1, FVMM_LN_BACKGR = 2, FVMM_FOLD = 4 } FOCUSVIEW_MARKER_MODE;