1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Drawing; 5 using System.Data; 6 using System.Linq; 7 using System.Text; 8 using System.Threading.Tasks; 9 using System.Windows.Forms; 10 using Mesen.GUI.Config; 11 using System.Globalization; 12 using System.Text.RegularExpressions; 13 14 namespace Mesen.GUI.Debugger.Controls 15 { 16 public partial class CodeViewerActions : UserControl 17 { 18 public event SetNextStatementEventHandler OnSetNextStatement; 19 public event ShowInSplitViewEventHandler OnShowInSplitView; 20 public event ShowInSplitViewEventHandler OnGoToDestination; 21 public event SwitchToSourceEventHandler OnSwitchView; 22 23 private int _lastClickedAddress = Int32.MaxValue; 24 private Ld65DbgImporter.SymbolInfo _lastClickedSymbol = null; 25 private CodeLabel _lastClickedLabel = null; 26 private string _newWatchValue = string.Empty; 27 private string _lastWord = string.Empty; 28 private Point _lastLocation = Point.Empty; 29 private DebugViewInfo _config; 30 31 public ICodeViewer Viewer { get; set; } 32 public bool IsSourceView { get; private set; } 33 CodeViewerActions()34 public CodeViewerActions() 35 { 36 InitializeComponent(); 37 } 38 CodeViewerActions(ICodeViewer viewer, bool isSourceView)39 public CodeViewerActions(ICodeViewer viewer, bool isSourceView) : this() 40 { 41 Viewer = viewer; 42 IsSourceView = isSourceView; 43 44 this.InitShortcuts(); 45 } 46 InitShortcuts()47 private void InitShortcuts() 48 { 49 Control parent = (Control)Viewer; 50 mnuEditInMemoryViewer.InitShortcut(parent, nameof(DebuggerShortcutsConfig.CodeWindow_EditInMemoryViewer)); 51 mnuEditLabel.InitShortcut(parent, nameof(DebuggerShortcutsConfig.CodeWindow_EditLabel)); 52 mnuSetNextStatement.InitShortcut(parent, nameof(DebuggerShortcutsConfig.CodeWindow_SetNextStatement)); 53 mnuShowNextStatement.InitShortcut(parent, nameof(DebuggerShortcutsConfig.GoToProgramCounter)); 54 mnuToggleBreakpoint.InitShortcut(parent, nameof(DebuggerShortcutsConfig.CodeWindow_ToggleBreakpoint)); 55 56 mnuUndoPrgChrEdit.InitShortcut(parent, nameof(DebuggerShortcutsConfig.Undo)); 57 mnuCopySelection.InitShortcut(parent, nameof(DebuggerShortcutsConfig.Copy)); 58 59 mnuSwitchView.InitShortcut(parent, nameof(DebuggerShortcutsConfig.CodeWindow_SwitchView)); 60 61 if(!IsSourceView) { 62 mnuNavigateBackward.InitShortcut(parent, nameof(DebuggerShortcutsConfig.CodeWindow_NavigateBack)); 63 mnuNavigateForward.InitShortcut(parent, nameof(DebuggerShortcutsConfig.CodeWindow_NavigateForward)); 64 65 mnuEditSelectedCode.InitShortcut(parent, nameof(DebuggerShortcutsConfig.CodeWindow_EditSelectedCode)); 66 mnuEditSubroutine.InitShortcut(parent, nameof(DebuggerShortcutsConfig.CodeWindow_EditSubroutine)); 67 68 mnuMarkAsCode.InitShortcut(parent, nameof(DebuggerShortcutsConfig.MarkAsCode)); 69 mnuMarkAsData.InitShortcut(parent, nameof(DebuggerShortcutsConfig.MarkAsData)); 70 mnuMarkAsUnidentifiedData.InitShortcut(parent, nameof(DebuggerShortcutsConfig.MarkAsUnidentified)); 71 } else { 72 mnuEditSourceFile.InitShortcut(parent, nameof(DebuggerShortcutsConfig.CodeWindow_EditSourceFile)); 73 } 74 } 75 InitMenu(DebugViewInfo config)76 public void InitMenu(DebugViewInfo config) 77 { 78 _config = config; 79 mnuPrgShowInline.Checked = false; 80 mnuPrgAddressReplace.Checked = false; 81 mnuPrgAddressBelow.Checked = false; 82 mnuHidePrgAddresses.Checked = false; 83 84 mnuShowByteCodeOnLeft.Checked = false; 85 mnuShowByteCodeBelow.Checked = false; 86 mnuHideByteCode.Checked = false; 87 88 mnuShowSourceAsComments.Checked = config.ShowSourceAsComments; 89 90 switch(config.ByteCodePosition) { 91 case ByteCodePosition.Left: 92 Viewer.CodeViewer.ShowContentNotes = true; 93 Viewer.CodeViewer.ShowSingleContentLineNotes = true; 94 this.mnuShowByteCodeOnLeft.Checked = true; 95 break; 96 97 case ByteCodePosition.Below: 98 Viewer.CodeViewer.ShowContentNotes = true; 99 Viewer.CodeViewer.ShowSingleContentLineNotes = false; 100 this.mnuShowByteCodeBelow.Checked = true; 101 break; 102 103 case ByteCodePosition.Hidden: 104 Viewer.CodeViewer.ShowContentNotes = false; 105 Viewer.CodeViewer.ShowSingleContentLineNotes = false; 106 this.mnuHideByteCode.Checked = true; 107 break; 108 } 109 110 switch(config.PrgAddressPosition) { 111 case PrgAddressPosition.Inline: 112 Viewer.CodeViewer.ShowCompactPrgAddresses = true; 113 Viewer.CodeViewer.ShowLineNumberNotes = false; 114 Viewer.CodeViewer.ShowSingleLineLineNumberNotes = false; 115 this.mnuPrgShowInline.Checked = true; 116 break; 117 118 case PrgAddressPosition.Replace: 119 Viewer.CodeViewer.ShowCompactPrgAddresses = false; 120 Viewer.CodeViewer.ShowLineNumberNotes = true; 121 Viewer.CodeViewer.ShowSingleLineLineNumberNotes = true; 122 this.mnuPrgAddressReplace.Checked = true; 123 break; 124 125 case PrgAddressPosition.Below: 126 Viewer.CodeViewer.ShowCompactPrgAddresses = false; 127 Viewer.CodeViewer.ShowLineNumberNotes = true; 128 Viewer.CodeViewer.ShowSingleLineLineNumberNotes = false; 129 this.mnuPrgAddressBelow.Checked = true; 130 break; 131 132 case PrgAddressPosition.Hidden: 133 Viewer.CodeViewer.ShowCompactPrgAddresses = false; 134 Viewer.CodeViewer.ShowLineNumberNotes = false; 135 Viewer.CodeViewer.ShowSingleLineLineNumberNotes = false; 136 this.mnuHidePrgAddresses.Checked = true; 137 break; 138 } 139 } 140 UpdateConfig()141 private void UpdateConfig() 142 { 143 this.InitMenu(_config); 144 ConfigManager.ApplyChanges(); 145 } 146 contextMenuCode_Opening(object sender, CancelEventArgs e)147 private void contextMenuCode_Opening(object sender, CancelEventArgs e) 148 { 149 UpdateContextMenuItemVisibility(contextMenu.Items); 150 151 int startAddress, endAddress; 152 string range; 153 GetSelectedAddressRange(out startAddress, out endAddress, out range); 154 mnuMarkSelectionAs.Enabled = startAddress >= 0 && endAddress >= 0 && startAddress <= endAddress; 155 if(mnuMarkSelectionAs.Enabled) { 156 mnuMarkSelectionAs.Text = "Mark selection as... (" + range + ")"; 157 } else { 158 mnuMarkSelectionAs.Text = "Mark selection as..."; 159 } 160 } 161 GetSelectedAddressRange(out int start, out int end, out string range)162 private void GetSelectedAddressRange(out int start, out int end, out string range) 163 { 164 int firstLineOfSelection = Viewer.CodeViewer.SelectionStart; 165 while(Viewer.CodeViewer.GetLineNumber(firstLineOfSelection) < 0) { 166 firstLineOfSelection++; 167 } 168 int firstLineAfterSelection = Viewer.CodeViewer.SelectionStart + Viewer.CodeViewer.SelectionLength + 1; 169 while(Viewer.CodeViewer.GetLineNumber(firstLineAfterSelection) < 0) { 170 firstLineAfterSelection++; 171 } 172 start = Viewer.CodeViewer.GetLineNumber(firstLineOfSelection); 173 end = Viewer.CodeViewer.GetLineNumber(firstLineAfterSelection) - 1; 174 175 range = ""; 176 if(start >= 0 && end >= 0) { 177 range = $"${start.ToString("X4")} - ${end.ToString("X4")}"; 178 start = InteropEmu.DebugGetAbsoluteAddress((UInt32)start); 179 end = InteropEmu.DebugGetAbsoluteAddress((UInt32)end); 180 } 181 } 182 MarkSelectionAs(CdlPrgFlags type)183 private void MarkSelectionAs(CdlPrgFlags type) 184 { 185 int startAddress, endAddress; 186 string range; 187 GetSelectedAddressRange(out startAddress, out endAddress, out range); 188 189 if(startAddress >= 0 && endAddress >= 0 && startAddress <= endAddress) { 190 InteropEmu.DebugMarkPrgBytesAs((UInt32)startAddress, (UInt32)endAddress, type); 191 192 frmDebugger debugger = DebugWindowManager.GetDebugger(); 193 if(debugger != null) { 194 debugger.UpdateDebugger(false); 195 } 196 } 197 } 198 mnuMarkAsCode_Click(object sender, EventArgs e)199 private void mnuMarkAsCode_Click(object sender, EventArgs e) 200 { 201 this.MarkSelectionAs(CdlPrgFlags.Code); 202 } 203 mnuMarkAsData_Click(object sender, EventArgs e)204 private void mnuMarkAsData_Click(object sender, EventArgs e) 205 { 206 this.MarkSelectionAs(CdlPrgFlags.Data); 207 } 208 mnuMarkAsUnidentifiedData_Click(object sender, EventArgs e)209 private void mnuMarkAsUnidentifiedData_Click(object sender, EventArgs e) 210 { 211 this.MarkSelectionAs(CdlPrgFlags.None); 212 } 213 mnuGoToLocation_Click(object sender, EventArgs e)214 private void mnuGoToLocation_Click(object sender, EventArgs e) 215 { 216 GoToLocation(); 217 } 218 GoToDestination(GoToDestination dest)219 public void GoToDestination(GoToDestination dest) 220 { 221 this.OnGoToDestination?.Invoke(Viewer, dest); 222 } 223 GetDestination()224 private GoToDestination GetDestination() 225 { 226 Ld65DbgImporter.ReferenceInfo definitionInfo = _lastClickedSymbol != null ? Viewer.SymbolProvider?.GetSymbolDefinition(_lastClickedSymbol) : null; 227 AddressTypeInfo addressInfo = _lastClickedSymbol != null ? Viewer.SymbolProvider?.GetSymbolAddressInfo(_lastClickedSymbol) : null; 228 return new GoToDestination() { 229 CpuAddress = _lastClickedAddress >= 0 ? _lastClickedAddress : (addressInfo != null ? InteropEmu.DebugGetRelativeAddress((UInt32)addressInfo.Address, addressInfo.Type) : -1), 230 Label = _lastClickedLabel, 231 AddressInfo = addressInfo, 232 File = definitionInfo?.FileName, 233 Line = definitionInfo?.LineNumber ?? 0 234 }; 235 } 236 GoToLocation()237 private void GoToLocation() 238 { 239 GoToDestination(GetDestination()); 240 } 241 mnuAddToWatch_Click(object sender, EventArgs e)242 private void mnuAddToWatch_Click(object sender, EventArgs e) 243 { 244 AddWatch(); 245 } 246 AddWatch()247 private void AddWatch() 248 { 249 WatchManager.AddWatch(_newWatchValue); 250 } 251 mnuShowInSplitView_Click(object sender, EventArgs e)252 private void mnuShowInSplitView_Click(object sender, EventArgs e) 253 { 254 ShowInSplitView(); 255 } 256 ShowInSplitView()257 private void ShowInSplitView() 258 { 259 this.OnShowInSplitView?.Invoke(Viewer, GetDestination()); 260 } 261 mnuEditLabel_Click(object sender, EventArgs e)262 private void mnuEditLabel_Click(object sender, EventArgs e) 263 { 264 if(UpdateContextMenu(_lastLocation)) { 265 if(_lastClickedAddress >= 0) { 266 AddressTypeInfo info = new AddressTypeInfo(); 267 InteropEmu.DebugGetAbsoluteAddressAndType((UInt32)_lastClickedAddress, info); 268 if(info.Address >= 0) { 269 ctrlLabelList.EditLabel((UInt32)info.Address, info.Type); 270 } else { 271 ctrlLabelList.EditLabel((UInt32)_lastClickedAddress, AddressType.Register); 272 } 273 } else if(_lastClickedLabel != null) { 274 ctrlLabelList.EditLabel(_lastClickedLabel.Address, _lastClickedLabel.AddressType); 275 } else if(_lastClickedSymbol != null) { 276 AddressTypeInfo info = Viewer.SymbolProvider.GetSymbolAddressInfo(_lastClickedSymbol); 277 if(info != null && info.Address >= 0) { 278 ctrlLabelList.EditLabel((UInt32)info.Address, info.Type); 279 } 280 } 281 } 282 } 283 mnuNavigateForward_Click(object sender, EventArgs e)284 private void mnuNavigateForward_Click(object sender, EventArgs e) 285 { 286 Viewer.CodeViewer.NavigateForward(); 287 } 288 mnuNavigateBackward_Click(object sender, EventArgs e)289 private void mnuNavigateBackward_Click(object sender, EventArgs e) 290 { 291 Viewer.CodeViewer.NavigateBackward(); 292 } 293 mnuToggleBreakpoint_Click(object sender, EventArgs e)294 private void mnuToggleBreakpoint_Click(object sender, EventArgs e) 295 { 296 this.ToggleBreakpoint(false); 297 } 298 ToggleBreakpoint(bool toggleEnabledFlag)299 public void ToggleBreakpoint(bool toggleEnabledFlag) 300 { 301 AddressTypeInfo info = Viewer.GetAddressInfo(Viewer.CodeViewer.SelectedLine); 302 if(info.Address < 0) { 303 //Current line has no address, try using the next line instead. 304 //(Used when trying to set a breakpoint on a row containing only a label) 305 info = Viewer.GetAddressInfo(Viewer.CodeViewer.SelectedLine + 1); 306 } 307 308 if(info.Address >= 0) { 309 BreakpointManager.ToggleBreakpoint(info, toggleEnabledFlag); 310 } 311 } 312 mnuShowByteCodeOnLeft_Click(object sender, EventArgs e)313 private void mnuShowByteCodeOnLeft_Click(object sender, EventArgs e) 314 { 315 _config.ByteCodePosition = ByteCodePosition.Left; 316 this.UpdateConfig(); 317 } 318 mnuShowByteCodeBelow_Click(object sender, EventArgs e)319 private void mnuShowByteCodeBelow_Click(object sender, EventArgs e) 320 { 321 _config.ByteCodePosition = ByteCodePosition.Below; 322 this.UpdateConfig(); 323 } 324 mnuHideByteCode_Click(object sender, EventArgs e)325 private void mnuHideByteCode_Click(object sender, EventArgs e) 326 { 327 _config.ByteCodePosition = ByteCodePosition.Hidden; 328 this.UpdateConfig(); 329 } 330 mnuShowSourceAsComments_Click(object sender, EventArgs e)331 private void mnuShowSourceAsComments_Click(object sender, EventArgs e) 332 { 333 _config.ShowSourceAsComments = mnuShowSourceAsComments.Checked; 334 this.UpdateConfig(); 335 } 336 mnuShowInlineCompactDisplay_Click(object sender, EventArgs e)337 private void mnuShowInlineCompactDisplay_Click(object sender, EventArgs e) 338 { 339 _config.PrgAddressPosition = PrgAddressPosition.Inline; 340 this.UpdateConfig(); 341 } 342 mnuReplaceCpuAddress_Click(object sender, EventArgs e)343 private void mnuReplaceCpuAddress_Click(object sender, EventArgs e) 344 { 345 _config.PrgAddressPosition = PrgAddressPosition.Replace; 346 this.UpdateConfig(); 347 } 348 mnuBelowCpuAddress_Click(object sender, EventArgs e)349 private void mnuBelowCpuAddress_Click(object sender, EventArgs e) 350 { 351 _config.PrgAddressPosition = PrgAddressPosition.Below; 352 this.UpdateConfig(); 353 } 354 mnuHidePrgAddresses_Click(object sender, EventArgs e)355 private void mnuHidePrgAddresses_Click(object sender, EventArgs e) 356 { 357 _config.PrgAddressPosition = PrgAddressPosition.Hidden; 358 this.UpdateConfig(); 359 } 360 mnuCopySelection_Click(object sender, EventArgs e)361 private void mnuCopySelection_Click(object sender, EventArgs e) 362 { 363 Viewer.CodeViewer.CopySelection(ConfigManager.Config.DebugInfo.CopyAddresses, ConfigManager.Config.DebugInfo.CopyByteCode, ConfigManager.Config.DebugInfo.CopyComments); 364 } 365 mnuShowNextStatement_Click(object sender, EventArgs e)366 private void mnuShowNextStatement_Click(object sender, EventArgs e) 367 { 368 this.ScrollToActiveAddress(); 369 } 370 ScrollToActiveAddress()371 public void ScrollToActiveAddress() 372 { 373 if(Viewer.ActiveAddress.HasValue) { 374 Viewer.ScrollToLineNumber((int)Viewer.ActiveAddress.Value); 375 } 376 } 377 mnuShowLineNotes_Click(object sender, EventArgs e)378 private void mnuShowLineNotes_Click(object sender, EventArgs e) 379 { 380 Viewer.CodeViewer.ShowLineNumberNotes = this.mnuShowLineNotes.Checked; 381 this.UpdateConfig(); 382 } 383 mnuFindOccurrences_Click(object sender, EventArgs e)384 private void mnuFindOccurrences_Click(object sender, EventArgs e) 385 { 386 FindOccurrences(); 387 } 388 FindOccurrences()389 private void FindOccurrences() 390 { 391 if(_lastClickedSymbol != null) { 392 Viewer.FindAllOccurrences(_lastClickedSymbol); 393 } else { 394 Viewer.FindAllOccurrences(_lastWord, true, true); 395 } 396 } 397 mnuUndoPrgChrEdit_Click(object sender, EventArgs e)398 private void mnuUndoPrgChrEdit_Click(object sender, EventArgs e) 399 { 400 if(InteropEmu.DebugHasUndoHistory()) { 401 InteropEmu.DebugPerformUndo(); 402 frmDebugger debugger = DebugWindowManager.GetDebugger(); 403 if(debugger != null) { 404 debugger.UpdateDebugger(false); 405 } 406 } 407 } 408 mnuSetNextStatement_Click(object sender, EventArgs e)409 private void mnuSetNextStatement_Click(object sender, EventArgs e) 410 { 411 this.OnSetNextStatement?.Invoke(new AddressEventArgs() { Address = (UInt32)Viewer.CodeViewer.CurrentLine }); 412 } 413 mnuEditSourceFile_Click(object sender, EventArgs e)414 private void mnuEditSourceFile_Click(object sender, EventArgs e) 415 { 416 Viewer.EditSourceFile(); 417 } 418 mnuEditSubroutine_Click(object sender, EventArgs e)419 private void mnuEditSubroutine_Click(object sender, EventArgs e) 420 { 421 Viewer.EditSubroutine(); 422 } 423 mnuEditSelectedCode_Click(object sender, EventArgs e)424 private void mnuEditSelectedCode_Click(object sender, EventArgs e) 425 { 426 Viewer.EditSelectedCode(); 427 } 428 mnuEditInMemoryViewer_Click(object sender, EventArgs e)429 private void mnuEditInMemoryViewer_Click(object sender, EventArgs e) 430 { 431 if(UpdateContextMenu(_lastLocation)) { 432 DebugWindowManager.OpenMemoryViewer(GetDestination()); 433 } 434 } 435 mnuSwitchView_Click(object sender, EventArgs e)436 private void mnuSwitchView_Click(object sender, EventArgs e) 437 { 438 if(Viewer.SymbolProvider != null) { 439 this.SwitchView(); 440 } 441 } 442 SwitchView()443 public void SwitchView() 444 { 445 this.OnSwitchView?.Invoke(Viewer); 446 } 447 ProcessMouseUp(Point location, MouseButtons button)448 public void ProcessMouseUp(Point location, MouseButtons button) 449 { 450 if(UpdateContextMenu(location)) { 451 if(button == MouseButtons.Left) { 452 if(ModifierKeys.HasFlag(Keys.Control) && ModifierKeys.HasFlag(Keys.Alt)) { 453 ShowInSplitView(); 454 } else if(ModifierKeys.HasFlag(Keys.Control)) { 455 AddWatch(); 456 } else if(ModifierKeys.HasFlag(Keys.Alt)) { 457 FindOccurrences(); 458 } 459 } 460 } 461 } 462 ProcessMouseDoubleClick(Point location)463 public void ProcessMouseDoubleClick(Point location) 464 { 465 if(UpdateContextMenu(location) && mnuGoToLocation.Enabled) { 466 GoToLocation(); 467 } 468 } 469 contextMenuCode_Closed(object sender, ToolStripDropDownClosedEventArgs e)470 private void contextMenuCode_Closed(object sender, ToolStripDropDownClosedEventArgs e) 471 { 472 mnuEditSelectedCode.Enabled = true; 473 mnuEditSubroutine.Enabled = true; 474 mnuEditSourceFile.Enabled = true; 475 } 476 UpdateContextMenuItemVisibility(ToolStripItemCollection items)477 public void UpdateContextMenuItemVisibility(ToolStripItemCollection items) 478 { 479 items[nameof(mnuUndoPrgChrEdit)].Enabled = InteropEmu.DebugHasUndoHistory(); 480 items[nameof(mnuShowNextStatement)].Enabled = Viewer.ActiveAddress.HasValue; 481 items[nameof(mnuSetNextStatement)].Enabled = Viewer.ActiveAddress.HasValue; 482 items[nameof(mnuEditSelectedCode)].Enabled = items[nameof(mnuEditSubroutine)].Enabled = InteropEmu.DebugIsExecutionStopped() && Viewer.CodeViewer.CurrentLine >= 0; 483 484 bool hasSymbolProvider = Viewer.SymbolProvider != null; 485 items[nameof(mnuShowSourceAsComments)].Visible = hasSymbolProvider; 486 items[nameof(mnuSwitchView)].Visible = hasSymbolProvider; 487 items[nameof(sepSwitchView)].Visible = hasSymbolProvider; 488 489 if(IsSourceView) { 490 items[nameof(mnuMarkSelectionAs)].Visible = false; 491 492 items[nameof(mnuEditSubroutine)].Visible = false; 493 items[nameof(mnuEditSelectedCode)].Visible = false; 494 items[nameof(mnuNavigateForward)].Visible = false; 495 items[nameof(mnuNavigateBackward)].Visible = false; 496 items[nameof(mnuEditLabel)].Visible = false; 497 items[nameof(sepNavigation)].Visible = false; 498 items[nameof(mnuShowSourceAsComments)].Visible = false; 499 items[nameof(sepMarkSelectionAs)].Visible = false; 500 } else { 501 items[nameof(mnuEditSourceFile)].Visible = false; 502 } 503 504 AddressTypeInfo addressInfo = Viewer.GetAddressInfo(Viewer.CodeViewer.SelectedLine); 505 if(addressInfo.Address >= 0) { 506 int relAddress = InteropEmu.DebugGetRelativeAddress((uint)addressInfo.Address, addressInfo.Type); 507 items[nameof(mnuPerfTracker)].Text = "Performance Tracker ($" + relAddress.ToString("X4") + ")"; 508 items[nameof(mnuPerfTracker)].Enabled = true; 509 } else { 510 items[nameof(mnuPerfTracker)].Text = "Performance Tracker"; 511 items[nameof(mnuPerfTracker)].Enabled = false; 512 } 513 } 514 UpdateContextMenu(Point mouseLocation)515 private bool UpdateContextMenu(Point mouseLocation) 516 { 517 _lastLocation = mouseLocation; 518 519 UpdateContextMenuItemVisibility(contextMenu.Items); 520 521 mnuSwitchView.Text = IsSourceView ? "Switch to Disassembly View" : "Switch to Source View"; 522 523 string word = Viewer.CodeViewer.GetWordUnderLocation(mouseLocation); 524 Ld65DbgImporter.SymbolInfo symbol = null; 525 CodeLabel codeLabel = null; 526 527 if(!word.StartsWith("$")) { 528 Match arrayMatch = CodeTooltipManager.LabelArrayFormat.Match(word); 529 if(arrayMatch.Success) { 530 word = arrayMatch.Groups[1].Value; 531 } 532 533 codeLabel = LabelManager.GetLabel(word); 534 535 if(Viewer.SymbolProvider != null && IsSourceView) { 536 int rangeStart, rangeEnd; 537 if(Viewer.CodeViewer.GetNoteRangeAtLocation(mouseLocation.Y, out rangeStart, out rangeEnd)) { 538 symbol = Viewer.SymbolProvider.GetSymbol(word, rangeStart, rangeEnd); 539 } 540 } 541 } 542 543 if(word.StartsWith("$") || codeLabel != null || symbol != null) { 544 //Cursor is on a numeric value or label 545 _lastWord = word; 546 547 if(word.StartsWith("$")) { 548 //CPU Address 549 _lastClickedAddress = Int32.Parse(word.Substring(1), NumberStyles.AllowHexSpecifier); 550 _lastClickedSymbol = null; 551 _lastClickedLabel = null; 552 _newWatchValue = "[$" + _lastClickedAddress.ToString("X") + "]"; 553 } else if(symbol != null) { 554 //Symbol 555 _lastClickedAddress = -1; 556 _lastClickedLabel = null; 557 _lastClickedSymbol = symbol; 558 _newWatchValue = "[" + word + "]"; 559 } else if(codeLabel != null) { 560 //Label 561 _lastClickedLabel = codeLabel; 562 _lastClickedAddress = -1; 563 _lastClickedSymbol = null; 564 _newWatchValue = "[" + word + "]"; 565 } 566 567 mnuGoToLocation.Enabled = true; 568 mnuGoToLocation.Text = $"Go to Location ({word})"; 569 570 mnuShowInSplitView.Enabled = true; 571 mnuShowInSplitView.Text = $"Show in Split View ({word})"; 572 573 mnuAddToWatch.Enabled = true; 574 mnuAddToWatch.Text = $"Add to Watch ({word})"; 575 576 mnuFindOccurrences.Enabled = true; 577 mnuFindOccurrences.Text = $"Find Occurrences ({word})"; 578 579 mnuEditLabel.Enabled = true; 580 mnuEditLabel.Text = $"Edit Label ({word})"; 581 582 mnuEditInMemoryViewer.Enabled = true; 583 mnuEditInMemoryViewer.Text = $"Edit in Memory Viewer ({word})"; 584 585 return true; 586 } else { 587 mnuGoToLocation.Enabled = false; 588 mnuGoToLocation.Text = "Go to Location"; 589 mnuShowInSplitView.Enabled = false; 590 mnuShowInSplitView.Text = "Show in Split View"; 591 mnuAddToWatch.Enabled = false; 592 mnuAddToWatch.Text = "Add to Watch"; 593 mnuFindOccurrences.Enabled = false; 594 mnuFindOccurrences.Text = "Find Occurrences"; 595 mnuEditLabel.Enabled = false; 596 mnuEditLabel.Text = "Edit Label"; 597 mnuEditInMemoryViewer.Enabled = false; 598 mnuEditInMemoryViewer.Text = $"Edit in Memory Viewer"; 599 600 _lastClickedLabel = null; 601 _lastClickedSymbol = null; 602 if(mouseLocation.X < Viewer.CodeViewer.CodeMargin) { 603 _lastClickedAddress = Viewer.CodeViewer.GetLineNumberAtPosition(mouseLocation.Y); 604 } else { 605 _lastClickedAddress = Viewer.CodeViewer.LastSelectedLine; 606 } 607 608 if(_lastClickedAddress >= 0) { 609 //Cursor is in the margin, over an address label 610 string address = $"${_lastClickedAddress.ToString("X4")}"; 611 _newWatchValue = $"[{address}]"; 612 _lastWord = address; 613 614 mnuShowInSplitView.Enabled = true; 615 mnuShowInSplitView.Text = $"Show in Split View ({address})"; 616 mnuAddToWatch.Enabled = true; 617 mnuAddToWatch.Text = $"Add to Watch ({address})"; 618 mnuFindOccurrences.Enabled = true; 619 mnuFindOccurrences.Text = $"Find Occurrences ({address})"; 620 mnuEditLabel.Enabled = true; 621 mnuEditLabel.Text = $"Edit Label ({address})"; 622 mnuEditInMemoryViewer.Enabled = true; 623 mnuEditInMemoryViewer.Text = $"Edit in Memory Viewer ({address})"; 624 return true; 625 } 626 627 return false; 628 } 629 } 630 SetPerformanceTracker(PerfTrackerMode mode)631 private void SetPerformanceTracker(PerfTrackerMode mode) 632 { 633 AddressTypeInfo addressInfo = Viewer.GetAddressInfo(Viewer.CodeViewer.SelectedLine); 634 InteropEmu.DebugSetPerformanceTracker(addressInfo.Address, addressInfo.Type, mode); 635 } 636 mnuPerfTrackerFullscreen_Click(object sender, EventArgs e)637 private void mnuPerfTrackerFullscreen_Click(object sender, EventArgs e) 638 { 639 SetPerformanceTracker(PerfTrackerMode.Fullscreen); 640 } 641 mnuPerfTrackerCompact_Click(object sender, EventArgs e)642 private void mnuPerfTrackerCompact_Click(object sender, EventArgs e) 643 { 644 SetPerformanceTracker(PerfTrackerMode.Compact); 645 } 646 mnuPerfTrackerTextOnly_Click(object sender, EventArgs e)647 private void mnuPerfTrackerTextOnly_Click(object sender, EventArgs e) 648 { 649 SetPerformanceTracker(PerfTrackerMode.TextOnly); 650 } 651 mnuPerfTrackerDisabled_Click(object sender, EventArgs e)652 private void mnuPerfTrackerDisabled_Click(object sender, EventArgs e) 653 { 654 SetPerformanceTracker(PerfTrackerMode.Disabled); 655 } 656 mnuPerfTracker_DropDownOpening(object sender, EventArgs e)657 private void mnuPerfTracker_DropDownOpening(object sender, EventArgs e) 658 { 659 PerfTrackerMode mode = InteropEmu.DebugGetPerformanceTrackerMode(); 660 mnuPerfTrackerFullscreen.Checked = mode == PerfTrackerMode.Fullscreen; 661 mnuPerfTrackerCompact.Checked = mode == PerfTrackerMode.Compact; 662 mnuPerfTrackerTextOnly.Checked = mode == PerfTrackerMode.TextOnly; 663 mnuPerfTrackerDisabled.Checked = mode == PerfTrackerMode.Disabled; 664 } 665 } 666 } 667