/*
* $Id$
*
* Copyright (C) 2003-2015 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library 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 Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.awt;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import org.jnode.driver.input.PointerEvent;
import org.jnode.driver.input.PointerListener;
import org.jnode.driver.video.HardwareCursorAPI;
/**
* @author Levente S\u00e1ntha
*/
public class AWTMouseEventGenerator implements PointerListener {
private static final int[] BUTTON_MASK = {
PointerEvent.BUTTON_LEFT, PointerEvent.BUTTON_RIGHT, PointerEvent.BUTTON_MIDDLE
};
private static final int[] BUTTON_NUMBER = {1, 2, 3};
private static int CLICK_REPEAT_DURATION = 400;
/**
* Queue where to post my events
*/
private final EventQueue eventQueue;
private final HardwareCursorAPI hwCursor;
private final KeyboardHandler keyboardHandler;
private final Dimension screenSize;
private boolean[] buttonPressed = new boolean[3];
private int[] buttonClickCount = new int[3];
private long[] buttonClickTime = new long[3];
private boolean postClicked = false;
private Component lastSource;
private Component dragSource;
private int x;
private int y;
public AWTMouseEventGenerator(EventQueue eventQueue, Dimension screenSize, HardwareCursorAPI hwCursor,
KeyboardHandler keyboardHandler) {
this.eventQueue = eventQueue;
this.screenSize = screenSize;
this.hwCursor = hwCursor;
this.keyboardHandler = keyboardHandler;
}
public void pointerStateChanged(PointerEvent event) {
long time = System.currentTimeMillis();
x = Math.min(screenSize.width - 1, Math.max(0, x + event.getX()));
y = Math.min(screenSize.height - 1, Math.max(0, y + event.getY()));
hwCursor.setCursorPosition(x, y);
Component source = findSource();
if (source == null || !source.isShowing()) return;
final int buttons = event.getButtons();
boolean eventFired = false;
for (int i = 0; i < 3; i++) {
if (time - buttonClickTime[i] > CLICK_REPEAT_DURATION) {
buttonClickTime[i] = 0;
buttonClickCount[i] = 0;
} else {
buttonClickTime[i] = time;
}
if ((buttons & BUTTON_MASK[i]) != 0) {
if (!buttonPressed[i]) {
buttonClickCount[i] += 1;
buttonClickTime[i] = time;
postEvent(source, MouseEvent.MOUSE_PRESSED, time, buttonClickCount[i], BUTTON_NUMBER[i]);
dragSource = source;
buttonPressed[i] = true;
eventFired = true;
postClicked = true;
break;
}
} else if (buttonPressed[i]) {
postEvent(dragSource, MouseEvent.MOUSE_RELEASED, time, buttonClickCount[i], BUTTON_NUMBER[i]);
if (postClicked || !postClicked && buttonClickCount[i] > 0) {
postEvent(source, MouseEvent.MOUSE_CLICKED, time, buttonClickCount[i], BUTTON_NUMBER[i]);
postClicked = false;
}
buttonPressed[i] = false;
eventFired = true;
break;
}
}
if (source != lastSource) {
if (lastSource != null) {
// Notify mouse exited
postEvent(lastSource, MouseEvent.MOUSE_EXITED, time, 0, MouseEvent.NOBUTTON);
}
// Notify mouse entered
postEvent(source, MouseEvent.MOUSE_ENTERED, time, 0, MouseEvent.NOBUTTON);
for (int i = buttonClickTime.length; --i > 0; buttonClickTime[i] = 0) ;
eventFired = true;
postClicked = false;
}
if (!eventFired) {
if (buttonPressed[0]) {
postEvent(dragSource, MouseEvent.MOUSE_DRAGGED, time, buttonClickCount[0], MouseEvent.BUTTON1);
} else if (buttonPressed[1]) {
postEvent(dragSource, MouseEvent.MOUSE_DRAGGED, time, buttonClickCount[1], MouseEvent.BUTTON2);
} else if (buttonPressed[2]) {
postEvent(dragSource, MouseEvent.MOUSE_DRAGGED, time, buttonClickCount[2], MouseEvent.BUTTON3);
} else {
postEvent(source, MouseEvent.MOUSE_MOVED, time, 0, MouseEvent.NOBUTTON);
}
postClicked = false;
}
lastSource = source;
}
/**
* Post a mouse event with the given id and button.
*
* @param id
* @param button
*/
private void postEvent(Component source, int id, long time, int clickCount, int button) {
if (!source.isShowing()) return;
// final Window w = SwingUtilities.getWindowAncestor(source);
// Point pwo = null;
// if (w != null && w.isShowing()) {
// pwo = w.getLocationOnScreen();
// } else {
// pwo = new Point(-1, -1);
// }
final Point p = source.getLocationOnScreen();
final boolean popupTrigger = (button == MouseEvent.BUTTON2);
final int ex = x - p.x; // - pwo.x;
final int ey = y - p.y; // - pwo.y;
final int modifiers = getModifiers();
final MouseEvent event = new MouseEvent(source, id, time, modifiers, ex, ey,
clickCount, popupTrigger, button);
eventQueue.postEvent(event);
}
private final Component findSource() {
final JNodeToolkit tk = (JNodeToolkit) Toolkit.getDefaultToolkit();
Component source = tk.getTopComponentAt(x, y);
if ((source != null) && source.isShowing()) {
return source;
} else {
return null;
}
}
private final int getModifiers() {
int modifiers = 0;
if (buttonPressed[0]) modifiers |= MouseEvent.BUTTON1_MASK;
if (buttonPressed[1]) modifiers |= MouseEvent.BUTTON2_MASK;
if (buttonPressed[2]) modifiers |= MouseEvent.BUTTON3_MASK;
return modifiers | keyboardHandler.getModifiers();
}
}