/** * Copyright 2012 Jason Sorensen (sorensenj@smert.net) * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ package net.smert.frameworkgl.helpers; import java.util.ArrayList; import java.util.List; import net.smert.frameworkgl.Fw; import org.lwjgl.glfw.GLFW; /** * * @author Jason Sorensen <sorensenj@smert.net> */ public class MouseHelper { private final static int GLFW_MOUSE_BUTTON_MOVE = GLFW.GLFW_MOUSE_BUTTON_LAST + 1; private final static int MOUSE_SIZE = GLFW.GLFW_MOUSE_BUTTON_LAST + 2; // Extra for mouse move private boolean isGrabbed; private final boolean[] isDown; private final boolean[] nextState; private final boolean[] wasDown; private float deltaWheelWithSensitivity; private float deltaXWithSensitivity; private float deltaYWithSensitivity; private int deltaWheel; private int deltaX; private int deltaY; private int mouseRawX; private int mouseRawY; private int mouseX; private int mouseY; private final int[] lwjglToMouse; private final List<MouseEvent> mouseEvents; public MouseHelper() { isDown = new boolean[Mouse.MAX_MOUSE.ordinal()]; nextState = new boolean[Mouse.MAX_MOUSE.ordinal()]; wasDown = new boolean[Mouse.MAX_MOUSE.ordinal()]; lwjglToMouse = new int[MOUSE_SIZE]; mouseEvents = new ArrayList<>(); } private void clampMouseXY() { if (mouseX < 0) { mouseX = 0; } else if (mouseX > Fw.config.getCurrentWidth()) { mouseX = Fw.config.getCurrentWidth(); } if (mouseY < 0) { mouseY = 0; } else if (mouseY > Fw.config.getCurrentHeight()) { mouseY = Fw.config.getCurrentHeight(); } } private void mapLwglToMouse() { // Map to none for (int i = 0; i < MOUSE_SIZE; i++) { lwjglToMouse[i] = Mouse.NONE.ordinal(); } lwjglToMouse[GLFW.GLFW_MOUSE_BUTTON_1] = Mouse.LEFT.ordinal(); lwjglToMouse[GLFW.GLFW_MOUSE_BUTTON_2] = Mouse.RIGHT.ordinal(); lwjglToMouse[GLFW.GLFW_MOUSE_BUTTON_3] = Mouse.MIDDLE.ordinal(); lwjglToMouse[GLFW.GLFW_MOUSE_BUTTON_4] = Mouse.BACK.ordinal(); lwjglToMouse[GLFW.GLFW_MOUSE_BUTTON_5] = Mouse.FORWARD.ordinal(); lwjglToMouse[GLFW.GLFW_MOUSE_BUTTON_6] = Mouse.NONE.ordinal(); // Unknown lwjglToMouse[GLFW.GLFW_MOUSE_BUTTON_7] = Mouse.NONE.ordinal(); // Unknown lwjglToMouse[GLFW.GLFW_MOUSE_BUTTON_8] = Mouse.NONE.ordinal(); // Unknown lwjglToMouse[GLFW_MOUSE_BUTTON_MOVE] = Mouse.MOVE.ordinal(); } public void addEvent(int button, int modifiers, boolean state) { MouseEvent event = new MouseEvent(); event.button = button; event.deltaWheel = deltaWheel; event.deltaX = deltaX; event.deltaY = deltaY; event.mappedButton = lwjglToMouse[event.button]; event.modifiers = modifiers; event.mouseX = mouseX; event.mouseY = mouseY; event.state = state; mouseEvents.add(event); nextState[event.mappedButton] = event.state; } public void centerCursor() { setCursorPosition(Fw.config.getCurrentWidth() / 2, Fw.config.getCurrentHeight() / 2); } public void clearDelta() { deltaWheelWithSensitivity = 0; deltaXWithSensitivity = 0; deltaYWithSensitivity = 0; deltaWheel = 0; deltaX = 0; deltaY = 0; } public void clearEvents() { nextState[Mouse.MOVE.ordinal()] = false; nextState[Mouse.WHEEL_DOWN.ordinal()] = false; nextState[Mouse.WHEEL_UP.ordinal()] = false; clearDelta(); mouseEvents.clear(); } public void clearNextState() { for (int i = 0; i < Mouse.MAX_MOUSE.ordinal(); i++) { nextState[i] = false; } } public int getDeltaWheel() { return deltaWheel; } public float getDeltaWheelWithSensitivity() { return deltaWheelWithSensitivity; } public int getDeltaX() { return deltaX; } public float getDeltaXWithSensitivity() { return deltaXWithSensitivity; } public int getDeltaY() { return deltaY; } public float getDeltaYWithSensitivity() { return deltaYWithSensitivity; } public int getMouseX() { return mouseX; } public int getMouseY() { return mouseY; } public void setCursorPosition(int x, int y) { mouseRawX = mouseX = x; mouseRawY = mouseY = y; clampMouseXY(); GLFW.glfwSetCursorPos(Fw.window.getWindow(), mouseX, mouseY); } public List<MouseEvent> getMouseEvents() { return mouseEvents; } public boolean isButtonDown(int button) { if ((button < 0) || (button >= isDown.length)) { throw new IllegalArgumentException("Invalid button: " + button); } return isDown[button]; } public boolean wasButtonDown(int button) { if ((button < 0) || (button >= wasDown.length)) { throw new IllegalArgumentException("Invalid button: " + button); } return wasDown[button]; } public boolean isButtonDown(Mouse mouse) { return isDown[mouse.ordinal()]; } public boolean wasButtonDown(Mouse mouse) { return wasDown[mouse.ordinal()]; } public boolean isGrabbed() { return isGrabbed; } public void grabMouseCursor() { isGrabbed = true; centerCursor(); updateInputMode(); } public void handleMoveEvent(double x, double y) { int newX = (int) x; int newY = (int) y; deltaX = (newX - mouseRawX); deltaY = -(newY - mouseRawY); deltaXWithSensitivity = deltaX * Fw.config.getMouseMoveSensitivity(); deltaYWithSensitivity = deltaY * Fw.config.getMouseMoveSensitivity(); mouseRawX = newX; mouseRawY = newY; mouseX += deltaX; mouseY += deltaY; clampMouseXY(); float totalDelta = deltaX + deltaY; nextState[Mouse.MOVE.ordinal()] = (totalDelta != 0); } public void handleScrollEvent(double xoffset, double yoffset) { deltaWheel = (int) yoffset; deltaWheelWithSensitivity = deltaWheel * Fw.config.getMouseWheelSensitivity(); if (deltaWheel < 0) { nextState[Mouse.WHEEL_DOWN.ordinal()] = true; } else if (deltaWheel > 0) { nextState[Mouse.WHEEL_UP.ordinal()] = true; } } public void init() { mapLwglToMouse(); reset(); } public void releaseMouseCursor() { isGrabbed = false; centerCursor(); updateInputMode(); } public void reset() { for (int i = 0; i < Mouse.MAX_MOUSE.ordinal(); i++) { isDown[i] = false; nextState[i] = false; wasDown[i] = false; } } public void update() { for (int i = 0; i < MOUSE_SIZE; i++) { wasDown[i] = isDown[i]; // Save last frame isDown[i] = nextState[i]; // Set current frame } } public void updateInputMode() { int value; if (isGrabbed) { value = GLFW.GLFW_CURSOR_DISABLED; } else { value = GLFW.GLFW_CURSOR_NORMAL; } GLFW.glfwSetInputMode(Fw.window.getWindow(), GLFW.GLFW_CURSOR, value); } public static class MouseEvent { /** * The state indicates that the button has been pressed when true */ public boolean state; /** * The raw button from LWJGL */ public int button; /** * The raw delta mouse wheel change without getMouseWheelSensitivity applied. */ public int deltaWheel; /** * The raw delta X position change without getMouseMoveSensitivity applied. */ public int deltaX; /** * The raw delta Y position change without getMouseMoveSensitivity applied. */ public int deltaY; /** * The mapped button to the framework's mouse */ public int mappedButton; /** * Bitfield describing which modifiers keys were held down */ public int modifiers; /** * The mouse X position associated with the event */ public int mouseX; /** * The mouse Y position associated with the event */ public int mouseY; } }