Package org.jnode.awt

Source Code of org.jnode.awt.MouseHandler$PointerAPIHandler

/*
* $Id$
*
* Copyright (C) 2003-2014 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 java.awt.event.MouseWheelEvent;
import java.util.Collection;
import java.util.HashSet;
import java.security.AccessController;
import java.security.PrivilegedAction;
import org.apache.log4j.Logger;
import org.jnode.driver.ApiNotFoundException;
import org.jnode.driver.Device;
import org.jnode.driver.DeviceUtils;
import org.jnode.driver.DeviceListener;
import org.jnode.driver.DeviceManager;
import org.jnode.driver.input.PointerAPI;
import org.jnode.driver.input.PointerEvent;
import org.jnode.driver.input.PointerListener;
import org.jnode.driver.video.HardwareCursor;
import org.jnode.driver.video.HardwareCursorAPI;
import javax.naming.NameNotFoundException;

/**
* @author Ewout Prangsma (epr@users.sourceforge.net)
* @author Levente S\u00e1ntha
*/
public class MouseHandler implements PointerListener {
    //todo refactor this pattern to be generally available in JNode for AWT and text consoles as well
    private static class PointerAPIHandler implements PointerAPI, DeviceListener {
        private Collection<PointerAPI> pointerList = new HashSet<PointerAPI>();
        private Collection<PointerListener> listenerList = new HashSet<PointerListener>();

        PointerAPIHandler() {
            try {
                DeviceManager dm = DeviceUtils.getDeviceManager();
                dm.addListener(this);
                for (Device device : dm.getDevicesByAPI(PointerAPI.class)) {
                    try {
                        pointerList.add(device.getAPI(PointerAPI.class));
                    } catch (ApiNotFoundException anfe) {
                        //ignore
                    }
                }
            } catch (NameNotFoundException nfe) {
                nfe.printStackTrace();
            }
        }

        public void addPointerListener(PointerListener listener) {
            listenerList.add(listener);
            for (PointerAPI api : pointerList) {
                api.addPointerListener(listener);
            }
        }

        public void removePointerListener(PointerListener listener) {
            listenerList.remove(listener);
            for (PointerAPI api : pointerList) {
                api.removePointerListener(listener);
            }
        }

        public void setPreferredListener(PointerListener listener) {
            for (PointerAPI api : pointerList) {
                api.setPreferredListener(listener);
            }
        }

        public void deviceStarted(Device device) {
            if (device.implementsAPI(PointerAPI.class)) {
                try {
                    PointerAPI api = device.getAPI(PointerAPI.class);
                    pointerList.add(api);
                    for (PointerListener listener : listenerList) {
                        api.addPointerListener(listener);
                    }
                } catch (ApiNotFoundException anfe) {
                    //ignore
                }
            }
        }

        public void deviceStop(Device device) {
            if (device.implementsAPI(PointerAPI.class)) {
                try {
                    PointerAPI api = device.getAPI(PointerAPI.class);
                    pointerList.remove(api);
                    for (PointerListener listener : listenerList) {
                        api.removePointerListener(listener);
                    }
                } catch (ApiNotFoundException anfe) {
                    //ignore
                }
            }
        }

        boolean hasPointer() {
            return !pointerList.isEmpty();
        }
    }

    private final PointerAPI pointerAPI;

    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 int lastButtons = 0;
    private final boolean[] buttonPressed = new boolean[3];
    private final int[] buttonClickCount = new int[3];
    private final long[] buttonClickTime = new long[3];
    private boolean postClicked = false;

    private static final Logger log = Logger.getLogger(MouseHandler.class);

    private Component lastSource;
    private Component dragSource;

    private int x;

    private int y;

    /**
     * Create a new instance.
     *
     * @param fbDevice        a frame buffer device
     * @param screenSize      screen size
     * @param eventQueue      the event queue instance
     * @param keyboardHandler keyboard handler
     */
    public MouseHandler(Device fbDevice, Dimension screenSize,
                        EventQueue eventQueue, KeyboardHandler keyboardHandler) {
        this.eventQueue = eventQueue;
        HardwareCursorAPI hwCursor = null;

        try {
            hwCursor = fbDevice.getAPI(HardwareCursorAPI.class);
        } catch (ApiNotFoundException ex) {
            log.info("No hardware-cursor found on device " + fbDevice.getId());
        }

        this.keyboardHandler = keyboardHandler;
        this.hwCursor = hwCursor;
        this.screenSize = screenSize;

        if (hwCursor != null) {
            hwCursor.setCursorImage(JNodeCursors.ARROW);
            hwCursor.setCursorVisible(true);
            hwCursor.setCursorPosition(0, 0);
        }
        this.pointerAPI = new PointerAPIHandler();
        pointerAPI.addPointerListener(this);
        AccessController.doPrivileged(new PrivilegedAction<Void>() {
            public Void run() {
                MouseHandler.this.pointerAPI.setPreferredListener(MouseHandler.this);
                return null;
            }
        });
    }

