Skip to content

UScreen: improved input handling (via optional interface) - #125

Open
Traben-0 wants to merge 62 commits into
masterfrom
feature/em-1645-closing-uscreen-via-esc-on-119-puts-you-in-the-menu-rather
Open

UScreen: improved input handling (via optional interface)#125
Traben-0 wants to merge 62 commits into
masterfrom
feature/em-1645-closing-uscreen-via-esc-on-119-puts-you-in-the-menu-rather

Conversation

@Traben-0

@Traben-0 Traben-0 commented Mar 5, 2026

Copy link
Copy Markdown
Contributor

new implementation based on feedback from DJ's old PR

Old pr: #52

Internal issue reference: EM-1645

Comment thread src/main/kotlin/gg/essential/universal/UScreen.kt Outdated
Comment thread src/main/kotlin/gg/essential/universal/UScreen.kt Outdated
@Traben-0
Traben-0 requested a review from Johni0702 March 5, 2026 13:27
Traben-0 added 8 commits March 6, 2026 14:30
- uSuperConsumableInputHandler() default instance should call super directly

- separate uKeypress and uCharTyped

Linear: EM-1645
Linear: EM-1645
…via-esc-on-119-puts-you-in-the-menu-rather' into feature/em-1645-closing-uscreen-via-esc-on-119-puts-you-in-the-menu-rather

# Conflicts:
#	src/main/kotlin/gg/essential/universal/UScreen.kt
Linear: EM-1645
Linear: EM-1645
Comment thread src/main/kotlin/gg/essential/universal/UScreen.kt Outdated
Comment thread src/main/kotlin/gg/essential/universal/UScreen.kt Outdated
Comment thread src/main/kotlin/gg/essential/universal/UScreen.kt Outdated
Comment thread src/main/kotlin/gg/essential/universal/UScreen.kt Outdated
Comment thread src/main/kotlin/gg/essential/universal/UScreen.kt Outdated
Comment thread src/main/kotlin/gg/essential/universal/UScreen.kt Outdated
Comment thread src/main/kotlin/gg/essential/universal/UScreen.kt Outdated
Comment thread src/main/kotlin/gg/essential/universal/UScreen.kt Outdated
Comment thread src/main/kotlin/gg/essential/universal/UScreen.kt Outdated
Comment thread src/main/kotlin/gg/essential/universal/UScreen.kt Outdated
Comment thread src/main/kotlin/gg/essential/universal/UScreen.kt Outdated
@Traben-0
Traben-0 requested a review from Johni0702 March 24, 2026 09:09
Comment thread src/main/kotlin/gg/essential/universal/UScreen.kt Outdated
Comment thread standalone/src/main/kotlin/gg/essential/universal/UScreen.kt Outdated
Comment thread standalone/src/main/kotlin/gg/essential/universal/standalone/UCWindow.kt Outdated

@Johni0702 Johni0702 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the integration in Elementa has given me two more ideas.

Comment thread src/main/kotlin/gg/essential/universal/UScreen.kt Outdated
Comment thread src/main/kotlin/gg/essential/universal/UScreen.kt Outdated
@Traben-0
Traben-0 requested a review from Johni0702 April 5, 2026 23:50
Comment thread src/main/kotlin/gg/essential/universal/UScreen.kt
Traben-0 added 3 commits April 9, 2026 11:53
…via-esc-on-119-puts-you-in-the-menu-rather' into feature/em-1645-closing-uscreen-via-esc-on-119-puts-you-in-the-menu-rather
@Traben-0
Traben-0 requested a review from Johni0702 April 9, 2026 02:13
Johni0702
Johni0702 previously approved these changes Apr 9, 2026

@Johni0702 Johni0702 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me again, but let's wait with merging until we've got the whole stack (UC+Elementa+Essential) done, in case we find more stuff that should be changed along the way.

@Traben-0

Copy link
Copy Markdown
Contributor Author

// Must be called with consistently scaled scroll deltas on all mc/lwjgl versions.
// This is to ensure a consistent scrolling experience across all versions.
// See onMouseScrolled(Double) for further explanation.
fun uMouseScrolled(x: Double, y: Double, scrollX: Double, scrollY: Double): Boolean =

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thought: I know MC doesn't provide them for scrolling, but should we maybe supply modifiers here for consistency on our end?

@Traben-0 Traben-0 Apr 26, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

elementa has atleast 3 calls to check modifier key presses via UKeyboard.is*KeyDown() in scroll events, so there is a precedent for needing them.

Granted there is currently no technical different between supplying UKeyboard.getKeyModifiers() here and using the UKeyboard.is*KeyDown() further within the events, other than the mentioned consistency between the mouse events.

Would also cover us if MC ever added them.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. Yeah, I think that would make sense.
GLFW doesn't currently provide that info, but there's an issue for it, which suggests that it should be possible. That issue hasn't been closed yet, and I see no conceptual reason to pass the modifiers with scroll events (like there are in case of the charType events), so I can see no reason for us not to already include it in our API.

@Traben-0
Traben-0 requested a review from Johni0702 April 27, 2026 03:45
else isControlKeyDown()

