2203 lines
52 KiB
C#
2203 lines
52 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Drawing;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Windows.Forms;
|
|
|
|
using BizHawk.Common;
|
|
using BizHawk.Common.NumberExtensions;
|
|
using BizHawk.Common.StringExtensions;
|
|
using BizHawk.Emulation.Common;
|
|
using BizHawk.Client.Common;
|
|
|
|
namespace BizHawk.Client.EmuHawk
|
|
{
|
|
public partial class HexEditor : Form, IToolForm
|
|
{
|
|
private const int FontWidth = 7; // Width of 1 digits
|
|
|
|
private readonly List<ToolStripMenuItem> _domainMenuItems = new List<ToolStripMenuItem>();
|
|
private readonly char[] _nibbles = { 'G', 'G', 'G', 'G', 'G', 'G', 'G', 'G' }; // G = off 0-9 & A-F are acceptable values
|
|
private readonly List<int> _secondaryHighlightedAddresses = new List<int>();
|
|
|
|
private readonly Dictionary<int, char> _textTable = new Dictionary<int, char>();
|
|
|
|
private int _defaultWidth;
|
|
private int _defaultHeight;
|
|
private int _rowsVisible;
|
|
private int _numDigits = 4;
|
|
private string _numDigitsStr = "{0:X4}";
|
|
private string _digitFormatString = "{0:X2}";
|
|
private int _addressHighlighted = -1;
|
|
private int _addressOver = -1;
|
|
|
|
private int _maxRow;
|
|
|
|
private MemoryDomain _domain = new MemoryDomain(
|
|
"NULL", 1024, MemoryDomain.Endian.Little, addr => 0, delegate(int a, byte v) { v = 0; });
|
|
|
|
private int _row;
|
|
private int _addr;
|
|
private string _findStr = string.Empty;
|
|
private bool _mouseIsDown;
|
|
private byte[] _rom;
|
|
private MemoryDomain _romDomain;
|
|
private HexFind _hexFind = new HexFind();
|
|
|
|
// Configurations
|
|
private bool _bigEndian;
|
|
private int _dataSize;
|
|
|
|
public HexEditor()
|
|
{
|
|
InitializeComponent();
|
|
AddressesLabel.BackColor = Color.Transparent;
|
|
LoadConfigSettings();
|
|
SetHeader();
|
|
Closing += (o, e) => SaveConfigSettings();
|
|
Header.Font = new Font("Courier New", 8);
|
|
AddressesLabel.Font = new Font("Courier New", 8);
|
|
AddressLabel.Font = new Font("Courier New", 8);
|
|
TopMost = Global.Config.HexEditorSettings.TopMost;
|
|
}
|
|
|
|
private int? HighlightedAddress
|
|
{
|
|
get
|
|
{
|
|
if (_addressHighlighted >= 0)
|
|
{
|
|
return _addressHighlighted;
|
|
}
|
|
|
|
return null; // Negative = no address highlighted
|
|
}
|
|
}
|
|
|
|
private Watch.WatchSize WatchSize
|
|
{
|
|
get
|
|
{
|
|
return (Watch.WatchSize)_dataSize;
|
|
}
|
|
}
|
|
|
|
#region API
|
|
|
|
public bool UpdateBefore
|
|
{
|
|
get { return false; }
|
|
}
|
|
|
|
public bool AskSave()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
public void UpdateValues()
|
|
{
|
|
if (!IsHandleCreated || IsDisposed)
|
|
{
|
|
return;
|
|
}
|
|
|
|
AddressesLabel.Text = GenerateMemoryViewString();
|
|
AddressLabel.Text = GenerateAddressString();
|
|
}
|
|
|
|
public void Restart()
|
|
{
|
|
if (!IsHandleCreated || IsDisposed)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var theDomain = _domain.Name.ToLower() == "file on disk" ? 999 : GetDomainInt(_domain.Name);
|
|
|
|
SetMemoryDomainMenu(); // Calls update routines, TODO: refactor, that is confusing!
|
|
|
|
if (theDomain.HasValue)
|
|
{
|
|
SetMemoryDomain(theDomain.Value);
|
|
}
|
|
|
|
SetHeader();
|
|
ResetScrollBar();
|
|
SetDataSize(_dataSize);
|
|
UpdateValues();
|
|
AddressLabel.Text = GenerateAddressString();
|
|
}
|
|
|
|
public void SetToAddresses(IEnumerable<int> addresses, MemoryDomain domain)
|
|
{
|
|
var addrList = addresses.ToList();
|
|
if (addrList.Any())
|
|
{
|
|
SetDomain(domain);
|
|
SetHighlighted(addrList[0]);
|
|
_secondaryHighlightedAddresses.Clear();
|
|
_secondaryHighlightedAddresses.AddRange(addrList.Where(addr => addr != addrList[0]).ToList());
|
|
ClearNibbles();
|
|
UpdateValues();
|
|
MemoryViewerBox.Refresh();
|
|
AddressLabel.Text = GenerateAddressString();
|
|
}
|
|
}
|
|
|
|
public byte[] ConvertTextToBytes(string str)
|
|
{
|
|
if (_textTable.Any())
|
|
{
|
|
var byteArr = new List<byte>();
|
|
foreach (var chr in str)
|
|
{
|
|
byteArr.Add((byte)_textTable.FirstOrDefault(kvp => kvp.Value == chr).Key);
|
|
}
|
|
|
|
return byteArr.ToArray();
|
|
}
|
|
|
|
return str.Select(Convert.ToByte).ToArray();
|
|
}
|
|
|
|
public void FindNext(string value, bool wrap)
|
|
{
|
|
var found = -1;
|
|
|
|
var search = value.Replace(" ", string.Empty).ToUpper();
|
|
if (string.IsNullOrEmpty(search))
|
|
{
|
|
return;
|
|
}
|
|
|
|
var numByte = search.Length / 2;
|
|
|
|
int startByte;
|
|
if (_addressHighlighted == -1)
|
|
{
|
|
startByte = 0;
|
|
}
|
|
else if (_addressHighlighted >= (_domain.Size - 1 - numByte))
|
|
{
|
|
startByte = 0;
|
|
}
|
|
else
|
|
{
|
|
startByte = _addressHighlighted + _dataSize;
|
|
}
|
|
|
|
for (var i = startByte; i < (_domain.Size - numByte); i++)
|
|
{
|
|
var ramblock = new StringBuilder();
|
|
for (var j = 0; j < numByte; j++)
|
|
{
|
|
ramblock.Append(string.Format("{0:X2}", (int)_domain.PeekByte(i + j)));
|
|
}
|
|
|
|
var block = ramblock.ToString().ToUpper();
|
|
if (search == block)
|
|
{
|
|
found = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (found > -1)
|
|
{
|
|
HighlightSecondaries(search, found);
|
|
GoToAddress(found);
|
|
_findStr = search;
|
|
}
|
|
else if (wrap == false)
|
|
{
|
|
FindPrev(value, true); // Search the opposite direction if not found
|
|
}
|
|
|
|
_hexFind.Close();
|
|
}
|
|
|
|
public void FindPrev(string value, bool wrap)
|
|
{
|
|
var found = -1;
|
|
|
|
var search = value.Replace(" ", string.Empty).ToUpper();
|
|
if (string.IsNullOrEmpty(search))
|
|
{
|
|
return;
|
|
}
|
|
|
|
var numByte = search.Length / 2;
|
|
|
|
int startByte;
|
|
if (_addressHighlighted == -1)
|
|
{
|
|
startByte = _domain.Size - _dataSize;
|
|
}
|
|
else
|
|
{
|
|
startByte = _addressHighlighted - 1;
|
|
}
|
|
|
|
for (var i = startByte; i >= 0; i--)
|
|
{
|
|
var ramblock = new StringBuilder();
|
|
for (var j = 0; j < numByte; j++)
|
|
{
|
|
ramblock.Append(string.Format("{0:X2}", (int)_domain.PeekByte(i + j)));
|
|
}
|
|
|
|
var block = ramblock.ToString().ToUpper();
|
|
if (search == block)
|
|
{
|
|
found = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (found > -1)
|
|
{
|
|
HighlightSecondaries(search, found);
|
|
GoToAddress(found);
|
|
_findStr = search;
|
|
}
|
|
else if (wrap == false)
|
|
{
|
|
FindPrev(value, true); // Search the opposite direction if not found
|
|
}
|
|
|
|
_hexFind.Close();
|
|
}
|
|
|
|
#endregion
|
|
|
|
private char Remap(byte val)
|
|
{
|
|
if (_textTable.Any())
|
|
{
|
|
if (_textTable.ContainsKey(val))
|
|
{
|
|
return _textTable[val];
|
|
}
|
|
|
|
return '?';
|
|
}
|
|
else
|
|
{
|
|
if (val < ' ')
|
|
{
|
|
return '.';
|
|
}
|
|
|
|
if (val >= 0x80)
|
|
{
|
|
return '.';
|
|
}
|
|
|
|
return (char)val;
|
|
}
|
|
}
|
|
|
|
private static int? GetDomainInt(string name)
|
|
{
|
|
for (var i = 0; i < Global.Emulator.MemoryDomains.Count; i++)
|
|
{
|
|
if (Global.Emulator.MemoryDomains[i].Name == name)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private static bool CurrentRomIsArchive()
|
|
{
|
|
var path = GlobalWin.MainForm.CurrentlyOpenRom;
|
|
if (path == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
using (var file = new HawkFile())
|
|
{
|
|
file.Open(path);
|
|
|
|
if (!file.Exists)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return file.IsArchive;
|
|
}
|
|
}
|
|
|
|
private static byte[] GetRomBytes()
|
|
{
|
|
var path = GlobalWin.MainForm.CurrentlyOpenRom;
|
|
if (path == null)
|
|
{
|
|
return new byte[] { 0xFF };
|
|
}
|
|
|
|
using (var file = new HawkFile())
|
|
{
|
|
file.Open(path);
|
|
|
|
if (!file.Exists)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (file.IsArchive)
|
|
{
|
|
var stream = file.GetStream();
|
|
return Util.ReadAllBytes(stream);
|
|
}
|
|
|
|
return File.ReadAllBytes(path);
|
|
}
|
|
}
|
|
|
|
private static int GetNumDigits(int i)
|
|
{
|
|
if (i <= 0x10000)
|
|
{
|
|
return 4;
|
|
}
|
|
|
|
return i <= 0x1000000 ? 6 : 8;
|
|
}
|
|
|
|
private static char ForceCorrectKeyString(char keycode)
|
|
{
|
|
return (char)keycode;
|
|
}
|
|
|
|
private void RefreshFloatingWindowControl()
|
|
{
|
|
Owner = Global.Config.RamSearchSettings.FloatingWindow ? null : GlobalWin.MainForm;
|
|
}
|
|
|
|
private static string GetSaveFileFromUser()
|
|
{
|
|
var sfd = new SaveFileDialog
|
|
{
|
|
Filter = "Text (*.txt)|*.txt|All Files|*.*",
|
|
RestoreDirectory = true
|
|
};
|
|
|
|
if (Global.Emulator is NullEmulator)
|
|
{
|
|
sfd.FileName = "MemoryDump";
|
|
sfd.InitialDirectory = PathManager.GetBasePathAbsolute();
|
|
}
|
|
else
|
|
{
|
|
sfd.FileName = PathManager.FilesystemSafeName(Global.Game);
|
|
sfd.InitialDirectory = Path.GetDirectoryName(PathManager.MakeAbsolutePath(Global.Config.RecentRoms.MostRecent, null));
|
|
}
|
|
|
|
var result = sfd.ShowHawkDialog();
|
|
|
|
return result == DialogResult.OK ? sfd.FileName : string.Empty;
|
|
}
|
|
|
|
private static bool IsHexKeyCode(char key)
|
|
{
|
|
if (key >= '0' && key <= '9') // 0-9
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (key >= 'a' && key <= 'f') // A-F
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (key >= 'A' && key <= 'F') // A-F
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private void HexEditor_Load(object sender, EventArgs e)
|
|
{
|
|
_defaultWidth = Size.Width; // Save these first so that the user can restore to its original size
|
|
_defaultHeight = Size.Height;
|
|
|
|
if (Global.Config.HexEditorSettings.UseWindowPosition)
|
|
{
|
|
Location = Global.Config.HexEditorSettings.WindowPosition;
|
|
}
|
|
|
|
if (Global.Config.HexEditorSettings.UseWindowSize)
|
|
{
|
|
Size = Global.Config.HexEditorSettings.WindowSize;
|
|
}
|
|
|
|
SetMemoryDomainMenu();
|
|
SetDataSize(_dataSize);
|
|
|
|
if (Global.Config.RecentTables.AutoLoad)
|
|
{
|
|
LoadFileFromRecent(Global.Config.RecentTables[0]);
|
|
}
|
|
|
|
UpdateValues();
|
|
}
|
|
|
|
private void LoadConfigSettings()
|
|
{
|
|
_bigEndian = Global.Config.HexEditorBigEndian;
|
|
_dataSize = Global.Config.HexEditorDataSize;
|
|
|
|
HexMenuStrip.BackColor = Global.Config.HexMenubarColor;
|
|
MemoryViewerBox.BackColor = Global.Config.HexBackgrndColor;
|
|
MemoryViewerBox.ForeColor = Global.Config.HexForegrndColor;
|
|
Header.BackColor = Global.Config.HexBackgrndColor;
|
|
Header.ForeColor = Global.Config.HexForegrndColor;
|
|
}
|
|
|
|
private void SaveConfigSettings()
|
|
{
|
|
if (_hexFind.IsHandleCreated || !_hexFind.IsDisposed)
|
|
{
|
|
_hexFind.Close();
|
|
}
|
|
|
|
if (Global.Config.SaveWindowPosition)
|
|
{
|
|
Global.Config.HexEditorSettings.Wndx = Location.X;
|
|
Global.Config.HexEditorSettings.Wndy = Location.Y;
|
|
Global.Config.HexEditorSettings.Width = Right - Left;
|
|
Global.Config.HexEditorSettings.Height = Bottom - Top;
|
|
}
|
|
|
|
Global.Config.HexEditorBigEndian = _bigEndian;
|
|
Global.Config.HexEditorDataSize = _dataSize;
|
|
}
|
|
|
|
private string GenerateAddressString()
|
|
{
|
|
var addrStr = new StringBuilder();
|
|
|
|
for (var i = 0; i < _rowsVisible; i++)
|
|
{
|
|
_row = i + HexScrollBar.Value;
|
|
_addr = _row << 4;
|
|
if (_addr >= _domain.Size)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (_numDigits == 4)
|
|
{
|
|
addrStr.Append(" "); // Hack to line things up better between 4 and 6
|
|
}
|
|
else if (_numDigits == 6)
|
|
{
|
|
addrStr.Append(" ");
|
|
}
|
|
|
|
addrStr.AppendLine(_addr.ToHexString(_numDigits));
|
|
}
|
|
|
|
return addrStr.ToString();
|
|
}
|
|
|
|
private string GenerateMemoryViewString()
|
|
{
|
|
var rowStr = new StringBuilder();
|
|
|
|
for (var i = 0; i < _rowsVisible; i++)
|
|
{
|
|
_row = i + HexScrollBar.Value;
|
|
_addr = _row << 4;
|
|
if (_addr >= _domain.Size)
|
|
{
|
|
break;
|
|
}
|
|
|
|
for (var j = 0; j < 16; j += _dataSize)
|
|
{
|
|
if (_addr + j + _dataSize <= _domain.Size)
|
|
{
|
|
rowStr.AppendFormat(_digitFormatString, MakeValue(_addr + j));
|
|
}
|
|
else
|
|
{
|
|
for (var t = 0; t < _dataSize; t++)
|
|
{
|
|
rowStr.Append(" ");
|
|
}
|
|
|
|
rowStr.Append(' ');
|
|
}
|
|
}
|
|
|
|
rowStr.Append(" | ");
|
|
for (var k = 0; k < 16; k++)
|
|
{
|
|
if (_addr + k < _domain.Size)
|
|
{
|
|
rowStr.Append(Remap(MakeByte(_addr + k)));
|
|
}
|
|
}
|
|
|
|
rowStr.AppendLine();
|
|
}
|
|
|
|
return rowStr.ToString();
|
|
}
|
|
|
|
private byte MakeByte(int address)
|
|
{
|
|
return Global.CheatList.IsActive(_domain, address)
|
|
? Global.CheatList.GetByteValue(_domain, address).Value
|
|
: _domain.PeekByte(address);
|
|
}
|
|
|
|
private int MakeValue(int address)
|
|
{
|
|
if (Global.CheatList.IsActive(_domain, address))
|
|
{
|
|
return Global.CheatList[_domain, address].Value.Value;
|
|
}
|
|
|
|
switch (_dataSize)
|
|
{
|
|
default:
|
|
case 1:
|
|
return _domain.PeekByte(address);
|
|
case 2:
|
|
return _domain.PeekWord(address, _bigEndian);
|
|
case 4:
|
|
return (int)_domain.PeekDWord(address, _bigEndian);
|
|
}
|
|
}
|
|
|
|
private void SetMemoryDomain(MemoryDomain d)
|
|
{
|
|
_domain = d;
|
|
_bigEndian = d.EndianType == MemoryDomain.Endian.Big;
|
|
_maxRow = _domain.Size / 2;
|
|
SetUpScrollBar();
|
|
if (0 >= HexScrollBar.Minimum && 0 <= HexScrollBar.Maximum)
|
|
{
|
|
HexScrollBar.Value = 0;
|
|
}
|
|
|
|
Refresh();
|
|
}
|
|
|
|
private void SetDomain(MemoryDomain domain)
|
|
{
|
|
SetMemoryDomain(GetDomainInt(domain.Name) ?? 0);
|
|
SetHeader();
|
|
}
|
|
|
|
// TODO: this should be removable or at least refactorable
|
|
private void SetMemoryDomain(int pos)
|
|
{
|
|
// <zeromus> THIS IS HORRIBLE.
|
|
if (pos == 999)
|
|
{
|
|
// <zeromus> THIS IS HORRIBLE.
|
|
_rom = GetRomBytes();
|
|
|
|
// <zeromus> THIS IS HORRIBLE.
|
|
_romDomain = new MemoryDomain(
|
|
"File on Disk", _rom.Length, MemoryDomain.Endian.Little, i => _rom[i], (i, value) => _rom[i] = value);
|
|
|
|
// <zeromus> THIS IS HORRIBLE.
|
|
SetMemoryDomain(_romDomain);
|
|
}
|
|
else if (pos < Global.Emulator.MemoryDomains.Count)
|
|
{
|
|
SetMemoryDomain(Global.Emulator.MemoryDomains[pos]);
|
|
}
|
|
|
|
SetHeader();
|
|
UpdateGroupBoxTitle();
|
|
ResetScrollBar();
|
|
UpdateValues();
|
|
MemoryViewerBox.Refresh();
|
|
}
|
|
|
|
private void UpdateGroupBoxTitle()
|
|
{
|
|
var addressesString = "0x" + string.Format("{0:X8}", _domain.Size / _dataSize).TrimStart('0');
|
|
MemoryViewerBox.Text = Global.Emulator.SystemId + " " + _domain + " - " + addressesString + " addresses";
|
|
}
|
|
|
|
private void SetMemoryDomainMenu()
|
|
{
|
|
MemoryDomainsMenuItem.DropDownItems.Clear();
|
|
|
|
for (var i = 0; i < Global.Emulator.MemoryDomains.Count; i++)
|
|
{
|
|
if (Global.Emulator.MemoryDomains[i].Size > 0)
|
|
{
|
|
var str = Global.Emulator.MemoryDomains[i].ToString();
|
|
var item = new ToolStripMenuItem { Text = str };
|
|
{
|
|
var temp = i;
|
|
item.Click += (o, ev) => SetMemoryDomain(temp);
|
|
}
|
|
|
|
if (i == 0)
|
|
{
|
|
SetMemoryDomain(i);
|
|
}
|
|
|
|
MemoryDomainsMenuItem.DropDownItems.Add(item);
|
|
_domainMenuItems.Add(item);
|
|
}
|
|
}
|
|
|
|
// Add File on Disk memory domain
|
|
// <zeromus> THIS IS HORRIBLE.
|
|
var rom_item = new ToolStripMenuItem { Text = "File on Disk" };
|
|
rom_item.Click += (o, ev) => SetMemoryDomain(999); // 999 will denote File on Disk
|
|
MemoryDomainsMenuItem.DropDownItems.Add(rom_item);
|
|
_domainMenuItems.Add(rom_item);
|
|
}
|
|
|
|
private Point GetPromptPoint()
|
|
{
|
|
return PointToScreen(
|
|
new Point(MemoryViewerBox.Location.X + 30, MemoryViewerBox.Location.Y + 30));
|
|
}
|
|
|
|
private void ClearNibbles()
|
|
{
|
|
for (var i = 0; i < 8; i++)
|
|
{
|
|
_nibbles[i] = 'G';
|
|
}
|
|
}
|
|
|
|
private void GoToAddress(int address)
|
|
{
|
|
if (address < 0)
|
|
{
|
|
address = 0;
|
|
}
|
|
|
|
if (address >= _domain.Size)
|
|
{
|
|
address = _domain.Size - 1;
|
|
}
|
|
|
|
SetHighlighted(address);
|
|
ClearNibbles();
|
|
UpdateValues();
|
|
MemoryViewerBox.Refresh();
|
|
AddressLabel.Text = GenerateAddressString();
|
|
}
|
|
|
|
private void SetHighlighted(int address)
|
|
{
|
|
if (address < 0)
|
|
{
|
|
address = 0;
|
|
}
|
|
|
|
if (address >= _domain.Size)
|
|
{
|
|
address = _domain.Size - 1;
|
|
}
|
|
|
|
if (!IsVisible(address))
|
|
{
|
|
var value = (address / 16) - _rowsVisible + 1;
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
HexScrollBar.Value = value;
|
|
}
|
|
|
|
_addressHighlighted = address;
|
|
_addressOver = address;
|
|
ClearNibbles();
|
|
UpdateFormText();
|
|
}
|
|
|
|
private void UpdateFormText()
|
|
{
|
|
if (_addressHighlighted >= 0)
|
|
{
|
|
Text = "Hex Editor - Editing Address 0x" + string.Format(_numDigitsStr, _addressHighlighted);
|
|
}
|
|
else
|
|
{
|
|
Text = "Hex Editor";
|
|
}
|
|
}
|
|
|
|
private bool IsVisible(int address)
|
|
{
|
|
var i = address >> 4;
|
|
return i >= HexScrollBar.Value && i < (_rowsVisible + HexScrollBar.Value);
|
|
}
|
|
|
|
private void SetHeader()
|
|
{
|
|
switch (_dataSize)
|
|
{
|
|
case 1:
|
|
Header.Text = " 0 1 2 3 4 5 6 7 8 9 A B C D E F";
|
|
break;
|
|
case 2:
|
|
Header.Text = " 0 2 4 6 8 A C E";
|
|
break;
|
|
case 4:
|
|
Header.Text = " 0 4 8 C";
|
|
break;
|
|
}
|
|
|
|
_numDigits = GetNumDigits(_domain.Size);
|
|
_numDigitsStr = "{0:X" + _numDigits + "} ";
|
|
}
|
|
|
|
private void SetDataSize(int size)
|
|
{
|
|
if (size == 1 || size == 2 || size == 4)
|
|
{
|
|
_dataSize = size;
|
|
_digitFormatString = "{0:X" + (_dataSize * 2) + "} ";
|
|
SetHeader();
|
|
UpdateGroupBoxTitle();
|
|
UpdateValues();
|
|
}
|
|
}
|
|
|
|
private Watch MakeWatch(int address)
|
|
{
|
|
switch (_dataSize)
|
|
{
|
|
default:
|
|
case 1:
|
|
return new ByteWatch(_domain, address, Watch.DisplayType.Hex, _bigEndian, string.Empty);
|
|
case 2:
|
|
return new WordWatch(_domain, address, Watch.DisplayType.Hex, _bigEndian, string.Empty);
|
|
case 4:
|
|
return new DWordWatch(_domain, address, Watch.DisplayType.Hex, _bigEndian, string.Empty);
|
|
}
|
|
}
|
|
|
|
private bool IsFrozen(int address)
|
|
{
|
|
return Global.CheatList.IsActive(_domain, address);
|
|
}
|
|
|
|
private void UnFreezeAddress(int address)
|
|
{
|
|
if (address >= 0)
|
|
{
|
|
// TODO: can't unfreeze address 0??
|
|
Global.CheatList.RemoveRange(
|
|
Global.CheatList.Where(x => x.Contains(address)).ToList());
|
|
}
|
|
|
|
MemoryViewerBox.Refresh();
|
|
}
|
|
|
|
// TODO refactor to int?
|
|
private void FreezeAddress(int address)
|
|
{
|
|
if (address >= 0)
|
|
{
|
|
var watch = Watch.GenerateWatch(
|
|
_domain,
|
|
address,
|
|
WatchSize,
|
|
Watch.DisplayType.Hex,
|
|
string.Empty,
|
|
_bigEndian);
|
|
|
|
Global.CheatList.Add(new Cheat(
|
|
watch,
|
|
watch.Value ?? 0));
|
|
}
|
|
}
|
|
|
|
private void FreezeSecondaries()
|
|
{
|
|
var cheats = new List<Cheat>();
|
|
foreach (var address in _secondaryHighlightedAddresses)
|
|
{
|
|
var watch = Watch.GenerateWatch(
|
|
_domain,
|
|
address,
|
|
WatchSize,
|
|
Watch.DisplayType.Hex,
|
|
string.Empty,
|
|
_bigEndian);
|
|
|
|
cheats.Add(new Cheat(
|
|
watch,
|
|
watch.Value ?? 0));
|
|
}
|
|
|
|
Global.CheatList.AddRange(cheats);
|
|
}
|
|
|
|
private void UnfreezeSecondaries()
|
|
{
|
|
Global.CheatList.RemoveRange(
|
|
Global.CheatList.Where(
|
|
cheat => !cheat.IsSeparator && cheat.Domain == _domain && _secondaryHighlightedAddresses.Contains(cheat.Address.Value)));
|
|
}
|
|
|
|
private void SaveFileBinary(string path)
|
|
{
|
|
var file = new FileInfo(path);
|
|
using (var binWriter = new BinaryWriter(File.Open(file.FullName, FileMode.Create)))
|
|
{
|
|
for (var i = 0; i < _domain.Size; i++)
|
|
{
|
|
binWriter.Write(_domain.PeekByte(i));
|
|
}
|
|
}
|
|
}
|
|
|
|
private string GetSaveFileFilter()
|
|
{
|
|
if (_domain.Name == "File on Disk")
|
|
{
|
|
var extension = Path.GetExtension(GlobalWin.MainForm.CurrentlyOpenRom);
|
|
|
|
return "Binary (*" + extension + ")|*" + extension + "|All Files|*.*";
|
|
}
|
|
|
|
return "Binary (*.bin)|*.bin|All Files|*.*";
|
|
}
|
|
|
|
private string GetBinarySaveFileFromUser()
|
|
{
|
|
var sfd = new SaveFileDialog
|
|
{
|
|
Filter = GetSaveFileFilter(),
|
|
RestoreDirectory = true
|
|
};
|
|
|
|
if (Global.Emulator is NullEmulator)
|
|
{
|
|
sfd.FileName = "MemoryDump";
|
|
sfd.InitialDirectory = PathManager.GetBasePathAbsolute();
|
|
}
|
|
else
|
|
{
|
|
if (_domain.Name == "File on Disk")
|
|
{
|
|
sfd.FileName = Path.GetFileName(Global.Config.RecentRoms.MostRecent);
|
|
}
|
|
else
|
|
{
|
|
sfd.FileName = PathManager.FilesystemSafeName(Global.Game);
|
|
}
|
|
|
|
sfd.InitialDirectory = Path.GetDirectoryName(PathManager.MakeAbsolutePath(Global.Config.RecentRoms.MostRecent, null));
|
|
}
|
|
|
|
var result = sfd.ShowHawkDialog();
|
|
|
|
return result == DialogResult.OK ? sfd.FileName : string.Empty;
|
|
}
|
|
|
|
private void ResetScrollBar()
|
|
{
|
|
HexScrollBar.Value = 0;
|
|
SetUpScrollBar();
|
|
Refresh();
|
|
}
|
|
|
|
private void SetUpScrollBar()
|
|
{
|
|
_rowsVisible = (MemoryViewerBox.Height - (fontHeight * 2) - (fontHeight / 2)) / fontHeight;
|
|
var totalRows = (_domain.Size + 15) / 16;
|
|
|
|
if (totalRows < _rowsVisible)
|
|
{
|
|
_rowsVisible = totalRows;
|
|
}
|
|
|
|
HexScrollBar.Maximum = totalRows - 1;
|
|
HexScrollBar.LargeChange = _rowsVisible;
|
|
HexScrollBar.Visible = totalRows > _rowsVisible;
|
|
|
|
AddressLabel.Text = GenerateAddressString();
|
|
}
|
|
|
|
private int GetPointedAddress(int x, int y)
|
|
{
|
|
int address;
|
|
|
|
// Scroll value determines the first row
|
|
var i = HexScrollBar.Value;
|
|
var rowoffset = y / fontHeight;
|
|
i += rowoffset;
|
|
int colWidth;
|
|
switch (_dataSize)
|
|
{
|
|
default:
|
|
case 1:
|
|
colWidth = 3;
|
|
break;
|
|
case 2:
|
|
colWidth = 5;
|
|
break;
|
|
case 4:
|
|
colWidth = 9;
|
|
break;
|
|
}
|
|
|
|
var column = x / (FontWidth * colWidth);
|
|
|
|
var start = GetTextOffset() - 50;
|
|
if (x > start)
|
|
{
|
|
column = (x - start) / (FontWidth / _dataSize);
|
|
}
|
|
|
|
if (i >= 0 && i <= _maxRow && column >= 0 && column < (16 / _dataSize))
|
|
{
|
|
address = (i * 16) + (column * _dataSize);
|
|
}
|
|
else
|
|
{
|
|
address = -1;
|
|
}
|
|
|
|
return address;
|
|
}
|
|
|
|
private void DoShiftClick()
|
|
{
|
|
if (_addressOver >= 0 && _addressOver < _domain.Size)
|
|
{
|
|
_secondaryHighlightedAddresses.Clear();
|
|
if (_addressOver < _addressHighlighted)
|
|
{
|
|
for (var x = _addressOver; x < _addressHighlighted; x++)
|
|
{
|
|
_secondaryHighlightedAddresses.Add(x);
|
|
}
|
|
}
|
|
else if (_addressOver > _addressHighlighted)
|
|
{
|
|
for (var x = _addressHighlighted + _dataSize; x <= _addressOver; x++)
|
|
{
|
|
_secondaryHighlightedAddresses.Add(x);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ClearHighlighted()
|
|
{
|
|
_addressHighlighted = -1;
|
|
UpdateFormText();
|
|
MemoryViewerBox.Refresh();
|
|
}
|
|
|
|
private Point GetAddressCoordinates(int address)
|
|
{
|
|
var extra = (address % _dataSize) * FontWidth * 2;
|
|
switch (_dataSize)
|
|
{
|
|
default:
|
|
case 1:
|
|
return new Point(((address % 16) * (FontWidth * 3)) + 67 + extra, (((address / 16) - HexScrollBar.Value) * fontHeight) + 30);
|
|
case 2:
|
|
return new Point((((address % 16) / _dataSize) * (FontWidth * 5)) + 67 + extra, (((address / 16) - HexScrollBar.Value) * fontHeight) + 30);
|
|
case 4:
|
|
return new Point((((address % 16) / _dataSize) * (FontWidth * 9)) + 67 + extra, (((address / 16) - HexScrollBar.Value) * fontHeight) + 30);
|
|
}
|
|
}
|
|
|
|
// TODO: rename this, but it is a hack work around for highlighting misaligned addresses that result from highlighting on in a smaller data size and switching size
|
|
private bool NeedsExtra(int val)
|
|
{
|
|
return val % _dataSize > 0;
|
|
}
|
|
|
|
private int GetTextOffset()
|
|
{
|
|
int start;
|
|
switch (_dataSize)
|
|
{
|
|
default:
|
|
case 1:
|
|
start = (16 * (FontWidth * 3)) + 67;
|
|
break;
|
|
case 2:
|
|
start = ((16 / _dataSize) * (FontWidth * 5)) + 67;
|
|
break;
|
|
case 4:
|
|
start = ((16 / _dataSize) * (FontWidth * 9)) + 67;
|
|
break;
|
|
}
|
|
|
|
start += FontWidth * 4;
|
|
return start;
|
|
}
|
|
|
|
private int GetTextX(int address)
|
|
{
|
|
return GetTextOffset() + ((address % 16) * FontWidth);
|
|
}
|
|
|
|
private bool HasNibbles()
|
|
{
|
|
return _nibbles.Any(x => x != 'G');
|
|
}
|
|
|
|
private string MakeNibbles()
|
|
{
|
|
var str = string.Empty;
|
|
for (var x = 0; x < (_dataSize * 2); x++)
|
|
{
|
|
if (_nibbles[x] != 'G')
|
|
{
|
|
str += _nibbles[x];
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
private void AddToSecondaryHighlights(int address)
|
|
{
|
|
if (address >= 0 && address < _domain.Size)
|
|
{
|
|
_secondaryHighlightedAddresses.Add(address);
|
|
}
|
|
}
|
|
|
|
// TODO: obsolete me
|
|
private void PokeWord(int address, byte _1, byte _2)
|
|
{
|
|
if (_bigEndian)
|
|
{
|
|
_domain.PokeByte(address, _2);
|
|
_domain.PokeByte(address + 1, _1);
|
|
}
|
|
else
|
|
{
|
|
_domain.PokeByte(address, _1);
|
|
_domain.PokeByte(address + 1, _2);
|
|
}
|
|
}
|
|
|
|
private void IncrementAddress(int address)
|
|
{
|
|
if (Global.CheatList.IsActive(_domain, address))
|
|
{
|
|
// TODO: Increment should be intelligent since IsActive is. If this address is part of a multi-byte cheat it should intelligently increment just that byte
|
|
Global.CheatList.FirstOrDefault(x => x.Domain == _domain && x.Address == address).Increment();
|
|
}
|
|
else
|
|
{
|
|
switch (_dataSize)
|
|
{
|
|
default:
|
|
case 1:
|
|
_domain.PokeByte(
|
|
address,
|
|
(byte)(_domain.PeekByte(address) + 1));
|
|
break;
|
|
case 2:
|
|
_domain.PokeWord(
|
|
address,
|
|
(ushort)(_domain.PeekWord(address, _bigEndian) + 1),
|
|
_bigEndian);
|
|
break;
|
|
case 4:
|
|
_domain.PokeDWord(
|
|
address,
|
|
_domain.PeekDWord(address, _bigEndian) + 1,
|
|
_bigEndian);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DecrementAddress(int address)
|
|
{
|
|
if (Global.CheatList.IsActive(_domain, address))
|
|
{
|
|
// TODO: Increment should be intelligent since IsActive is. If this address is part of a multi-byte cheat it should intelligently increment just that byte
|
|
Global.CheatList.FirstOrDefault(x => x.Domain == _domain && x.Address == address).Decrement();
|
|
}
|
|
else
|
|
{
|
|
switch (_dataSize)
|
|
{
|
|
default:
|
|
case 1:
|
|
_domain.PokeByte(
|
|
address,
|
|
(byte)(_domain.PeekByte(address) - 1));
|
|
break;
|
|
case 2:
|
|
_domain.PokeWord(
|
|
address,
|
|
(ushort)(_domain.PeekWord(address, _bigEndian) - 1),
|
|
_bigEndian);
|
|
break;
|
|
case 4:
|
|
_domain.PokeDWord(
|
|
address,
|
|
_domain.PeekDWord(address, _bigEndian) - 1,
|
|
_bigEndian);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private string ValueString(int address)
|
|
{
|
|
if (address != -1)
|
|
{
|
|
return string.Format(_digitFormatString, MakeValue(address)).Trim();
|
|
}
|
|
|
|
return string.Empty;
|
|
}
|
|
|
|
private string GetFindValues()
|
|
{
|
|
if (HighlightedAddress.HasValue)
|
|
{
|
|
var values = ValueString(HighlightedAddress.Value);
|
|
return _secondaryHighlightedAddresses.Aggregate(values, (current, x) => current + ValueString(x));
|
|
}
|
|
|
|
return string.Empty;
|
|
}
|
|
|
|
private void HighlightSecondaries(string value, int found)
|
|
{
|
|
// This function assumes that the primary highlighted value has been set and sets the remaining characters in this string
|
|
_secondaryHighlightedAddresses.Clear();
|
|
|
|
var addrLength = _dataSize * 2;
|
|
if (value.Length <= addrLength)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var numToHighlight = (value.Length / addrLength) - 1;
|
|
|
|
for (var i = 0; i < numToHighlight; i++)
|
|
{
|
|
_secondaryHighlightedAddresses.Add(found + 1 + i);
|
|
}
|
|
}
|
|
|
|
private bool LoadTable(string path)
|
|
{
|
|
var file = new FileInfo(path);
|
|
if (!file.Exists)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
using (var sr = file.OpenText())
|
|
{
|
|
string line;
|
|
|
|
while ((line = sr.ReadLine()) != null)
|
|
{
|
|
var parts = line.Split('=');
|
|
_textTable.Add(
|
|
int.Parse(parts[0],
|
|
NumberStyles.HexNumber), parts[1].First());
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#region Events
|
|
|
|
#region File Menu
|
|
|
|
private void FileSubMenu_DropDownOpened(object sender, EventArgs e)
|
|
{
|
|
if (_domain.Name == "File on Disk")
|
|
{
|
|
SaveMenuItem.Visible = !CurrentRomIsArchive();
|
|
SaveAsBinaryMenuItem.Text = "Save as ROM...";
|
|
}
|
|
else
|
|
{
|
|
SaveAsBinaryMenuItem.Text = "Save as binary...";
|
|
}
|
|
|
|
CloseTableFileMenuItem.Enabled = _textTable.Any();
|
|
}
|
|
|
|
private void SaveMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
if (!CurrentRomIsArchive())
|
|
{
|
|
SaveFileBinary(GlobalWin.MainForm.CurrentlyOpenRom);
|
|
}
|
|
}
|
|
|
|
private void SaveAsBinaryMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
var path = GetBinarySaveFileFromUser();
|
|
if (!string.IsNullOrEmpty(path))
|
|
{
|
|
SaveFileBinary(path);
|
|
}
|
|
}
|
|
|
|
private void SaveAsTextMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
var path = GetSaveFileFromUser();
|
|
if (!string.IsNullOrWhiteSpace(path))
|
|
{
|
|
var file = new FileInfo(path);
|
|
using (var sw = new StreamWriter(file.FullName))
|
|
{
|
|
var sb = new StringBuilder();
|
|
|
|
for (var i = 0; i < _domain.Size / 16; i++)
|
|
{
|
|
for (var j = 0; j < 16; j++)
|
|
{
|
|
sb.Append(string.Format("{0:X2} ", _domain.PeekByte((i * 16) + j)));
|
|
}
|
|
|
|
sb.AppendLine();
|
|
}
|
|
|
|
sw.WriteLine(sb);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void LoadTableFileMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
var ofd = new OpenFileDialog
|
|
{
|
|
FileName = Path.GetFileNameWithoutExtension(Global.Config.RecentRoms.MostRecent) + ".tbl",
|
|
InitialDirectory = Path.GetDirectoryName(PathManager.MakeAbsolutePath(Global.Config.RecentRoms.MostRecent, null)),
|
|
Filter = "Text Table files (*.tbl)|*.tbl|All Files|*.*",
|
|
RestoreDirectory = false
|
|
};
|
|
|
|
GlobalWin.Sound.StopSound();
|
|
var result = ofd.ShowDialog();
|
|
GlobalWin.Sound.StartSound();
|
|
|
|
if (result == DialogResult.OK)
|
|
{
|
|
LoadTable(ofd.FileName);
|
|
Global.Config.RecentTables.Add(ofd.FileName);
|
|
UpdateValues();
|
|
}
|
|
}
|
|
|
|
private void CloseTableFileMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
_textTable.Clear();
|
|
}
|
|
|
|
public void LoadFileFromRecent(string path)
|
|
{
|
|
|
|
var result = LoadTable(path);
|
|
if (!result)
|
|
{
|
|
ToolHelpers.HandleLoadError(Global.Config.RecentTables, path);
|
|
}
|
|
else
|
|
{
|
|
Global.Config.RecentTables.Add(path);
|
|
UpdateValues();
|
|
}
|
|
}
|
|
|
|
private void RecentTablesSubMenu_DropDownOpened(object sender, EventArgs e)
|
|
{
|
|
RecentTablesSubMenu.DropDownItems.Clear();
|
|
RecentTablesSubMenu.DropDownItems.AddRange(
|
|
ToolHelpers.GenerateRecentMenu(Global.Config.RecentTables, LoadFileFromRecent));
|
|
|
|
RecentTablesSubMenu.DropDownItems.Add(
|
|
ToolHelpers.GenerateAutoLoadItem(Global.Config.RecentTables));
|
|
}
|
|
|
|
private void ExitMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
Close();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Edit
|
|
|
|
private void EditMenuItem_DropDownOpened(object sender, EventArgs e)
|
|
{
|
|
FindNextMenuItem.Enabled = !string.IsNullOrWhiteSpace(_findStr);
|
|
}
|
|
|
|
private void CopyMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
var value = HighlightedAddress.HasValue ? ValueString(HighlightedAddress.Value) : string.Empty;
|
|
value = _secondaryHighlightedAddresses.Aggregate(value, (current, x) => current + ValueString(x));
|
|
if (!string.IsNullOrWhiteSpace(value))
|
|
{
|
|
Clipboard.SetDataObject(value);
|
|
}
|
|
}
|
|
|
|
private void PasteMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
var data = Clipboard.GetDataObject();
|
|
|
|
if (data != null && data.GetDataPresent(DataFormats.Text))
|
|
{
|
|
var clipboardRaw = (string)data.GetData(DataFormats.Text);
|
|
var hex = clipboardRaw.DoHexString();
|
|
|
|
var numBytes = hex.Length / 2;
|
|
for (var i = 0; i < numBytes; i++)
|
|
{
|
|
var value = int.Parse(hex.Substring(i * 2, 2), NumberStyles.HexNumber);
|
|
var address = _addressHighlighted + i;
|
|
_domain.PokeByte(address, (byte)value);
|
|
}
|
|
|
|
UpdateValues();
|
|
}
|
|
}
|
|
|
|
private void FindMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
_findStr = GetFindValues();
|
|
if (!_hexFind.IsHandleCreated || _hexFind.IsDisposed)
|
|
{
|
|
_hexFind = new HexFind();
|
|
_hexFind.SetLocation(PointToScreen(AddressesLabel.Location));
|
|
_hexFind.SetInitialValue(_findStr);
|
|
_hexFind.Show();
|
|
}
|
|
else
|
|
{
|
|
_hexFind.SetInitialValue(_findStr);
|
|
_hexFind.Focus();
|
|
}
|
|
}
|
|
|
|
private void FindNextMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
FindNext(_findStr, false);
|
|
}
|
|
|
|
private void FindPrevMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
FindPrev(_findStr, false);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Options
|
|
|
|
private void OptionsSubMenu_DropDownOpened(object sender, EventArgs e)
|
|
{
|
|
BigEndianMenuItem.Checked = _bigEndian;
|
|
DataSizeByteMenuItem.Checked = _dataSize == 1;
|
|
DataSizeWordMenuItem.Checked = _dataSize == 2;
|
|
DataSizeDWordMenuItem.Checked = _dataSize == 4;
|
|
|
|
if (HighlightedAddress.HasValue && IsFrozen(HighlightedAddress.Value))
|
|
{
|
|
FreezeAddressMenuItem.Image = Properties.Resources.Unfreeze;
|
|
FreezeAddressMenuItem.Text = "Un&freeze Address";
|
|
}
|
|
else
|
|
{
|
|
FreezeAddressMenuItem.Image = Properties.Resources.Freeze;
|
|
FreezeAddressMenuItem.Text = "&Freeze Address";
|
|
}
|
|
|
|
AddToRamWatchMenuItem.Enabled =
|
|
FreezeAddressMenuItem.Enabled =
|
|
HighlightedAddress.HasValue;
|
|
}
|
|
|
|
private void MemoryDomainsMenuItem_DropDownOpened(object sender, EventArgs e)
|
|
{
|
|
foreach (var menuItem in _domainMenuItems)
|
|
{
|
|
menuItem.Checked = _domain.Name == menuItem.Text;
|
|
}
|
|
}
|
|
|
|
private void DataSizeByteMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
SetDataSize(1);
|
|
}
|
|
|
|
private void DataSizeWordMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
SetDataSize(2);
|
|
}
|
|
|
|
private void DataSizeDWordMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
SetDataSize(4);
|
|
}
|
|
|
|
private void BigEndianMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
_bigEndian ^= true;
|
|
UpdateValues();
|
|
}
|
|
|
|
private void GoToAddressMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
var inputPrompt = new InputPrompt { Text = "Go to Address", StartLocation = GetPromptPoint() };
|
|
inputPrompt.SetMessage("Enter a hexadecimal value");
|
|
inputPrompt.ShowHawkDialog();
|
|
|
|
if (inputPrompt.UserOk && inputPrompt.UserText.IsHex())
|
|
{
|
|
GoToAddress(int.Parse(inputPrompt.UserText, NumberStyles.HexNumber));
|
|
}
|
|
|
|
AddressLabel.Text = GenerateAddressString();
|
|
}
|
|
|
|
private void AddToRamWatchMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
if (HighlightedAddress.HasValue || _secondaryHighlightedAddresses.Any())
|
|
{
|
|
GlobalWin.Tools.LoadRamWatch(true);
|
|
}
|
|
|
|
if (HighlightedAddress.HasValue)
|
|
{
|
|
GlobalWin.Tools.RamWatch.AddWatch(MakeWatch(HighlightedAddress.Value));
|
|
}
|
|
|
|
_secondaryHighlightedAddresses.ForEach(addr =>
|
|
GlobalWin.Tools.RamWatch.AddWatch(MakeWatch(addr)));
|
|
}
|
|
|
|
private void FreezeAddressMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
if (HighlightedAddress.HasValue)
|
|
{
|
|
if (IsFrozen(HighlightedAddress.Value))
|
|
{
|
|
UnFreezeAddress(HighlightedAddress.Value);
|
|
UnfreezeSecondaries();
|
|
}
|
|
else
|
|
{
|
|
FreezeAddress(HighlightedAddress.Value);
|
|
FreezeSecondaries();
|
|
}
|
|
}
|
|
|
|
ToolHelpers.UpdateCheatRelatedTools(null, null);
|
|
MemoryViewerBox.Refresh();
|
|
}
|
|
|
|
private void UnfreezeAllMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
Global.CheatList.RemoveAll();
|
|
}
|
|
|
|
private void PokeAddressMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
var addresses = new List<int>();
|
|
if (HighlightedAddress.HasValue)
|
|
{
|
|
addresses.Add(HighlightedAddress.Value);
|
|
}
|
|
|
|
if (_secondaryHighlightedAddresses.Any())
|
|
{
|
|
addresses.AddRange(_secondaryHighlightedAddresses);
|
|
}
|
|
|
|
if (addresses.Any())
|
|
{
|
|
var poke = new RamPoke
|
|
{
|
|
InitialLocation = GetAddressCoordinates(addresses[0])
|
|
};
|
|
|
|
var watches = addresses.Select(
|
|
address => Watch.GenerateWatch(
|
|
_domain,
|
|
address,
|
|
(Watch.WatchSize)_dataSize,
|
|
Watch.DisplayType.Hex,
|
|
string.Empty,
|
|
_bigEndian));
|
|
|
|
poke.SetWatch(watches);
|
|
poke.ShowHawkDialog();
|
|
UpdateValues();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Settings Menu
|
|
|
|
private void SettingsSubMenu_DropDownOpened(object sender, EventArgs e)
|
|
{
|
|
AutoloadMenuItem.Checked = Global.Config.AutoLoadHexEditor;
|
|
SaveWindowsPositionMenuItem.Checked = Global.Config.SaveWindowPosition;
|
|
AlwaysOnTopMenuItem.Checked = Global.Config.HexEditorSettings.TopMost;
|
|
FloatingWindowMenuItem.Checked = Global.Config.HexEditorSettings.FloatingWindow;
|
|
}
|
|
|
|
private void SetColorsMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
new HexColorsForm().ShowHawkDialog();
|
|
}
|
|
|
|
private void ResetColorsToDefaultMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
MemoryViewerBox.BackColor = Color.FromName("Control");
|
|
MemoryViewerBox.ForeColor = Color.FromName("ControlText");
|
|
this.HexMenuStrip.BackColor = Color.FromName("Control");
|
|
Header.BackColor = Color.FromName("Control");
|
|
Header.ForeColor = Color.FromName("ControlText");
|
|
Global.Config.HexMenubarColor = Color.FromName("Control");
|
|
Global.Config.HexForegrndColor = Color.FromName("ControlText");
|
|
Global.Config.HexBackgrndColor = Color.FromName("Control");
|
|
Global.Config.HexFreezeColor = Color.LightBlue;
|
|
Global.Config.HexHighlightColor = Color.Pink;
|
|
Global.Config.HexHighlightFreezeColor = Color.Violet;
|
|
}
|
|
|
|
private void AutoloadMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
Global.Config.AutoLoadHexEditor ^= true;
|
|
}
|
|
|
|
private void SaveWindowsPositionMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
Global.Config.SaveWindowPosition ^= true;
|
|
}
|
|
|
|
private void AlwaysOnTopMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
Global.Config.HexEditorSettings.TopMost ^= true;
|
|
TopMost = Global.Config.HexEditorSettings.TopMost;
|
|
}
|
|
|
|
private void FloatingWindowMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
Global.Config.HexEditorSettings.FloatingWindow ^= true;
|
|
RefreshFloatingWindowControl();
|
|
}
|
|
|
|
private void RestoreDefaultSettingsMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
Size = new Size(_defaultWidth, _defaultHeight);
|
|
SetUpScrollBar();
|
|
|
|
Global.Config.HexEditorSettings.TopMost = false;
|
|
Global.Config.HexEditorSettings.SaveWindowPosition = true;
|
|
Global.Config.HexEditorSettings.FloatingWindow = false;
|
|
Global.Config.AutoLoadHexEditor = false;
|
|
|
|
RefreshFloatingWindowControl();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Context Menu and Dialog Events
|
|
|
|
private void HexEditor_Resize(object sender, EventArgs e)
|
|
{
|
|
SetUpScrollBar();
|
|
UpdateValues();
|
|
}
|
|
|
|
private void HexEditor_ResizeEnd(object sender, EventArgs e)
|
|
{
|
|
SetUpScrollBar();
|
|
}
|
|
|
|
private void HexEditor_KeyDown(object sender, KeyEventArgs e)
|
|
{
|
|
if (e.Control && e.KeyCode == Keys.G)
|
|
{
|
|
GoToAddressMenuItem_Click(sender, e);
|
|
return;
|
|
}
|
|
|
|
if (e.Control && e.KeyCode == Keys.P)
|
|
{
|
|
PokeAddressMenuItem_Click(sender, e);
|
|
return;
|
|
}
|
|
|
|
int newHighlighted;
|
|
switch (e.KeyCode)
|
|
{
|
|
case Keys.Up:
|
|
newHighlighted = _addressHighlighted - 16;
|
|
if (e.Modifiers == Keys.Shift)
|
|
{
|
|
for (var i = newHighlighted + 1; i <= _addressHighlighted; i++)
|
|
{
|
|
AddToSecondaryHighlights(i);
|
|
}
|
|
|
|
GoToAddress(newHighlighted);
|
|
}
|
|
else
|
|
{
|
|
_secondaryHighlightedAddresses.Clear();
|
|
GoToAddress(newHighlighted);
|
|
}
|
|
|
|
break;
|
|
case Keys.Down:
|
|
newHighlighted = _addressHighlighted + 16;
|
|
if (e.Modifiers == Keys.Shift)
|
|
{
|
|
for (var i = newHighlighted - 16; i < newHighlighted; i++)
|
|
{
|
|
AddToSecondaryHighlights(i);
|
|
}
|
|
|
|
GoToAddress(newHighlighted);
|
|
}
|
|
else
|
|
{
|
|
_secondaryHighlightedAddresses.Clear();
|
|
GoToAddress(newHighlighted);
|
|
}
|
|
|
|
break;
|
|
case Keys.Left:
|
|
newHighlighted = _addressHighlighted - (1 * _dataSize);
|
|
if (e.Modifiers == Keys.Shift)
|
|
{
|
|
AddToSecondaryHighlights(_addressHighlighted);
|
|
GoToAddress(newHighlighted);
|
|
}
|
|
else
|
|
{
|
|
_secondaryHighlightedAddresses.Clear();
|
|
GoToAddress(newHighlighted);
|
|
}
|
|
|
|
break;
|
|
case Keys.Right:
|
|
newHighlighted = _addressHighlighted + (1 * _dataSize);
|
|
if (e.Modifiers == Keys.Shift)
|
|
{
|
|
AddToSecondaryHighlights(_addressHighlighted);
|
|
GoToAddress(newHighlighted);
|
|
}
|
|
else
|
|
{
|
|
_secondaryHighlightedAddresses.Clear();
|
|
GoToAddress(newHighlighted);
|
|
}
|
|
|
|
break;
|
|
case Keys.PageUp:
|
|
newHighlighted = _addressHighlighted - (_rowsVisible * 16);
|
|
if (e.Modifiers == Keys.Shift)
|
|
{
|
|
for (var i = newHighlighted + 1; i <= _addressHighlighted; i++)
|
|
{
|
|
AddToSecondaryHighlights(i);
|
|
}
|
|
|
|
GoToAddress(newHighlighted);
|
|
}
|
|
else
|
|
{
|
|
_secondaryHighlightedAddresses.Clear();
|
|
GoToAddress(newHighlighted);
|
|
}
|
|
|
|
break;
|
|
case Keys.PageDown:
|
|
newHighlighted = _addressHighlighted + (_rowsVisible * 16);
|
|
if (e.Modifiers == Keys.Shift)
|
|
{
|
|
for (var i = _addressHighlighted + 1; i < newHighlighted; i++)
|
|
{
|
|
AddToSecondaryHighlights(i);
|
|
}
|
|
|
|
GoToAddress(newHighlighted);
|
|
}
|
|
else
|
|
{
|
|
_secondaryHighlightedAddresses.Clear();
|
|
GoToAddress(newHighlighted);
|
|
}
|
|
|
|
break;
|
|
case Keys.Tab:
|
|
_secondaryHighlightedAddresses.Clear();
|
|
if (e.Modifiers == Keys.Shift)
|
|
{
|
|
GoToAddress(_addressHighlighted - 8);
|
|
}
|
|
else
|
|
{
|
|
GoToAddress(_addressHighlighted + 8);
|
|
}
|
|
|
|
break;
|
|
case Keys.Home:
|
|
if (e.Modifiers == Keys.Shift)
|
|
{
|
|
for (var i = 1; i <= _addressHighlighted; i++)
|
|
{
|
|
AddToSecondaryHighlights(i);
|
|
}
|
|
|
|
GoToAddress(0);
|
|
}
|
|
else
|
|
{
|
|
_secondaryHighlightedAddresses.Clear();
|
|
GoToAddress(0);
|
|
}
|
|
|
|
break;
|
|
case Keys.End:
|
|
newHighlighted = _domain.Size - _dataSize;
|
|
if (e.Modifiers == Keys.Shift)
|
|
{
|
|
for (var i = _addressHighlighted; i < newHighlighted; i++)
|
|
{
|
|
AddToSecondaryHighlights(i);
|
|
}
|
|
|
|
GoToAddress(newHighlighted);
|
|
}
|
|
else
|
|
{
|
|
_secondaryHighlightedAddresses.Clear();
|
|
GoToAddress(newHighlighted);
|
|
}
|
|
|
|
break;
|
|
case Keys.Add:
|
|
IncrementContextItem_Click(sender, e);
|
|
break;
|
|
case Keys.Subtract:
|
|
DecrementContextItem_Click(sender, e);
|
|
break;
|
|
case Keys.Space:
|
|
FreezeAddressMenuItem_Click(sender, e);
|
|
break;
|
|
case Keys.Delete:
|
|
if (e.Modifiers == Keys.Shift)
|
|
{
|
|
Global.CheatList.RemoveAll();
|
|
}
|
|
else
|
|
{
|
|
if (HighlightedAddress.HasValue)
|
|
{
|
|
UnFreezeAddress(HighlightedAddress.Value);
|
|
}
|
|
}
|
|
|
|
break;
|
|
case Keys.W:
|
|
if (e.Modifiers == Keys.Control)
|
|
{
|
|
AddToRamWatchMenuItem_Click(sender, e);
|
|
}
|
|
|
|
break;
|
|
case Keys.Escape:
|
|
_secondaryHighlightedAddresses.Clear();
|
|
ClearHighlighted();
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void HexEditor_KeyPress(object sender, KeyPressEventArgs e)
|
|
{
|
|
if (!IsHexKeyCode(e.KeyChar))
|
|
{
|
|
e.Handled = true;
|
|
return;
|
|
}
|
|
|
|
if ((ModifierKeys & (Keys.Control | Keys.Shift | Keys.Alt)) != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
switch (_dataSize)
|
|
{
|
|
default:
|
|
case 1:
|
|
if (_nibbles[0] == 'G')
|
|
{
|
|
_nibbles[0] = ForceCorrectKeyString(e.KeyChar);
|
|
}
|
|
else
|
|
{
|
|
var temp = _nibbles[0].ToString() + ForceCorrectKeyString(e.KeyChar);
|
|
var x = byte.Parse(temp, NumberStyles.HexNumber);
|
|
_domain.PokeByte(_addressHighlighted, x);
|
|
ClearNibbles();
|
|
SetHighlighted(_addressHighlighted + 1);
|
|
UpdateValues();
|
|
}
|
|
|
|
break;
|
|
case 2:
|
|
if (_nibbles[0] == 'G')
|
|
{
|
|
_nibbles[0] = ForceCorrectKeyString(e.KeyChar);
|
|
}
|
|
else if (_nibbles[1] == 'G')
|
|
{
|
|
_nibbles[1] = ForceCorrectKeyString(e.KeyChar);
|
|
}
|
|
else if (_nibbles[2] == 'G')
|
|
{
|
|
_nibbles[2] = ForceCorrectKeyString(e.KeyChar);
|
|
}
|
|
else if (_nibbles[3] == 'G')
|
|
{
|
|
var temp = _nibbles[0].ToString() + _nibbles[1];
|
|
var x1 = byte.Parse(temp, NumberStyles.HexNumber);
|
|
|
|
var temp2 = _nibbles[2].ToString() + ((char)e.KeyChar);
|
|
var x2 = byte.Parse(temp2, NumberStyles.HexNumber);
|
|
|
|
PokeWord(_addressHighlighted, x1, x2);
|
|
ClearNibbles();
|
|
SetHighlighted(_addressHighlighted + 2);
|
|
UpdateValues();
|
|
}
|
|
|
|
break;
|
|
case 4:
|
|
if (_nibbles[0] == 'G')
|
|
{
|
|
_nibbles[0] = ForceCorrectKeyString(e.KeyChar);
|
|
}
|
|
else if (_nibbles[1] == 'G')
|
|
{
|
|
_nibbles[1] = ForceCorrectKeyString(e.KeyChar);
|
|
}
|
|
else if (_nibbles[2] == 'G')
|
|
{
|
|
_nibbles[2] = ForceCorrectKeyString(e.KeyChar);
|
|
}
|
|
else if (_nibbles[3] == 'G')
|
|
{
|
|
_nibbles[3] = ForceCorrectKeyString(e.KeyChar);
|
|
}
|
|
else if (_nibbles[4] == 'G')
|
|
{
|
|
_nibbles[4] = ForceCorrectKeyString(e.KeyChar);
|
|
}
|
|
else if (_nibbles[5] == 'G')
|
|
{
|
|
_nibbles[5] = ForceCorrectKeyString(e.KeyChar);
|
|
}
|
|
else if (_nibbles[6] == 'G')
|
|
{
|
|
_nibbles[6] = ForceCorrectKeyString(e.KeyChar);
|
|
}
|
|
else if (_nibbles[7] == 'G')
|
|
{
|
|
var temp = _nibbles[0].ToString() + _nibbles[1];
|
|
var x1 = byte.Parse(temp, NumberStyles.HexNumber);
|
|
|
|
var temp2 = _nibbles[2].ToString() + _nibbles[3];
|
|
var x2 = byte.Parse(temp2, NumberStyles.HexNumber);
|
|
|
|
var temp3 = _nibbles[4].ToString() + _nibbles[5];
|
|
var x3 = byte.Parse(temp3, NumberStyles.HexNumber);
|
|
|
|
var temp4 = _nibbles[6].ToString() + ForceCorrectKeyString(e.KeyChar);
|
|
var x4 = byte.Parse(temp4, NumberStyles.HexNumber);
|
|
|
|
PokeWord(_addressHighlighted, x1, x2);
|
|
PokeWord(_addressHighlighted + 2, x3, x4);
|
|
ClearNibbles();
|
|
SetHighlighted(_addressHighlighted + 4);
|
|
UpdateValues();
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
UpdateValues();
|
|
}
|
|
|
|
private void ViewerContextMenuStrip_Opening(object sender, CancelEventArgs e)
|
|
{
|
|
var data = Clipboard.GetDataObject();
|
|
|
|
CopyContextItem.Visible =
|
|
FreezeContextItem.Visible =
|
|
AddToRamWatchContextItem.Visible =
|
|
PokeContextItem.Visible =
|
|
IncrementContextItem.Visible =
|
|
DecrementContextItem.Visible =
|
|
ContextSeparator2.Visible =
|
|
HighlightedAddress.HasValue || _secondaryHighlightedAddresses.Any();
|
|
|
|
UnfreezeAllContextItem.Visible = Global.CheatList.ActiveCount > 0;
|
|
PasteContextItem.Visible = data != null && data.GetDataPresent(DataFormats.Text);
|
|
|
|
ContextSeparator1.Visible =
|
|
HighlightedAddress.HasValue ||
|
|
_secondaryHighlightedAddresses.Any() ||
|
|
(data != null && data.GetDataPresent(DataFormats.Text));
|
|
|
|
if (HighlightedAddress.HasValue && IsFrozen(HighlightedAddress.Value))
|
|
{
|
|
FreezeContextItem.Text = "Un&freeze";
|
|
FreezeContextItem.Image = Properties.Resources.Unfreeze;
|
|
}
|
|
else
|
|
{
|
|
FreezeContextItem.Text = "&Freeze";
|
|
FreezeContextItem.Image = Properties.Resources.Freeze;
|
|
}
|
|
}
|
|
|
|
private void IncrementContextItem_Click(object sender, EventArgs e)
|
|
{
|
|
if (HighlightedAddress.HasValue)
|
|
{
|
|
IncrementAddress(HighlightedAddress.Value);
|
|
}
|
|
|
|
_secondaryHighlightedAddresses.ForEach(IncrementAddress);
|
|
|
|
UpdateValues();
|
|
}
|
|
|
|
private void DecrementContextItem_Click(object sender, EventArgs e)
|
|
{
|
|
if (HighlightedAddress.HasValue)
|
|
{
|
|
DecrementAddress(HighlightedAddress.Value);
|
|
}
|
|
|
|
_secondaryHighlightedAddresses.ForEach(DecrementAddress);
|
|
|
|
UpdateValues();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MemoryViewer Events
|
|
|
|
private void HexEditor_MouseWheel(object sender, MouseEventArgs e)
|
|
{
|
|
var delta = 0;
|
|
if (e.Delta > 0)
|
|
{
|
|
delta = -1;
|
|
}
|
|
else if (e.Delta < 0)
|
|
{
|
|
delta = 1;
|
|
}
|
|
|
|
var newValue = HexScrollBar.Value + delta;
|
|
if (newValue < HexScrollBar.Minimum)
|
|
{
|
|
newValue = HexScrollBar.Minimum;
|
|
}
|
|
|
|
if (newValue > HexScrollBar.Maximum - HexScrollBar.LargeChange + 1)
|
|
{
|
|
newValue = HexScrollBar.Maximum - HexScrollBar.LargeChange + 1;
|
|
}
|
|
|
|
if (newValue != HexScrollBar.Value)
|
|
{
|
|
HexScrollBar.Value = newValue;
|
|
MemoryViewerBox.Refresh();
|
|
}
|
|
}
|
|
|
|
private void MemoryViewerBox_Paint(object sender, PaintEventArgs e)
|
|
{
|
|
var activeCheats = Global.CheatList.Where(x => x.Enabled);
|
|
foreach (var cheat in activeCheats)
|
|
{
|
|
if (IsVisible(cheat.Address ?? 0))
|
|
{
|
|
if (_domain.ToString() == cheat.Domain.Name)
|
|
{
|
|
var rect = new Rectangle(GetAddressCoordinates(cheat.Address ?? 0), new Size(15 * (int)cheat.Size, fontHeight));
|
|
e.Graphics.DrawRectangle(new Pen(Brushes.Black), rect);
|
|
e.Graphics.FillRectangle(new SolidBrush(Global.Config.HexFreezeColor), rect);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (_addressHighlighted >= 0 && IsVisible(_addressHighlighted))
|
|
{
|
|
var point = GetAddressCoordinates(_addressHighlighted);
|
|
var textX = GetTextX(_addressHighlighted);
|
|
var textpoint = new Point(textX, point.Y);
|
|
|
|
var rect = new Rectangle(point, new Size(15 * _dataSize + (NeedsExtra(_addressHighlighted) ? FontWidth : 0), fontHeight));
|
|
e.Graphics.DrawRectangle(new Pen(Brushes.Black), rect);
|
|
|
|
var textrect = new Rectangle(textpoint, new Size(8 * _dataSize, fontHeight));
|
|
|
|
if (Global.CheatList.IsActive(_domain, _addressHighlighted))
|
|
{
|
|
e.Graphics.FillRectangle(new SolidBrush(Global.Config.HexHighlightFreezeColor), rect);
|
|
e.Graphics.FillRectangle(new SolidBrush(Global.Config.HexHighlightFreezeColor), textrect);
|
|
}
|
|
else
|
|
{
|
|
e.Graphics.FillRectangle(new SolidBrush(Global.Config.HexHighlightColor), rect);
|
|
e.Graphics.FillRectangle(new SolidBrush(Global.Config.HexHighlightColor), textrect);
|
|
}
|
|
}
|
|
|
|
foreach (var address in _secondaryHighlightedAddresses)
|
|
{
|
|
var point = GetAddressCoordinates(address);
|
|
var textX = GetTextX(address);
|
|
var textpoint = new Point(textX, point.Y);
|
|
|
|
var rect = new Rectangle(point, new Size(15 * _dataSize, fontHeight));
|
|
e.Graphics.DrawRectangle(new Pen(Brushes.Black), rect);
|
|
|
|
var textrect = new Rectangle(textpoint, new Size(8, fontHeight));
|
|
|
|
if (Global.CheatList.IsActive(_domain, address))
|
|
{
|
|
e.Graphics.FillRectangle(new SolidBrush(Global.Config.HexHighlightFreezeColor), rect);
|
|
e.Graphics.FillRectangle(new SolidBrush(Global.Config.HexHighlightFreezeColor), textrect);
|
|
}
|
|
else
|
|
{
|
|
e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(0x77FFD4D4)), rect);
|
|
e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(0x77FFD4D4)), textrect);
|
|
}
|
|
}
|
|
|
|
if (HasNibbles())
|
|
{
|
|
e.Graphics.DrawString(MakeNibbles(), new Font("Courier New", 8, FontStyle.Italic), Brushes.Black, new Point(158, 4));
|
|
}
|
|
}
|
|
|
|
private void AddressesLabel_MouseUp(object sender, MouseEventArgs e)
|
|
{
|
|
_mouseIsDown = false;
|
|
}
|
|
|
|
private void AddressesLabel_MouseMove(object sender, MouseEventArgs e)
|
|
{
|
|
_addressOver = GetPointedAddress(e.X, e.Y);
|
|
|
|
if (_mouseIsDown)
|
|
{
|
|
DoShiftClick();
|
|
MemoryViewerBox.Refresh();
|
|
}
|
|
}
|
|
|
|
private void AddressesLabel_MouseLeave(object sender, EventArgs e)
|
|
{
|
|
_addressOver = -1;
|
|
MemoryViewerBox.Refresh();
|
|
}
|
|
|
|
private void AddressesLabel_MouseDown(object sender, MouseEventArgs e)
|
|
{
|
|
if (e.Button == MouseButtons.Left)
|
|
{
|
|
var pointed_address = GetPointedAddress(e.X, e.Y);
|
|
if (pointed_address >= 0)
|
|
{
|
|
if ((ModifierKeys & Keys.Control) == Keys.Control)
|
|
{
|
|
if (pointed_address == _addressHighlighted)
|
|
{
|
|
ClearHighlighted();
|
|
}
|
|
else if (_secondaryHighlightedAddresses.Contains(pointed_address))
|
|
{
|
|
_secondaryHighlightedAddresses.Remove(pointed_address);
|
|
}
|
|
else
|
|
{
|
|
_secondaryHighlightedAddresses.Add(pointed_address);
|
|
}
|
|
}
|
|
else if ((ModifierKeys & Keys.Shift) == Keys.Shift)
|
|
{
|
|
DoShiftClick();
|
|
}
|
|
else
|
|
{
|
|
SetHighlighted(pointed_address);
|
|
_secondaryHighlightedAddresses.Clear();
|
|
_findStr = string.Empty;
|
|
}
|
|
|
|
MemoryViewerBox.Refresh();
|
|
}
|
|
|
|
_mouseIsDown = true;
|
|
}
|
|
}
|
|
|
|
private void HexScrollBar_ValueChanged(object sender, EventArgs e)
|
|
{
|
|
UpdateValues();
|
|
}
|
|
|
|
protected override void OnShown(EventArgs e)
|
|
{
|
|
RefreshFloatingWindowControl();
|
|
base.OnShown(e);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
}
|
|
}
|