Fix misinterpreted if statement
Build and Test j3270 / Build JAR & Run Tests (Java 17) (push) Successful in 42s
Build and Test j3270 / Build JAR & Run Tests (Java 21) (push) Successful in 52s
Build and Test j3270 / Build JAR & Run Tests (Java 11) (push) Successful in 1m30s

This commit is contained in:
2026-09-28 04:19:06 +00:00
parent 8d5672c708
commit daac11472d
2 changed files with 145 additions and 7 deletions
@@ -239,7 +239,7 @@ public class TerminalPanel extends JPanel implements java.awt.print.Printable, I
public void mousePressed(MouseEvent e) { public void mousePressed(MouseEvent e) {
Window win = SwingUtilities.getWindowAncestor(TerminalPanel.this); Window win = SwingUtilities.getWindowAncestor(TerminalPanel.this);
boolean wasWindowInactive = (win != null && (!win.isActive() || !win.isFocused())); boolean wasWindowInactive = (win != null && (!win.isActive() || !win.isFocused()));
boolean wasPanelUnfocused = !hasFocus(); boolean wasPanelUnfocused = !java.awt.GraphicsEnvironment.isHeadless() && !hasFocus();
isActivationClick = wasWindowInactive || wasPanelUnfocused; isActivationClick = wasWindowInactive || wasPanelUnfocused;
if (win != null && wasWindowInactive) { if (win != null && wasWindowInactive) {
@@ -556,13 +556,12 @@ public class TerminalPanel extends JPanel implements java.awt.print.Printable, I
boolean isToggleField = (desEbcdic == 0x6F || desAscii == '?' || desAscii == '\uFF1F' || boolean isToggleField = (desEbcdic == 0x6F || desAscii == '?' || desAscii == '\uFF1F' ||
desEbcdic == 0x6E || desAscii == '>' || desAscii == '\uFF1E'); desEbcdic == 0x6E || desAscii == '>' || desAscii == '\uFF1E');
boolean isEnterField = (desEbcdic == 0x50 || desAscii == '&' || desAscii == '\uFF06'); boolean isEnterField = (desEbcdic == 0x50 || desAscii == '&' || desAscii == '\uFF06');
boolean isProtected = haus.nightmare.lib3270j.protocol.DS3270Constants.faIsProtected(fa);
boolean isDoubleClick = (e.getClickCount() >= 2); // Automatic mouse selection applies to toggle fields (? -> >) and enter fields (&).
// For detectable fields (FA bits 4-5 = 01 or 11): // Standard text fields (space/null designator) must NOT trigger light-pen selection
// Double-clicking or invoking mnemonic [cursel] toggles the designator character (? -> >). // on normal mouse clicks, so users can position cursor and edit text normally (HoD parity).
// If field has immediate select attribute, immediately transmit Cursor Select AID (0x7E). // Hardware light-pen emulation on space designators only fires when lightPenMode is active.
if (lightPenMode || isDoubleClick || isToggleField || isEnterField || !isProtected) { if (lightPenMode || isToggleField || isEnterField) {
if (client.lightPenSelect(clickAddr)) { if (client.lightPenSelect(clickAddr)) {
refreshScreen(); refreshScreen();
return; return;
@@ -119,4 +119,143 @@ public class TerminalPanelSelectionTest {
} catch (HeadlessException ignored) { } catch (HeadlessException ignored) {
} }
} }
@Test
@DisplayName("Clicking an unprotected, intensified line (e.g. XEDIT current line) does not transmit AID_SELECT")
public void testClickOnUnprotectedIntensifiedFieldDoesNotTriggerAidSelect() {
try {
TerminalPanel panel = new TerminalPanel();
panel.setSize(800, 600);
Telnet3270Client client = new Telnet3270Client(new ConnectionConfig("localhost", 23));
client.getTelnetFSM().setConnectionState(ConnectionState.CONNECTED_3270);
ScreenBuffer sb = client.getScreenBuffer();
sb.erase(false);
// Row 3 (address 240): Unprotected, intensified line with spaces (XEDIT located line)
int row3Start = 3 * 80;
sb.setCellFA(row3Start, (byte) (FA_PRINTABLE | FA_INT_HIGH_SEL)); // Unprotected, high intensity (detectable)
// Space designator and COBOL text
String lineText = " IDENTIFICATION DIVISION.";
for (int i = 0; i < lineText.length(); i++) {
sb.getCell(row3Start + 1 + i).ucs4 = lineText.charAt(i);
sb.getCell(row3Start + 1 + i).ec = (byte) (lineText.charAt(i) == ' ' ? 0x40 : 0xC1 + i);
}
panel.setClient(client);
int cellW = panel.cellWidth > 0 ? panel.cellWidth : 10;
int cellH = panel.cellHeight > 0 ? panel.cellHeight : 18;
int ox = panel.getRenderOffsetX();
int oy = panel.getRenderOffsetY();
MouseListener[] mouseListeners = panel.getMouseListeners();
assertTrue(mouseListeners.length > 0);
MouseListener ml = mouseListeners[0];
// Click at row 3, col 28 (like in j3270.log)
int clickX = ox + 28 * cellW + cellW / 2;
int clickY = oy + 3 * cellH + cellH / 2;
MouseEvent pressEvent = new MouseEvent(panel, MouseEvent.MOUSE_PRESSED, System.currentTimeMillis(),
0, clickX, clickY, 1, false, MouseEvent.BUTTON1);
ml.mousePressed(pressEvent);
MouseEvent releaseEvent = new MouseEvent(panel, MouseEvent.MOUSE_RELEASED, System.currentTimeMillis(),
0, clickX, clickY, 1, false, MouseEvent.BUTTON1);
ml.mouseReleased(releaseEvent);
// Cursor must move to clicked address without sending AID_SELECT (AID 0x7E)
assertEquals(row3Start + 28, sb.getCursorAddress(), "Cursor must be placed at clicked position");
assertEquals(AID_NO, client.getInputProcessor().getLastAid(), "No AID must be transmitted on single click");
// Text on line must NOT have been modified or cleared
assertEquals('I', (char) sb.getCell(row3Start + 8).ucs4);
} catch (HeadlessException ignored) {
}
}
@Test
@DisplayName("Clicking a toggle field (? -> >) toggles the designator without transmitting AID")
public void testClickOnToggleField() {
try {
TerminalPanel panel = new TerminalPanel();
panel.setSize(800, 600);
Telnet3270Client client = new Telnet3270Client(new ConnectionConfig("localhost", 23));
client.getTelnetFSM().setConnectionState(ConnectionState.CONNECTED_3270);
ScreenBuffer sb = client.getScreenBuffer();
sb.erase(false);
// Field with ? designator
sb.setCellFA(0, (byte) (FA_PRINTABLE | FA_INT_NORM_SEL));
sb.getCell(1).ucs4 = '?';
sb.getCell(1).ec = (byte) 0x6F;
panel.setClient(client);
int cellW = panel.cellWidth > 0 ? panel.cellWidth : 10;
int cellH = panel.cellHeight > 0 ? panel.cellHeight : 18;
int ox = panel.getRenderOffsetX();
int oy = panel.getRenderOffsetY();
MouseListener ml = panel.getMouseListeners()[0];
int clickX = ox + 1 * cellW + cellW / 2;
int clickY = oy + cellH / 2;
ml.mousePressed(new MouseEvent(panel, MouseEvent.MOUSE_PRESSED, System.currentTimeMillis(),
0, clickX, clickY, 1, false, MouseEvent.BUTTON1));
ml.mouseReleased(new MouseEvent(panel, MouseEvent.MOUSE_RELEASED, System.currentTimeMillis(),
0, clickX, clickY, 1, false, MouseEvent.BUTTON1));
assertEquals('>', (char) sb.getCell(1).ucs4, "Toggle field ? should toggle to > on click");
assertEquals(AID_NO, client.getInputProcessor().getLastAid(), "No AID transmitted for deferred toggle field");
} catch (HeadlessException ignored) {
}
}
@Test
@DisplayName("Clicking an unprotected space-designator field when lightPenMode is enabled transmits AID_SELECT")
public void testClickInLightPenModeTransmitsAidSelect() {
try {
TerminalPanel panel = new TerminalPanel();
panel.setSize(800, 600);
Telnet3270Client client = new Telnet3270Client(new ConnectionConfig("localhost", 23));
client.getTelnetFSM().setConnectionState(ConnectionState.CONNECTED_3270);
ScreenBuffer sb = client.getScreenBuffer();
sb.erase(false);
// Unprotected, high-intensity field with space designator
sb.setCellFA(0, (byte) (FA_PRINTABLE | FA_INT_HIGH_SEL));
sb.getCell(1).ucs4 = ' ';
sb.getCell(1).ec = (byte) 0x40;
panel.setClient(client);
panel.toggleLightPen();
assertTrue(panel.isLightPenMode());
int cellW = panel.cellWidth > 0 ? panel.cellWidth : 10;
int cellH = panel.cellHeight > 0 ? panel.cellHeight : 18;
int ox = panel.getRenderOffsetX();
int oy = panel.getRenderOffsetY();
MouseListener ml = panel.getMouseListeners()[0];
int clickX = ox + 1 * cellW + cellW / 2;
int clickY = oy + cellH / 2;
ml.mousePressed(new MouseEvent(panel, MouseEvent.MOUSE_PRESSED, System.currentTimeMillis(),
0, clickX, clickY, 1, false, MouseEvent.BUTTON1));
ml.mouseReleased(new MouseEvent(panel, MouseEvent.MOUSE_RELEASED, System.currentTimeMillis(),
0, clickX, clickY, 1, false, MouseEvent.BUTTON1));
assertEquals(AID_SELECT, client.getInputProcessor().getLastAid(), "AID_SELECT must be transmitted in lightPenMode");
} catch (HeadlessException ignored) {
}
}
} }