Consume the dialed key using KeyBindings

Could you help me use KeyBinding and Consume to input Chars together, just like demostraded my SSCCE with KeyListener

 import java.awt.*; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import javax.swing.*; public class Login { private static final long serialVersionUID = 1L; /* PassWord for unlock*/ private PswChecker checker = new PswChecker("pass"); public Login() { JTextField firstField = new JTextField(10); firstField.addKeyListener(passwordKeyListener); JLabel firstLabel = new JLabel("Password is 'pass' ", JLabel.RIGHT); firstLabel.setLabelFor(firstField); JPanel p = new JPanel(); p.setLayout(new GridLayout(0, 2, 5, 5)); p.add(firstLabel); p.add(firstField); JFrame f = new JFrame("login"); f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); f.setContentPane(p); f.setLocationByPlatform(true); f.pack(); f.setVisible(true); } // private KeyListener passwordKeyListener = new KeyListener() { private boolean enabled = true; @Override public void keyTyped(KeyEvent e) { if (!enabled) { return; } if (e.getKeyChar() != KeyEvent.CHAR_UNDEFINED) { boolean b = checker.accept(e.getKeyChar()); e.consume(); if (b) { enabled = false; if (e.getComponent() != null) { e.getComponent().removeKeyListener(this); } unlock(); } } } @Override public void keyReleased(KeyEvent e) { } @Override public void keyPressed(KeyEvent e) { } }; void unlock() { JOptionPane.showMessageDialog(null, "unlocked"); } public static void main(String[] args) { javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { Login log = new Login(); } }); } class PswChecker { private String password = null; private boolean unlocked = false; private long lastInputTimestamp = 0L; private int index = 0; public PswChecker(String password) { if (password == null) { throw new IllegalArgumentException("Null password"); } if (password.trim().length() == 0) { throw new IllegalArgumentException("Empty password"); } this.password = password; } public boolean accept(char c) { if (unlocked) { return true; } long timestamp = System.currentTimeMillis(); if (timestamp - lastInputTimestamp > 700) { index = 0; } lastInputTimestamp = timestamp; if (password.charAt(index) == c) { index++; } else { if (password.charAt(0) == c) { index = 1; } else { index = 0; } } unlocked = (index == password.length()); return unlocked; } public boolean isUnlocked() { return unlocked; } public boolean isLocked() { return !unlocked; } @Override public String toString() { return unlocked ? "UNLOCKED" : "LOCKED"; } /*private boolean check(String keystrokes, String password, boolean expectUnLocked) { PswChecker checker = new PswChecker(password); for (int i = 0; i < keystrokes.length(); i++) { checker.accept(keystrokes.charAt(i)); } return checker.isUnlocked(); }*/ } } 
+1
source share
1 answer

For security, consider the JPasswordField illustrated here . This will allow the use of the DocumentFilter discussed here .

Addition: Even for a more general case, I would use a DocumentFilter , as shown below. I would use key bindings to share Action among components, as shown in this example keyboard .

Addition. To illustrate @kleopatra's comment, I updated the code to bind ESC to Reset . As a practical question, I would use only keys that are not yet tied to the actions of the text field or are necessary for normal use.

 import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import javax.swing.*; import javax.swing.text.*; /** @see https://stackoverflow.com/q/9610386/230513 */ public class Login { private static final String PWD = "pass"; private static final String RESET = "Reset"; private PlainDocument doc = new PlainDocument(); private JTextField text = new JTextField(doc, "", 10); public Login() { doc.setDocumentFilter(new FieldFilter(PWD)); JLabel label = new JLabel("Password is '" + PWD + "'", JLabel.RIGHT); label.setLabelFor(text); text.setToolTipText("Press ESC to reset."); text.getInputMap().put( KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), RESET); text.getActionMap().put(RESET, new Reset()); JPanel p = new JPanel(); p.setLayout(new GridLayout(0, 2, 5, 5)); p.add(label); p.add(text); JFrame f = new JFrame("Login"); f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); f.setContentPane(p); f.setLocationByPlatform(true); f.pack(); f.setVisible(true); } private static class FieldFilter extends DocumentFilter { private String password; private boolean unlocked; private StringBuilder sb = new StringBuilder(); public FieldFilter(String password) { this.password = password; } @Override public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException { if (unlocked) { super.replace(fb, offset, length, text, attrs); } else { sb.append(text); unlocked = password.equals(sb.toString()); } } public void reset() { sb.delete(0, sb.length()); unlocked = false; } } private static class Reset extends AbstractAction { @Override public void actionPerformed(ActionEvent e) { JTextField jtf = (JTextField) e.getSource(); PlainDocument doc = (PlainDocument) jtf.getDocument(); try { doc.remove(0, doc.getLength()); } catch (BadLocationException ex) { ex.printStackTrace(System.err); } FieldFilter filter = (FieldFilter) doc.getDocumentFilter(); filter.reset(); } } public static void main(String[] args) { javax.swing.SwingUtilities.invokeLater(new Runnable() { @Override public void run() { Login log = new Login(); } }); } } 
+3
source

All Articles