Can one use stylus without AWT / JAVAFX?
Hi,
I am trying to add support for graphic tablets to the OPENRNDR creative coding framework written in Kotlin. First I tried using https://github.com/nicarran/jpen but it's no longer under active development and I have issues making it work. I was pointed to this repo and I'm very happy that there are packages I can use from Gradle.
Question: is it possible to use it without AWT or JAVAFX? OPENRNDR uses LWJGL which in turn uses GLFW. I do have access to window size, window position, pointer position and button states. What I'm missing is pressure and tilt.
Is the readme the only documentation available so far?
I see the included demos are rich in features and source code files. An idea for the future: include a minimal demo only showing how to read the state from the stylus. I think that would make it easier to understand how to integrate it in a project.
Thank you for writing and sharing your code.
This is the code I came up with for testing (it's the whole program):
import org.lecturestudio.stylus.*
import org.openrndr.application
import org.openrndr.color.rgb
import org.openrndr.math.Vector2
fun main() = application {
program {
var pressure = 0.0
var tilt = Vector2.ZERO
val manager = StylusManager.getInstance()
val stylusListener: StylusListener = object : StylusListener {
override fun onCursorChange(event: StylusEvent?) {
println(event)
}
override fun onCursorMove(event: StylusEvent) {
event.axesData.let {
pressure = it.pressure
tilt = Vector2(it.tiltX, it.tiltY) * 0.5 + 0.5
}
}
override fun onButtonDown(event: StylusEvent?) {
println(event)
}
override fun onButtonUp(event: StylusEvent?) {
println(event)
}
}
manager.attachStylusListener(stylusListener, this)
extend {
if(mouse.pressedButtons.isNotEmpty()) {
drawer.stroke = null
drawer.fill = rgb(tilt.x, tilt.y, 1.0)
drawer.circle(mouse.position, pressure * 50.0)
}
}
}
}
I added stylus to the build.gradle.kts file but the program fails to start with this error:
May 29, 2022 2:06:38 PM org.lecturestudio.stylus.StylusManager <clinit>
SEVERE: Load stylus library failed
java.lang.NullPointerException
at java.base/java.util.Objects.requireNonNull(Objects.java:208)
at java.base/java.nio.file.Files.copy(Files.java:3112)
at org.lecturestudio.stylus.internal.NativeLoader.loadLibrary(NativeLoader.java:62)
at org.lecturestudio.stylus.StylusManager.<clinit>(StylusManager.java:30)
at apps2022.TestStylusKt$main$1$1.invokeSuspend(testStylus.kt:12)
at apps2022.TestStylusKt$main$1$1.invoke(testStylus.kt)
at apps2022.TestStylusKt$main$1$1.invoke(testStylus.kt)
...
Any suggestions to solve this? I'm on Linux, latest Idea & Gradle.
I tried setting JAVA_HOME correctly, then running mvn install, then copying the produced stylus-jni/target/lib/libstylus.so file to /usr/lib and various other folders but that did not help.
I was having the same problem, and got it working by copying both the stylus library as well as the stylus-jni library. I'm still struggling to get a simple example (like the one you have above) working though, so if you manage to get something like that working let me know
My colleague showed me how to use the right dependencies:
dependencies {
implementation("org.lecturestudio.stylus:stylus:0.2.0")
runtimeOnly("org.lecturestudio.stylus:stylus:0.2.0:linux-x86_64")
}
With that I didn't need to build it myself and the library is found. Unfortunately also couldn't make it work. We get this error:
Exception in thread "main" java.lang.NoSuchFieldError: nativeHandle
at org.lecturestudio.stylus.StylusManager.attachStylusListener(Native Method)
at Stylus01Kt$main$1$1.invokeSuspend(Stylus01.kt:31)
at Stylus01Kt$main$1$1.invoke(Stylus01.kt)
at Stylus01Kt$main$1$1.invoke(Stylus01.kt)
at org.openrndr.ApplicationBuilder$program$1.setup(ApplicationBuilder.kt:15)
at org.openrndr.internal.gl3.ApplicationGLFWGL3$loop$15.invokeSuspend(ApplicationGLFWGL3.kt:803)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:284)
at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:85)
at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
at org.openrndr.internal.gl3.ApplicationGLFWGL3.loop(ApplicationGLFWGL3.kt:802)
at org.openrndr.Application$Companion.run(Application.kt:70)
at org.openrndr.ApplicationKt.application(Application.kt:120)
at org.openrndr.ApplicationBuilderKt.application(ApplicationBuilder.kt:81)
at Stylus01Kt.main(Stylus01.kt:6)
at Stylus01Kt.main(Stylus01.kt)
It looks like some method is not found. A JVM method called from C++ maybe? How does it fail in your case @Polian ?
Yeah, that's the same error I'm getting. I dug around in the C++ a little, but I'm not familiar with this kind of code, and couldn't figure out what could be going wrong
It looks like some method is not found. A JVM method called from C++ maybe? How does it fail in your case @Polian ?
Yes, you need to define a nativeHandle member variable of type long inside the listener class itself (like this: AwtStylusManager.java#L140, I don't know why it's designed that way.
Since I couldn't make it work at the time, and since I'm on Linux, I went for this approach: https://codeberg.org/hamoid/openrndr-oddity-coffer/src/branch/master/src/main/kotlin/kinputevents