ULA Implemented. Scanline renderer so cycle accurate
This commit is contained in:
55
Desktop/DebuggerForm.Designer.cs
generated
55
Desktop/DebuggerForm.Designer.cs
generated
@@ -39,7 +39,6 @@
|
||||
lblTStates = new Label();
|
||||
txtMemoryStart = new TextBox();
|
||||
btnStep = new Button();
|
||||
btnRun = new Button();
|
||||
btnRefreshMemory = new Button();
|
||||
txtMemoryView = new RichTextBox();
|
||||
lstDisassembly = new ListBox();
|
||||
@@ -56,6 +55,9 @@
|
||||
lblIE = new Label();
|
||||
btnReset = new Button();
|
||||
uiUpdateTimer = new System.Windows.Forms.Timer(components);
|
||||
lblFrames = new Label();
|
||||
lblFPS = new Label();
|
||||
lblFrameTime = new Label();
|
||||
SuspendLayout();
|
||||
//
|
||||
// lblAF
|
||||
@@ -160,16 +162,6 @@
|
||||
btnStep.UseVisualStyleBackColor = true;
|
||||
btnStep.Click += btnStep_Click;
|
||||
//
|
||||
// btnRun
|
||||
//
|
||||
btnRun.Location = new Point(119, 418);
|
||||
btnRun.Margin = new Padding(2);
|
||||
btnRun.Name = "btnRun";
|
||||
btnRun.Size = new Size(90, 27);
|
||||
btnRun.TabIndex = 13;
|
||||
btnRun.Text = "Run";
|
||||
btnRun.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// btnRefreshMemory
|
||||
//
|
||||
btnRefreshMemory.Location = new Point(425, 21);
|
||||
@@ -215,7 +207,7 @@
|
||||
btnExit.Name = "btnExit";
|
||||
btnExit.Size = new Size(90, 27);
|
||||
btnExit.TabIndex = 18;
|
||||
btnExit.Text = "Full Exit";
|
||||
btnExit.Text = "Exit";
|
||||
btnExit.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// label1
|
||||
@@ -304,13 +296,47 @@
|
||||
// uiUpdateTimer
|
||||
//
|
||||
uiUpdateTimer.Enabled = true;
|
||||
uiUpdateTimer.Interval = 1;
|
||||
uiUpdateTimer.Tick += uiUpdateTimer_Tick;
|
||||
//
|
||||
// lblFrames
|
||||
//
|
||||
lblFrames.AutoSize = true;
|
||||
lblFrames.Location = new Point(538, 320);
|
||||
lblFrames.Margin = new Padding(2, 0, 2, 0);
|
||||
lblFrames.Name = "lblFrames";
|
||||
lblFrames.Size = new Size(124, 20);
|
||||
lblFrames.TabIndex = 28;
|
||||
lblFrames.Text = "Frames Rendered";
|
||||
//
|
||||
// lblFPS
|
||||
//
|
||||
lblFPS.AutoSize = true;
|
||||
lblFPS.Location = new Point(630, 397);
|
||||
lblFPS.Margin = new Padding(2, 0, 2, 0);
|
||||
lblFPS.Name = "lblFPS";
|
||||
lblFPS.Size = new Size(32, 20);
|
||||
lblFPS.TabIndex = 29;
|
||||
lblFPS.Text = "FPS";
|
||||
//
|
||||
// lblFrameTime
|
||||
//
|
||||
lblFrameTime.AutoSize = true;
|
||||
lblFrameTime.Location = new Point(575, 356);
|
||||
lblFrameTime.Margin = new Padding(2, 0, 2, 0);
|
||||
lblFrameTime.Name = "lblFrameTime";
|
||||
lblFrameTime.Size = new Size(87, 20);
|
||||
lblFrameTime.TabIndex = 30;
|
||||
lblFrameTime.Text = "Frame Time";
|
||||
//
|
||||
// DebuggerForm
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(8F, 20F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
ClientSize = new Size(928, 454);
|
||||
Controls.Add(lblFrameTime);
|
||||
Controls.Add(lblFPS);
|
||||
Controls.Add(lblFrames);
|
||||
Controls.Add(btnReset);
|
||||
Controls.Add(lblIE);
|
||||
Controls.Add(lblIff2);
|
||||
@@ -325,7 +351,6 @@
|
||||
Controls.Add(lstDisassembly);
|
||||
Controls.Add(txtMemoryView);
|
||||
Controls.Add(btnRefreshMemory);
|
||||
Controls.Add(btnRun);
|
||||
Controls.Add(btnStep);
|
||||
Controls.Add(txtMemoryStart);
|
||||
Controls.Add(lblTStates);
|
||||
@@ -355,7 +380,6 @@
|
||||
private Label lblTStates;
|
||||
private TextBox txtMemoryStart;
|
||||
private Button btnStep;
|
||||
private Button btnRun;
|
||||
private Button btnRefreshMemory;
|
||||
private RichTextBox txtMemoryView;
|
||||
private ListBox lstStack;
|
||||
@@ -372,6 +396,9 @@
|
||||
private Label lblIE;
|
||||
private Button btnReset;
|
||||
private System.Windows.Forms.Timer uiUpdateTimer;
|
||||
private Label lblFrames;
|
||||
private Label lblFPS;
|
||||
private Label lblFrameTime;
|
||||
//private TextBox textBox4;
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,6 @@ namespace Desktop
|
||||
private readonly Z80 _cpu;
|
||||
private readonly MemoryBus _memoryBus;
|
||||
private readonly Form1 _mainForm;
|
||||
private bool _isRunning = false;
|
||||
private ushort? _breakpoint = null;
|
||||
|
||||
public DebuggerForm(Z80 cpu, MemoryBus memoryBus, Form1 mainForm)
|
||||
{
|
||||
@@ -61,15 +59,12 @@ namespace Desktop
|
||||
|
||||
private void uiUpdateTimer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
// Every 100ms, take a snapshot of the CPU state and draw it to the screen.
|
||||
// This makes the registers look like they are spinning matrix-style while running!
|
||||
UpdateDisplay();
|
||||
}
|
||||
|
||||
// This is the master function that pulls state from the CPU
|
||||
// Current Emulator State
|
||||
private void UpdateDisplay()
|
||||
{
|
||||
// 1. Update Registers (Formatting as 4-character Hex strings)
|
||||
lblAF.Text = $"AF: {_cpu.AF.Word:X4}";
|
||||
lblBC.Text = $"BC: {_cpu.BC.Word:X4}";
|
||||
lblDE.Text = $"DE: {_cpu.DE.Word:X4}";
|
||||
@@ -81,12 +76,11 @@ namespace Desktop
|
||||
lblIff1.Text = $"IFF1: {_cpu.IFF1}";
|
||||
lblIff2.Text = $"IFF2: {_cpu.IFF2}";
|
||||
lblIE.Text = $"Interrupt Mode: {_cpu.InterruptMode}";
|
||||
|
||||
// 2. Update Flags & T-States
|
||||
lblFlags.Text = $"Flags: {_cpu.GetFlagsString()}";
|
||||
lblTStates.Text = $"T-States: {_cpu.TotalTStates}";
|
||||
|
||||
// 3. Update Memory Viewer
|
||||
lblFrames.Text = $"Frames Rendered: {_mainForm.TotalFrameCount}";
|
||||
lblFrameTime.Text = $"Frame Time: {((float)_mainForm.FrameTime):F1}ms";
|
||||
lblFPS.Text = $"FPS: {_mainForm.FramesPerSecond:F2}";
|
||||
UpdateMemoryView();
|
||||
UpdateStackView();
|
||||
UpdateDisassemblyView();
|
||||
|
||||
2
Desktop/Form1.Designer.cs
generated
2
Desktop/Form1.Designer.cs
generated
@@ -112,7 +112,7 @@
|
||||
// debuggerToolStripMenuItem
|
||||
//
|
||||
debuggerToolStripMenuItem.Name = "debuggerToolStripMenuItem";
|
||||
debuggerToolStripMenuItem.Size = new Size(224, 26);
|
||||
debuggerToolStripMenuItem.Size = new Size(159, 26);
|
||||
debuggerToolStripMenuItem.Text = "Debugger";
|
||||
debuggerToolStripMenuItem.Click += openDebuggerToolStripMenuItem_Click;
|
||||
//
|
||||
|
||||
239
Desktop/Form1.cs
239
Desktop/Form1.cs
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.IO;
|
||||
using Core.Cpu;
|
||||
using Core.Io;
|
||||
using Core.Memory;
|
||||
@@ -14,37 +14,18 @@ namespace Desktop
|
||||
private Z80 _cpu = null!;
|
||||
private MemoryBus _memoryBus = null!;
|
||||
private IO_Bus _simpleIoBus = null!;
|
||||
private ULA _ula = null!;
|
||||
private TapManager _tapManager = null!;
|
||||
private int _ulaFrameCount = 0;
|
||||
private DebuggerForm? _debugger = null;
|
||||
private string _baseTitle = "";
|
||||
private bool _isRunning = false;
|
||||
private bool _isPaused = false;
|
||||
private bool _resetFlag = false;
|
||||
public ushort? Breakpoint = null; // Public so the debugger can set it!
|
||||
private DebuggerForm _debugger = null;
|
||||
|
||||
// The 16 physical colors of the ZX Spectrum (ARGB format)
|
||||
private readonly int[] SpectrumColors = new int[]
|
||||
{
|
||||
// Normal Colors (Bright = 0)
|
||||
unchecked((int)0xFF000000), // 0: Black
|
||||
unchecked((int)0xFF0000D7), // 1: Blue
|
||||
unchecked((int)0xFFD70000), // 2: Red
|
||||
unchecked((int)0xFFD700D7), // 3: Magenta
|
||||
unchecked((int)0xFF00D700), // 4: Green
|
||||
unchecked((int)0xFF00D7D7), // 5: Cyan
|
||||
unchecked((int)0xFFD7D700), // 6: Yellow
|
||||
unchecked((int)0xFFD7D7D7), // 7: White
|
||||
|
||||
// Bright Colors (Bright = 1)
|
||||
unchecked((int)0xFF000000), // 8: Bright Black
|
||||
unchecked((int)0xFF0000FF), // 9: Bright Blue
|
||||
unchecked((int)0xFFFF0000), // 10: Bright Red
|
||||
unchecked((int)0xFFFF00FF), // 11: Bright Magenta
|
||||
unchecked((int)0xFF00FF00), // 12: Bright Green
|
||||
unchecked((int)0xFF00FFFF), // 13: Bright Cyan
|
||||
unchecked((int)0xFFFFFF00), // 14: Bright Yellow
|
||||
unchecked((int)0xFFFFFFFF) // 15: Bright White
|
||||
};
|
||||
public ushort? Breakpoint = null;
|
||||
public long TotalFrameCount = 0;
|
||||
public double FramesPerSecond = 0;
|
||||
public double TotalFrameTime = 0;
|
||||
public double FrameTime = 0;
|
||||
|
||||
|
||||
public Form1()
|
||||
{
|
||||
@@ -56,18 +37,17 @@ namespace Desktop
|
||||
{
|
||||
try
|
||||
{
|
||||
_baseTitle = this.Text;
|
||||
_memoryBus = new MemoryBus();
|
||||
_simpleIoBus = new IO_Bus();
|
||||
_ula = new ULA(_memoryBus, _simpleIoBus);
|
||||
_tapManager = new TapManager();
|
||||
_memoryBus.CrapRAMData();
|
||||
byte[] romData = RomLoader.Load("48.rom");
|
||||
_memoryBus.LoadRom(romData);
|
||||
|
||||
_cpu = new Z80(_memoryBus, _simpleIoBus, _tapManager);
|
||||
_cpu.WaitStateCallback = _ula.GetContentionDelay;
|
||||
|
||||
// Pass 'this' so the DebuggerForm can talk back to this main window
|
||||
//DebuggerForm debugger = new DebuggerForm(_cpu, _memoryBus, this);
|
||||
//debugger.Show();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -81,28 +61,22 @@ namespace Desktop
|
||||
if (_isRunning) return;
|
||||
_isRunning = true;
|
||||
_isPaused = false;
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
const int TStatesPerFrame = 69888;
|
||||
long nextFrameTargetTStates = _cpu.TotalTStates + TStatesPerFrame;
|
||||
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
|
||||
long frameCount = 0;
|
||||
long nextScanlineTarget = _cpu.TotalTStates + TStatesPerFrame;
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
var fpsStopwatch = Stopwatch.StartNew();
|
||||
long scanlineCount = 0;
|
||||
|
||||
while (_isRunning)
|
||||
{
|
||||
//if(_resetFlag)
|
||||
//{
|
||||
// _resetFlag = false;
|
||||
// stopwatch.Reset();
|
||||
// nextFrameTargetTStates = _cpu.TotalTStates + TStatesPerFrame;
|
||||
// frameCount = 0;
|
||||
//}
|
||||
{
|
||||
|
||||
if (_isPaused)
|
||||
{
|
||||
System.Threading.Thread.Sleep(10); // Don't melt the host CPU while paused
|
||||
Thread.Sleep(10);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -110,7 +84,6 @@ namespace Desktop
|
||||
if (Breakpoint.HasValue && _cpu.PC == Breakpoint.Value)
|
||||
{
|
||||
_isPaused = true;
|
||||
// Optional: You could force the debugger to open here!
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -118,22 +91,43 @@ namespace Desktop
|
||||
_cpu.Step();
|
||||
|
||||
// --- Check for End of Frame ---
|
||||
if (_cpu.TotalTStates >= nextFrameTargetTStates)
|
||||
if (_cpu.TotalTStates >= nextScanlineTarget)
|
||||
{
|
||||
_cpu.RequestInterrupt();
|
||||
nextFrameTargetTStates += TStatesPerFrame;
|
||||
frameCount++;
|
||||
// Tell the ULA to draw one line of pixels
|
||||
_ula.RenderScanline((int)scanlineCount % 312);
|
||||
|
||||
// Render the screen
|
||||
this.Invoke((MethodInvoker)delegate { RenderScreen(); });
|
||||
nextScanlineTarget += 224; // Advance target by ONE line (224 T-States)
|
||||
scanlineCount++;
|
||||
|
||||
// Throttle to real-time (50 FPS = 20ms)
|
||||
long targetTimeMs = frameCount * 20;
|
||||
long elapsedMs = stopwatch.ElapsedMilliseconds;
|
||||
|
||||
if (elapsedMs < targetTimeMs)
|
||||
// Hit the bottom of the screen (Line 312)?
|
||||
if (scanlineCount % 312 == 0)
|
||||
{
|
||||
System.Threading.Thread.Sleep((int)(targetTimeMs - elapsedMs));
|
||||
_cpu.RequestInterrupt(); // 50Hz interrupt
|
||||
|
||||
this.Invoke((MethodInvoker)delegate
|
||||
{
|
||||
UpdateScreenBitmap();
|
||||
this.Text = $"{_baseTitle} - FPS: {FramesPerSecond:F1}";
|
||||
});
|
||||
TotalFrameCount++;
|
||||
|
||||
// Throttle to real-time (50 FPS = 20ms)
|
||||
long targetTimeMs = (scanlineCount / 312) * 20;
|
||||
long elapsedMs = stopwatch.ElapsedMilliseconds;
|
||||
|
||||
if (elapsedMs < targetTimeMs)
|
||||
{
|
||||
Thread.Sleep((int)(targetTimeMs - elapsedMs));
|
||||
}
|
||||
TotalFrameTime += fpsStopwatch.Elapsed.TotalMilliseconds;
|
||||
if (TotalFrameCount % 50 == 0)
|
||||
{
|
||||
FramesPerSecond = 1000.0 / (TotalFrameTime / 50.0);
|
||||
FrameTime = TotalFrameTime / 50.0;
|
||||
TotalFrameTime = 0;
|
||||
}
|
||||
|
||||
fpsStopwatch.Restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -141,13 +135,33 @@ namespace Desktop
|
||||
catch (Exception ex)
|
||||
{
|
||||
_isPaused = true;
|
||||
this.Invoke((MethodInvoker)delegate {
|
||||
this.Invoke((MethodInvoker)delegate
|
||||
{
|
||||
MessageBox.Show(ex.Message, "CPU Crash", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void UpdateScreenBitmap()
|
||||
{
|
||||
// Build the bitmap
|
||||
Bitmap bmp = new Bitmap(ULA.ScreenWidth, ULA.ScreenHeight, PixelFormat.Format32bppArgb);
|
||||
BitmapData bmpData = bmp.LockBits(
|
||||
new Rectangle(0, 0, ULA.ScreenWidth, ULA.ScreenHeight),
|
||||
ImageLockMode.WriteOnly,
|
||||
bmp.PixelFormat);
|
||||
|
||||
// Pull the raw pixel data
|
||||
Marshal.Copy(_ula.FrameBuffer, 0, bmpData.Scan0, _ula.FrameBuffer.Length);
|
||||
bmp.UnlockBits(bmpData);
|
||||
|
||||
if (picScreen.Image != null) picScreen.Image.Dispose();
|
||||
picScreen.Image = bmp;
|
||||
}
|
||||
|
||||
private void loadTAPToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
using (OpenFileDialog ofd = new OpenFileDialog())
|
||||
@@ -155,13 +169,8 @@ namespace Desktop
|
||||
ofd.Filter = "Spectrum TAP Files|*.tap";
|
||||
if (ofd.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
// The Desktop UI reads the file from the hard drive
|
||||
byte[] tapBytes = System.IO.File.ReadAllBytes(ofd.FileName);
|
||||
|
||||
// The pure Core logic processes the bytes
|
||||
byte[] tapBytes = File.ReadAllBytes(ofd.FileName);
|
||||
_cpu._tapManager.LoadTapData(tapBytes);
|
||||
|
||||
//MessageBox.Show("Tape inserted! Type LOAD \"\" and press Enter.", "Tape Deck");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -169,10 +178,10 @@ namespace Desktop
|
||||
{
|
||||
using (OpenFileDialog ofd = new OpenFileDialog())
|
||||
{
|
||||
ofd.Filter = "Spectrum Snapshot Files (*.sna)|*.sna";
|
||||
ofd.Filter = "Snapshot Files (sna,z80)|*.sna";
|
||||
if (ofd.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
byte[] snaBytes = System.IO.File.ReadAllBytes(ofd.FileName);
|
||||
byte[] snaBytes = File.ReadAllBytes(ofd.FileName);
|
||||
_cpu.LoadSNA(snaBytes);
|
||||
}
|
||||
}
|
||||
@@ -189,7 +198,6 @@ namespace Desktop
|
||||
|
||||
private void btnReset_Click(object sender, EventArgs e)
|
||||
{
|
||||
//_resetFlag = true;
|
||||
_isPaused = true;
|
||||
_cpu.Reset();
|
||||
_memoryBus.CleanRAMData();
|
||||
@@ -213,84 +221,7 @@ namespace Desktop
|
||||
_debugger.BringToFront();
|
||||
}
|
||||
}
|
||||
|
||||
// Public so the Debugger's background thread can call it 50 times a second
|
||||
public void RenderScreen()
|
||||
{
|
||||
_ulaFrameCount++;
|
||||
bool invertFlashPhase = (_ulaFrameCount % 32) >= 16;
|
||||
|
||||
// --- NEW: Expanded screen size (32px border on all sides) ---
|
||||
const int screenWidth = 320;
|
||||
const int screenHeight = 256;
|
||||
const int borderSize = 32;
|
||||
|
||||
int[] pixelData = new int[screenWidth * screenHeight];
|
||||
|
||||
// --- NEW: Fill the background with the Border Color ---
|
||||
// (Note: The hardware border always uses standard brightness, never bright)
|
||||
int currentBorderColor = SpectrumColors[_simpleIoBus.BorderColorIndex];
|
||||
Array.Fill(pixelData, currentBorderColor);
|
||||
|
||||
// Loop through the 6144 bytes of Pixel RAM
|
||||
for (int offset = 0; offset < 6144; offset++)
|
||||
{
|
||||
ushort address = (ushort)(0x4000 + offset);
|
||||
byte pixels = _memoryBus.Read(address);
|
||||
|
||||
int y = ((offset & 0x0700) >> 8) |
|
||||
((offset & 0x00E0) >> 2) |
|
||||
((offset & 0x1800) >> 5);
|
||||
|
||||
int x = (offset & 0x001F) * 8;
|
||||
|
||||
int attrRow = y / 8;
|
||||
int attrCol = x / 8;
|
||||
ushort attrAddress = (ushort)(0x5800 + (attrRow * 32) + attrCol);
|
||||
byte attr = _memoryBus.Read(attrAddress);
|
||||
|
||||
int ink = attr & 0x07;
|
||||
int paper = (attr >> 3) & 0x07;
|
||||
int brightOffset = (attr & 0x40) != 0 ? 8 : 0;
|
||||
bool isFlashSet = (attr & 0x80) != 0;
|
||||
|
||||
int inkColor = SpectrumColors[ink + brightOffset];
|
||||
int paperColor = SpectrumColors[paper + brightOffset];
|
||||
|
||||
if (isFlashSet && invertFlashPhase)
|
||||
{
|
||||
int temp = inkColor;
|
||||
inkColor = paperColor;
|
||||
paperColor = temp;
|
||||
}
|
||||
|
||||
// Draw the 8 pixels
|
||||
for (int bit = 0; bit < 8; bit++)
|
||||
{
|
||||
bool isPixelSet = (pixels & (1 << (7 - bit))) != 0;
|
||||
|
||||
// --- NEW: Add the 32px border offset to our X and Y calculations! ---
|
||||
int renderY = y + borderSize;
|
||||
int renderX = x + borderSize + bit;
|
||||
|
||||
// Map it to our new, wider pixel array
|
||||
pixelData[(renderY * screenWidth) + renderX] = isPixelSet ? inkColor : paperColor;
|
||||
}
|
||||
}
|
||||
|
||||
// --- NEW: Update Bitmap dimensions to match the new 320x256 array ---
|
||||
Bitmap bmp = new Bitmap(screenWidth, screenHeight, PixelFormat.Format32bppArgb);
|
||||
BitmapData bmpData = bmp.LockBits(
|
||||
new Rectangle(0, 0, screenWidth, screenHeight),
|
||||
ImageLockMode.WriteOnly,
|
||||
bmp.PixelFormat);
|
||||
|
||||
Marshal.Copy(pixelData, 0, bmpData.Scan0, pixelData.Length);
|
||||
bmp.UnlockBits(bmpData);
|
||||
|
||||
if (picScreen.Image != null) picScreen.Image.Dispose();
|
||||
picScreen.Image = bmp;
|
||||
}
|
||||
|
||||
private void UpdateMatrix(int row, int col, bool isPressed)
|
||||
{
|
||||
if (isPressed)
|
||||
@@ -305,14 +236,14 @@ namespace Desktop
|
||||
}
|
||||
}
|
||||
|
||||
// Hook this to Form1's KeyDown event
|
||||
|
||||
protected override void OnKeyDown(KeyEventArgs e)
|
||||
{
|
||||
HandleKey(e.KeyCode, true);
|
||||
base.OnKeyDown(e);
|
||||
}
|
||||
|
||||
// Hook this to Form1's KeyUp event
|
||||
|
||||
protected override void OnKeyUp(KeyEventArgs e)
|
||||
{
|
||||
HandleKey(e.KeyCode, false);
|
||||
@@ -370,15 +301,15 @@ namespace Desktop
|
||||
case Keys.L: UpdateMatrix(6, 1, isPressed); break;
|
||||
case Keys.K: UpdateMatrix(6, 2, isPressed); break;
|
||||
case Keys.J: UpdateMatrix(6, 3, isPressed); break;
|
||||
case Keys.H: UpdateMatrix(6, 4, isPressed); break;
|
||||
case Keys.H: UpdateMatrix(6, 4, isPressed); break;
|
||||
|
||||
// Row 7
|
||||
case Keys.Space: UpdateMatrix(7, 0, isPressed); break;
|
||||
case Keys.ControlKey: UpdateMatrix(7, 1, isPressed); break; // Symbol Shift
|
||||
case Keys.M: UpdateMatrix(7, 2, isPressed); break;
|
||||
case Keys.N: UpdateMatrix(7, 3, isPressed); break;
|
||||
case Keys.B: UpdateMatrix(7, 4, isPressed); break;
|
||||
case Keys.B: UpdateMatrix(7, 4, isPressed); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user