diff --git a/src/main/java/haus/nightmare/a3270/MainActivity.kt b/src/main/java/haus/nightmare/a3270/MainActivity.kt index 95a622c..9b4fdb9 100644 --- a/src/main/java/haus/nightmare/a3270/MainActivity.kt +++ b/src/main/java/haus/nightmare/a3270/MainActivity.kt @@ -298,7 +298,12 @@ class MainActivity : ComponentActivity() { return true } KeyEvent.KEYCODE_ENTER, KeyEvent.KEYCODE_NUMPAD_ENTER -> { - viewModel.sendAid(AID_ENTER) + if (shift) { + viewModel.eraseEof() + isShiftPressedState.value = false + } else { + viewModel.sendAid(AID_ENTER) + } return true } KeyEvent.KEYCODE_TAB -> { @@ -320,7 +325,7 @@ class MainActivity : ComponentActivity() { } KeyEvent.KEYCODE_ESCAPE -> { if (shift) { - viewModel.sendAid(AID_CLEAR) + viewModel.eraseInput() isShiftPressedState.value = false } else { viewModel.resetKeyboard() @@ -577,6 +582,10 @@ fun MainScreen( viewModel.eraseInput() terminalInputViewRef?.showSoftKeyboard() }, + onEraseEof = { + viewModel.eraseEof() + terminalInputViewRef?.showSoftKeyboard() + }, onAttn = { viewModel.sendAid(AID_PA1) terminalInputViewRef?.showSoftKeyboard() diff --git a/src/main/java/haus/nightmare/a3270/ui/FunctionKeyBar.kt b/src/main/java/haus/nightmare/a3270/ui/FunctionKeyBar.kt index 6f3fe8b..9cd9352 100644 --- a/src/main/java/haus/nightmare/a3270/ui/FunctionKeyBar.kt +++ b/src/main/java/haus/nightmare/a3270/ui/FunctionKeyBar.kt @@ -40,6 +40,7 @@ fun TwoRowKeyBar( onTab: () -> Unit, onBackTab: () -> Unit, onEraseInput: () -> Unit = {}, + onEraseEof: () -> Unit = {}, onAttn: () -> Unit = {}, onSysReq: () -> Unit = {}, onCursorSelect: () -> Unit = {}, @@ -219,14 +220,59 @@ fun TwoRowKeyBar( } ) - // 3. RESET - KeyButton("RESET", Color(0xFFE67700), modifier = Modifier.weight(1f), hapticFeedbackEnabled = hapticFeedbackEnabled, innerPaddingHorizontal = 0.dp, onClick = onReset) + // 3. RESET / ERASE (Erase Input) depending on Shift state + val resetLabel = if (isShiftPressed) "ERASE" else "RESET" + KeyButton( + label = resetLabel, + color = Color(0xFFE67700), + modifier = Modifier.weight(1f), + hapticFeedbackEnabled = hapticFeedbackEnabled, + innerPaddingHorizontal = 0.dp, + onClick = { + if (isShiftPressed) { + onEraseInput() + onClearShift() + } else { + onReset() + } + } + ) - // 4. ENTER - KeyButton("ENTER", Color(0xFF2B8A3E), modifier = Modifier.weight(1f), hapticFeedbackEnabled = hapticFeedbackEnabled, innerPaddingHorizontal = 0.dp, onClick = { onSendAid(AID_ENTER) }) + // 4. ENTER / EOF (Erase EOF) depending on Shift state + val enterLabel = if (isShiftPressed) "EOF" else "ENTER" + KeyButton( + label = enterLabel, + color = Color(0xFF2B8A3E), + modifier = Modifier.weight(1f), + hapticFeedbackEnabled = hapticFeedbackEnabled, + innerPaddingHorizontal = 0.dp, + onClick = { + if (isShiftPressed) { + onEraseEof() + onClearShift() + } else { + onSendAid(AID_ENTER) + } + } + ) - // 5. CLEAR - KeyButton("CLEAR", Color(0xFFC92A2A), modifier = Modifier.weight(1f), hapticFeedbackEnabled = hapticFeedbackEnabled, innerPaddingHorizontal = 0.dp, onClick = { onSendAid(AID_CLEAR) }) + // 5. CLEAR / ATTN (Attention) depending on Shift state + val clearLabel = if (isShiftPressed) "ATTN" else "CLEAR" + KeyButton( + label = clearLabel, + color = Color(0xFFC92A2A), + modifier = Modifier.weight(1f), + hapticFeedbackEnabled = hapticFeedbackEnabled, + innerPaddingHorizontal = 0.dp, + onClick = { + if (isShiftPressed) { + onAttn() + onClearShift() + } else { + onSendAid(AID_CLEAR) + } + } + ) // 6. PA1 KeyButton("PA1", Color(0xFF495057), modifier = Modifier.weight(1f), hapticFeedbackEnabled = hapticFeedbackEnabled, innerPaddingHorizontal = 0.dp, onClick = { onSendAid(AID_PA1) }) diff --git a/src/test/java/haus/nightmare/a3270/HardwareKeyboardInputTest.kt b/src/test/java/haus/nightmare/a3270/HardwareKeyboardInputTest.kt index 7bf57fc..e314349 100644 --- a/src/test/java/haus/nightmare/a3270/HardwareKeyboardInputTest.kt +++ b/src/test/java/haus/nightmare/a3270/HardwareKeyboardInputTest.kt @@ -212,4 +212,30 @@ class HardwareKeyboardInputTest { assertTrue(result) assertEquals(AID_ENTER, inputProcessor.lastAid) } + + @Test + fun testEraseInputAndAttention() { + // Position 0: Unprotected FA + screenBuffer.setCellFA(0, (FA_PRINTABLE or FA_MODIFY).toByte()) + // Position 10: Protected FA + screenBuffer.setCellFA(10, (FA_PRINTABLE or FA_PROTECT).toByte()) + // Position 20: Unprotected FA + screenBuffer.setCellFA(20, (FA_PRINTABLE or FA_MODIFY).toByte()) + + screenBuffer.getCell(1).ucs4 = 'X' + screenBuffer.getCell(1).ec = translator.unicodeToEbcdic('X').toByte() + screenBuffer.getCell(21).ucs4 = 'Y' + screenBuffer.getCell(21).ec = translator.unicodeToEbcdic('Y').toByte() + + inputProcessor.eraseInput() + + // Unprotected fields should be cleared and reset + assertEquals(0, screenBuffer.getCell(1).ec.toInt()) + assertEquals(0, screenBuffer.getCell(21).ec.toInt()) + assertEquals(1, screenBuffer.cursorAddress) + + // Attention AID + inputProcessor.sendAid(AID_PA1) + assertEquals(AID_PA1, inputProcessor.lastAid) + } }