Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 44 additions & 26 deletions shotpath.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,6 @@ public class ShotPath : Form
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern bool DestroyIcon(IntPtr handle);

[DllImport("user32.dll")]
private static extern bool SetProcessDPIAware();

private const int HOTKEY_ID = 9000;
private const int HOTKEY_ID_CTRL = 9001;
private const int HOTKEY_ID_ALT = 9002;
Expand Down Expand Up @@ -160,24 +157,27 @@ private void TakeScreenshot(bool copyAsImage = false, bool uploadToImgur = false
{
// Small delay to let menus settle
System.Threading.Thread.Sleep(100);

// Use virtual screen to capture entire desktop (handles multi-monitor automatically)
Rectangle virtualScreen = SystemInformation.VirtualScreen;
selectionForm = new SelectionForm(virtualScreen);

selectionForm = new SelectionForm();
if (selectionForm.ShowDialog() == DialogResult.OK)
{
Rectangle selection = selectionForm.Selection;

// Use the pre-captured screenshot from SelectionForm
using (Bitmap bitmap = new Bitmap(selection.Width, selection.Height))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
// Account for virtual screen offset
// Selection coordinates are in virtual screen space
Rectangle sourceRect = new Rectangle(
selection.X - SystemInformation.VirtualScreen.X,
selection.Y - SystemInformation.VirtualScreen.Y,
selection.X - virtualScreen.X,
selection.Y - virtualScreen.Y,
selection.Width,
selection.Height
);

g.DrawImage(selectionForm.Screenshot, 0, 0, sourceRect, GraphicsUnit.Pixel);
}

Expand Down Expand Up @@ -571,10 +571,16 @@ protected override void Dispose(bool disposing)
base.Dispose(disposing);
}

[DllImport("user32.dll")]
private static extern bool SetProcessDpiAwarenessContext(IntPtr value);

private static readonly IntPtr DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 = new IntPtr(-4);

[STAThread]
static void Main()
{
SetProcessDPIAware();
// Use modern DPI awareness for proper multi-monitor support
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new ShotPath());
Expand All @@ -597,29 +603,29 @@ public class SelectionForm : Form
[DllImport("user32.dll")]
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);


private const int GWL_EXSTYLE = -20;
private const int WS_EX_TRANSPARENT = 0x00000020;
private const int WS_EX_LAYERED = 0x00080000;

public SelectionForm()
public SelectionForm(Rectangle virtualScreen)
{
// Set DPI awareness
this.AutoScaleMode = AutoScaleMode.None;

// Get virtual screen bounds (all monitors)
Rectangle bounds = SystemInformation.VirtualScreen;

// Capture screenshot before showing form
screenshot = new Bitmap(bounds.Width, bounds.Height);
// Capture screenshot of entire virtual screen
screenshot = new Bitmap(virtualScreen.Width, virtualScreen.Height);
using (Graphics g = Graphics.FromImage(screenshot))
{
g.CopyFromScreen(bounds.X, bounds.Y, 0, 0, bounds.Size);
g.CopyFromScreen(virtualScreen.X, virtualScreen.Y, 0, 0, virtualScreen.Size);
}

this.FormBorderStyle = FormBorderStyle.None;
this.Cursor = Cursors.Cross;
this.Location = new Point(bounds.X, bounds.Y);
this.Size = new Size(bounds.Width, bounds.Height);
this.StartPosition = FormStartPosition.Manual;

// Position form to cover entire virtual screen
this.Location = virtualScreen.Location;
this.Size = virtualScreen.Size;
this.TopMost = true;
this.DoubleBuffered = true;
this.ShowInTaskbar = false;
Expand All @@ -635,7 +641,8 @@ private void OnMouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
startPoint = e.Location;
// Convert form-local coordinates to global screen coordinates
startPoint = new Point(e.X + this.Location.X, e.Y + this.Location.Y);
isSelecting = true;
}
}
Expand All @@ -644,10 +651,13 @@ private void OnMouseMove(object sender, MouseEventArgs e)
{
if (isSelecting)
{
int x = Math.Min(startPoint.X, e.X);
int y = Math.Min(startPoint.Y, e.Y);
int width = Math.Abs(startPoint.X - e.X);
int height = Math.Abs(startPoint.Y - e.Y);
// Convert form-local coordinates to global screen coordinates
Point currentPoint = new Point(e.X + this.Location.X, e.Y + this.Location.Y);

int x = Math.Min(startPoint.X, currentPoint.X);
int y = Math.Min(startPoint.Y, currentPoint.Y);
int width = Math.Abs(startPoint.X - currentPoint.X);
int height = Math.Abs(startPoint.Y - currentPoint.Y);

selection = new Rectangle(x, y, width, height);
this.Invalidate();
Expand Down Expand Up @@ -677,9 +687,17 @@ private void OnPaint(object sender, PaintEventArgs e)

if (selection.Width > 0 && selection.Height > 0)
{
// Convert global selection coordinates to local form coordinates for drawing
Rectangle localSelection = new Rectangle(
selection.X - this.Location.X,
selection.Y - this.Location.Y,
selection.Width,
selection.Height
);

// Draw darkened overlay outside selection
Region region = new Region(this.ClientRectangle);
region.Exclude(selection);
region.Exclude(localSelection);

using (SolidBrush brush = new SolidBrush(Color.FromArgb(120, 0, 0, 0)))
{
Expand All @@ -690,7 +708,7 @@ private void OnPaint(object sender, PaintEventArgs e)
using (Pen pen = new Pen(Color.Red, 2))
{
pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
e.Graphics.DrawRectangle(pen, selection);
e.Graphics.DrawRectangle(pen, localSelection);
}
}
else
Expand Down
Binary file modified shotpath.exe
Binary file not shown.