using System.ComponentModel; using System.Drawing.Drawing2D; using System.Runtime.InteropServices; using SuzuMagnifier.Dtos; using static System.Windows.Forms.Design.AxImporter; namespace SuzuMagnifier { public partial class Form1 : Form { [StructLayout(LayoutKind.Sequential)] public struct POINT { public int X; public int Y; } [DllImport("user32.dll")] private static extern bool GetCursorPos(out POINT lpPoint); public static Point GetMousePosition() { GetCursorPos(out var p); return new Point(p.X, p.Y); } private readonly System.Windows.Forms.Timer _timer = new(); private Bitmap? _bitmap; private string jsonfigFilename; public Form1() { InitializeComponent(); this.BackColor = Color.Black; this.DoubleBuffered = true; this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer, true); this.Text = Application.ProductName; _timer.Interval = this.UpdateFrequency; _timer.Tick += (sender, e) => { UpdateMagnifier(); }; } protected async override void OnLoad(EventArgs e) { base.OnLoad(e); var args = GetCommandLine()!; jsonfigFilename = args.Where(x => (x.Key.Equals("o") || x.Key.Equals("open"))).Select(x => x.Value).FirstOrDefault(); if (string.IsNullOrWhiteSpace(jsonfigFilename)) { jsonfigFilename = Path.ChangeExtension(Application.ExecutablePath, "jsonfig"); } if (System.IO.File.Exists(jsonfigFilename)) { var newSettings = await LoadSettings(jsonfigFilename); if (newSettings == null) { newSettings = new SavedOptions(); } this.HighQuality = newSettings.HighQuality; this.ZoomFactor = newSettings.ZoomFactor; //this.UpdateFrequency = newSettings.UpdateFrequency; this.ShowCrosshair = newSettings.ShowCrosshair; this.CrosshairSize = newSettings.CrosshairSize; this.CrosshairColour = newSettings.CrosshairColour; } } protected override void OnShown(EventArgs e) { base.OnShown(e); //_timer.Start(); } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); var g = e.Graphics; if (!_timer.Enabled) { TextRenderer.DrawText(g, "Press [Space] To Start", this.Font, this.ClientRectangle, this.ForeColor, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.NoPadding); } if (_bitmap == null) { return; } if (this.HighQuality) { g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.PixelOffsetMode = PixelOffsetMode.HighQuality; g.SmoothingMode = SmoothingMode.HighQuality; } else { g.InterpolationMode = InterpolationMode.NearestNeighbor; g.PixelOffsetMode = PixelOffsetMode.None; g.SmoothingMode = SmoothingMode.None; } g.DrawImage(_bitmap, this.ClientRectangle); // Draw center crosshair if (this.ShowCrosshair) { var cx = Divide(this.Width, 2); var cy = Divide(this.Height, 2); g.DrawLine(new Pen(this.CrosshairColour), cx - this.CrosshairSize, cy, cx + this.CrosshairSize, cy); g.DrawLine(new Pen(this.CrosshairColour), cx, cy - this.CrosshairSize, cx, cy + this.CrosshairSize); } } protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e) { base.OnPreviewKeyDown(e); if (e.Control) { switch (e.KeyCode) { //case Keys.D0: // this.ZoomFactor = 1; // break; //case Keys.OemMinus: // this.ZoomFactor--; // break; //case Keys.Oemplus: // this.ZoomFactor++; // break; //case Keys.F11: // toolStripMenuItem5_Click(null, null); // break; default: break; } } else { switch (e.KeyCode) { case Keys.Space: if (_timer.Enabled) { _timer.Stop(); } else { _timer.Start(); } break; case Keys.Escape: exitiToolStripMenuItem_Click(null, null); break; //case Keys.F11: // toolStripMenuItem3_Click(null, null); // break; default: break; } } } protected async override void OnFormClosing(FormClosingEventArgs e) { base.OnFormClosing(e); var result = MessageBox.Show("Do you want to save settings to file?", "Save Settings?", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question); if (result == DialogResult.Yes) { var result2 = await SaveSettings(jsonfigFilename); if (result2) { return; } MessageBox.Show("Could not save settings. An error has occurred.", "Save Settings?", MessageBoxButtons.OK, MessageBoxIcon.Error); e.Cancel = true; } else if (result == DialogResult.No) { // Do nothing } else { e.Cancel = true; } } [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public bool HighQuality { get; set; } = false; [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public int ZoomFactor { get => field; set { if (value < 0) { field = 1; return; } if (value > 20) { field = 20; return; } field = value; } } = 2; [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public int UpdateFrequency { get; set; } = 33; [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public bool ShowCrosshair { get; set; } = true; [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public int CrosshairSize { get => field; set { if (value < 5) { field = 5; return; } if (value > 200) { field = 200; return; } field = value; } } = 20; [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public Color CrosshairColour { get; set; } = Color.FromArgb(255, 255, 0); private void contextMenuStrip1_Opening(object sender, CancelEventArgs e) { toolStripMenuItem1.Enabled = !_timer.Enabled; toolStripMenuItem2.Enabled = _timer.Enabled; toolStripMenuItem5.Checked = this.TopMost; showToolStripMenuItem.Checked = this.ShowCrosshair; smallToolStripMenuItem.Checked = (this.CrosshairSize == 10); mediumToolStripMenuItem.Checked = (this.CrosshairSize == 20); largeToolStripMenuItem.Checked = (this.CrosshairSize == 50); agentaToolStripMenuItem.Checked = this.CrosshairColour == Color.FromArgb(255, 0, 255); cyanToolStripMenuItem.Checked = this.CrosshairColour == Color.FromArgb(0, 255, 255); yellowToolStripMenuItem.Checked = this.CrosshairColour == Color.FromArgb(255, 255, 0); greenToolStripMenuItem.Checked = this.CrosshairColour == Color.FromArgb(0, 255, 0); redToolStripMenuItem.Checked = this.CrosshairColour == Color.FromArgb(255, 0, 0); blackToolStripMenuItem.Checked = this.CrosshairColour == Color.FromArgb(0, 0, 0); whiteToolStripMenuItem.Checked = this.CrosshairColour == Color.FromArgb(255, 255, 255); fasterToolStripMenuItem.Checked = !this.HighQuality; fasterToolStripMenuItem.Enabled = this.HighQuality; highToolStripMenuItem.Checked = this.HighQuality; highToolStripMenuItem.Enabled = !this.HighQuality; } #region context menu /// /// Start /// /// /// private void toolStripMenuItem1_Click(object sender, EventArgs e) { if (_timer.Enabled) { return; } _timer.Start(); } /// /// Stop /// /// /// private void toolStripMenuItem2_Click(object sender, EventArgs e) { if (!_timer.Enabled) { return; } _timer.Stop(); } /// /// Quality, fast /// /// /// private void fastToolStripMenuItem_Click(object sender, EventArgs e) { this.HighQuality = false; } /// /// QUality, high /// /// /// private void highToolStripMenuItem_Click(object sender, EventArgs e) { this.HighQuality = true; } /// /// Zoom, increase /// /// /// private void toolStripMenuItem7_Click(object sender, EventArgs e) { this.ZoomFactor++; } /// /// Zoom, decrease /// /// /// private void toolStripMenuItem8_Click(object sender, EventArgs e) { this.ZoomFactor--; } /// /// Zoom, reset /// /// /// private void resetToolStripMenuItem_Click(object sender, EventArgs e) { this.ZoomFactor = 1; } /// /// Crosshair, colour, magenta /// /// /// private void agentaToolStripMenuItem_Click(object sender, EventArgs e) { this.CrosshairColour = Color.FromArgb(255, 0, 255); } /// /// Crosshair, colour, cyan /// /// /// private void cyanToolStripMenuItem_Click(object sender, EventArgs e) { this.CrosshairColour = Color.FromArgb(0, 255, 255); } /// /// Crosshair, colour, yellow /// /// /// private void yellowToolStripMenuItem_Click(object sender, EventArgs e) { this.CrosshairColour = Color.FromArgb(255, 255, 0); } /// /// Crosshair, colour, green /// /// /// private void greenToolStripMenuItem_Click(object sender, EventArgs e) { this.CrosshairColour = Color.FromArgb(0, 255, 0); } /// /// Crosshair, colour, red /// /// /// private void redToolStripMenuItem_Click(object sender, EventArgs e) { this.CrosshairColour = Color.FromArgb(255, 0, 0); } /// /// Crosshair, colour, black /// /// /// private void blackToolStripMenuItem_Click(object sender, EventArgs e) { this.CrosshairColour = Color.FromArgb(0, 0, 0); } /// /// Crosshair, colour, white /// /// /// private void whiteToolStripMenuItem_Click(object sender, EventArgs e) { this.CrosshairColour = Color.FromArgb(255, 255, 255); } /// /// ALways on top /// /// /// private void toolStripMenuItem5_Click(object sender, EventArgs e) { this.TopMost = !this.TopMost; } /// /// Fullscreen /// /// /// private void toolStripMenuItem3_Click(object sender, EventArgs e) { if (this.WindowState == FormWindowState.Normal) { this.FormBorderStyle = FormBorderStyle.None; this.WindowState = FormWindowState.Maximized; } else { this.FormBorderStyle = FormBorderStyle.Sizable; this.WindowState = FormWindowState.Normal; } } /// /// Exit /// /// /// private void exitiToolStripMenuItem_Click(object sender, EventArgs e) { if (_timer.Enabled) { _timer.Stop(); _timer.Dispose(); } this.Close(); } /// /// Crosshair, toggle /// /// /// private void showToolStripMenuItem_Click(object sender, EventArgs e) { this.ShowCrosshair = !this.ShowCrosshair; } /// /// Croisshair, size, small /// /// /// private void smallToolStripMenuItem_Click(object sender, EventArgs e) { this.CrosshairSize = 10; } /// /// Croisshair, size, medium /// /// /// private void mediumToolStripMenuItem_Click(object sender, EventArgs e) { this.CrosshairSize = 20; } /// /// Croisshair, size, large /// /// /// private void largeToolStripMenuItem_Click(object sender, EventArgs e) { this.CrosshairSize = 50; } #endregion private void UpdateMagnifier() { //var mouse = Cursor.Position; var mouse = GetMousePosition(); var w = Divide(this.Width, this.ZoomFactor); var h = Divide(this.Height, this.ZoomFactor); var cx = Divide(w, 2); var cy = Divide(h, 2); var x = mouse.X - cx; var y = mouse.Y - cy; var sourceRect = new Rectangle(x, y, w, h); _bitmap?.Dispose(); _bitmap = null; _bitmap = new Bitmap(sourceRect.Width, sourceRect.Height); using Graphics g = Graphics.FromImage(_bitmap); g.CopyFromScreen(sourceRect.Location, Point.Empty, sourceRect.Size); this.Invalidate(); } private int Divide(int x, int y) { return (int)Math.Floor((decimal)x / y); } /// /// Get execution arguments. /// /// private List> GetCommandLine() { var result = new List>(); var args = Environment.GetCommandLineArgs() ?? new string[0]; if (args.Length <= 1) { return result; } var key = string.Empty; var flag = false; for (int i = 1; i < args.Length; i++) { var text = args[i]; if (string.IsNullOrWhiteSpace(text)) { continue; } if (text.StartsWith("-")) { if (flag) { result.Add(new KeyValuePair(key, string.Empty)); } key = text?.TrimStart('-')?.Trim() ?? string.Empty; flag = true; } else { result.Add(new KeyValuePair(key, text?.Trim() ?? string.Empty)); flag = false; } } return result; } private async Task LoadSettings(string filename) { if (!System.IO.File.Exists(filename)) { return null; } string sourceCode; try { sourceCode = await System.IO.File.ReadAllTextAsync(filename); } catch (Exception) { return null; } if (string.IsNullOrWhiteSpace(sourceCode)) { return null; } try { return System.Text.Json.JsonSerializer.Deserialize(sourceCode); } catch (Exception) { return null; } } private async Task SaveSettings(string filename) { var result = new SavedOptions(); result.AutoStart = false; result.HighQuality = this.HighQuality; result.ZoomFactor = this.ZoomFactor; result.UpdateFrequency = this.UpdateFrequency; result.ShowCrosshair = this.ShowCrosshair; result.CrosshairSize = this.CrosshairSize; result.CrosshairColour = this.CrosshairColour; string sourceCode = ""; try { sourceCode = System.Text.Json.JsonSerializer.Serialize(result); } catch (Exception) { return false; } if (string.IsNullOrWhiteSpace(sourceCode)) { return false; } if (System.IO.File.Exists(filename)) { try { System.IO.File.Delete(filename); } catch (Exception) { return false; } } try { await System.IO.File.WriteAllTextAsync(filename, sourceCode); } catch (Exception) { return false; } return true; } } }