java.awt.Robot kepress not working for JPasswordField when using KeyEvent.VK_COMPOSE key and character combinations
I have a swing application with virtual keyboard and is running in Linux. When I click on a textfield, I open virtual keyboard and user can click keys and is able to input.
In Linux , we need to support some compose key characters.
Eg : Pressing Compose Key and then pressing key 's' twice gives ß
What I do in my virtual keyboard is when user presses Compose key, Using java.awt.Robot.kepress I do the keypress of KeyEvent.VK_COMPOSE. And then when a is pressed I do robot.kepress(83) annd when a is pressed again I do the same thing.
Below is what I do overall.
Robot robot = new Robot();
// On pressing compose Key
robot.keyPress(KeyEvent.VK_COMPOSE);
robot.keyRelease(KeyEvent.VK_COMPOSE);
int c = 83; // Key s
// On First Press
robot.keyPress(c);
robot.keyRelease(c);
//On Second Press
robot.keyPress(c);
robot.keyRelease(c);
The above is working for JTextfield. When I press compose key & then press s twice, text field shows ß. So it's working fine
But the same is not working in JPasswordField. On pressing compose and s once, nothing gets printed in field as expected. But on second press, password field prints the dot. But when I check the value, it's s not ß
What's the reason for it? Is there any limitation in JPasswordField or Robot?
I need to make it so using Robot.keyPress(keycode) will press the correct key that was pressed on a different computer/keyboard.
Right now, pressing '/' will give me a key code that would press (using robot) ';' on a different computer. I'm using getKeyCode() from KeyEvent to get the keycode.
Literally the only code I'm using is Robot.keyPress() and KeyEvent.getKeyCode().
So how can I make the robot press the right key?
I register
getInputMap().put(KeyStroke.getKeyStroke("pressed RIGHT"), "go right");
When testing the code I get: While I hold the right arrow key down, the action is triggered repeatedly and not only once as I would have expected this.
Interestingly
getInputMap().put(KeyStroke.getKeyStroke("released RIGHT"), "stop");
triggers stop only when the key is finally released.
Is there a way to register a key stroke on an input map, so that the associated action is only triggered once at the moment when the key is pressed?
Documentation of KeyStroke:
A KeyStroke represents a key action on the keyboard, or equivalent
input device. KeyStrokes can correspond to only a press or release of
a particular key, just as KEY_PRESSED and KEY_RELEASED KeyEvents do;
alternately, they can correspond to typing a specific Java character,
just as KEY_TYPED KeyEvents do. In all cases, KeyStrokes can specify
modifiers (alt, shift, control, meta, altGraph, or a combination
thereof) which must be present during the action for an exact match.
To trigger the event only once, at release time, I suggest to register
getInputMap().put(KeyStroke.getKeyStroke("typed RIGHT"), "go right");
The documentation of KeyStroke.getKeyStroke(String) is:
Parses a string and returns a KeyStroke. The string must have the
following syntax:
modifiers* (typedID | pressedReleasedID)
modifiers := shift | control | ctrl | meta | alt | altGraph
typedID := typed <typedKey>
typedKey := string of length 1 giving Unicode character.
pressedReleasedID := (pressed | released) key
key := KeyEvent key code name, i.e. the name following "VK_".
To trigger the event only once, at press time, I suggest to register the press and release events to manage yourself a latch with a boolean.
Is there a way to register a key stroke on an input map, so that the associated action is only triggered once at the moment when the key is pressed?
Remove the keyPressed binding from the InputMap. Then for the keyReleased Action you add the keyPressed binding back to the InputMap.
However, even this can cause problems because on a Windows OS the sequence of KeyEvents is:
pressed, pressed, pressed.... released.
This makes sense to me as generally when you hold the key down you want the character to repeat. However, on a Mac I believe the sequence is:
pressed, released, pressed, released, pressed, released
which doesn't make sense to me and makes it difficult to determine when a key has truly been released.
The "key typed" event operates per platform behaviour -- which, as standard since before the 1980's, has always included auto-repeat. This would be driven by the low-level events from the OS.
You could try not holding down the keys? You shouldn't be mashing the keyboard, it's a precision instrument.
You can possibly change the key-stroke binding (to avoid receiving auto-repeat) or otherwise use a custom event-listener & handle only the low-level keydown/ keyup event once. Low-level events may however expose keycodes (as they are below the level of actually typing any one character) rather than characters.
When I press "Delete" button on the keyboard, program gets three events - KEY_PRESSED, KEY_TYPED, and KEY_RELEASED. The problem is, in KEY_PRESSED and KEY_RELEASED, parameter "keyCode" is set, but in the KEY_TYPED it is not (in fact, there no meaningful info in that event). With F5 key, it is even funnier - KEY_PRESSED and KEY_RELEASED are registered, but KEY_TYPED never occurs.
The listener was added via Toolkit.getDefaultToolkit().addAWTEventListener(). Using JDK 6.26.
What could be my problem?
EDIT:
Here are the events that happen when Delete key is pressed:
java.awt.event.KeyEvent[KEY_PRESSED,keyCode=127,keyText=Delete,keyChar=Delete,keyLocation=KEY_LOCATION_STANDARD,rawCode=119,primaryLevelUnicode=127,scancode=0] on javax.swing.JButton[,0,0,61x30,alignmentX=0.0,alignmentY=0.5,border=javax.swing.plaf.synth.SynthBorder#50f38cf0,flags=288,maximumSize=,minimumSize=,preferredSize=,defaultIcon=javax.swing.ImageIcon#6ae2d0b2,disabledIcon=,disabledSelectedIcon=,margin=javax.swing.plaf.InsetsUIResource[top=0,left=0,bottom=0,right=0],paintBorder=true,paintFocus=true,pressedIcon=,rolloverEnabled=true,rolloverIcon=,rolloverSelectedIcon=,selectedIcon=,text=SVG,defaultCapable=false]
java.awt.event.KeyEvent[KEY_TYPED,keyCode=0,keyText=Unknown keyCode: 0x0,keyChar=Delete,keyLocation=KEY_LOCATION_UNKNOWN,rawCode=0,primaryLevelUnicode=127,scancode=0] on javax.swing.JButton[,0,0,61x30,alignmentX=0.0,alignmentY=0.5,border=javax.swing.plaf.synth.SynthBorder#50f38cf0,flags=288,maximumSize=,minimumSize=,preferredSize=,defaultIcon=javax.swing.ImageIcon#6ae2d0b2,disabledIcon=,disabledSelectedIcon=,margin=javax.swing.plaf.InsetsUIResource[top=0,left=0,bottom=0,right=0],paintBorder=true,paintFocus=true,pressedIcon=,rolloverEnabled=true,rolloverIcon=,rolloverSelectedIcon=,selectedIcon=,text=SVG,defaultCapable=false]
java.awt.event.KeyEvent[KEY_RELEASED,keyCode=127,keyText=Delete,keyChar=Delete,keyLocation=KEY_LOCATION_STANDARD,rawCode=119,primaryLevelUnicode=127,scancode=0] on javax.swing.JButton[,0,0,61x30,alignmentX=0.0,alignmentY=0.5,border=javax.swing.plaf.synth.SynthBorder#50f38cf0,flags=288,maximumSize=,minimumSize=,preferredSize=,defaultIcon=javax.swing.ImageIcon#6ae2d0b2,disabledIcon=,disabledSelectedIcon=,margin=javax.swing.plaf.InsetsUIResource[top=0,left=0,bottom=0,right=0],paintBorder=true,paintFocus=true,pressedIcon=,rolloverEnabled=true,rolloverIcon=,rolloverSelectedIcon=,selectedIcon=,text=SVG,defaultCapable=false]
better would be implements KeyBindings
part of keyboard are reserved Keys for built-in JComponent funcionality, more informations from #camickrs UIManager Defaults
depends of reason(s) why you needed implents KeyListener, because for there are lots of another Listeners for various JComponent, that should be filtering or register text changes inside
some of JComponent Models generated Events from Mouse and Keyboard input
From the JavaDoc The "key typed" event. This event is generated when a character is entered. In the simplest case, it is produced by a single key press. Often, however, characters are produced by series of key presses, and the mapping from key pressed events to key typed events may be many-to-one or many-to-many.
You are trying to get the F5 key which is probably not registered as a character being entered. By using the KEY_RELEASED you will consistently get the result you are looking for and the API is behaving as expected.
Key typed events ALWAYS generate '0' as the key code. Look up the method getKeyChar() instead, or (as has been suggested) listen for keyReleased() instead.
getKeyChar(): http://goo.gl/ajH03
What are VK_META and META_MASK in the Java Robot class? Any example that explains what they are or what they do would be very helpful.
Also, VK_META gives me an invalid keycode error on my Windows 7 PC.
VK_META and META_MASK are defined in KeyEvent and InputEvent classes. They both define the META key as a standalone key pressed and as a modifier used pressing another key respectively.
The META key is a key used in old keyboards and now can be emulated using the Windows Key.
Robot class allows to simulate key strokes (pressed, released, typed) and mouse movement, "acting" as a user using the keyboard and mouse. When you use the robot class, you define the sequence of "actions" to simulate, mouse movements and keyboard usage. If you want to simulate the META key pressed or used as a modifier, need to pass the keyCode and these two constants define the keyCode for META typed and modifier.
You can have problems using this key depending some factors, such your keyboard layout, keyboard configuration, operating system...
If you have problem, try avoid using this key except you need to simulate the Windows (PC) or Command (Mac) key.