区分虚拟(机器人)和物理 KeyEvents
Differentiating Between Virtual (Robot) and Physical KeyEvents
我想知道是否有区分 KeyEvent 对象的虚拟(来自 AWT 机器人)和物理源的合适方法?
我正在制作虚拟键盘,但希望键盘消失when/if用户使用物理键盘。
下面的示例说明了我需要解决的问题(同时忽略了实现实际虚拟键盘的其他问题)。我正在尝试修复 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);
}
}
}
因此,我最终采用的路线并不能保证解决确定 KeyEvent 是来自机器人还是物理源的一般问题,但它可以让我检测是否有机器人外部的任何输入.
我只是做了一个机器人预期事件的队列。收到事件后,我会通过轮询队列来检查机器人是否打算按下该键。这几乎可以保证检测到是否存在物理事件,但由于同步性问题,不能保证找到 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);
}
}
}
我想知道是否有区分 KeyEvent 对象的虚拟(来自 AWT 机器人)和物理源的合适方法?
我正在制作虚拟键盘,但希望键盘消失when/if用户使用物理键盘。
下面的示例说明了我需要解决的问题(同时忽略了实现实际虚拟键盘的其他问题)。我正在尝试修复 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);
}
}
}
因此,我最终采用的路线并不能保证解决确定 KeyEvent 是来自机器人还是物理源的一般问题,但它可以让我检测是否有机器人外部的任何输入.
我只是做了一个机器人预期事件的队列。收到事件后,我会通过轮询队列来检查机器人是否打算按下该键。这几乎可以保证检测到是否存在物理事件,但由于同步性问题,不能保证找到 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);
}
}
}