    void setCursorImage(HardwareCursor ci) {
        if (hwCursor != null) {
            synchronized (this) {
                hwCursor.setCursorImage(ci);
                hwCursor.setCursorVisible(true);
            }
        }
    }

    /**
     * Close this handler
     */
    public void close() {
        if (pointerAPI != null) {
            pointerAPI.removePointerListener(this);           
        }
       
        if (hwCursor != null) {
            // hide the cursor so that it won't stay displayed
            // if we stay in graphic mode
            hwCursor.setCursorVisible(false);
        }
    }

    /**
     * Move the mouse pointer to absolute coordinates (x, y).
     *
     * @param x the destination x coordinate
     * @param y the destination y coordinate
     * @see java.awt.peer.RobotPeer#mouseMove(int, int)
     */
    void mouseMove(int x, int y) {
        // buttons and z unchanged (true means absolute values)
        pointerStateChanged(lastButtons, x, y, 0, true);
    }

    /**
     * Press one or more mouse buttons.
     *
     * @param buttons the buttons to press; a bitmask of one or more of
     *                these {@link java.awt.event.InputEvent} fields:
     *                <p/>
     *                <ul>
     *                <li>BUTTON1_MASK</li>
     *                <li>BUTTON2_MASK</li>
     *                <li>BUTTON3_MASK</li>
     *                </ul>
     * @see java.awt.peer.RobotPeer#mousePress(int)
     */
    void mousePress(int buttons) {
        // x, y and z unchanged (false means relative values)
        pointerStateChanged(buttons | lastButtons, 0, 0, 0, false);
    }

    /**
     * Release one or more mouse buttons.
     *
     * @param buttons the buttons to release; a bitmask of one or more
     *                of these {@link java.awt.event.InputEvent} fields:
     *                <p/>
     *                <ul>
     *                <li>BUTTON1_MASK</li>
     *                <li>BUTTON2_MASK</li>
     *                <li>BUTTON3_MASK</li>
     *                </ul>
     * @see java.awt.peer.RobotPeer#mouseRelease(int)
     */
    void mouseRelease(int buttons) {
        // x, y and z unchanged (false means relative values)
        pointerStateChanged(lastButtons & (~buttons), 0, 0, 0, false);
    }

    /**
     * Rotate the mouse scroll wheel.
     *
     * @param wheelAmt number of steps to rotate mouse wheel.  negative
     *                 to rotate wheel up (away from the user), positive to rotate wheel
     *                 down (toward the user). So, this is a relative value.
     * @see java.awt.peer.RobotPeer#mouseWheel(int)
     */
    void mouseWheel(int wheelAmt) {
        // buttons, x and y unchanged (false means relative values)
        pointerStateChanged(lastButtons, 0, 0, wheelAmt, false);
    }

    int getX() {
        return x;
    }

    int getY() {
        return y;
    }

    void setCursor(int x, int y) {
        this.x = x;
        this.y = y;
        if (hwCursor != null)
            hwCursor.setCursorPosition(x, y);
    }

    public void pointerStateChanged(PointerEvent event) {
        pointerStateChanged(event.getButtons(), event.getX(), event.getY(),
            event.getZ(), event.isAbsolute());
        event.consume();
    }