@JvmStatic
fun isCommandKeyDown(): Boolean = isKeyDown(KEY_LMETA) || isKeyDown(KEY_RMETA)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Would call this isSuperKeyDown, for consistency with our Modifier.isSuper.

That, or isMetaKeyDown, since that's what we call our KEY_ constants. But I think staying consistent with the new stuff (and lwjgl3, which also calls them GLFW_KEY_LEFT/RIGHT_SUPER) is better here.

I don't think we're calling it Command anywhere else.


@JvmStatic
fun isKeyComboCtrlA(key: Int): Boolean = key == KEY_A && isCtrlKeyDown() && !isShiftKeyDown() && !isAltKeyDown()
fun getKeyModifiers(): Modifiers = Modifiers(isControlKeyDown(), isShiftKeyDown(), isAltKeyDown(), isCommandKeyDown())

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thought: Not sure we should even provide this new variant of the getModifiers method.

You usually shouldn't be using getModifiers anyway because it depends on global state. You should be using the Modifiers instance that comes with your mouseClick/etc. call.

Comment on lines -393 to +415
data class Modifiers(val isCtrl: Boolean, val isShift: Boolean, val isAlt: Boolean)
data class Modifiers(
val isCtrl: Boolean,
val isShift: Boolean,
val isAlt: Boolean,
val isSuper: Boolean,
) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: Breaking change. Also need to supply a three-args copy method. See the red lines in the .api file diff.

it.uCharTyped(typedChar.code)
}
} ?: @Suppress("DEPRECATION") onKeyPressed(keyCode, typedChar, UKeyboard.getModifiers())
} ?: @Suppress("DEPRECATION") onKeyPressed(keyCode, typedChar, UKeyboard.getKeyModifiers())

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: Breaking change. We must only change the modifier we pass to the new methods, we must not change the ones we pass to the old methods because people might already be relying on that behavior.

Comment on lines 384 to 397
final override fun mouseClicked(mouseX: Int, mouseY: Int, mouseButton: Int) {
inputHandler?.uMouseClicked(mouseX.restoreFrac(UMouse.Scaled.x), mouseY.restoreFrac(UMouse.Scaled.y), mouseButton, UKeyboard.getModifiers())
inputHandler?.uMouseClicked(mouseX.restoreFrac(UMouse.Scaled.x), mouseY.restoreFrac(UMouse.Scaled.y), mouseButton, UKeyboard.getKeyModifiers())
?: @Suppress("DEPRECATION") onMouseClicked(mouseX.toDouble(), mouseY.toDouble(), mouseButton)
}

final override fun mouseReleased(mouseX: Int, mouseY: Int, state: Int) {
inputHandler?.uMouseReleased(mouseX.restoreFrac(UMouse.Scaled.x), mouseY.restoreFrac(UMouse.Scaled.y), state, UKeyboard.getModifiers())
inputHandler?.uMouseReleased(mouseX.restoreFrac(UMouse.Scaled.x), mouseY.restoreFrac(UMouse.Scaled.y), state, UKeyboard.getKeyModifiers())
?: @Suppress("DEPRECATION") onMouseReleased(mouseX.toDouble(), mouseY.toDouble(), state)
}

final override fun mouseClickMove(mouseX: Int, mouseY: Int, clickedMouseButton: Int, timeSinceLastClick: Long) {
inputHandler?.uMouseDragged(mouseX.restoreFrac(UMouse.Scaled.x), mouseY.restoreFrac(UMouse.Scaled.y), clickedMouseButton, UKeyboard.getModifiers())
inputHandler?.uMouseDragged(mouseX.restoreFrac(UMouse.Scaled.x), mouseY.restoreFrac(UMouse.Scaled.y), clickedMouseButton, UKeyboard.getKeyModifiers())
?: @Suppress("DEPRECATION") onMouseDragged(mouseX.toDouble(), mouseY.toDouble(), clickedMouseButton, timeSinceLastClick)
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: Each of these has a pre-processed version that needs to be updated as well.

Comment on lines +435 to +437
val isOSModifier = if (UMinecraft.isRunningOnMac) isSuper else isCtrl
fun isPlatformModifierActive() =
if (UMinecraft.isRunningOnMac) isSuper && !isShift && !isAlt && !isCtrl
else isCtrl && !isShift && !isAlt && !isSuper

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: What's the motivation for this rename?

I personally prefer OS over Platform.
Platform is usually what we call the underlying Minecraft version (or standalone UC framework).

I'm also not convinced we should have the ModifierActive suffix. It's inconsistent with all the other properties (though admittedly this one also works somewhat differently, although not that differently).
The Modifier is somewhat redundant because it's in the Modifiers class and will usually be called like modifiers.isPlatformModifierActive().
The Active assumes that this class is only used for the active modifiers. That's not strictly necessary though. This class could also be used for other purposes (e.g. storing the modifiers for a set of keybindings). I suppose one could still say that the modifier is active for that keybind then, but it just feels a bit off.

question: What's the motivation for this being a function rather than a property now?

question: What's the motivation for checking that other modifiers aren't pressed?

While I suppose this is a common thing one might want when checking for common shortcut combos, it does prevent one from easily recognizing shortcuts which use multiple modifiers.
So maybe should be provided as a separate option, in addition to the basic one.

Edit: Ah, third question is answered by the next commit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants