Skip to content

Conversation

maximilien-noal
Copy link
Member

@maximilien-noal maximilien-noal commented Aug 11, 2025

Fixes the most glaring issues in the current keyboard implementation.

The keyboard did not have an internal buffer.
It did not have a delay to ignore key

It did not support being disabled/renabled (which is a keyboard command)

The IRQ1 handler didn't call the keyboard intercept from INT15H first before processing.

The corresponding INT15H interrupt was not implemented.

INT9H did not read the keyboard through the Data port.

We could not read the keyboard through the Data port while an emulated program read it at the same time.

I still have a lot to implement (a proper Keyboard Controller, which also links to the mouse and aux port, typematic stuff, keyboard ScanCode sets, support all keyboard commands, move the scanCode translation elsewhere, support DOS keyboard layouts on top...)

But at least the DOS Console stuff (like in text menus, for example the one in Oh No! More Lemmings, or the DUNE 2 SETUP program), are useable now.

Monkey Island 1 can also properly be paused with the space bar thanks to the delay.

I tested a lot of games without issues (Krondor, Dune, Dune II, Wolf3D, Shangai II, ...)

@maximilien-noal maximilien-noal self-assigned this Aug 11, 2025
@maximilien-noal maximilien-noal added input Emulator input method support hardware hardware device (can be virtual) emulation bugfix fixes a bug labels Aug 11, 2025
@maximilien-noal maximilien-noal force-pushed the fix/keyboard_buffer branch 3 times, most recently from d051c80 to 082e61b Compare August 24, 2025 16:58
@maximilien-noal maximilien-noal marked this pull request as ready for review August 24, 2025 20:07
@maximilien-noal maximilien-noal changed the title fix: keyboard (oh no more lemmings) (NOT) (WIP) fix: keyboard buffer and delay and INT9H ASM with Enable/Disable commands Aug 24, 2025
@maximilien-noal maximilien-noal changed the title fix: keyboard buffer and delay and INT9H ASM with Enable/Disable commands feature: keyboard buffer and delay and INT9H ASM with Enable/Disable commands Aug 24, 2025
@maximilien-noal maximilien-noal added the enhancement New feature or request label Aug 24, 2025
public override void Run() {
byte? scanCode = _keyboard.KeyboardEvent.ScanCode;
byte ascii = _keyboard.KeyboardEvent.AsciiCode ?? 0;
_keyboard.WriteByte(KeyboardPorts.Command, (byte)KeyboardCommand.DisablePortKbd);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldnt this logic to disable keyboard, read data and enable again be in keyboard class? Overrides might need it.
I wonder why doing so though, to ensure no other key gets added to the buffer? Wouldn't that solve the problem partially considering between time keyboard request irq1 and time this actually gets called, some time could already have passed? (Think about masked irq or other irq being processed)

byte scanCode = _keyboard.ReadByte(KeyboardPorts.Data);
_keyboard.WriteByte(KeyboardPorts.Command, (byte)KeyboardCommand.EnablePortKbd);

byte savedAl = State.AL;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ushort savedAX = State.AX since you use both al and ah?

_performanceMeasurer.UpdateValue(_cpuState.Cycles);
_timer.Tick();
_dmaController.PerformDmaTransfers();
_inputEventQueue.ProcessAllPendingInputEvents();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why cant this be done on ui thread that would put events in a queue in each device? Wouldn't this be less impactful than checking that every cycle?

internal void OnMainWindowClosing() => _isAppClosing = true;

internal void OnKeyUp(KeyEventArgs e) {
if (IsPaused) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't this be checked in one common class that would be used to enquête events for the devices? UI would push events thrre and it would ignore them if paused

Updated the PS2Keyboard, Mouse, VgaCard, and MouseDriver
classes to use more specific interfaces for handling keyboard,
mouse, and video events. Removed the IGui interface and
introduced IGuiKeyboardEvents, IGuiMouseEvents, and
IGuiVideoPresentation for better separation of concerns.
The HeadlessGui class now implements these new interfaces,
and the Spice86DependencyInjection and MainWindowViewModel
classes were modified accordingly to support the changes.
- Introduced `InputEventQueue` for processing keyboard and mouse events in a thread-safe manner.
- Updated `EmulationLoop` to include `_inputEventQueue` and modified its constructor to accept this new parameter.
- Enhanced the main execution method of `EmulationLoop` to process input events during each iteration.
- Updated documentation for the `IsPaused` property for clarity.
- Modified `Spice86DependencyInjection` and `DosFileManagerTests` to integrate the new input event handling functionality.
Introduced the `Intel8042PS2KeyboardMouseController` class to implement PS/2 keyboard and mouse logic, replacing the old `PS2Keyboard` class. Updated the `KeyboardCommand` enum to include a new command, `ReadKeyboardVersion`. Modified `BiosKeyboardInt9Handler` and `EmulationLoop` to utilize the new controller. Improved buffer management, command execution, and event handling throughout the application.
Replaced `AvaloniaKeyConverter` with `KeyboardScancodeConverter` for improved scancode and ASCII conversion. Introduced `PhysicalKey` and `KbdKey` enums to standardize key representation and align with modern standards. Removed the `Key` enum and its references.

Refactored `Intel8042PS2KeyboardMouseController` to use the new converter and simplified typematic handling. Updated `BiosKeyboardInt9Handler` to process scancodes and update BIOS flags, mimicking DOSBox's `IRQ1_Handler`.

Simplified `MainWindowViewModel` and `EmulationLoop` by removing redundant dependencies. Updated tests and dependency injection to reflect these changes. Overall, these updates enhance maintainability, extensibility, and compatibility with DOSBox-style emulation.
Refactored `Intel8042PS2KeyboardMouseController` to `Intel8042Controller` for clarity and updated its constructor to include `EmulatorEventClock` for managing timed events. Extracted `PS2Keyboard` into its own class and refactored it to use `EmulatorEventClock` for typematic/repeat handling. Improved scancode handling with support for sets 1, 2, and 3.

Introduced `EmulatorEventClock` to manage timed events, integrated it into `EmulationLoop`, and updated related classes (`BiosKeyboardInt9Handler`, `Machine`, `Spice86DependencyInjection`) to use the new `Intel8042Controller`. Removed redundant code, improved modularity, and updated tests to reflect these changes.
@maximilien-noal maximilien-noal changed the title feature: All-in-one keyboard PS/2 emulation once and for all feature: All-in-one PS/2 micro-controller and keyboard emulation once and for all Sep 21, 2025
Comment on lines +631 to +636
if ((param & (1 << 0)) == 0) {
if (_loggerService.IsEnabled(LogEventLevel.Warning)) {
_loggerService.Warning("I8042: Clearing P2 bit 0 locks a real PC");
}
// System restart is not suported.
}

Check notice

Code scanning / CodeQL

Nested 'if' statements can be combined Note

These 'if' statements can be combined.

Copilot Autofix

AI 4 days ago

The issue occurs in src/Spice86.Core/Emulator/Devices/Input/Keyboard/Intel8042Controller.cs at lines 630–633. The nested if statements should be merged into a single if statement using the && operator, so that both guards are combined and the block is only executed if both conditions are true. No change to the functionality will result, but the code will be easier to read.

No imports or method definitions are required for this change. Only the lines containing the nested if statements and the logging statement should be changed.


Suggested changeset 1
src/Spice86.Core/Emulator/Devices/Input/Keyboard/Intel8042Controller.cs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/Spice86.Core/Emulator/Devices/Input/Keyboard/Intel8042Controller.cs b/src/Spice86.Core/Emulator/Devices/Input/Keyboard/Intel8042Controller.cs
--- a/src/Spice86.Core/Emulator/Devices/Input/Keyboard/Intel8042Controller.cs
+++ b/src/Spice86.Core/Emulator/Devices/Input/Keyboard/Intel8042Controller.cs
@@ -627,12 +627,11 @@
             case KeyboardCommand.WriteOutputPort: // 0xd1
                 // Writes the controller output port (P2)
                 _a20Gate.IsEnabled = (param & (1 << 1)) != 0;
-                if ((param & (1 << 0)) == 0) {
-                    if (_loggerService.IsEnabled(LogEventLevel.Warning)) {
-                        _loggerService.Warning("I8042: Clearing P2 bit 0 locks a real PC");
-                    }
-                    // System restart is not suported.
+                if ((param & (1 << 0)) == 0 && _loggerService.IsEnabled(LogEventLevel.Warning)) {
+                    _loggerService.Warning("I8042: Clearing P2 bit 0 locks a real PC");
                 }
+                // System restart is not suported.
+
                 break;
             case KeyboardCommand.SimulateInputKbd: // 0xd2
                 // Acts as if the byte was received from keyboard
EOF
@@ -627,12 +627,11 @@
case KeyboardCommand.WriteOutputPort: // 0xd1
// Writes the controller output port (P2)
_a20Gate.IsEnabled = (param & (1 << 1)) != 0;
if ((param & (1 << 0)) == 0) {
if (_loggerService.IsEnabled(LogEventLevel.Warning)) {
_loggerService.Warning("I8042: Clearing P2 bit 0 locks a real PC");
}
// System restart is not suported.
if ((param & (1 << 0)) == 0 && _loggerService.IsEnabled(LogEventLevel.Warning)) {
_loggerService.Warning("I8042: Clearing P2 bit 0 locks a real PC");
}
// System restart is not suported.

break;
case KeyboardCommand.SimulateInputKbd: // 0xd2
// Acts as if the byte was received from keyboard
Copilot is powered by AI and may make mistakes. Always verify output.
Unable to commit as this autofix suggestion is now outdated
Comment on lines 668 to 672
if (code == 0xf0 && (lines & 0b0001) == 0) {
if(_loggerService.IsEnabled(LogEventLevel.Warning)) {
_loggerService.Warning("System Reset is not implemented");
}
}

Check notice

Code scanning / CodeQL

Nested 'if' statements can be combined Note

These 'if' statements can be combined.

Copilot Autofix

AI 4 days ago

The fix is to collapse the nested if statements at lines 667–669 into a single conditional using the logical && operator, following C# operator precedence (which is well-defined for &&). The new line will join the inner and outer conditions:
if (code == 0xf0 && (lines & 0b0001) == 0 && _loggerService.IsEnabled(LogEventLevel.Warning)) { ... }
Only lines 667–670 are affected. No new imports or definitions are required.


Suggested changeset 1
src/Spice86.Core/Emulator/Devices/Input/Keyboard/Intel8042Controller.cs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/Spice86.Core/Emulator/Devices/Input/Keyboard/Intel8042Controller.cs b/src/Spice86.Core/Emulator/Devices/Input/Keyboard/Intel8042Controller.cs
--- a/src/Spice86.Core/Emulator/Devices/Input/Keyboard/Intel8042Controller.cs
+++ b/src/Spice86.Core/Emulator/Devices/Input/Keyboard/Intel8042Controller.cs
@@ -664,10 +664,8 @@
                         (code != 0xf0 && param != 0b1111)) {
                         WarnLinePulse();
                     }
-                    if (code == 0xf0 && (lines & 0b0001) == 0) {
-                        if (_loggerService.IsEnabled(LogEventLevel.Warning)) {
-                            _loggerService.Warning("System Reset is not implemented");
-                        }
+                    if (code == 0xf0 && (lines & 0b0001) == 0 && _loggerService.IsEnabled(LogEventLevel.Warning)) {
+                        _loggerService.Warning("System Reset is not implemented");
                     }
                 } else {
                     // If we are here, than either this function
EOF
@@ -664,10 +664,8 @@
(code != 0xf0 && param != 0b1111)) {
WarnLinePulse();
}
if (code == 0xf0 && (lines & 0b0001) == 0) {
if (_loggerService.IsEnabled(LogEventLevel.Warning)) {
_loggerService.Warning("System Reset is not implemented");
}
if (code == 0xf0 && (lines & 0b0001) == 0 && _loggerService.IsEnabled(LogEventLevel.Warning)) {
_loggerService.Warning("System Reset is not implemented");
}
} else {
// If we are here, than either this function
Copilot is powered by AI and may make mistakes. Always verify output.
Unable to commit as this autofix suggestion is now outdated
}
}

private void ProcessScancode(byte scanCode, ref byte flags1, ref byte flags2, ref byte flags3, ref byte leds) {

Check notice

Code scanning / CodeQL

Too many 'ref' parameters Note

Method 'ProcessScancode' has 4 'ref' parameters and might be hard to understand.

Copilot Autofix

AI 5 days ago

The best solution is to encapsulate the four byte values (flags1, flags2, flags3, and leds) into a new dedicated struct or class, for example, KeyboardState. The ProcessScancode method signature should then take a single KeyboardState object (ideally by reference if mutation is needed for performance, or as a class reference type if acceptable). All internal code that previously referenced the ref bytes should now access the properties of KeyboardState. This change improves code readability, maintainability, and reduces the method’s complexity. Only the region encompassing the relevant method declaration and its usages within this file need updating; any usages outside this file must be disregarded as per the instructions.


Suggested changeset 1
src/Spice86.Core/Emulator/InterruptHandlers/Input/Keyboard/BiosKeyboardInt9Handler.cs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/Spice86.Core/Emulator/InterruptHandlers/Input/Keyboard/BiosKeyboardInt9Handler.cs b/src/Spice86.Core/Emulator/InterruptHandlers/Input/Keyboard/BiosKeyboardInt9Handler.cs
--- a/src/Spice86.Core/Emulator/InterruptHandlers/Input/Keyboard/BiosKeyboardInt9Handler.cs
+++ b/src/Spice86.Core/Emulator/InterruptHandlers/Input/Keyboard/BiosKeyboardInt9Handler.cs
@@ -272,37 +272,44 @@
         }
     }
 
-    private void ProcessScancode(byte scanCode, ref byte flags1, ref byte flags2, ref byte flags3, ref byte leds) {
+    private class KeyboardState {
+        public byte Flags1;
+        public byte Flags2;
+        public byte Flags3;
+        public byte Leds;
+    }
+
+    private void ProcessScancode(byte scanCode, KeyboardState state) {
         switch (scanCode) {
         /* First the hard ones  */
         case 0xfa:	/* Acknowledge */
-            leds |= 0x10;
+            state.Leds |= 0x10;
             break;
         case 0xe1:	/* Extended key special. Only pause uses this */
-            flags3 |= 0x01;
+            state.Flags3 |= 0x01;
             break;
         case 0xe0:						/* Extended key */
-            flags3 |= 0x02;
+            state.Flags3 |= 0x02;
             break;
         case 0x1d:						/* Ctrl Pressed */
-            if ((flags3 & 0x01) == 0) {
-                flags1 |= 0x04;
-                if ((flags3 & 0x02) != 0) flags3 |= 0x04;
-                else flags2 |= 0x01;
+            if ((state.Flags3 & 0x01) == 0) {
+                state.Flags1 |= 0x04;
+                if ((state.Flags3 & 0x02) != 0) state.Flags3 |= 0x04;
+                else state.Flags2 |= 0x01;
             }	/* else it's part of the pause scancodes */
             break;
         case 0x9d:						/* Ctrl Released */
-            if ((flags3 & 0x01) == 0) {
-                if ((flags3 & 0x02) != 0) flags3 = (byte)(flags3 & ~0x04);
-                else flags2 = (byte)(flags2 & ~0x01);
-                if (!((flags3 & 0x04) != 0 || (flags2 & 0x01) != 0)) flags1 = (byte)(flags1 & ~0x04);
+            if ((state.Flags3 & 0x01) == 0) {
+                if ((state.Flags3 & 0x02) != 0) state.Flags3 = (byte)(state.Flags3 & ~0x04);
+                else state.Flags2 = (byte)(state.Flags2 & ~0x01);
+                if (!((state.Flags3 & 0x04) != 0 || (state.Flags2 & 0x01) != 0)) state.Flags1 = (byte)(state.Flags1 & ~0x04);
             }
             break;
         case 0x2a:						/* Left Shift Pressed */
-            flags1 |= 0x02;
+            state.Flags1 |= 0x02;
             break;
         case 0xaa:						/* Left Shift Released */
-            flags1 = (byte)(flags1 & ~0x02);
+            state.Flags1 = (byte)(state.Flags1 & ~0x02);
             break;
         case 0x36:						/* Right Shift Pressed */
             flags1 |= 0x01;
EOF
@@ -272,37 +272,44 @@
}
}

private void ProcessScancode(byte scanCode, ref byte flags1, ref byte flags2, ref byte flags3, ref byte leds) {
private class KeyboardState {
public byte Flags1;
public byte Flags2;
public byte Flags3;
public byte Leds;
}

private void ProcessScancode(byte scanCode, KeyboardState state) {
switch (scanCode) {
/* First the hard ones */
case 0xfa: /* Acknowledge */
leds |= 0x10;
state.Leds |= 0x10;
break;
case 0xe1: /* Extended key special. Only pause uses this */
flags3 |= 0x01;
state.Flags3 |= 0x01;
break;
case 0xe0: /* Extended key */
flags3 |= 0x02;
state.Flags3 |= 0x02;
break;
case 0x1d: /* Ctrl Pressed */
if ((flags3 & 0x01) == 0) {
flags1 |= 0x04;
if ((flags3 & 0x02) != 0) flags3 |= 0x04;
else flags2 |= 0x01;
if ((state.Flags3 & 0x01) == 0) {
state.Flags1 |= 0x04;
if ((state.Flags3 & 0x02) != 0) state.Flags3 |= 0x04;
else state.Flags2 |= 0x01;
} /* else it's part of the pause scancodes */
break;
case 0x9d: /* Ctrl Released */
if ((flags3 & 0x01) == 0) {
if ((flags3 & 0x02) != 0) flags3 = (byte)(flags3 & ~0x04);
else flags2 = (byte)(flags2 & ~0x01);
if (!((flags3 & 0x04) != 0 || (flags2 & 0x01) != 0)) flags1 = (byte)(flags1 & ~0x04);
if ((state.Flags3 & 0x01) == 0) {
if ((state.Flags3 & 0x02) != 0) state.Flags3 = (byte)(state.Flags3 & ~0x04);
else state.Flags2 = (byte)(state.Flags2 & ~0x01);
if (!((state.Flags3 & 0x04) != 0 || (state.Flags2 & 0x01) != 0)) state.Flags1 = (byte)(state.Flags1 & ~0x04);
}
break;
case 0x2a: /* Left Shift Pressed */
flags1 |= 0x02;
state.Flags1 |= 0x02;
break;
case 0xaa: /* Left Shift Released */
flags1 = (byte)(flags1 & ~0x02);
state.Flags1 = (byte)(state.Flags1 & ~0x02);
break;
case 0x36: /* Right Shift Pressed */
flags1 |= 0x01;
Copilot is powered by AI and may make mistakes. Always verify output.
Unable to commit as this autofix suggestion is now outdated
Comment on lines +443 to +444
if ((flags1 & 0x08) != 0) asciiscan = 0xa600;
else asciiscan = (ushort)((asciiscan & 0xff) | 0xe000);

Check notice

Code scanning / CodeQL

Missed ternary opportunity Note

Both branches of this 'if' statement write to the same variable - consider using '?' to express intent better.

Copilot Autofix

AI 5 days ago

To fix the problem, we should replace the if-else assignment to asciiscan on line 454–455 with a single ternary assignment, reducing code duplication and improving clarity. The correct change is to replace:

if ((flags1 & 0x08) != 0) asciiscan = 0xa600;
else asciiscan = (ushort)((asciiscan & 0xff) | 0xe000);

with:

asciiscan = ((flags1 & 0x08) != 0) ? (ushort)0xa600 : (ushort)((asciiscan & 0xff) | 0xe000);

This preserves the original assignment logic without altering any other part of the function. All changes should be within src/Spice86.Core/Emulator/InterruptHandlers/Input/Keyboard/BiosKeyboardInt9Handler.cs in the given lines.


Suggested changeset 1
src/Spice86.Core/Emulator/InterruptHandlers/Input/Keyboard/BiosKeyboardInt9Handler.cs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/Spice86.Core/Emulator/InterruptHandlers/Input/Keyboard/BiosKeyboardInt9Handler.cs b/src/Spice86.Core/Emulator/InterruptHandlers/Input/Keyboard/BiosKeyboardInt9Handler.cs
--- a/src/Spice86.Core/Emulator/InterruptHandlers/Input/Keyboard/BiosKeyboardInt9Handler.cs
+++ b/src/Spice86.Core/Emulator/InterruptHandlers/Input/Keyboard/BiosKeyboardInt9Handler.cs
@@ -451,8 +451,7 @@
             if ((flags3 & 0x02) != 0) {
                 /* extended key (numblock), return and slash need special handling */
                 if (scanCode == 0x1c) {	/* return */
-                    if ((flags1 & 0x08) != 0) asciiscan = 0xa600;
-                    else asciiscan = (ushort)((asciiscan & 0xff) | 0xe000);
+                    asciiscan = ((flags1 & 0x08) != 0) ? (ushort)0xa600 : (ushort)((asciiscan & 0xff) | 0xe000);
                 } else if (scanCode == 0x35) {	/* slash */
                     if ((flags1 & 0x08) != 0) asciiscan = 0xa400;
                     else if ((flags1 & 0x04) != 0) asciiscan = 0x9500;
EOF
@@ -451,8 +451,7 @@
if ((flags3 & 0x02) != 0) {
/* extended key (numblock), return and slash need special handling */
if (scanCode == 0x1c) { /* return */
if ((flags1 & 0x08) != 0) asciiscan = 0xa600;
else asciiscan = (ushort)((asciiscan & 0xff) | 0xe000);
asciiscan = ((flags1 & 0x08) != 0) ? (ushort)0xa600 : (ushort)((asciiscan & 0xff) | 0xe000);
} else if (scanCode == 0x35) { /* slash */
if ((flags1 & 0x08) != 0) asciiscan = 0xa400;
else if ((flags1 & 0x04) != 0) asciiscan = 0x9500;
Copilot is powered by AI and may make mistakes. Always verify output.
Unable to commit as this autofix suggestion is now outdated
Comment on lines +312 to +316
if (_buffer[idx].IsFromAux) {
_status.IsDataFromAux = true;
} else {
_status.IsDataFromAux = false;
}

Check notice

Code scanning / CodeQL

Missed ternary opportunity Note

Both branches of this 'if' statement write to the same variable - consider using '?' to express intent better.

Copilot Autofix

AI 4 days ago

To fix this problem, replace the conditional assignment to _status.IsDataFromAux with a single-line ternary assignment.

  • Original region: lines 312-315.
  • Change: Replace the if ... else ... block assigning to _status.IsDataFromAux with a single line: _status.IsDataFromAux = _buffer[idx].IsFromAux ? true : false;
  • The ternary is strictly correct (though just assigning _buffer[idx].IsFromAux would suffice since it is already a boolean), as per the recommendation ("use ternary operator"), but for maximum clarity and minimal change you can use the ternary as suggested.

No imports or other definitions are needed; only edit the assignment block.

Suggested changeset 1
src/Spice86.Core/Emulator/Devices/Input/Keyboard/Intel8042Controller.cs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/Spice86.Core/Emulator/Devices/Input/Keyboard/Intel8042Controller.cs b/src/Spice86.Core/Emulator/Devices/Input/Keyboard/Intel8042Controller.cs
--- a/src/Spice86.Core/Emulator/Devices/Input/Keyboard/Intel8042Controller.cs
+++ b/src/Spice86.Core/Emulator/Devices/Input/Keyboard/Intel8042Controller.cs
@@ -309,11 +309,11 @@
 
         // Transfer one byte of data from buffer to output port
         _dataByte = _buffer[idx].Data;
-        if (_buffer[idx].IsFromAux) {
-            _status.IsDataFromAux = true;
-        } else {
-            _status.IsDataFromAux = false;
-        }
+        _status.IsDataFromAux = _buffer[idx].IsFromAux ? true : false;
+
+
+
+
         _status.IsDataNew = true;
         RestartDelayTimer();
         ActivateIrqsIfNeeded();
EOF
@@ -309,11 +309,11 @@

// Transfer one byte of data from buffer to output port
_dataByte = _buffer[idx].Data;
if (_buffer[idx].IsFromAux) {
_status.IsDataFromAux = true;
} else {
_status.IsDataFromAux = false;
}
_status.IsDataFromAux = _buffer[idx].IsFromAux ? true : false;




_status.IsDataNew = true;
RestartDelayTimer();
ActivateIrqsIfNeeded();
Copilot is powered by AI and may make mistakes. Always verify output.
Unable to commit as this autofix suggestion is now outdated
Comment on lines +337 to +341
if (isFromKbd && _config.TranslationEnabled) {
_buffer[idx].Data = GetTranslated(value);
} else {
_buffer[idx].Data = value;
}

Check notice

Code scanning / CodeQL

Missed ternary opportunity Note

Both branches of this 'if' statement write to the same variable - consider using '?' to express intent better.

Copilot Autofix

AI 4 days ago

To fix the issue, replace the if-else block currently used to assign a value to _buffer[idx].Data with a single line that uses the ternary operator to assign either GetTranslated(value) or value based on the condition isFromKbd && _config.TranslationEnabled. The change should be made within the method BufferAdd on lines 337–341 in Intel8042Controller.cs. No new imports, methods, or definitions are necessary; simply replace the block with the ternary assignment.

Suggested changeset 1
src/Spice86.Core/Emulator/Devices/Input/Keyboard/Intel8042Controller.cs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/Spice86.Core/Emulator/Devices/Input/Keyboard/Intel8042Controller.cs b/src/Spice86.Core/Emulator/Devices/Input/Keyboard/Intel8042Controller.cs
--- a/src/Spice86.Core/Emulator/Devices/Input/Keyboard/Intel8042Controller.cs
+++ b/src/Spice86.Core/Emulator/Devices/Input/Keyboard/Intel8042Controller.cs
@@ -334,11 +334,7 @@
 
         int idx = (_bufferStartIdx + _bufferNumUsed++) % BufferSize;
 
-        if (isFromKbd && _config.TranslationEnabled) {
-            _buffer[idx].Data = GetTranslated(value);
-        } else {
-            _buffer[idx].Data = value;
-        }
+        _buffer[idx].Data = (isFromKbd && _config.TranslationEnabled) ? GetTranslated(value) : value;
         _buffer[idx].IsFromAux = isFromAux;
         _buffer[idx].IsFromKbd = isFromKbd;
         _buffer[idx].SkipDelay = skipDelay || (!isFromAux && !isFromKbd);
EOF
@@ -334,11 +334,7 @@

int idx = (_bufferStartIdx + _bufferNumUsed++) % BufferSize;

if (isFromKbd && _config.TranslationEnabled) {
_buffer[idx].Data = GetTranslated(value);
} else {
_buffer[idx].Data = value;
}
_buffer[idx].Data = (isFromKbd && _config.TranslationEnabled) ? GetTranslated(value) : value;
_buffer[idx].IsFromAux = isFromAux;
_buffer[idx].IsFromKbd = isFromKbd;
_buffer[idx].SkipDelay = skipDelay || (!isFromAux && !isFromKbd);
Copilot is powered by AI and may make mistakes. Always verify output.
Unable to commit as this autofix suggestion is now outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugfix fixes a bug enhancement New feature or request hardware hardware device (can be virtual) emulation input Emulator input method support
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants