/*******************************************************************************
* Breakout Cave Survey Visualizer
*
* Copyright (C) 2014 James Edwards
*
* jedwards8 at fastmail dot fm
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*******************************************************************************/
package com.andork.plot;
import static java.awt.event.InputEvent.BUTTON1_DOWN_MASK;
import static java.awt.event.InputEvent.BUTTON2_DOWN_MASK;
import static java.awt.event.InputEvent.BUTTON3_DOWN_MASK;
import java.awt.AWTException;
import java.awt.Component;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.SwingUtilities;
public class MouseLooper extends MouseAdapter {
private static Robot createRobot() {
try {
return new Robot();
} catch (AWTException ex) {
return null;
}
}
Robot robot;
MouseEvent pressEvent;
Point lastDragPoint;
int xOffset;
int yOffset;
Point fakeLocation = null;
Point fakeLocationOnScreen = null;
List<MouseAdapter> adapters = new ArrayList<MouseAdapter>();
public MouseLooper() {
this(createRobot());
}
public MouseLooper(Robot robot) {
this.robot = robot;
}
public void addMouseAdapter(MouseAdapter a) {
if (!adapters.contains(a)) {
adapters.add(a);
}
}
@Override
public void mouseClicked(MouseEvent e) {
MouseEvent re = repositionEvent(e);
for (MouseAdapter adapter : adapters) {
adapter.mouseClicked(re);
}
}
@Override
public void mouseDragged(MouseEvent e) {
if (pressEvent == null) {
return;
}
if (robot != null) {
Component c = e.getComponent();
Rectangle bounds;
if (c instanceof JComponent) {
bounds = ((JComponent) c).getVisibleRect();
} else {
bounds = SwingUtilities.getLocalBounds(c);
}
Point p = new Point();
SwingUtilities.convertPointToScreen(p, c);
bounds.setLocation(p);
Rectangle screenBounds = c.getGraphicsConfiguration().getBounds();
screenBounds.x++;
screenBounds.y++;
screenBounds.width -= 2;
screenBounds.height -= 2;
bounds = bounds.intersection(screenBounds);
bounds.x -= p.x;
bounds.y -= p.y;
if (lastDragPoint != null) {
xOffset += e.getX() - lastDragPoint.x;
yOffset += e.getY() - lastDragPoint.y;
}
if (!bounds.contains(e.getPoint())) {
int newX = (e.getX() - bounds.x) % bounds.width;
if (newX < 0) {
newX += bounds.width;
}
newX += bounds.x;
int newY = (e.getY() - bounds.y) % bounds.height;
if (newY < 0) {
newY += bounds.height;
}
newY += bounds.y;
Point newLoc = new Point();
SwingUtilities.convertPointToScreen(newLoc, c);
lastDragPoint = null;
robot.mouseMove(newLoc.x + newX, newLoc.y + newY);
} else {
lastDragPoint = e.getPoint();
}
if (fakeLocation == null) {
fakeLocation = new Point();
fakeLocationOnScreen = new Point();
}
fakeLocation.x = pressEvent.getX() + xOffset;
fakeLocation.y = pressEvent.getY() + yOffset;
fakeLocationOnScreen.x = pressEvent.getXOnScreen() + xOffset;
fakeLocationOnScreen.y = pressEvent.getYOnScreen() + yOffset;
}
MouseEvent re = repositionEvent(e);
for (MouseAdapter adapter : adapters) {
adapter.mouseDragged(re);
}
}
@Override
public void mouseEntered(MouseEvent e) {
MouseEvent re = repositionEvent(e);
for (MouseAdapter adapter : adapters) {
adapter.mouseEntered(re);
}
}
@Override
public void mouseExited(MouseEvent e) {
MouseEvent re = repositionEvent(e);
for (MouseAdapter adapter : adapters) {
adapter.mouseExited(re);
}
}
@Override
public void mouseMoved(MouseEvent e) {
MouseEvent re = repositionEvent(e);
for (MouseAdapter adapter : adapters) {
adapter.mouseMoved(re);
}
}
@Override
public void mousePressed(MouseEvent e) {
if (pressEvent == null) {
pressEvent = e;
lastDragPoint = null;
xOffset = 0;
yOffset = 0;
}
MouseEvent re = repositionEvent(e);
for (MouseAdapter adapter : adapters) {
adapter.mousePressed(re);
}
}
@Override
public void mouseReleased(MouseEvent e) {
MouseEvent re = repositionEvent(e);
for (MouseAdapter adapter : adapters) {
adapter.mouseReleased(re);
}
if ((e.getModifiersEx() & (BUTTON1_DOWN_MASK | BUTTON2_DOWN_MASK | BUTTON3_DOWN_MASK)) == 0) {
pressEvent = null;
lastDragPoint = null;
fakeLocation = null;
fakeLocationOnScreen = null;
}
}
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
MouseWheelEvent re = repositionEvent(e);
for (MouseAdapter adapter : adapters) {
adapter.mouseWheelMoved(re);
}
}
public void removeMouseAdapter(MouseAdapter a) {
adapters.remove(a);
}
private MouseEvent repositionEvent(MouseEvent e) {
if (fakeLocation == null) {
return e;
}
return new MouseEvent(e.getComponent(), e.getID(), e.getWhen(), e.getModifiers(),
fakeLocation.x, fakeLocation.y, fakeLocationOnScreen.x, fakeLocationOnScreen.y,
e.getClickCount(), e.isPopupTrigger(), e.getButton());
}
private MouseWheelEvent repositionEvent(MouseWheelEvent e) {
if (fakeLocation == null) {
return e;
}
MouseWheelEvent mwe = e;
return new MouseWheelEvent(e.getComponent(), e.getID(), e.getWhen(), e.getModifiers(),
fakeLocation.x, fakeLocation.y, fakeLocationOnScreen.x, fakeLocationOnScreen.y,
e.getClickCount(), e.isPopupTrigger(),
mwe.getScrollType(), mwe.getScrollAmount(), mwe.getWheelRotation());
}
}