1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Xml.Serialization; 7 using System.Windows.Forms; 8 using Mesen.GUI.Forms; 9 using static Mesen.GUI.Forms.BaseForm; 10 11 namespace Mesen.GUI.Config 12 { 13 public class DebuggerShortcutsConfig 14 { 15 //Shared 16 [ShortcutName("Increase Font Size")] 17 public XmlKeys IncreaseFontSize = Keys.Control | Keys.Oemplus; 18 [ShortcutName("Decrease Font Size")] 19 public XmlKeys DecreaseFontSize = Keys.Control | Keys.OemMinus; 20 [ShortcutName("Reset Font Size")] 21 public XmlKeys ResetFontSize = Keys.Control | Keys.D0; 22 23 [ShortcutName("Go To...")] 24 public XmlKeys GoTo = Keys.Control | Keys.G; 25 26 [ShortcutName("Find")] 27 public XmlKeys Find = Keys.Control | Keys.F; 28 [ShortcutName("Find Next")] 29 public XmlKeys FindNext = Keys.F3; 30 [ShortcutName("Find Previous")] 31 public XmlKeys FindPrev = Keys.Shift | Keys.F3; 32 33 [ShortcutName("Undo")] 34 public XmlKeys Undo = Keys.Control | Keys.Z; 35 [ShortcutName("Copy")] 36 public XmlKeys Copy = Keys.Control | Keys.C; 37 [ShortcutName("Cut")] 38 public XmlKeys Cut = Keys.Control | Keys.X; 39 [ShortcutName("Paste")] 40 public XmlKeys Paste = Keys.Control | Keys.V; 41 [ShortcutName("Select All")] 42 public XmlKeys SelectAll = Keys.Control | Keys.A; 43 44 [ShortcutName("Refresh")] 45 public XmlKeys Refresh = Keys.F5; 46 47 [ShortcutName("Mark Selection as Code")] 48 public XmlKeys MarkAsCode = Keys.Control | Keys.D1; 49 [ShortcutName("Mark Selection as Data")] 50 public XmlKeys MarkAsData = Keys.Control | Keys.D2; 51 [ShortcutName("Mark Selection as Unidentified Code/Data")] 52 public XmlKeys MarkAsUnidentified = Keys.Control | Keys.D3; 53 54 [ShortcutName("Go to All")] 55 public XmlKeys GoToAll = Keys.Control | Keys.Oemcomma; 56 57 [ShortcutName("PPU Viewer: Toggle View")] 58 public XmlKeys PpuViewer_ToggleView = Keys.Control | Keys.Q; 59 [ShortcutName("PPU Viewer: Toggle Zoom")] 60 public XmlKeys PpuViewer_ToggleZoom = Keys.Control | Keys.W; 61 62 [ShortcutName("Nametable Viewer: Add breakpoint (Tile)")] 63 public XmlKeys PpuViewer_AddBreakpointTile = Keys.F9; 64 [ShortcutName("Nametable Viewer: Add breakpoint (Attribute)")] 65 public XmlKeys PpuViewer_AddBreakpointAttribute = Keys.F10; 66 67 [ShortcutName("Edit in Memory Viewer")] 68 public XmlKeys CodeWindow_EditInMemoryViewer = Keys.F1; 69 [ShortcutName("View in disassembly")] 70 public XmlKeys MemoryViewer_ViewInDisassembly = Keys.None; 71 72 [ShortcutName("Open APU Viewer")] 73 public XmlKeys OpenApuViewer = Keys.Control | Keys.U; 74 [ShortcutName("Open Assembler")] 75 public XmlKeys OpenAssembler = Keys.Control | Keys.K; 76 [ShortcutName("Open Debugger")] 77 public XmlKeys OpenDebugger = Keys.Control | Keys.D; 78 [ShortcutName("Open Event Viewer")] 79 public XmlKeys OpenEventViewer = Keys.Control | Keys.E; 80 [ShortcutName("Open Memory Tools")] 81 public XmlKeys OpenMemoryTools = Keys.Control | Keys.M; 82 [ShortcutName("Open PPU Viewer")] 83 public XmlKeys OpenPpuViewer = Keys.Control | Keys.P; 84 [ShortcutName("Open Performance Profiler")] 85 public XmlKeys OpenProfiler = Keys.Control | Keys.Y; 86 [ShortcutName("Open Script Window")] 87 public XmlKeys OpenScriptWindow = Keys.Control | Keys.N; 88 [ShortcutName("Open Trace Logger")] 89 public XmlKeys OpenTraceLogger = Keys.Control | Keys.J; 90 [ShortcutName("Open Text Hooker")] 91 public XmlKeys OpenTextHooker = Keys.Control | Keys.H; 92 [ShortcutName("Open Watch Window")] 93 public XmlKeys OpenWatchWindow = Keys.Control | Keys.W; 94 95 [ShortcutName("Open Nametable Viewer (Compact)")] 96 public XmlKeys OpenNametableViewer = Keys.Control | Keys.D1; 97 [ShortcutName("Open CHR Viewer (Compact)")] 98 public XmlKeys OpenChrViewer = Keys.Control | Keys.D2; 99 [ShortcutName("Open Sprite Viewer (Compact)")] 100 public XmlKeys OpenSpriteViewer = Keys.Control | Keys.D3; 101 [ShortcutName("Open Palette Viewer (Compact)")] 102 public XmlKeys OpenPaletteViewer = Keys.Control | Keys.D4; 103 104 //Debugger window 105 [ShortcutName("Reset")] 106 public XmlKeys Reset = Keys.Control | Keys.R; 107 [ShortcutName("Power Cycle")] 108 public XmlKeys PowerCycle = Keys.Control | Keys.T; 109 110 [ShortcutName("Continue")] 111 public XmlKeys Continue = Keys.F5; 112 [ShortcutName("Break")] 113 public XmlKeys Break = Keys.Control | Keys.Alt | Keys.Cancel; 114 [ShortcutName("Toggle Break/Continue")] 115 public XmlKeys ToggleBreakContinue = Keys.Escape; 116 [ShortcutName("Step Into")] 117 public XmlKeys StepInto = Keys.F11; 118 [ShortcutName("Step Over")] 119 public XmlKeys StepOver = Keys.F10; 120 [ShortcutName("Step Out")] 121 public XmlKeys StepOut = Keys.Shift | Keys.F11; 122 [ShortcutName("Step Back")] 123 public XmlKeys StepBack = Keys.Shift | Keys.F10; 124 125 [ShortcutName("Run one CPU Cycle")] 126 public XmlKeys RunCpuCycle = Keys.None; 127 [ShortcutName("Run one PPU Cycle")] 128 public XmlKeys RunPpuCycle = Keys.F6; 129 [ShortcutName("Run one scanline")] 130 public XmlKeys RunPpuScanline = Keys.F7; 131 [ShortcutName("Run one frame")] 132 public XmlKeys RunPpuFrame = Keys.F8; 133 134 [ShortcutName("Break In...")] 135 public XmlKeys BreakIn = Keys.Control | Keys.B; 136 [ShortcutName("Break On...")] 137 public XmlKeys BreakOn = Keys.Alt | Keys.B; 138 139 [ShortcutName("Find Occurrences")] 140 public XmlKeys FindOccurrences = Keys.Control | Keys.Shift | Keys.F; 141 [ShortcutName("Go To Program Counter")] 142 public XmlKeys GoToProgramCounter = Keys.Alt | Keys.Multiply; 143 144 [ShortcutName("Toggle Verified Data Display")] 145 public XmlKeys ToggleVerifiedData = Keys.Alt | Keys.D1; 146 [ShortcutName("Toggle Unidentified Code/Data Display")] 147 public XmlKeys ToggleUnidentifiedCodeData = Keys.Alt | Keys.D2; 148 149 [ShortcutName("Code Window: Set Next Statement")] 150 public XmlKeys CodeWindow_SetNextStatement = Keys.Control | Keys.Shift | Keys.F10; 151 [ShortcutName("Code Window: Edit Subroutine")] 152 public XmlKeys CodeWindow_EditSubroutine = Keys.F4; 153 [ShortcutName("Code Window: Edit Selected Code")] 154 public XmlKeys CodeWindow_EditSelectedCode = Keys.None; 155 [ShortcutName("Code Window: Edit Source File (Source View)")] 156 public XmlKeys CodeWindow_EditSourceFile = Keys.F4; 157 [ShortcutName("Code Window: Edit Label")] 158 public XmlKeys CodeWindow_EditLabel = Keys.F2; 159 [ShortcutName("Code Window: Navigate Back")] 160 public XmlKeys CodeWindow_NavigateBack = Keys.Alt | Keys.Left; 161 [ShortcutName("Code Window: Navigate Forward")] 162 public XmlKeys CodeWindow_NavigateForward = Keys.Alt | Keys.Right; 163 [ShortcutName("Code Window: Toggle Breakpoint")] 164 public XmlKeys CodeWindow_ToggleBreakpoint = Keys.F9; 165 [ShortcutName("Code Window: Disable/Enable Breakpoint")] 166 public XmlKeys CodeWindow_DisableEnableBreakpoint = Keys.Control | Keys.F9; 167 [ShortcutName("Code Window: Switch View (Disassembly / Source View)")] 168 public XmlKeys CodeWindow_SwitchView = Keys.Control | Keys.Q; 169 170 [ShortcutName("Function List: Edit Label")] 171 public XmlKeys FunctionList_EditLabel = Keys.F2; 172 [ShortcutName("Function List: Add Breakpoint")] 173 public XmlKeys FunctionList_AddBreakpoint = Keys.None; 174 [ShortcutName("Function List: Find Occurrences")] 175 public XmlKeys FunctionList_FindOccurrences = Keys.None; 176 177 [ShortcutName("Label List: Add Label")] 178 public XmlKeys LabelList_Add = Keys.Insert; 179 [ShortcutName("Label List: Edit Label")] 180 public XmlKeys LabelList_Edit = Keys.F2; 181 [ShortcutName("Label List: Delete Label")] 182 public XmlKeys LabelList_Delete = Keys.Delete; 183 [ShortcutName("Label List: Add Breakpoint")] 184 public XmlKeys LabelList_AddBreakpoint = Keys.None; 185 [ShortcutName("Label List: Add to Watch")] 186 public XmlKeys LabelList_AddToWatch = Keys.None; 187 [ShortcutName("Label List: Find Occurrences")] 188 public XmlKeys LabelList_FindOccurrences = Keys.None; 189 [ShortcutName("Label List: View in CPU Memory")] 190 public XmlKeys LabelList_ViewInCpuMemory = Keys.None; 191 [ShortcutName("Label List: View in [memory type]")] 192 public XmlKeys LabelList_ViewInMemoryType = Keys.None; 193 194 [ShortcutName("Breakpoint List: Add Breakpoint")] 195 public XmlKeys BreakpointList_Add = Keys.Insert; 196 [ShortcutName("Breakpoint List: Edit Breakpoint")] 197 public XmlKeys BreakpointList_Edit = Keys.F2; 198 [ShortcutName("Breakpoint List: Go To Location")] 199 public XmlKeys BreakpointList_GoToLocation = Keys.None; 200 [ShortcutName("Breakpoint List: Delete Breakpoint")] 201 public XmlKeys BreakpointList_Delete = Keys.Delete; 202 203 [ShortcutName("Watch List: Delete")] 204 public XmlKeys WatchList_Delete = Keys.Delete; 205 [ShortcutName("Watch List: Move Up")] 206 public XmlKeys WatchList_MoveUp = Keys.Control | Keys.Up; 207 [ShortcutName("Watch List: Move Down")] 208 public XmlKeys WatchList_MoveDown = Keys.Control | Keys.Down; 209 210 [ShortcutName("Save Rom")] 211 public XmlKeys SaveRom = Keys.Control | Keys.S; 212 [ShortcutName("Save Rom As...")] 213 public XmlKeys SaveRomAs = Keys.None; 214 [ShortcutName("Save edits as IPS patch...")] 215 public XmlKeys SaveEditAsIps = Keys.None; 216 [ShortcutName("Revert PRG/CHR changes")] 217 public XmlKeys RevertPrgChrChanges = Keys.None; 218 219 //Memory Tools 220 [ShortcutName("Freeze")] 221 public XmlKeys MemoryViewer_Freeze = Keys.Control | Keys.Q; 222 [ShortcutName("Unfreeze")] 223 public XmlKeys MemoryViewer_Unfreeze = Keys.Control | Keys.W; 224 [ShortcutName("Add to Watch")] 225 public XmlKeys MemoryViewer_AddToWatch = Keys.None; 226 [ShortcutName("Edit Breakpoint")] 227 public XmlKeys MemoryViewer_EditBreakpoint = Keys.None; 228 [ShortcutName("Edit Label")] 229 public XmlKeys MemoryViewer_EditLabel = Keys.None; 230 [ShortcutName("Import")] 231 public XmlKeys MemoryViewer_Import = Keys.Control | Keys.O; 232 [ShortcutName("Export")] 233 public XmlKeys MemoryViewer_Export = Keys.Control | Keys.S; 234 [ShortcutName("View in CPU/PPU Memory")] 235 public XmlKeys MemoryViewer_ViewInCpuMemory = Keys.None; 236 [ShortcutName("View in [memory type]")] 237 public XmlKeys MemoryViewer_ViewInMemoryType = Keys.None; 238 239 //Script Window 240 [ShortcutName("Open Script")] 241 public XmlKeys ScriptWindow_OpenScript = Keys.Control | Keys.N; 242 [ShortcutName("Save Script")] 243 public XmlKeys ScriptWindow_SaveScript = Keys.Control | Keys.S; 244 [ShortcutName("Run Script")] 245 public XmlKeys ScriptWindow_RunScript = Keys.F5; 246 [ShortcutName("Stop Script")] 247 public XmlKeys ScriptWindow_StopScript = Keys.Escape; 248 GetShortcutDisplay(Keys keys)249 public static string GetShortcutDisplay(Keys keys) 250 { 251 if(keys == Keys.None) { 252 return ""; 253 } else { 254 string keyString = new KeysConverter().ConvertToString(keys); 255 return keyString.Replace("+None", "").Replace("Oemcomma", ",").Replace("Oemplus", "+").Replace("Oemtilde", "Tilde").Replace("OemMinus", "-").Replace("Cancel", "Break").Replace("Escape", "Esc"); 256 } 257 } 258 259 private static Dictionary<WeakReference<ToolStripMenuItem>, string> _bindings = new Dictionary<WeakReference<ToolStripMenuItem>, string>(); 260 private static Dictionary<WeakReference<ToolStripMenuItem>, WeakReference<Control>> _parents = new Dictionary<WeakReference<ToolStripMenuItem>, WeakReference<Control>>(); RegisterMenuItem(ToolStripMenuItem item, Control parent, string fieldName)261 public static void RegisterMenuItem(ToolStripMenuItem item, Control parent, string fieldName) 262 { 263 var weakRef = new WeakReference<ToolStripMenuItem>(item); 264 _bindings[weakRef] = fieldName; 265 _parents[weakRef] = new WeakReference<Control>(parent); 266 267 //Remove old references 268 var dictCopy = new Dictionary<WeakReference<ToolStripMenuItem>, string>(_bindings); 269 270 //Iterate on a copy to avoid "collection was modified" error 271 foreach(var kvp in dictCopy) { 272 ToolStripMenuItem menuItem; 273 if(!kvp.Key.TryGetTarget(out menuItem)) { 274 _bindings.Remove(kvp.Key); 275 _parents.Remove(kvp.Key); 276 } 277 } 278 } 279 UpdateMenus()280 public static void UpdateMenus() 281 { 282 foreach(WeakReference<ToolStripMenuItem> itemRef in _bindings.Keys) { 283 ToolStripMenuItem item; 284 if(itemRef.TryGetTarget(out item)) { 285 string fieldName = _bindings[itemRef]; 286 Control parent; 287 _parents[itemRef].TryGetTarget(out parent); 288 if(parent != null) { 289 UpdateShortcutItem(item, parent, fieldName); 290 } 291 } 292 } 293 } 294 ClearProcessCmdKeyHandler(ToolStripMenuItem item, Control parent)295 public static void ClearProcessCmdKeyHandler(ToolStripMenuItem item, Control parent) 296 { 297 Form parentForm = parent.FindForm(); 298 if(parentForm is BaseForm) { 299 (parentForm as BaseForm).OnProcessCmdKey -= ((ShortcutInfo)item.Tag).KeyHandler; 300 } 301 ((ShortcutInfo)item.Tag).KeyHandler = null; 302 } 303 UpdateShortcutItem(ToolStripMenuItem item, Control parent, string fieldName)304 public static void UpdateShortcutItem(ToolStripMenuItem item, Control parent, string fieldName) 305 { 306 if(item.Tag == null) { 307 item.Tag = new ShortcutInfo() { KeyHandler = null, ShortcutKey = fieldName }; 308 } else if(((ShortcutInfo)item.Tag).KeyHandler != null) { 309 ClearProcessCmdKeyHandler(item, parent); 310 } 311 312 Keys keys = (XmlKeys)typeof(DebuggerShortcutsConfig).GetField(fieldName).GetValue(ConfigManager.Config.DebugInfo.Shortcuts); 313 if((keys != Keys.None && !ToolStripManager.IsValidShortcut(keys)) || Program.IsMono) { 314 //Support normally invalid shortcut keys as a shortcut 315 item.ShortcutKeys = Keys.None; 316 item.ShortcutKeyDisplayString = GetShortcutDisplay(keys); 317 318 Form parentForm = parent.FindForm(); 319 if(parentForm is BaseForm) { 320 ProcessCmdKeyHandler onProcessCmdKeyHandler = (Keys keyData, ref bool processed) => { 321 if(!processed && item.Enabled && parent.ContainsFocus && keyData == keys) { 322 item.PerformClick(); 323 processed = true; 324 } 325 }; 326 327 ((ShortcutInfo)item.Tag).KeyHandler = onProcessCmdKeyHandler; 328 (parentForm as BaseForm).OnProcessCmdKey += onProcessCmdKeyHandler; 329 } 330 } else { 331 item.ShortcutKeys = keys; 332 item.ShortcutKeyDisplayString = GetShortcutDisplay(keys); 333 } 334 } 335 } 336 337 public static class ToolStripMenuItemExtensions 338 { InitShortcut(this ToolStripMenuItem item, Control parent, string fieldName)339 public static void InitShortcut(this ToolStripMenuItem item, Control parent, string fieldName) 340 { 341 DebuggerShortcutsConfig.UpdateShortcutItem(item, parent, fieldName); 342 DebuggerShortcutsConfig.RegisterMenuItem(item, parent, fieldName); 343 } 344 } 345 346 public class ShortcutInfo 347 { 348 public string ShortcutKey; 349 public ProcessCmdKeyHandler KeyHandler; 350 } 351 352 public class XmlKeys 353 { 354 private Keys _keys = Keys.None; 355 XmlKeys()356 public XmlKeys() { } XmlKeys(Keys k)357 public XmlKeys(Keys k) { _keys = k; } 358 operator Keys(XmlKeys k)359 public static implicit operator Keys(XmlKeys k) 360 { 361 return k._keys; 362 } 363 operator XmlKeys(Keys k)364 public static implicit operator XmlKeys(Keys k) 365 { 366 return new XmlKeys(k); 367 } 368 369 [XmlAttribute] 370 public string Value 371 { 372 get { return _keys.ToString(); } 373 set 374 { 375 try { 376 Enum.TryParse<Keys>(value, out _keys); 377 } catch(Exception) { 378 _keys = Keys.None; 379 } 380 } 381 } 382 } 383 384 public class ShortcutNameAttribute : Attribute 385 { 386 public string Name { get; private set; } 387 ShortcutNameAttribute(string name)388 public ShortcutNameAttribute(string name) 389 { 390 this.Name = name; 391 } 392 } 393 } 394