区分虚拟(机器人)和物理KeyEvents

时间:2015-01-15 19:51:53

标签: java swing awt awtrobot

我想知道是否有一种方法可以区分虚拟(来自AWT的机器人)和KeyEvent对象的物理来源?

我正在制作一个虚拟键盘,但是当用户使用物理键盘时,希望键盘消失。

下面是一个示例,说明我需要解决的问题(忽略实现实际虚拟键盘的另一个问题)。我正在尝试修复FIXME行下面的if / else语句(我意识到逻辑不正确)。

import java.awt.AWTEvent;
import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class RobotTest
{
    public static void main( String[] args )
    {
        new RobotTest();
    }

    public RobotTest()
    {
        // Create a "virtual keyboard"
        MyWindow window = new MyWindow();
        window.setVisible( true );

        // Event listener to differentiate between virtual and physical key events.
        Toolkit.getDefaultToolkit().addAWTEventListener( new AWTEventListener()
        {
            @Override
            public void eventDispatched( final AWTEvent e )
            {
                if (( e instanceof KeyEvent )
                        && ( ( KeyEvent ) e ).getID()==KeyEvent.KEY_PRESSED
                        && ( ( KeyEvent ) e ).getKeyCode()==KeyEvent.VK_A)
                {
                    // FIXME: BELOW IS GUARANTEED FALSE
                    if ( ( ( KeyEvent ) e ).getSource() instanceof Robot)
                    {
                        System.out.println("FROM ROBOT");
                    }
                    else
                    {
                        System.out.println("FROM KEYBOARD");
                    }
                }
            }
        }, AWTEvent.KEY_EVENT_MASK);
    }

    // prototype keyboard with an "A" key.
    private class MyWindow extends JFrame
    {
        public MyWindow()
        {
            JPanel content = new JPanel();
            content.setLayout( new BorderLayout() );

            // Button that emulates pressing A
            JButton button = new JButton( "A" );
            button.addActionListener( new ActionListener()
            {
                @Override
                public void actionPerformed( ActionEvent e )
                {
                    try
                    {
                        Robot r = new Robot();
                        r.keyPress( KeyEvent.VK_A );
                        r.keyRelease( KeyEvent.VK_A );
                    }
                    catch( AWTException ex )
                    {
                        ex.printStackTrace();
                    }
                }
            });

            content.add( button, BorderLayout.CENTER );
            setContentPane( content );

            setSize(50, 50);
        }
    }
}

1 个答案:

答案 0 :(得分:0)

所以我最终选择的路线并不能保证解决确定KeyEvent是来自机器人还是来自物理源的一般问题,但它可以让我检测机器人外是否有任何输入。 / p>

我只是从机器人队列出预期事件的队列。收到事件后,我会检查机器人是否打算通过轮询队列来按下该键。这几乎可以保证检测是否存在物理事件,但由于同步性问题,无法保证找到KeyEvent的源。我已经附上了(非常简单的)解决方案,以防任何人使用它。

import java.awt.AWTEvent;
import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.LinkedList;
import java.util.Queue;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class RobotTest
{
    // CHANGE #1: store a queue of virtual key presses.
    public static Queue<Integer> robotKeys = new LinkedList<Integer>();


    public static void main( String[] args )
    {
        new RobotTest();
    }


    public RobotTest()
    {
        // Create a "virtual keyboard"
        MyWindow window = new MyWindow();
        window.setVisible( true );

        // Event listener to differentiate between virtual and physical key events.
        Toolkit.getDefaultToolkit().addAWTEventListener( new AWTEventListener()
        {
            @Override
            public void eventDispatched( final AWTEvent e )
            {
                if (( e instanceof KeyEvent )
                        && ( ( KeyEvent ) e ).getID()==KeyEvent.KEY_PRESSED
                        && ( ( KeyEvent ) e ).getKeyCode()==KeyEvent.VK_A)
                {
                    // CHANGE #2: check the received event against the front of the queue.
                    Integer expectedRobotKey = robotKeys.poll();
                    if (expectedRobotKey != null && expectedRobotKey == ( ( KeyEvent ) e ).getKeyCode())
                    {
                        System.out.println("No physical input detected.");
                    }
                    else
                    {
                        System.out.println("Physical input detected.");
                    }
                }
            }
        }, AWTEvent.KEY_EVENT_MASK);
    }

    // prototype keyboard with an "A" key.
    private class MyWindow extends JFrame
    {
        public MyWindow()
        {
            JPanel content = new JPanel();
            content.setLayout( new BorderLayout() );

            // Button that emulates pressing A
            JButton button = new JButton( "A" );
            button.addActionListener( new ActionListener()
            {
                @Override
                public void actionPerformed( ActionEvent e )
                {
                    try
                    {
                        Robot r = new Robot();
                        // CHANGE #3: add events to the stored queue before sending them out.
                        robotKeys.add( KeyEvent.VK_A );
                        r.keyPress( KeyEvent.VK_A );
                        r.keyRelease( KeyEvent.VK_A );
                    }
                    catch( AWTException ex )
                    {
                        ex.printStackTrace();
                    }
                }
            });

            content.add( button, BorderLayout.CENTER );
            setContentPane( content );

            setSize(50, 50);
        }
    }
}