我想知道是否有一种方法可以区分虚拟(来自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);
}
}
}
答案 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);
}
}
}