package util.input; import java.awt.Point; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionAdapter; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.JComponent; /** * MouseInput catches events from the Mouse Input Device and passes them to Input. * @author Gavin Ovsak, Ying Chen */ public class MouseInput extends InputDevice { JComponent myComponent; public static final String DEVICE = "Mouse"; private Point lastPosition; private Point lastClickPosition; private long lastClickTime = 0; private String lastClickButton = ""; private Input myInput; private InputDevice inDev = this; private Map<Integer, String> mouseNameMap; private List<ButtonState> downButtons = new ArrayList<ButtonState>(); private boolean gestureAlreadyNotified = false; /** * Constructs a Mouse Input object with a component to set up listeners * to and an Input object to send actions to. * @param component * @param input */ public MouseInput(JComponent component, Input input) { super(DEVICE, input); myComponent = component; mouseNameMap = new HashMap<Integer, String>(); mouseNameMap.put(MouseEvent.BUTTON1, "Left"); mouseNameMap.put(MouseEvent.BUTTON2, "Center"); mouseNameMap.put(MouseEvent.BUTTON3, "Right"); initialize(); myInput = input; } /** * Creates a Position Object containing the data in a MouseEvent. * @param e * @return */ private PositionObject makePositionObject(MouseEvent e) { return new PositionObject(e.getX(), myComponent.getWidth(), e.getY(), myComponent.getHeight(), e.getWhen()); } /** * Creates a RollObject containing the data in a MouseWheelEvent * @param e * @return */ private RollObject makeWheelObject(MouseWheelEvent e) { return new RollObject(e.getWhen(), e.getWheelRotation()); } /** * Returns the wall closest to the given point. * @return */ private String getClosestWall() { int[] wallDistances = new int[5]; String[] walls = { "Left", "Right", "Top", "Bottom" }; wallDistances[0] = lastPosition.x; wallDistances[1] = myComponent.getWidth() - lastPosition.x; wallDistances[2] = lastPosition.y; wallDistances[3] = myComponent.getHeight() - lastPosition.y; int min = 9999; int minIndex = 0; for (int i = 0; i < 4; i++) { int newMin = Math.min(wallDistances[i], min); if (newMin != min) { minIndex = i; } min = newMin; } return walls[minIndex]; } /** * Returns the direction that a point is from (0, 0) * @return */ private String getDirection(Point pt) { String[] walls = { "Right", "Left", "Down", "Up" }; int index = (Math.abs(pt.x) - Math.abs(pt.y) > 0) ? ((int) Math .signum(pt.x) + 1) / 2 : ((int) Math.signum(pt.y) + 1) / 2 + 2; return walls[index]; } /** * Sets up a mouse listener. implements MouseMotionAdapter with * mouseMove and MouseDrag */ private void initialize() { myComponent.addMouseMotionListener(new MouseMotionAdapter() { public void mouseMoved(MouseEvent e) { lastPosition = e.getPoint(); notifyInputAction("Mouse_Move", makePositionObject(e)); } public void mouseDragged(MouseEvent e) { lastPosition = e.getPoint(); notifyInputAction("Mouse_Drag", makePositionObject(e)); for (ButtonState downButton : downButtons) { if (!gestureAlreadyNotified && downButton.getPosition() != null && lastPosition.distance(downButton.getPosition()) > Integer.parseInt(myInput .getSetting("DoubleClickDistanceThreshold"))) { notifyInputAction( downButton.getFullName() + "_Drag" + getDirection(new Point(downButton .getPosition().x - lastPosition.x, downButton .getPosition().y - lastPosition.y)), makePositionObject(e)); gestureAlreadyNotified = true; } } } }); myComponent.addMouseListener(new MouseListener() { //Required by the MouseListener Interface but unused @Override public void mouseClicked(MouseEvent e) { } @Override public void mouseEntered(MouseEvent e) { notifyInputAction("Mouse_MoveIn", makePositionObject(e)); } @Override public void mouseExited(MouseEvent e) { if (lastPosition != null) { notifyInputAction("Mouse_MoveOut", makePositionObject(e)); notifyInputAction("Mouse_MoveOut" + getClosestWall(), makePositionObject(e)); for (ButtonState downButton : downButtons) { notifyInputAction(downButton.getFullName() + "_DragOut" + getClosestWall(), makePositionObject(e)); } if (!downButtons.isEmpty()) notifyInputAction("Mouse_DragOut", makePositionObject(e)); } } @Override public void mousePressed(MouseEvent e) { String buttonName = mouseNameMap.get(e.getButton()); ButtonState downButton = new ButtonState(DEVICE, buttonName, e.getWhen(), inDev, e.getPoint()); downButtons.add(downButton); notifyInputAction("Mouse_" + buttonName + "_Down", makePositionObject(e)); } @Override public void mouseReleased(MouseEvent e) { String buttonName = mouseNameMap.get(e.getButton()); ButtonState temp = new ButtonState(DEVICE, buttonName, e .getWhen(), inDev); notifyInputAction(temp.getFullName() + "_Up", makePositionObject(e)); notifyInputAction(temp.getFullName() + "_KeyUp", makePositionObject(e)); // Legacy Support notifyInputAction(temp.getFullName() + "_Click", makePositionObject(e)); // Legacy Support long timeDifference = temp.getTime() - downButtons.remove(downButtons.indexOf(temp)) .getTime(); if (timeDifference < Integer.parseInt(myInput .getSetting("ShortClickTimeThreshold"))) { notifyInputAction(temp.getFullName() + "_ShortClick", makePositionObject(e)); } if (timeDifference > Integer.parseInt(myInput .getSetting("LongClickTimeThreshold"))) { notifyInputAction(temp.getFullName() + "_LongClick", makePositionObject(e)); } if (lastClickPosition != null && lastClickButton.equals(buttonName) && lastClickPosition.distance(e.getPoint()) < Integer.parseInt(myInput .getSetting("DoubleClickDistanceThreshold")) && e.getWhen() - lastClickTime < Integer.parseInt(myInput .getSetting("DoubleClickTimeThreshold"))) { notifyInputAction(temp.getFullName() + "_DoubleClick", makePositionObject(e)); } lastClickPosition = e.getPoint(); lastClickTime = e.getWhen(); lastClickButton = buttonName; gestureAlreadyNotified = false; } }); myComponent.addMouseWheelListener(new MouseWheelListener() { /** * This will send two types of signals. It will send * "Mouse_Wheel_Down" signal if the user scrolls the wheel towards * him and it will send "Mouse_Wheel_Up" signal if the user scrolls * the wheel away from him. */ @Override public void mouseWheelMoved(MouseWheelEvent e) { if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) { if (e.getWheelRotation() > 0) notifyInputAction(DEVICE + "_Wheel" + "_Down", makeWheelObject(e)); else notifyInputAction(DEVICE + "_Wheel" + "_Up", makeWheelObject(e)); } } }); } /** * Notifies the Input class of input events as they occur. * @param keyInfo * @param e */ public void notifyInput(String keyInfo, MouseEvent e) { notifyInputAction(keyInfo, makePositionObject(e)); } }