Fix aid keys
This commit is contained in:
@@ -760,11 +760,6 @@ public class GraphicsPlane {
|
||||
(double) px[offset + i + 1], (double) py[offset + i + 1],
|
||||
boundaryColorArgb, lineType, lineWidth);
|
||||
}
|
||||
if (pLen >= 3 && (px[offset] != px[offset + pLen - 1] || py[offset] != py[offset + pLen - 1])) {
|
||||
drawLine((double) px[offset + pLen - 1], (double) py[offset + pLen - 1],
|
||||
(double) px[offset], (double) py[offset],
|
||||
boundaryColorArgb, lineType, lineWidth);
|
||||
}
|
||||
}
|
||||
offset += pLen;
|
||||
}
|
||||
|
||||
@@ -237,6 +237,86 @@ public class InputProcessor {
|
||||
return;
|
||||
}
|
||||
|
||||
if (gocaDecoder != null && gocaDecoder.isGraphicsCursorActive()) {
|
||||
int gx = gocaDecoder.getGraphicCursorX();
|
||||
int gy = gocaDecoder.getGraphicCursorY();
|
||||
int cols = (screen != null && screen.getCols() > 0) ? screen.getCols() : 80;
|
||||
int numRows = (screen != null && screen.getRows() > 0) ? screen.getRows() : 24;
|
||||
int cursorAddr = screen != null ? screen.getCursorAddress() : 0;
|
||||
int row = cursorAddr / cols;
|
||||
int col = cursorAddr % cols;
|
||||
|
||||
byte[] sf = haus.nightmare.lib3270j.graphics.GraphicInputBuilder.buildGraphicInput(
|
||||
gx, gy, row, col, aidCode, false, false, false
|
||||
);
|
||||
|
||||
StringBuilder sfHex = new StringBuilder();
|
||||
for (byte b : sf) {
|
||||
sfHex.append(String.format("%02X ", b & 0xFF));
|
||||
}
|
||||
log.info(String.format(
|
||||
"sendAid (graphic): goca=(%d, %d) row=%d col=%d cursorAddr=%d aid=0x%02X SF_HEX=[%s]",
|
||||
gx, gy, row, col, cursorAddr, aidCode, sfHex.toString().trim()
|
||||
));
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
|
||||
// Structured Field AID (0x88) + 56-byte Graphic Input SF
|
||||
out.write(AID_SF);
|
||||
try {
|
||||
out.write(sf);
|
||||
} catch (java.io.IOException ignored) {}
|
||||
|
||||
// Trailing AID + cursor address
|
||||
out.write(aidCode);
|
||||
byte[] caddr = encodeAddress(cursorAddr, numRows, cols);
|
||||
out.write(caddr[0] & 0xFF);
|
||||
out.write(caddr[1] & 0xFF);
|
||||
|
||||
if (aidCode == AID_PA1 || aidCode == AID_PA2 || aidCode == AID_PA3) {
|
||||
sendAidResponse(out.toByteArray());
|
||||
return;
|
||||
}
|
||||
|
||||
if (screen.isFormatted()) {
|
||||
int size = screen.getRows() * screen.getCols();
|
||||
for (int i = 0; i < size; i++) {
|
||||
ExtendedAttribute ea = screen.getCell(i);
|
||||
if (ea.isFieldAttribute() && faIsModified(ea.fa & 0xFF)) {
|
||||
int fieldStart = (i + 1) % size;
|
||||
|
||||
// Always send SBA and address of first character in field
|
||||
out.write(ORDER_SBA);
|
||||
byte[] addr = encodeAddress(fieldStart, screen.getRows(), screen.getCols());
|
||||
out.write(addr[0] & 0xFF);
|
||||
out.write(addr[1] & 0xFF);
|
||||
|
||||
// Send all non-null characters in field (suppressing 0x00)
|
||||
int pos = fieldStart;
|
||||
while (!screen.getCell(pos).isFieldAttribute()) {
|
||||
int b = screen.getCell(pos).ec & 0xFF;
|
||||
if (b != 0x00) {
|
||||
out.write(b);
|
||||
}
|
||||
pos = (pos + 1) % size;
|
||||
if (pos == fieldStart) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int size = screen.getRows() * screen.getCols();
|
||||
for (int i = 0; i < size; i++) {
|
||||
int b = screen.getCell(i).ec & 0xFF;
|
||||
if (b != 0x00) {
|
||||
out.write(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sendAidResponse(out.toByteArray());
|
||||
return;
|
||||
}
|
||||
|
||||
if (aidCode == AID_PA1 || aidCode == AID_PA2 || aidCode == AID_PA3) {
|
||||
// PA keys: send AID + optional PID + cursor address only (no modified data)
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
|
||||
@@ -451,4 +451,91 @@ public class InputProcessorTest {
|
||||
// SBA order at byte 3
|
||||
assertEquals((byte) ORDER_SBA, result[3]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendAidWhenGraphicsCursorActiveFraming() {
|
||||
screen.erase(false);
|
||||
screen.setCellFA(0, (byte) (FA_PRINTABLE | FA_MODIFY));
|
||||
screen.getCell(1).ec = (byte) 0xC1; // 'A'
|
||||
screen.setCellFA(5, (byte) (FA_PRINTABLE | FA_PROTECT));
|
||||
screen.setCursorAddress(2);
|
||||
|
||||
haus.nightmare.lib3270j.graphics.GraphicsPlane plane = new haus.nightmare.lib3270j.graphics.GraphicsPlane(800, 600);
|
||||
haus.nightmare.lib3270j.graphics.GocaDecoder goca = new haus.nightmare.lib3270j.graphics.GocaDecoder(plane);
|
||||
goca.setGraphicsCursorActive(true);
|
||||
goca.setGraphicCursorPosition(150, -80);
|
||||
|
||||
java.util.concurrent.atomic.AtomicReference<byte[]> sent = new java.util.concurrent.atomic.AtomicReference<>();
|
||||
InputProcessor input = new InputProcessor(screen, translator, null) {
|
||||
@Override
|
||||
protected void sendAidResponse(byte[] data) {
|
||||
sent.set(data);
|
||||
}
|
||||
};
|
||||
input.setGocaDecoder(goca);
|
||||
|
||||
input.sendAid(AID_ENTER);
|
||||
|
||||
byte[] result = sent.get();
|
||||
assertNotNull(result);
|
||||
// Total expected length:
|
||||
// 1 (AID_SF 0x88) + 56 (SF) + 1 (AID_ENTER 0x7D) + 2 (Cursor Addr) + 1 (SBA) + 2 (Field Addr) + 1 (Data 'A') = 64 bytes
|
||||
assertEquals(64, result.length);
|
||||
assertEquals((byte) AID_SF, result[0]);
|
||||
// SF length = 52 (0x00 0x34) per IBM HOD / GOCA specification
|
||||
assertEquals(0x00, result[1]);
|
||||
assertEquals(0x34, result[2]);
|
||||
// SF ID = 0x0F0F
|
||||
assertEquals(0x0F, result[3]);
|
||||
assertEquals(0x0F, result[4]);
|
||||
// Coordinates in SF at index 1 + 24 = 25
|
||||
int gx = (result[25] << 8) | (result[26] & 0xFF);
|
||||
int gy = (result[27] << 8) | (result[28] & 0xFF);
|
||||
assertEquals(150, (short) gx);
|
||||
assertEquals(-80, (short) gy);
|
||||
// Keyboard constants at index 1 + 31 = 32 and 1 + 33 = 34
|
||||
assertEquals(0x07, result[32]);
|
||||
assertEquals(0x07, result[34]);
|
||||
assertEquals((byte) 0xFF, result[35]);
|
||||
assertEquals((byte) AID_ENTER, result[36]);
|
||||
|
||||
// Trailing AID at index 57
|
||||
assertEquals((byte) AID_ENTER, result[57]);
|
||||
// Trailing SBA at 60
|
||||
assertEquals((byte) ORDER_SBA, result[60]);
|
||||
// Trailing field content 'A' at 63
|
||||
assertEquals((byte) 0xC1, result[63]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendAidPAWhenGraphicsCursorActiveFraming() {
|
||||
screen.erase(false);
|
||||
screen.setCellFA(0, (byte) (FA_PRINTABLE | FA_MODIFY));
|
||||
screen.getCell(1).ec = (byte) 0xC1;
|
||||
screen.setCursorAddress(2);
|
||||
|
||||
haus.nightmare.lib3270j.graphics.GraphicsPlane plane = new haus.nightmare.lib3270j.graphics.GraphicsPlane(800, 600);
|
||||
haus.nightmare.lib3270j.graphics.GocaDecoder goca = new haus.nightmare.lib3270j.graphics.GocaDecoder(plane);
|
||||
goca.setGraphicsCursorActive(true);
|
||||
goca.setGraphicCursorPosition(100, 200);
|
||||
|
||||
java.util.concurrent.atomic.AtomicReference<byte[]> sent = new java.util.concurrent.atomic.AtomicReference<>();
|
||||
InputProcessor input = new InputProcessor(screen, translator, null) {
|
||||
@Override
|
||||
protected void sendAidResponse(byte[] data) {
|
||||
sent.set(data);
|
||||
}
|
||||
};
|
||||
input.setGocaDecoder(goca);
|
||||
|
||||
input.sendAid(AID_PA1);
|
||||
|
||||
byte[] result = sent.get();
|
||||
assertNotNull(result);
|
||||
// 1 (AID_SF 0x88) + 56 (SF) + 1 (AID_PA1 0x6C) + 2 (Cursor Addr) = 60 bytes (no modified field data)
|
||||
assertEquals(60, result.length);
|
||||
assertEquals((byte) AID_SF, result[0]);
|
||||
assertEquals((byte) AID_PA1, result[36]); // Keyboard AID in SF
|
||||
assertEquals((byte) AID_PA1, result[57]); // Trailing AID
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user