Переназначение клавиатуры на низком уровне - PullRequest
2 голосов
/ 15 июня 2011

Мы заменяем устаревшее приложение C, изначально написанное для MSDOS (да, верите или нет!).Это приложение использует специально переназначенную клавиатуру, которая перехватывает прерывание клавиатуры DOS (помните, что ??!), Чтобы иногда изменять коды сканирования клавиш, нажимаемых пользователем, чтобы происходила различная обработка.Затем на клавиши были нанесены специальные метки, сообщающие пользователям «новое» значение этих клавиш.

Новая версия Java требуется для сохранения этой раскладки клавиатуры, с которой целевая группа пользователей хорошо знакома.

Пример того, что мы пытаемся сделать, таков:

Возможно, вы никогда не задумывались об этом, но цифровая клавиатура современного телефона противоположна цифровой клавиатуре компьютерной клавиатуры.На первом 1-2-3 находится в верхнем ряду, а на втором - в нижнем ряду.Мы должны сделать так, чтобы цифровая клавиатура была похожа на телефон.Скажем, когда пользователь набирает «7» на цифровой клавиатуре, мы хотим, чтобы он выглядел так, как будто он набрал «1», когда он набирает «8», мы хотим «2», когда он набирает «3»нам нужна цифра "9".

Нам нужно сделать гораздо больше, чтобы эмулировать DOS-приложение, но сейчас мы даже не можем решить этот простой случай.Я прошел через связывание ключей, KeyAdapters, KeyListeners и даже KeyEventDispatchers, и я не могу сделать эту работу.Я почти уверен, что нам нужно работать на самом низком уровне, который нам позволяет Java, чтобы максимально приблизиться к тому, что делает унаследованное приложение.И, разумеется, мы хотим, чтобы реализация была максимально чистой, чтобы код уровня приложения не был завален входными картами, ActionMaps и т. Д. В максимально возможной степени это необходимо обрабатывать глобально.Кто-нибудь может помочь?

Ответы [ 4 ]

3 голосов
/ 15 июня 2011

Если бы я делал это, я написал бы Java-приложение, не беспокоясь о привязках клавиш.Предположим, что когда компонент получает событие №7 для своего # 7, не беспокойтесь о том, действительно ли 7 или 1 были напечатаны.Приложение не должно заботиться о том, как клавиши отображаются на клавиатуре.Это должно позволить вам немедленно начать разработку приложения.

Что касается переопределения привязок клавиш, кажется, что вы хотите посмотреть: http://download.oracle.com/javase/7/docs/api/java/awt/KeyEventDispatcher.html

Похоже, вы можете написать свой собственный KeyEventDispatcher для обработки всей логики сопоставления клавиш, и это предотвращаетлогика отображения от того, чтобы испортить остальную логику в вашем приложении.

2 голосов
/ 15 июня 2011

Я также согласен с тем, что KeyEventDispatcher должен работать. Но если это проблема версии / платформы, то, возможно, вы можете использовать пользовательскую очередь событий. См. Глобальная диспетчеризация событий

2 голосов
/ 15 июня 2011

Это хакерство, и я признаю, что сам не использовал его, но вы можете создать подкласс KeyEvent и переопределить поля по мере необходимости. Так что yourSubclass.VK_NUMPAD1 - это целочисленное значение KeyEvent.VK_NUMPAD7, yourSubclass.VK_NUMPAD2 - это целочисленное значение KeyEvent.VK_NUMPAD8 и так далее. Тогда используйте ваш подкласс везде, где обычно используется KeyEvent.

1 голос
/ 16 июня 2011

Мой стек переполнен! Ответ был здесь: http://download.oracle.com/javase/6/docs/api/java/awt/event/KeyEvent.html который говорит:

Для нажатия клавиши и отпускания клавиши события, метод getKeyCode возвращает код события. Для набранного ключа события, метод getKeyCode всегда возвращает VK_UNDEFINED.

Моя первоначальная попытка показала, что он может получить код ключа для KEY_TYPED. Это не могло, и это было событие 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<Integer, Character> keyMap = 
                    new HashMap<Integer, Character>() { 
                {
                    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);
    }

}

Спасибо всем, кто подтолкнул меня к ответу.

, что подводит меня к следующему вопросу ... следите за обновлениями.

...