1 /* 2 * Copyright (c) 2002-2008 LWJGL Project 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * * Neither the name of 'LWJGL' nor the names of 17 * its contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 package org.lwjgl.opengl; 33 34 /** 35 * An AWT implementation of a LWJGL compatible Mouse event queue. 36 * @author elias_naur 37 */ 38 39 import java.awt.Component; 40 import java.awt.Point; 41 import java.awt.event.MouseEvent; 42 import java.awt.event.MouseListener; 43 import java.awt.event.MouseMotionListener; 44 import java.awt.event.MouseWheelEvent; 45 import java.awt.event.MouseWheelListener; 46 import java.nio.ByteBuffer; 47 import java.nio.IntBuffer; 48 49 import org.lwjgl.input.Mouse; 50 51 class MouseEventQueue extends EventQueue implements MouseListener, MouseMotionListener, MouseWheelListener { 52 private static final int WHEEL_SCALE = 120; 53 public static final int NUM_BUTTONS = 3; 54 55 private final Component component; 56 57 private boolean grabbed; 58 59 /** The accumulated mouse deltas returned by poll() */ 60 private int accum_dx; 61 private int accum_dy; 62 private int accum_dz; 63 64 /** The last mouse position */ 65 private int last_x; 66 private int last_y; 67 68 /** Saved control key state for ctrl-click right button emulation */ 69 private boolean saved_control_state; 70 71 /** Event scratch array */ 72 private final ByteBuffer event = ByteBuffer.allocate(Mouse.EVENT_SIZE); 73 74 /** Buttons array */ 75 private final byte[] buttons = new byte[NUM_BUTTONS]; 76 MouseEventQueue(Component component)77 MouseEventQueue(Component component) { 78 super(Mouse.EVENT_SIZE); 79 this.component = component; 80 } 81 register()82 public synchronized void register() { 83 resetCursorToCenter(); 84 if (component != null) { 85 component.addMouseListener(this); 86 component.addMouseMotionListener(this); 87 component.addMouseWheelListener(this); 88 } 89 } 90 unregister()91 public synchronized void unregister() { 92 if (component != null) { 93 component.removeMouseListener(this); 94 component.removeMouseMotionListener(this); 95 component.removeMouseWheelListener(this); 96 } 97 } 98 getComponent()99 protected Component getComponent() { 100 return component; 101 } 102 setGrabbed(boolean grabbed)103 public synchronized void setGrabbed(boolean grabbed) { 104 this.grabbed = grabbed; 105 resetCursorToCenter(); 106 } 107 isGrabbed()108 public synchronized boolean isGrabbed() { 109 return grabbed; 110 } 111 transformY(int y)112 protected int transformY(int y) { 113 if (component != null) { 114 return component.getHeight() - 1 - y; 115 } 116 return y; 117 } 118 resetCursorToCenter()119 protected void resetCursorToCenter() { 120 clearEvents(); 121 accum_dx = accum_dy = 0; 122 if (component != null) { 123 Point cursor_location = AWTUtil.getCursorPosition(component); 124 if (cursor_location != null) { 125 last_x = cursor_location.x; 126 last_y = cursor_location.y; 127 } 128 } 129 } 130 putMouseEvent(byte button, byte state, int dz, long nanos)131 private void putMouseEvent(byte button, byte state, int dz, long nanos) { 132 if (grabbed) 133 putMouseEventWithCoords(button, state, 0, 0, dz, nanos); 134 else 135 putMouseEventWithCoords(button, state, last_x, last_y, dz, nanos); 136 } 137 putMouseEventWithCoords(byte button, byte state, int coord1, int coord2, int dz, long nanos)138 protected void putMouseEventWithCoords(byte button, byte state, int coord1, int coord2, int dz, long nanos) { 139 event.clear(); 140 event.put(button).put(state).putInt(coord1).putInt(coord2).putInt(dz).putLong(nanos); 141 event.flip(); 142 putEvent(event); 143 } 144 poll(IntBuffer coord_buffer, ByteBuffer buttons_buffer)145 public synchronized void poll(IntBuffer coord_buffer, ByteBuffer buttons_buffer) { 146 if ( grabbed ) { 147 coord_buffer.put(0, accum_dx); 148 coord_buffer.put(1, accum_dy); 149 } else { 150 coord_buffer.put(0, last_x); 151 coord_buffer.put(1, last_y); 152 } 153 coord_buffer.put(2, accum_dz); 154 accum_dx = accum_dy = accum_dz = 0; 155 int old_position = buttons_buffer.position(); 156 buttons_buffer.put(buttons, 0, buttons.length); 157 buttons_buffer.position(old_position); 158 } 159 setCursorPos(int x, int y, long nanos)160 private void setCursorPos(int x, int y, long nanos) { 161 y = transformY(y); 162 if ( grabbed ) 163 return; 164 int dx = x - last_x; 165 int dy = y - last_y; 166 addDelta(dx, dy); 167 last_x = x; 168 last_y = y; 169 putMouseEventWithCoords((byte)-1, (byte)0, x, y, 0, nanos); 170 } 171 addDelta(int dx, int dy)172 protected void addDelta(int dx, int dy) { 173 accum_dx += dx; 174 accum_dy += dy; 175 } 176 mouseClicked(MouseEvent e)177 public void mouseClicked(MouseEvent e) { 178 } 179 mouseEntered(MouseEvent e)180 public void mouseEntered(MouseEvent e) { 181 } 182 mouseExited(MouseEvent e)183 public void mouseExited(MouseEvent e) { 184 } 185 handleButton(MouseEvent e)186 private void handleButton(MouseEvent e) { 187 byte state; 188 switch (e.getID()) { 189 case MouseEvent.MOUSE_PRESSED: 190 state = 1; 191 break; 192 case MouseEvent.MOUSE_RELEASED: 193 state = 0; 194 break; 195 default: 196 throw new IllegalArgumentException("Not a valid event ID: " + e.getID()); 197 } 198 byte button; 199 switch (e.getButton()) { 200 case MouseEvent.NOBUTTON: 201 // Nothing to do, so return 202 return; 203 case MouseEvent.BUTTON1: 204 // Emulate right click if ctrl is down 205 if (state == 1) 206 saved_control_state = e.isControlDown(); 207 if (saved_control_state) { 208 if (buttons[1] == state) 209 return; // ignore 210 button = (byte)1; 211 } else { 212 button = (byte)0; 213 } 214 break; 215 case MouseEvent.BUTTON2: 216 button = (byte)2; 217 break; 218 case MouseEvent.BUTTON3: 219 if (buttons[1] == state) 220 return; // ignore 221 button = (byte)1; 222 break; 223 default: 224 throw new IllegalArgumentException("Not a valid button: " + e.getButton()); 225 } 226 setButton(button, state, e.getWhen()*1000000); 227 } 228 mousePressed(MouseEvent e)229 public synchronized void mousePressed(MouseEvent e) { 230 handleButton(e); 231 } 232 setButton(byte button, byte state, long nanos)233 private void setButton(byte button, byte state, long nanos) { 234 buttons[button] = state; 235 putMouseEvent(button, state, 0, nanos); 236 } 237 mouseReleased(MouseEvent e)238 public synchronized void mouseReleased(MouseEvent e) { 239 handleButton(e); 240 } 241 handleMotion(MouseEvent e)242 private void handleMotion(MouseEvent e) { 243 if (grabbed) { 244 updateDeltas(e.getWhen()*1000000); 245 } else { 246 setCursorPos(e.getX(), e.getY(), e.getWhen()*1000000); 247 } 248 } 249 mouseDragged(MouseEvent e)250 public synchronized void mouseDragged(MouseEvent e) { 251 handleMotion(e); 252 } 253 mouseMoved(MouseEvent e)254 public synchronized void mouseMoved(MouseEvent e) { 255 handleMotion(e); 256 } 257 handleWheel(int amount, long nanos)258 private void handleWheel(int amount, long nanos) { 259 accum_dz += amount; 260 putMouseEvent((byte)-1, (byte)0, amount, nanos); 261 } 262 updateDeltas(long nanos)263 protected void updateDeltas(long nanos) { 264 } 265 mouseWheelMoved(MouseWheelEvent e)266 public synchronized void mouseWheelMoved(MouseWheelEvent e) { 267 int wheel_amount = -e.getWheelRotation() * WHEEL_SCALE; 268 handleWheel(wheel_amount, e.getWhen()*1000000); 269 } 270 } 271