Skip to content

Commit 4dfacb3

Browse files
committed
feat(screenshot): add window screenshot capture by window title
- Implement window screenshot feature using Win32 API FindWindow and GetWindowRect - Capture specified window area including optional cursor drawing - Log detailed info and errors during window capture process - Add handling for new "-ws|" command to trigger window screenshot - Ensure high DPI awareness context during capture - Validate parameters and manage save path for captured images
1 parent a9a2efb commit 4dfacb3

File tree

4 files changed

+78
-0
lines changed

4 files changed

+78
-0
lines changed
41.4 KB
Loading

@Resources/icons/Window.png

-4.61 KB
Loading

FinalShot/FinalShot.cs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,22 @@ public static class ScreenshotManager
9191
private static extern IntPtr SetThreadDpiAwarenessContext(IntPtr dpiContext);
9292
private static readonly IntPtr DPI_PER_MONITOR_AWARE_V2 = new IntPtr(-4);
9393

94+
[DllImport("user32.dll", CharSet = CharSet.Auto)]
95+
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
96+
97+
[DllImport("user32.dll")]
98+
[return: MarshalAs(UnmanagedType.Bool)]
99+
private static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
100+
101+
[StructLayout(LayoutKind.Sequential)]
102+
private struct RECT
103+
{
104+
public int Left;
105+
public int Top;
106+
public int Right;
107+
public int Bottom;
108+
}
109+
94110
[DllImport("user32.dll")]
95111
private static extern bool GetCursorInfo(out CURSORINFO pci);
96112

@@ -198,6 +214,62 @@ public static void TakeCustom(Settings settings, Action finishCallback)
198214
Application.Run(new CustomScreenshotForm(settings, finishCallback));
199215
}
200216

217+
public static void TakeWindowScreenshot(Settings settings, string windowTitle)
218+
{
219+
Logger.Log($"TakeWindowScreenshot() called. WindowTitle='{windowTitle}'");
220+
if (string.IsNullOrEmpty(settings.SavePath))
221+
{
222+
Logger.Log("TakeWindowScreenshot: SavePath is empty, aborting.");
223+
return;
224+
}
225+
226+
if (string.IsNullOrWhiteSpace(windowTitle))
227+
{
228+
Logger.Log("TakeWindowScreenshot: WindowTitle is empty, aborting.");
229+
return;
230+
}
231+
232+
WithHighDpiContext(() =>
233+
{
234+
IntPtr hWnd = FindWindow(null, windowTitle);
235+
if (hWnd == IntPtr.Zero)
236+
{
237+
Logger.Log($"TakeWindowScreenshot: Window '{windowTitle}' not found.");
238+
return;
239+
}
240+
241+
if (GetWindowRect(hWnd, out RECT rect))
242+
{
243+
int width = rect.Right - rect.Left;
244+
int height = rect.Bottom - rect.Top;
245+
246+
if (width <= 0 || height <= 0)
247+
{
248+
Logger.Log($"TakeWindowScreenshot: Invalid window dimensions {width}x{height}");
249+
return;
250+
}
251+
252+
Rectangle bounds = new Rectangle(rect.Left, rect.Top, width, height);
253+
Logger.Log($"TakeWindowScreenshot: Capturing window at {bounds}");
254+
255+
using (var bmp = new Bitmap(width, height))
256+
using (var g = Graphics.FromImage(bmp))
257+
{
258+
g.CopyFromScreen(bounds.Location, Point.Empty, bounds.Size);
259+
if (settings.ShowCursor)
260+
DrawCursor(g, bounds);
261+
SaveImageSafely(bmp, settings);
262+
}
263+
}
264+
else
265+
{
266+
Logger.Log($"TakeWindowScreenshot: Failed to get window rect for '{windowTitle}'");
267+
}
268+
});
269+
270+
ExecuteFinishAction(settings);
271+
}
272+
201273

202274
public static void CompositeCapture(Rectangle rect, Settings settings)
203275
{
@@ -450,6 +522,12 @@ public static void ExecuteBang(IntPtr data, IntPtr args)
450522
ScreenshotManager.ExecuteFinishAction(settings);
451523
});
452524
}
525+
else if (cmd.StartsWith("-ws|", StringComparison.OrdinalIgnoreCase))
526+
{
527+
string windowTitle = cmd.Substring(4); // Extract everything after "-ws|"
528+
Logger.Log($"ExecuteBang: Window screenshot requested for '{windowTitle}'");
529+
ScreenshotManager.TakeWindowScreenshot(settings, windowTitle);
530+
}
453531
else if (cmd.StartsWith("ExecuteBatch ", StringComparison.OrdinalIgnoreCase))
454532
{
455533
if (int.TryParse(cmd.Split(' ')[1], out int code))

Resources/Skins/FinalShot/Main.ini

198 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)