    /**
     * @param buttons  a vlaue encoding the state of mouse buttons
     * @param newX     a relative or absolute value for x coordinate
     * @param newY     a relative or absolute value for y coordinate
     * @param newZ     a relative or absolute value for wheel mouse
     * @param absolute are newX, newY and newZ relative or absolute values ?
     */
    void pointerStateChanged(int buttons, int newX, int newY, int newZ, boolean absolute) {
        long time = System.currentTimeMillis();
        final int newAbsX = absolute ? newX : x + newX;
        final int newAbsY = absolute ? newY : y + newY;
        x = Math.min(screenSize.width - 1, Math.max(0, newAbsX));
        y = Math.min(screenSize.height - 1, Math.max(0, newAbsY));
        if (hwCursor != null) hwCursor.setCursorPosition(x, y);

        lastButtons = buttons;

        Component source = findSource();
        if (source == null || !source.isShowing()) return;
        if (newZ != 0) {
            postEvent(source, MouseEvent.MOUSE_WHEEL, time, 0, MouseEvent.NOBUTTON, newZ);
        }

        boolean eventFired = false;
        for (int i = 0; i < 3; i++) {
            if (time - buttonClickTime[i] > CLICK_REPEAT_DURATION) {
                buttonClickCount[i] = 0;
            }

            if ((buttons & BUTTON_MASK[i]) != 0) {
                if (!buttonPressed[i]) {
                    buttonClickTime[i] = time;
                    buttonClickCount[i] += 1;
                    postEvent(source, MouseEvent.MOUSE_PRESSED, time, buttonClickCount[i], BUTTON_NUMBER[i], 0);
                    dragSource = source;
                    buttonPressed[i] = true;
                    eventFired = true;
                    postClicked = true;
                    break;
                }
            } else if (buttonPressed[i]) {
                buttonClickTime[i] = time;
                postEvent(dragSource, MouseEvent.MOUSE_RELEASED, time, buttonClickCount[i], BUTTON_NUMBER[i], 0);
                if (postClicked || buttonClickCount[i] > 0) {
                    postEvent(source, MouseEvent.MOUSE_CLICKED, time, buttonClickCount[i], BUTTON_NUMBER[i], 0);
                    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, 0);
                if (lastSource.isCursorSet())
                    lastSource.setCursor(lastSource.getCursor());
            }
            // Notify mouse entered
            postEvent(source, MouseEvent.MOUSE_ENTERED, time, 0, MouseEvent.NOBUTTON, 0);
            if (source.isCursorSet())
                source.setCursor(source.getCursor());

            eventFired = true;
            postClicked = false;
        }

        if (!eventFired) {
            if (buttonPressed[0]) {
                postEvent(dragSource, MouseEvent.MOUSE_DRAGGED, time, buttonClickCount[0], MouseEvent.BUTTON1, 0);
            } else if (buttonPressed[1]) {
                postEvent(dragSource, MouseEvent.MOUSE_DRAGGED, time, buttonClickCount[1], MouseEvent.BUTTON2, 0);
            } else if (buttonPressed[2]) {
                postEvent(dragSource, MouseEvent.MOUSE_DRAGGED, time, buttonClickCount[2], MouseEvent.BUTTON3, 0);
            } else {
                postEvent(source, MouseEvent.MOUSE_MOVED, time, 0, MouseEvent.NOBUTTON, 0);
            }
            postClicked = false;
        }
        lastSource = source;
    }

    /**
     * Post a mouse event with the given properties.
     *
     * @param source     the source component of the event
     * @param id         the event identifier
     * @param time       the time of occurence of this event
     * @param clickCount the number of mouse clicks
     * @param button     the mouse button in action
     * @param wheelAmt   the amount that the mouse wheel was rotated
     */
    private void postEvent(Component source, int id, long time, int clickCount, int button, int wheelAmt) {
        if (!source.isShowing()) return;
//        final Window w = SwingUtilities.getWindowAncestor(source);
//        Point pwo;
//        if (w != null && w.isShowing()) {
//            pwo = w.getLocationOnScreen();
//        } else {
//            pwo = new Point(0, 0);
//        }

        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();
        MouseEvent event;
        if (id == MouseEvent.MOUSE_WHEEL) {
            event = new MouseWheelEvent(source, id, time, modifiers, ex, ey,
                1, popupTrigger, MouseWheelEvent.WHEEL_UNIT_SCROLL,
                wheelAmt, //TODO check what to put here
                wheelAmt); //TODO check what to put here
        } else {
            event = new MouseEvent(source, id, time, modifiers, ex, ey,
                clickCount, popupTrigger, button);
            if (id == MouseEvent.MOUSE_PRESSED) {
                ((JNodeToolkit) Toolkit.getDefaultToolkit()).activateWindow(source);
            }
        }

        //debug
        /*
        if (
            id == MouseEvent.MOUSE_PRESSED ||
            id == MouseEvent.MOUSE_RELEASED ||
            id == MouseEvent.MOUSE_CLICKED ||
            id == MouseEvent.MOUSE_ENTERED ||
            id == MouseEvent.MOUSE_EXITED
            ) {

              org.jnode.vm.Unsafe.debug(event.toString()+"\n");
              org.jnode.vm.Unsafe.debug("x="+ x + " y=" + y +" ex="+ ex + " ey=" + ey +
                  " p.x=" + p.x + " p.y=" + p.y +"\n");
        }
        */
        //todo enable this for isolate support in the gui
        //JNodeToolkit.postToTarget(event, source);
        eventQueue.postEvent(event);
    }

    private 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 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();
    }
}
TOP

Related Classes of org.jnode.awt.MouseHandler$PointerAPIHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.