This commit is contained in:
@@ -434,7 +434,7 @@ public class ConnectionConfig {
|
||||
return terminalName;
|
||||
}
|
||||
if (isDynamicModel()) {
|
||||
return extendedDataStream ? "IBM-DYNAMIC-E" : "IBM-DYNAMIC";
|
||||
return "IBM-DYNAMIC";
|
||||
}
|
||||
return extendedDataStream ? model.getTerminalType() : model.getBaseTerminalType();
|
||||
}
|
||||
|
||||
@@ -462,8 +462,23 @@ public class Telnet3270Client {
|
||||
public void processFieldMark() { inputProcessor.processFieldMark(); }
|
||||
|
||||
/** Toggle Insert Mode. */
|
||||
public void toggleInsert() { inputProcessor.setInsertMode(!inputProcessor.isInsertMode()); }
|
||||
public void processToggleInsert() { inputProcessor.processToggleInsert(); }
|
||||
public boolean isInsertMode() { return inputProcessor != null && inputProcessor.isInsertMode(); }
|
||||
public void toggleInsert() { if (inputProcessor != null) inputProcessor.setInsertMode(!inputProcessor.isInsertMode()); }
|
||||
public void processToggleInsert() { if (inputProcessor != null) inputProcessor.processToggleInsert(); }
|
||||
|
||||
/** Document Mode (Entry Assist) operations. */
|
||||
public boolean isDocMode() { return screenBuffer != null && screenBuffer.isEntryAssistDOCmode(); }
|
||||
public void setDocMode(boolean b) { if (screenBuffer != null) screenBuffer.setEntryAssistDOCmode(b); if (oia != null) oia.notifyOIAChanged(); }
|
||||
public void toggleDocMode() { setDocMode(!isDocMode()); }
|
||||
|
||||
public boolean isWordWrap() { return screenBuffer != null && screenBuffer.isEntryAssistWordWrap(); }
|
||||
public void setWordWrap(boolean b) { if (screenBuffer != null) screenBuffer.setEntryAssistWordWrap(b); if (oia != null) oia.notifyOIAChanged(); }
|
||||
public void toggleWordWrap() { setWordWrap(!isWordWrap()); }
|
||||
|
||||
/** APL Keyboard Mode operations. */
|
||||
public boolean isAplMode() { return inputProcessor != null && inputProcessor.isAplKeyboardMode(); }
|
||||
public void setAplMode(boolean b) { if (inputProcessor != null) inputProcessor.setAplKeyboardMode(b); }
|
||||
public void toggleAplMode() { if (inputProcessor != null) inputProcessor.toggleAplKeyboardMode(); }
|
||||
|
||||
/** Move word left. */
|
||||
public void processWordLeft() { inputProcessor.processWordLeft(); }
|
||||
|
||||
@@ -46,11 +46,11 @@ public enum TerminalModel {
|
||||
/**
|
||||
* Returns the terminal type string for TN3270E negotiation.
|
||||
* e.g., "IBM-3279-4-E" for a color model 4 with extended data stream,
|
||||
* or "IBM-DYNAMIC-E" for dynamic model.
|
||||
* or "IBM-DYNAMIC" for dynamic model.
|
||||
*/
|
||||
public String getTerminalType() {
|
||||
if (modelNumber == 0) {
|
||||
return "IBM-DYNAMIC-E";
|
||||
return "IBM-DYNAMIC";
|
||||
}
|
||||
return String.format("IBM-327%c-%d-E", color ? '9' : '8', modelNumber);
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ public class ECLOIA implements ECLConstants {
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void notifyOIAChanged() {
|
||||
public synchronized void notifyOIAChanged() {
|
||||
ECLOIAEvent event = new ECLOIAEvent(this, ECLOIAEvent.OIA_UPDATE, getInputInhibited(),
|
||||
getAlphanumericType(), isInsertMode(), getStatusString());
|
||||
for (haus.nightmare.lib3270j.ecl.ECLOIANotify l : listeners) {
|
||||
@@ -484,6 +484,7 @@ public class ECLOIA implements ECLConstants {
|
||||
if (isNumeric()) s |= STATE_NUMFIELD;
|
||||
if (screen != null && screen.isEntryAssistDOCmode()) s |= STATE_DOC_MODE;
|
||||
if (screen != null && screen.isEntryAssistWordWrap()) s |= STATE_WORDWRAP;
|
||||
if (isApl()) s |= STATE_APL;
|
||||
if (isXSystem()) s |= STATE_SYS_LOCK;
|
||||
if (isXComm()) s |= STATE_COMM_CHECK;
|
||||
return s;
|
||||
@@ -494,6 +495,21 @@ public class ECLOIA implements ECLConstants {
|
||||
public int getStatusFlags() { return GetStatusFlags(); }
|
||||
public long getStatusFlagsEx() { return GetStatusFlagsEx(); }
|
||||
|
||||
public boolean isApl() {
|
||||
return inputProcessor != null && inputProcessor.isAplKeyboardMode();
|
||||
}
|
||||
public boolean IsApl() { return isApl(); }
|
||||
|
||||
public boolean isDocMode() {
|
||||
return screen != null && screen.isEntryAssistDOCmode();
|
||||
}
|
||||
public boolean IsDocMode() { return isDocMode(); }
|
||||
|
||||
public boolean isWordWrap() {
|
||||
return screen != null && screen.isEntryAssistWordWrap();
|
||||
}
|
||||
public boolean IsWordWrap() { return isWordWrap(); }
|
||||
|
||||
public synchronized void setBitmaskState(long flag, boolean on) {
|
||||
this.previousState = this.state;
|
||||
if (on) {
|
||||
|
||||
@@ -118,7 +118,91 @@ public class InputProcessor {
|
||||
}
|
||||
}
|
||||
public boolean isInsertMode() { return insertMode; }
|
||||
public void setInsertMode(boolean insert) { this.insertMode = insert; }
|
||||
public void setInsertMode(boolean insert) {
|
||||
this.insertMode = insert;
|
||||
if (oia != null) {
|
||||
oia.notifyOIAChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface BellListener {
|
||||
void onBell();
|
||||
}
|
||||
|
||||
private BellListener bellListener;
|
||||
private boolean bellEnabled = false;
|
||||
private int bellColumn = 74; // 0-based index for column 75
|
||||
private boolean insertOffOnAid = true;
|
||||
private boolean aplKeyboardMode = false;
|
||||
private boolean numericFieldLock = true;
|
||||
private boolean autoSkipEnabled = true;
|
||||
|
||||
public void setBellListener(BellListener listener) { this.bellListener = listener; }
|
||||
public BellListener getBellListener() { return bellListener; }
|
||||
public boolean isBellEnabled() { return bellEnabled; }
|
||||
public void setBellEnabled(boolean enabled) { this.bellEnabled = enabled; }
|
||||
public int getBellColumn() { return bellColumn; }
|
||||
public void setBellColumn(int col) { this.bellColumn = col; }
|
||||
|
||||
public boolean isInsertOffOnAid() { return insertOffOnAid; }
|
||||
public void setInsertOffOnAid(boolean val) { this.insertOffOnAid = val; }
|
||||
|
||||
public boolean isAplKeyboardMode() { return aplKeyboardMode; }
|
||||
public void setAplKeyboardMode(boolean enabled) {
|
||||
this.aplKeyboardMode = enabled;
|
||||
if (oia != null) {
|
||||
oia.notifyOIAChanged();
|
||||
}
|
||||
}
|
||||
public void toggleAplKeyboardMode() {
|
||||
setAplKeyboardMode(!aplKeyboardMode);
|
||||
}
|
||||
|
||||
public boolean isNumericFieldLock() { return numericFieldLock; }
|
||||
public void setNumericFieldLock(boolean lock) { this.numericFieldLock = lock; }
|
||||
|
||||
public boolean isAutoSkipEnabled() { return autoSkipEnabled; }
|
||||
public void setAutoSkipEnabled(boolean enabled) { this.autoSkipEnabled = enabled; }
|
||||
|
||||
/**
|
||||
* Map ASCII key character to IBM 3270 APL / Graphic Escape code point.
|
||||
*/
|
||||
private int getAplCodeForChar(char ch) {
|
||||
char upper = Character.toUpperCase(ch);
|
||||
switch (upper) {
|
||||
case 'A': return 0x81; // ⍺ Alpha
|
||||
case 'B': return 0x82; // ⊥ Up tack / decode
|
||||
case 'C': return 0x83; // ∩ Intersection
|
||||
case 'D': return 0x84; // ⌊ Floor
|
||||
case 'E': return 0x85; // │ Vertical line
|
||||
case 'F': return 0x87; // ∇ Del / Grad
|
||||
case 'G': return 0x88; // ∆ Delta
|
||||
case 'H': return 0x89; // ⍳ Iota
|
||||
case 'I': return 0x8A; // → Right arrow
|
||||
case 'J': return 0x8B; // ⍞ Quote Quad
|
||||
case 'K': return 0x8C; // ≤ Less than or equal
|
||||
case 'L': return 0xAD; // [ Bracket left
|
||||
case 'M': return 0x8E; // × Multiply
|
||||
case 'N': return 0x8F; // ÷ Divide
|
||||
case 'O': return 0x90; // ⍟ Circle Star
|
||||
case 'P': return 0x91; // ⌹ Domino / Quad divide
|
||||
case 'Q': return 0x92; // ⊤ Down tack / encode
|
||||
case 'R': return 0x95; // ⍴ Rho
|
||||
case 'S': return 0x94; // ⌈ Ceiling
|
||||
case 'T': return 0x98; // ⍷ Epsilon underbar
|
||||
case 'U': return 0x93; // ∪ Union
|
||||
case 'V': return 0x97; // ≠ Not equal
|
||||
case 'W': return 0x96; // ⍵ Omega
|
||||
case 'X': return 0xAC; // ⍉ Transpose
|
||||
case 'Y': return 0xA8; // ↑ Up arrow / Take
|
||||
case 'Z': return 0xA9; // ↓ Down arrow / Drop
|
||||
case '-': return 0xA2; // ─ Horizontal line
|
||||
case '|': return 0x85; // │ Vertical line
|
||||
case '+': return 0xCB; // ┼ Cross
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enter a character at the current cursor position.
|
||||
@@ -142,8 +226,8 @@ public class InputProcessor {
|
||||
int baddr = screen.getCursorAddress();
|
||||
baddr = ((baddr % size) + size) % size;
|
||||
|
||||
// Entry Assist DOC mode / Word Wrap handling
|
||||
if ((screen.isEntryAssistDOCmode() || screen.isEntryAssistWordWrap()) && !isNvtMode()) {
|
||||
// Entry Assist Word Wrap handling
|
||||
if (screen.isEntryAssistWordWrap() && !isNvtMode()) {
|
||||
int curCol = baddr % screen.getCols();
|
||||
int endCol = screen.getEntryAssistEndColumn();
|
||||
int startCol = screen.getEntryAssistStartColumn();
|
||||
@@ -178,7 +262,7 @@ public class InputProcessor {
|
||||
}
|
||||
|
||||
// Numeric-only field check: digits 0-9, minus (-), period (.), space ( ), DUP, FM
|
||||
if (faIsNumeric(faVal & 0xFF)) {
|
||||
if (numericFieldLock && faIsNumeric(faVal & 0xFF)) {
|
||||
boolean isValidNumeric = (ch >= '0' && ch <= '9') || ch == '-' || ch == '.' || ch == ' '
|
||||
|| ch == '*' || ch == ';' || ch == (char) FCORDER_DUP || ch == (char) FCORDER_FM;
|
||||
if (!isValidNumeric) {
|
||||
@@ -191,8 +275,20 @@ public class InputProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
// Translate character to EBCDIC
|
||||
int ebc = translator.unicodeToEbcdic(ch);
|
||||
// Translate character to EBCDIC (or APL Graphic Escape if in APL Keyboard Mode)
|
||||
boolean isAplChar = false;
|
||||
int ebc = -1;
|
||||
if (aplKeyboardMode) {
|
||||
int aplCode = getAplCodeForChar(ch);
|
||||
if (aplCode >= 0) {
|
||||
ebc = aplCode;
|
||||
ch = translator.mapAPL(aplCode);
|
||||
isAplChar = true;
|
||||
}
|
||||
}
|
||||
if (ebc < 0) {
|
||||
ebc = translator.unicodeToEbcdic(ch);
|
||||
}
|
||||
if (ebc < 0) return;
|
||||
|
||||
if (insertMode) {
|
||||
@@ -229,6 +325,9 @@ public class InputProcessor {
|
||||
ExtendedAttribute ea = screen.getCell(baddr);
|
||||
ea.ec = (byte) ebc;
|
||||
ea.ucs4 = ch;
|
||||
if (isAplChar) {
|
||||
ea.cs = ExtendedAttribute.CS_GE;
|
||||
}
|
||||
|
||||
// Set MDT on field attribute
|
||||
if (screen.isFormatted()) {
|
||||
@@ -244,7 +343,7 @@ public class InputProcessor {
|
||||
int nextAddr = screen.incrementAddress(baddr);
|
||||
if (screen.getCell(nextAddr).isFieldAttribute()) {
|
||||
byte nextFa = screen.getCell(nextAddr).fa;
|
||||
if (faIsSkip(nextFa & 0xFF)) {
|
||||
if (autoSkipEnabled && faIsSkip(nextFa & 0xFF)) {
|
||||
// Auto-skip field (Protected + Numeric): jump to next unprotected field
|
||||
int skipTarget = screen.findNextUnprotected(nextAddr);
|
||||
screen.setCursorAddress(skipTarget);
|
||||
@@ -264,6 +363,28 @@ public class InputProcessor {
|
||||
screen.setCursorAddress((baddr + 1) % size);
|
||||
}
|
||||
|
||||
// Entry Assist DOC mode: if we typed into or past the right margin, advance to startCol on next row
|
||||
if (screen != null && screen.isEntryAssistDOCmode() && !screen.isEntryAssistWordWrap() && !isNvtMode()) {
|
||||
int typedCol = baddr % screen.getCols();
|
||||
if (typedCol >= screen.getEntryAssistEndColumn()) {
|
||||
int curRow = baddr / screen.getCols();
|
||||
int nextRow = (curRow + 1) % screen.getRows();
|
||||
int targetAddr = nextRow * screen.getCols() + screen.getEntryAssistStartColumn();
|
||||
if (screen.isFormatted()) {
|
||||
targetAddr = screen.findNextUnprotected(targetAddr - 1);
|
||||
}
|
||||
screen.setCursorAddress(targetAddr);
|
||||
}
|
||||
}
|
||||
|
||||
// Audible End-of-Line Warning Signal
|
||||
if (bellEnabled && screen != null) {
|
||||
int curCol = screen.getCursorCol();
|
||||
if (curCol == bellColumn && bellListener != null) {
|
||||
bellListener.onBell();
|
||||
}
|
||||
}
|
||||
|
||||
screen.markAllChanged();
|
||||
screen.updateDisplaySnapshot();
|
||||
}
|
||||
@@ -523,6 +644,9 @@ public class InputProcessor {
|
||||
}
|
||||
|
||||
if (aidCode == AID_CLEAR) {
|
||||
if (insertOffOnAid && insertMode) {
|
||||
setInsertMode(false);
|
||||
}
|
||||
screen.clear();
|
||||
screen.markAllChanged();
|
||||
if (graphicsPlane != null) {
|
||||
@@ -538,6 +662,10 @@ public class InputProcessor {
|
||||
return;
|
||||
}
|
||||
|
||||
if (insertOffOnAid && insertMode) {
|
||||
setInsertMode(false);
|
||||
}
|
||||
|
||||
lastAid = aidCode;
|
||||
setKeyboardLocked(true);
|
||||
|
||||
@@ -792,6 +920,10 @@ public class InputProcessor {
|
||||
}
|
||||
|
||||
public void tab() {
|
||||
if (screen != null && screen.isEntryAssistDOCmode()) {
|
||||
screen.processWordTab(true);
|
||||
return;
|
||||
}
|
||||
int addr = screen.findNextUnprotected(screen.getCursorAddress());
|
||||
screen.setCursorAddress(addr);
|
||||
screen.updateDisplaySnapshot();
|
||||
@@ -806,6 +938,10 @@ public class InputProcessor {
|
||||
}
|
||||
|
||||
public void backTab() {
|
||||
if (screen != null && screen.isEntryAssistDOCmode()) {
|
||||
screen.processWordTab(false);
|
||||
return;
|
||||
}
|
||||
if (!screen.isFormatted()) return;
|
||||
int size = screen.getRows() * screen.getCols();
|
||||
if (size <= 0) return;
|
||||
@@ -1546,6 +1682,22 @@ public class InputProcessor {
|
||||
case "lightpen":
|
||||
processLightPen();
|
||||
break;
|
||||
case "docmode":
|
||||
if (screen != null) {
|
||||
screen.setEntryAssistDOCmode(!screen.isEntryAssistDOCmode());
|
||||
if (oia != null) oia.notifyOIAChanged();
|
||||
}
|
||||
break;
|
||||
case "wordwrap":
|
||||
if (screen != null) {
|
||||
screen.setEntryAssistWordWrap(!screen.isEntryAssistWordWrap());
|
||||
if (oia != null) oia.notifyOIAChanged();
|
||||
}
|
||||
break;
|
||||
case "apl":
|
||||
case "aplmode":
|
||||
toggleAplKeyboardMode();
|
||||
break;
|
||||
default:
|
||||
if (token.startsWith("pf")) {
|
||||
try {
|
||||
|
||||
@@ -1071,12 +1071,16 @@ public class ScreenBuffer {
|
||||
public void setEntryAssistTabStops(int[] stops) { this.tabStops = stops; }
|
||||
public void SetEntryAssistTabStops(int[] stops) { setEntryAssistTabStops(stops); }
|
||||
|
||||
public void setLeftMargin(int n) { setEntryAssistStartColumn(n); }
|
||||
public void setRightMargin(int n) { setEntryAssistEndColumn(n); }
|
||||
public void setWordTabPositions(int[] stops) { setEntryAssistTabStops(stops); }
|
||||
|
||||
/**
|
||||
* Perform Entry Assist word wrap if typing near/past end margin.
|
||||
* Moves any partial word typed on the current line to the beginning of the next line (docStartCol).
|
||||
*/
|
||||
public synchronized boolean handleWordWrap(int curAddr, char typedChar) {
|
||||
if (!docMode && !wordWrap) return false;
|
||||
if (!wordWrap) return false;
|
||||
int size = rows * cols;
|
||||
if (size <= 0) return false;
|
||||
curAddr = ((curAddr % size) + size) % size;
|
||||
|
||||
@@ -75,9 +75,6 @@ public class TelnetFSM {
|
||||
return list;
|
||||
}
|
||||
if (config.isDynamicModel()) {
|
||||
if (config.isExtendedDataStream()) {
|
||||
list.add("IBM-DYNAMIC-E");
|
||||
}
|
||||
list.add("IBM-DYNAMIC");
|
||||
list.add("IBM-3279-4-E");
|
||||
list.add("IBM-3279-4");
|
||||
|
||||
Reference in New Issue
Block a user