public class LinuxKeyboardReader extends SwingKeyboardReader
SwingKeyboardReader
implementation for clients which require
NCURSES/Linux compatibility.
Known Issues and/or TODOs
Modifier and Type | Field and Description |
---|---|
private boolean |
escPressed
Track events that occur when the ESC key is pressed.
|
private java.util.Map<java.lang.Integer,java.lang.Integer> |
xlateAlt
Translation map of Progress key codes to Progress alt key codes.
|
keyDownEvents, queue, xlate
Constructor and Description |
---|
LinuxKeyboardReader()
Adds special translations related to NCURSES.
|
Modifier and Type | Method and Description |
---|---|
void |
keyPressed(java.awt.event.KeyEvent evt)
This method is called when any key is pressed or when a multi-key
combination (CTRL, SHIFT, ALT modifiers) is pressed.
|
void |
keyTyped(java.awt.event.KeyEvent evt)
This method is called when a pressed key (or a multi-key combination) is
converted to a higher level representation.
|
private int |
processEscape(int code,
boolean alt)
If the last key pressed was the escape key, modify the code by bitwise
ORing 1024 and return that value if the result has a valid key label as
returned by the Progress-compatible
Keyboard.keyLabel() . |
findKeyEventByKeyCode, insert, isModifier, isSpecialCharacter, keyReleased, mergeWithLastEvent, read
private boolean escPressed
private final java.util.Map<java.lang.Integer,java.lang.Integer> xlateAlt
public LinuxKeyboardReader()
public void keyPressed(java.awt.event.KeyEvent evt)
keyTyped(java.awt.event.KeyEvent)
.
Once a valid key code is generated, that key code is added to the key input queue in FIFO order. Any keys that are not recognized as having valid counterparts in the 4GL key code mappings, are simply ignored (nothing is added to the key input queue for unrecognized keys).
This method is used to generate key codes 128 and above. There are 3 paths through this method:
When the map lookup of the 4GL key code occurs, usually the returned 4GL key code is posted into the end of the key input queue without change. But there are some cases in which the 4GL key code is modified first.
If the 4GL key code is VK_TAB and the SHIFT modifier key is on (the
shift key was pressed at the time the tab was pressed), then a VK_BACKTAB
is posted to the queue. Otherwise, the VK_TAB is ignored because it is
naturally processed in keyTyped()
(but the back tab is not).
If the escape key was not pressed, but the ALT modifier was pressed when this key code was generated, then a 2nd level of translation table lookups occurs. The 4GL key code is checked in an ALT translation table. If there is a mapped value, that value replaces the previously generated 4GL key code and is placed in the queue.
All other ESC and ALT processing is the same as already described in the
keyTyped
method.
keyPressed
in interface java.awt.event.KeyListener
keyPressed
in class java.awt.event.KeyAdapter
evt
- The high level key event to process.public void keyTyped(java.awt.event.KeyEvent evt)
Once a valid key code is generated, that key code is added to the key input queue in FIFO order.
The non-visual values 0 through 31 are handled almost "for free". The user generates these in the following manner:
Key Code User Input Notes -------- ----------------------- -------------------------------------- 0 CTRL+2 Special code in this method supports this. 1 CTRL+A 2 CTRL+B 3 CTRL+C 4 CTRL+D 5 CTRL+E 6 CTRL+F 7 CTRL+G 8 CTRL+H or VK_BACKSPACE 9 CTRL+I or VK_TAB The containing frame's focus traversal keys must be forced to the empty set in order for this to work. 10 CTRL+J or VK_ENTER NOT DELIVERED, handled in keyPressed() 11 CTRL+K 12 CTRL+L 13 CTRL+M 14 CTRL+N 15 CTRL+O 16 CTRL+P 17 CTRL+Q 18 CTRL+R 19 CTRL+S 20 CTRL+T 21 CTRL+U 22 CTRL+V 23 CTRL+W 24 CTRL+X 25 CTRL+Y 26 CTRL+Z 27 VK_ESCAPE NOT DELIVERED, 4GL doesn't ever return this. 28 CTRL+\ 29 CTRL+] 30 CTRL+6 Special code in this method supports this. 31 CTRL+- Special code in this method supports this.
Two of the above codes are never returned in Progress (10 and 27) and so they are excluded here too.
Key code 10 is the ASCII linefeed and it is generated from either the CTRL+J or the VK_ENTER key combinations in Java. These combinations always generate a key code of 13 in Progress, which is the ASCII carriage return code. Since this is a translation of Java codes to 4GL key codes, this method bypasses these key combinations and logic exists in keyPressed() to handle the translation.
The key code 27 is the ASCII escape code. In character terminals it is used to notify the application of a special condition. Progress did this "eating" the escape key and then usually encoding the next character as its normal key code bitwise OR'd with 1024. In other words, they encode the fact that there was a preceding escape key my encoding a modifier in a more significant bit that cannot be set directly by user keyboard input. It is important to note that the escape key is pressed, then released and then the next key that is pressed is modified and sent. This means that pressing the escape key causes state to be stored so that the next key can be modified.
Terminals (and thus the 4GL which was originally designed to work exclusively as a terminal application) give the ALT key an ESC-like behavior. When used instead of pressing a preceding ESC key, it generates the same modified result. The primary difference is that it must be pressed at the same time as the key to be modified.
For example, pressing the '2' key generates a key code of 50 which is the ASCII code for the digit 2. Pressing ESC (and releasing it) and then pressing the '2' key, generates the key code 1074 (which is 50 | 1024). The key code 1074 is also generated when the user holds the ALT key down while simultaneously pressing the '2' key.
It should be noted that pressing ESC and then ESC will clear the special mode. In other words, the next character sent to the server after 2 sequential escape keys will be the unmodified key code, just as if the escape key was never pressed in the first place.
The ALT key has a similar affect. If an ESC key is pressed and then an ALT+key combination is pressed, the result is the unmodified key code. The ALT key negates the previous ESC state. So the modification of key codes only occurs if a single escape was the most recent key AND ALT is not pressed OR the last key was not an escape key and the ALT key was pressed.
To be clear, the ALT key cannot be pressed and release on its own. In such a case it doesn't have the effect of escape, but is instead just ignored. The ALT key MUST be held down while another key is pressed for it to have the modification affect.
When there is any use of ESC/ALT with the lowercase alphabetic characters 'a' through 'z', the code uppercases them before modification. The reasons for doing this are not clear, but there was this comment in the original NCURSES-based key processing implementation:
Remapping lowercase Latin to uppercase. This differs with Progress but seems to be more convenient to user because Ctrl+<letter> combinations are case insensitive (and even keyboard layout insensitive). Note the usage of direct calculation not Character class methods. This is because we are dealing with integer key codes not characters so this is dirty hack anyway.
Finally, the escape driven modification of key codes is only done if the
non-modified key code is found to have a non-empty string as a key label.
This is determined by a call to Keyboard.keyLabel(code)
and
checking the returned string.
Key codes 0, 30 and 31 are all created based on CTRL + a key that is in the number row of the keyboard. Normally, CTRL+@ generates 0, CTRL+^ generates 30 and CTRL+_ generates 31. In Java, @, ^ and _ characters can only be generated using the SHIFT key and the '2', '6' or '-' keys respectively. In Progress, no shift key is needed to generate the resulting 0, 30 or 31 key codes. While all the other CTRL+key codes between 0 and 31 are handled by Java naturally in the keyTyped() method, the proper support for 0, 30 and 31 is implemented by custom logic in this method.
Key codes between 32 and 127 inclusive are naturally created by Java and are passed to this method ready to go. This includes the non-visual VK_DELETE key which is mapped to 127. All other characters are visual and their key codes are naturally created by Java by their common key on the keyboard OR by their common key + SHIFT. For example, 'g' generates 103 (the ASCII code for 'g') and SHIFT+'g' generates 71 which is the ASCII code for 'G'. '4' generates code 52 (ASCII for the digit 4) and SHIFT+'4' (on a U.S. keyboard layout) generates 36 which is the ASCII code for '$'. This is all exactly the same as how it works in the NCURSES-based implementation. The only exception to the above is that there is custom logic to generate the key code 512 when ESC then VK_DELETE (or ALT+VK_DELETE) is encountered. This is an anomaly in how Progress treats the ESC modifier and it had to be dealt with specially.
keyTyped
in interface java.awt.event.KeyListener
keyTyped
in class java.awt.event.KeyAdapter
evt
- The high level key event to process.private int processEscape(int code, boolean alt)
Keyboard.keyLabel()
. If
there is no valid label, -1 will be returned. If the escape pressed
flag is not active, the parameter will be returned unchanged.
After this method is called, the escape flag will be off.
If the alt modifier is ON but the escape flag is OFF, this method will treat the case as if the escape flag was ON. If the escape flag is already ON and the alt modifier is ON, then the alt modifier CANCELS the previously pending escape flag and no translation is done.
code
- The key code for the next key being processed.alt
- State of the ALT modifier. true
if the modifier
was ON when the given key was pressed.