工具包详细解析
(二) 输入处理工具类
SafeKeyboardInput类
SafeKeyboardInput类是一个安全的键盘输入处理类,实现了KeyListener接口。当由于种种原因导致帧速率过低时,普通的键盘输入处理可能会漏掉一些事件。本类中使用将所有接受到的键盘事件储存在一个数组中,当需要处理的时候再按照顺序依次处理所有的键盘事件,因此不会漏掉任何键盘事件。但是这样也存在一个问题,如果之前接受到的键盘事件不需要处理,则需要调用flush函数来清空之前接收到的键盘事件。
修饰符 | 类型 | 名称 | 说明 |
---|
private | enum | EventType | 表示键盘事件类型的枚举类 |
private | class | Event | 表示键盘事件的类 |
private | LinkedList< Event> | eventThread | 接收到的键盘事件列表 |
private | LinkedList< Event> | gameThread | 正在处理的键盘事件列表 |
private | Event | event | 当前正在处理的键盘事件 |
private | int[] | polled | 表示键盘中所有键的数组(共256个) |
修饰符 | 返回值 | 函数名 | 参数 | 说明 |
---|
public | | SafeKeyboardInput | () | 默认构造函数 |
public synchronized | boolean | keyDown | (int keyCode) | 返回一个键是否被按下 |
public synchronized | boolean | keyDownOnce | (int keyCode) | 返回一个键是否有且被按下一次 |
public synchronized | boolean | processEvent | () | 处理事件,返回是否还有时间未处理 |
public | Character | getKeyTyped | () | 返回单击的字符 |
public synchronized | void | poll | () | 每帧调用,刷新待处理的键盘事件 |
public synchronized | void | flush | () | 清除之前未处理的所有事件 |
public synchronized | void | keyPressed | (KeyEvent e) | 键盘按下事件触发 |
public synchronized | void | keyReleased | (KeyEvent e) | 键盘释放事件触发 |
public synchronized | void | keyTyped | (KeyEvent e) | 键盘单击事件触发 |
package Rendering.utils;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.LinkedList;
public class SafeKeyboardInput implements KeyListener {
private enum EventType {
PRESSED,
RELEASED,
TYPED,
}
private class Event {
KeyEvent event;
EventType type;
public Event(KeyEvent event, EventType type) {
this.event = event;
this.type = type;
}
}
private LinkedList<Event> eventThread = new LinkedList<Event>();
private LinkedList<Event> gameThread = new LinkedList<Event>();
private Event event = null;
private int[] polled;
public SafeKeyboardInput() {
polled = new int[256];
}
public synchronized boolean keyDown(int keyCode) {
return keyCode == event.event.getKeyCode() && polled[keyCode] > 0;
}
public synchronized boolean keyDownOnce(int keyCode) {
return keyCode == event.event.getKeyCode() && polled[keyCode] == 1;
}
public synchronized boolean processEvent() {
event = gameThread.poll();
if (event != null) {
int keyCode = event.event.getKeyCode();
if (keyCode >= 0 && keyCode < polled.length) {
if (event.type == EventType.PRESSED) {
polled[keyCode]++;
} else if (event.type == EventType.RELEASED) {
polled[keyCode] = 0;
}
}
}
return event != null;
}
public Character getKeyTyped() {
if (event.type != EventType.TYPED) {
return null;
} else {
return event.event.getKeyChar();
}
}
public synchronized void poll() {
LinkedList<Event> swap = eventThread;
eventThread = gameThread;
gameThread = swap;
}
public synchronized void flush() {
eventThread = new LinkedList<Event>();
gameThread = new LinkedList<Event>();
}
public synchronized void keyPressed(KeyEvent e) {
eventThread.add(new Event(e, EventType.PRESSED));
}
public synchronized void keyReleased(KeyEvent e) {
eventThread.add(new Event(e, EventType.RELEASED));
}
public synchronized void keyTyped(KeyEvent e) {
eventThread.add(new Event(e, EventType.TYPED));
}
}
RelativeMouseInput类
RelativeMouseInput类是一个既可以处理绝对鼠标事件,还可以处理相对鼠标事件的鼠标事件处理类,实现了MouseListener接口, MouseMotionListener接口和MouseWheelListener接口。当设置relative字段为false时,处理绝对鼠标事件;设置relative字段为true时,处理相对鼠标事件。
修饰符 | 类型 | 名称 | 说明 |
---|
private static final | int | BUTTON_COUNT | 表示鼠标所有按键的数目(3) |
private | Point | mousePos | 鼠标当前帧的位置 |
private | Point | currentPos | 鼠标的实时位置 |
private | boolean[] | mouse | 存储鼠标的按键是否被按下的数组 |
private | int[] | polled | 表示鼠标所有键的数组 |
private | int | notches | 鼠标滚轮的转动距离 |
private | int | polledNotches | 当前帧鼠标滚轮的转动距离 |
private | int | dx | 鼠标相对上一帧移动的x值 |
private | int | dy | 鼠标相对上一帧移动的y值 |
private | Robot | robot | 自动实现移动鼠标 |
private | Component | component | 鼠标所在的组件 |
private | boolean | relative | 处理绝对或相对鼠标事件 |
修饰符 | 返回值 | 函数名 | 参数 | 说明 |
---|
public | | RelativeMouseInput | (Component component) | 构造函数 |
public synchronized | void | poll | () | 每帧调用,刷新当前帧的鼠标位置和滚轮位置 |
public synchronized | boolean | isRelative | () | 返回是否为相对鼠标事件 |
public synchronized | void | setRelative | (boolean relative) | 更改绝对/相对鼠标事件 |
public synchronized | Point | getPosition | () | 返回鼠标当前帧的绝对位置/相对上一帧的位置 |
public synchronized | int | getNotches | () | 返回当前帧鼠标滚轮的转动距离 |
public synchronized | boolean | buttonDown | (int button) | 返回一个键是否被按下 |
public synchronized | boolean | buttonDownOnce | (int button) | 返回一个键是否有且被按下一次 |
public synchronized | void | mousePressed | (MouseEvent e) | 鼠标按下事件触发 |
public synchronized | void | mouseReleased | (MouseEvent e) | 鼠标释放事件触发 |
public | void | mouseClicked | (MouseEvent e) | 鼠标单击事件触发 |
public synchronized | void | mouseEntered | (MouseEvent e) | 鼠标进入事件触发 |
public synchronized | void | mouseExited | (MouseEvent e) | 鼠标移出事件触发 |
public synchronized | void | mouseDragged | (MouseEvent e) | 鼠标拖动事件触发 |
public synchronized | void | mouseMoved | (MouseEvent e) | 鼠标移动事件触发 |
public synchronized | void | mouseWheelMoved | (MouseWheelEvent e) | |
private | Point | getComponentCenter | () | 返回鼠标所在的组件 |
private | void | centerMouse | () | 移动鼠标到所在组件的中央 |
public | void | moveMouse | (Vector2f mousePos) | 移动鼠标到组件的指定位置 |
package Rendering.utils;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class RelativeMouseInput
implements MouseListener, MouseMotionListener, MouseWheelListener {
private static final int BUTTON_COUNT=3;
private Point mousePos;
private Point currentPos;
private boolean[] mouse;
private int[] polled;
private int notches;
private int polledNotches;
private int dx, dy;
private Robot robot;
private Component component;
private boolean relative;
public RelativeMouseInput(Component component) {
this.component = component;
try {
robot = new Robot();
} catch (Exception e) {
e.printStackTrace();
}
mousePos = new Point(0, 0);
currentPos = new Point(0, 0);
mouse = new boolean[BUTTON_COUNT];
polled = new int[BUTTON_COUNT];
}
public synchronized void poll(){
if (isRelative()) {
mousePos = new Point(dx, dy);
} else {
mousePos = new Point(currentPos);
}
dx = dy = 0;
polledNotches = notches;
notches = 0;
for (int i = 0; i < mouse.length; i++) {
if (mouse[i]) {
polled[i]++;
} else {
polled[i] = 0;
}
}
}
public synchronized boolean isRelative() {
return relative;
}
public synchronized void setRelative(boolean relative) {
this.relative = relative;
if (relative) {
centerMouse();
}
}
public synchronized Point getPosition() {
return mousePos;
}
public synchronized int getNotches() {
return polledNotches;
}
public synchronized boolean buttonDown(int button) {
return polled[button-1]>0;
}
public synchronized boolean buttonDownOnce(int button) {
return polled[button-1]==1;
}
public synchronized void mousePressed(MouseEvent e) {
int button=e.getButton()-1;
if (button >= 0 && button < mouse.length) {
mouse[button] = true;
}
}
public synchronized void mouseReleased(MouseEvent e) {
int button=e.getButton()-1;
if (button >= 0 && button < mouse.length) {
mouse[button] = false;
}
}
public void mouseClicked(MouseEvent e) {
//Not needed
}
public synchronized void mouseEntered(MouseEvent e) {
mouseMoved(e);
}
public synchronized void mouseExited(MouseEvent e) {
mouseMoved(e);
}
public synchronized void mouseDragged(MouseEvent e) {
mouseMoved(e);
}
public synchronized void mouseMoved(MouseEvent e) {
if (isRelative()) {
Point p = e.getPoint();
Point center = getComponentCenter();
dx += p.x - center.x;
dy += p.y - center.y;
centerMouse();
} else {
currentPos = e.getPoint();
}
}
public synchronized void mouseWheelMoved(MouseWheelEvent e) {
notches += e.getWheelRotation();
}
private Point getComponentCenter() {
int w = component.getWidth();
int h = component.getHeight();
return new Point(w / 2, h / 2);
}
private void centerMouse() {
if (robot != null && component.isShowing()) {
Point center = getComponentCenter();
SwingUtilities.convertPointToScreen(center, component);
robot.mouseMove(center.x, center.y);
}
}
public void moveMouse(Vector2f mousePos) {
if (robot != null && component.isShowing()) {
Point tmp = new Point((int) mousePos.x, (int) mousePos.y);
SwingUtilities.convertPointToScreen(tmp, component);
robot.mouseMove(tmp.x, tmp.y);
} else {
JOptionPane.showMessageDialog(
component, "Can not support similar!!!",
"Warning", JOptionPane.INFORMATION_MESSAGE
);
}
}
}
更多:
第一篇
第二篇
第三篇
第四篇
第五篇
第六篇
第七篇
最终篇
源代码