将键盘重新映射到较低级别

我们正在替换最初为MSDOS编写的遗留C应用程序(是的,信不信由你!)。 此应用程序使用一个特殊重映射的键盘拦截DOS键盘中断(记住??!)有时会改变用户按下的键的扫描码,以便进行不同的处理。 然后在按键上放置特殊标签,告诉用户这些按键的“新”含义。

需要新的Java版本来保留目标用户群非常熟悉的键盘布局。

我们尝试做的一个例子如下:

您可能从未想过这一点,但现代电话的数字键盘与计算机键盘的数字键盘相反。 前者1-2-3位于顶行,后者位于底行。 我们需要使键盘的数字键盘看起来像电话。 让我们说,当用户在数字键盘上输入“7”时,我们希望它看起来好像输入“1”,当他输入“8”时,我们想要一个“2”,当他输入“3”时我们想要一个“9”。

我们还需要做更多的事情来模拟DOS应用程序,但我们现在甚至无法解决这个简单的案例。 我已经遍布Key Binding,KeyAdapters,KeyListeners,甚至KeyEventDispatcher,我无法做到这一点。 我很确定我们必须在Java允许的最低级别上工作,以尽可能接近遗留应用程序的工作。 不用说,我们希望最干净的实现成为可能,这样应用程序级代码就不会被inputMaps和actionMaps等所困扰。尽可能地,这需要全局处理。 有人可以帮忙吗?

如果我这样做,我会编写Java App而不必担心密钥绑定。 假设当一个组件获得#7#7的键事件时,不要担心7或1是否真的被键入。 该应用程序不应该关心如何在键盘上映射键。 这应该可以让您立即开始开发应用程序。

至于重写键绑定,这看起来像你想看的地方: http : //download.oracle.com/javase/7/docs/api/java/awt/KeyEventDispatcher.html

听起来你可以编写自己的KeyEventDispatcher来处理所有的键映射逻辑,它可以防止映射逻辑弄乱应用程序中的其余逻辑。

这很hacky,我承认我自己没有使用它,但你可以KeyEvent并根据需要覆盖这些字段。 所以yourSubclass.VK_NUMPAD1KeyEvent.VK_NUMPAD7的整数值, yourSubclass.VK_NUMPAD2KeyEvent.VK_NUMPAD7的整数值,等等。 然后在任何地方使用你的子类,通常使用KeyEvent

我也同意KeyEventDispatcher应该可以工作。 但如果这是一个版本/平台问题,那么也许您可以使用自定义事件队列。 请参阅全局事件调度

我的堆栈溢出! 答案在这里: http : //download.oracle.com/javase/6/docs/api/java/awt/event/KeyEvent.html其中说:

对于按键和键释放事件,getKeyCode方法返回事件的keyCode。 对于键类型事件,getKeyCode方法始终返回VK_UNDEFINED。

我最初的尝试认为它可以获得KEY_TYPED上的keyCode。 它不能,并且KEY_TYPED事件正在破坏KEY_PRESSED中完成的映射。

这是一个有效的实现:

 import static java.awt.event.KeyEvent.*; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.KeyEventDispatcher; import java.awt.KeyboardFocusManager; import java.awt.event.KeyEvent; import java.util.HashMap; import java.util.Map; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.SwingConstants; public class KeyboardDispatcherDemo extends JFrame { /** * This class shows how to map numeric keypad keys. * It performs two conversions: * 1. lower-to-uppercase * 2. if numeric keypad 7-9 is typed, 1-3 appears and vice versa. * * This is modified from the code at * http://www.exampledepot.com/egs/java.awt/DispatchKey.html#comment-51807 * which demoes the lower-to-upper conversion. * * It doesn't yet handle modified numeric keypad keys. * */ public KeyboardDispatcherDemo() { KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher( new KeyEventDispatcher() { private char lastMappedKey; private final Map keyMap = new HashMap() { { put(VK_NUMPAD1, '7'); put(VK_NUMPAD2, '8'); put(VK_NUMPAD3, '9'); put(VK_NUMPAD7, '1'); put(VK_NUMPAD8, '2'); put(VK_NUMPAD9, '3'); }}; public boolean dispatchKeyEvent(KeyEvent e) { System.out.println(String.format("INPUT: %s", e.toString())); boolean dispatch = false; switch (e.getID()) { case KeyEvent.KEY_PRESSED: dispatch = dispatchKeyPressed(e); break; case KeyEvent.KEY_TYPED: dispatch = dispatchKeyTyped(e); break; case KeyEvent.KEY_RELEASED: dispatch = dispatchKeyReleased(e); break; default: throw new IllegalArgumentException(); } System.out.println(String.format("OUTPUT: %s", e.toString())); System.out.println(); return dispatch; } private boolean dispatchKeyPressed(KeyEvent e) { char k = e.getKeyChar(); if (k != CHAR_UNDEFINED) { if (Character.isLetter(k)) { e.setKeyChar(Character.toUpperCase(e.getKeyChar())); } else if (e.getModifiers() == 0){ Character mapping = keyMap.get(e.getKeyCode()); if (mapping != null) { e.setKeyChar(mapping); } } // save the last mapping so that KEY_TYPED can use it. // note we don't do this for modifier keys. this.lastMappedKey = e.getKeyChar(); } return false; } // KEY_TYPED events don't have keyCodes so we rely on the // lastMappedKey that was saved on KeyPressed. private boolean dispatchKeyTyped(KeyEvent e) { char k = e.getKeyChar(); if (k != CHAR_UNDEFINED) { e.setKeyChar(lastMappedKey); } return false; } private boolean dispatchKeyReleased(KeyEvent e) { char k = e.getKeyChar(); if (k != CHAR_UNDEFINED) { e.setKeyChar(lastMappedKey); this.lastMappedKey=CHAR_UNDEFINED; } return false; } }); setTitle("KeyboardDispatcherDemo"); JPanel panel = new JPanel(); panel.setBackground(new Color(204, 153, 255)); panel.setLayout(new BorderLayout()); getContentPane().add(panel, BorderLayout.CENTER); JTextArea staticText = new JTextArea(); staticText.setText("This demonstrates how to map numeric keypad keys. It uppercases all letters and converts Numeric Keypad 1-3 to 7-9 and vice versa. Try it."); staticText.setLineWrap(true); staticText.setWrapStyleWord(true); panel.add(staticText, BorderLayout.NORTH); staticText.setFocusable(false); JTextField textField = new JTextField(); textField.setText(""); textField.setHorizontalAlignment(SwingConstants.LEFT); panel.add(textField, BorderLayout.SOUTH); textField.setColumns(10); textField.setFocusable(true); setSize(getPreferredSize()); setVisible(true); } /** * @param args */ public static void main(String[] args) { new KeyboardDispatcherDemo(); } @Override public Dimension getPreferredSize() { // TODO Auto-generated method stub return new Dimension(400,300); } } 

感谢所有推动我回答问题的人。

这让我想到了下一个问题…敬请期待。