Last active
September 8, 2020 11:43
-
-
Save dzikoysk/0b77744386a659bb7ead629f53830bfd to your computer and use it in GitHub Desktop.
Clip hardware cursor on Windows using libGDX with LWJGL2 backend, otherwise catch cursor with a standard API
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.badlogic.gdx.ApplicationAdapter; | |
import com.badlogic.gdx.ApplicationListener; | |
import com.badlogic.gdx.Gdx; | |
import org.lwjgl.LWJGLUtil; | |
import org.lwjgl.opengl.Display; | |
import org.panda_lang.utilities.commons.function.Lazy; | |
import java.lang.reflect.InvocationTargetException; | |
import java.lang.reflect.Method; | |
// LWJGL2 resets mouse clipping every mouse update, | |
// so we need to call setupCursorClipping() method constantly | |
// LWJGL3 is not supported due to display impl through the GLFW. | |
// LWJGL 3 implementation: https://gist.github.com/dzikoysk/b0e2f24048f8fee0ab9253d9d7ab9aa3 | |
public final class Lwjgl2CatchCursorAdapter { | |
// Lazy class is just a Supplier with cache support | |
private static final Lazy<Long> HWND = new Lazy<>(() -> { | |
try { | |
Method getImplementationMethod = Display.class.getDeclaredMethod("getImplementation"); | |
getImplementationMethod.setAccessible(true); | |
Object implementation = getImplementationMethod.invoke(null); | |
Class<?> windowsDisplayClass = Class.forName("org.lwjgl.opengl.WindowsDisplay"); | |
if (!windowsDisplayClass.isInstance(implementation)) { | |
throw new Exception("The current platform must be Windows!"); | |
} | |
Method getHwndMethod = windowsDisplayClass.getDeclaredMethod("getHwnd"); | |
getHwndMethod.setAccessible(true); | |
return (Long) getHwndMethod.invoke(implementation); | |
} catch (Exception exception) { | |
throw new RuntimeException(exception); | |
} | |
}); | |
private static final Lazy<Method> SETUP_CURSOR_CLIPPING_METHOD = new Lazy<>(() -> { | |
try { | |
Class<?> windowsDisplayClass = Class.forName("org.lwjgl.opengl.WindowsDisplay"); | |
Method setupCursorClippingMethod = windowsDisplayClass.getDeclaredMethod("setupCursorClipping", long.class); | |
setupCursorClippingMethod.setAccessible(true); | |
return setupCursorClippingMethod; | |
} catch (Exception exception) { | |
throw new RuntimeException(exception); | |
} | |
}); | |
/** | |
* Clip cursor manually on Windows | |
*/ | |
public static void setupCursorClipping() throws InvocationTargetException, IllegalAccessException { | |
SETUP_CURSOR_CLIPPING_METHOD.get().invoke(null, HWND.get()); | |
} | |
/** | |
* Catch cursor with hardware support on Windows. | |
* The method returns {@link com.badlogic.gdx.ApplicationListener} which should call: | |
* - create() | |
* - resume() | |
* - dispose() | |
*/ | |
public static ApplicationListener createCatchCursorAdapter() { | |
if (LWJGLUtil.getPlatform() != LWJGLUtil.PLATFORM_WINDOWS) { | |
return new ApplicationAdapter() { | |
@Override | |
public void create() { | |
Gdx.input.setCursorCatched(true); | |
} | |
@Override | |
public void dispose() { | |
Gdx.input.setCursorCatched(false); | |
} | |
}; | |
} | |
// Related to enhanced cursor renderer implementation on Windows | |
// Details: https://stackoverflow.com/a/16181555/3426515 | |
// Using: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-clipcursor | |
return new ApplicationAdapter() { | |
@Override | |
public void create() { | |
setupCursorClippingMethod(); | |
} | |
@Override | |
public void resume() { | |
setupCursorClippingMethod(); | |
} | |
@Override | |
public void dispose() { | |
Gdx.input.setCursorCatched(false); | |
} | |
private void setupCursorClippingMethod() { | |
try { | |
setupCursorClipping(); | |
} catch (IllegalAccessException | InvocationTargetException e) { | |
throw new RuntimeException(e); | |
} | |
} | |
}; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment