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;
}
}
}