steamworks.js
steamworks.js copied to clipboard
Add utils.showFloatingGamepadTextInput()
This one was pretty weird, due to the callback.
Unlike all other callbacks in steamworks-rs, the show_gamepad_text_input and show_floating_gamepad_text_input functions expect a dismissed_cb callback as an argument to the function.
https://github.com/Noxime/steamworks-rs/blob/e9cdf88f1c436871e2f72d9726da6eceac0679d4/src/utils.rs#L281
/// Opens a floating keyboard over the game content and sends OS keyboard keys directly to the game.
///
/// The text field position is specified in pixels relative the origin of the game window and is used to
/// position the floating keyboard in a way that doesn't cover the text field.
///
/// Callback is triggered when user dismisses the text input
pub fn show_floating_gamepad_text_input<F>(
&self,
keyboard_mode: FloatingGamepadTextInputMode,
x: i32,
y: i32,
width: i32,
height: i32,
mut dismissed_cb: F,
) -> bool
where
F: FnMut() + 'static + Send, // TODO: Support FnOnce callbacks
{
unsafe {
register_callback(&self._inner, move |_: FloatingGamepadTextInputDismissed| {
dismissed_cb();
});
sys::SteamAPI_ISteamUtils_ShowFloatingGamepadTextInput(
self.utils,
keyboard_mode.into(),
x,
y,
width,
height,
)
}
}
The FloatingGamepadTextInputDismissed struct simply doesn't have #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] as other callback structs do, so when I tried adding FloatingGamepadTextInputDismissed to callback.rs here in steamworks.js, the compile failed when I tried to register_callback::<steamworks::FloatingGamepadTextInputDismissed>(threadsafe_handler).
I guess I could investigate fixing that as a bug in steamworks-rs, but I don't actually happen to need the FloatingGamepadTextInputDismissed callback, myself, so, in this PR, I'm just passing show_floating_gamepad_text_input an empty callback, just to satisfy the compiler. Presumably, if someone needs the FloatingGamepadTextInputDismissed callback, they can implement it themselves (perhaps adding serde support to FloatingGamepadTextInputDismissed in steamworks-rs first, then getting that merged, and then adding it to callback.rs here.
Would it be possible to implement a JS-based callback parameter in this case? It'd be awesome if the end user could write code like this:
showFloatingGamepadTextInput(FloatingGamepadTextInputMode.SingleLine, x, y, width, number, () => {
console.log('callback, input dismissed');
});
My NAPI skills are still pretty weak. (I mostly write these PRs by copying and pasting! 🫠)
Implementing that would also be necessary in order to implement the non-floating showGamepadTextInput method, which returns the typed text in a callback as a string.
Would it be possible to implement a JS-based callback parameter in this case? It'd be awesome if the end user could write code like this:
showFloatingGamepadTextInput(FloatingGamepadTextInputMode.SingleLine, x, y, width, number, () => { console.log('callback, input dismissed'); });
Agreed. We can do it with a threadsafe function on napi. I can work on it later
If I understand correctly, this will enable us to open virtual keyboard on Steam Deck, when an input is clicked, is that correct? What is the current state? Is there some workaround until this is released?
There's no workaround; we just have to wait. (Unless you know enough NAPI to fix callbacks in my PR…?)
@ceifa what would it take to get this merged and released, even without the ability to pass a callback for now?
I published this PR as @nkzw/steamworks.js 0.4.0 on top of the current version for anyone who needs this in the short-term.
Hey @dfabulich! Thanks again for the PR and sorry for the delay. Because I don't have a steam deck to test it myself, can you help me clarify the following questions?
- The current implementation of "showFloatingGamepadTextInput" works out of the box, as it works as a keyboard and electron/html can handle them just fine?
- I guess the "showGamepadTextInput" does not work, as it is an external input, which would give us the result in a callback (not implemented)?
I just open sourced my integration for Athena Crisis, see this commit: https://github.com/nkzw-tech/athena-crisis/commit/27e5ab8bac926fd5b0c9f5f22432c910d46fce85
To answer your questions:
showFloatingGamepadTextInputwill open the keyboard whenever you call the function, not automatically when tapping input elements (of course). With the code I shared above, it will work reasonably well and opens the keyboard when focusing an input element and it forwards keypresses correctly. However, I've found that it does not always respect the dimensions that I pass in, putting the keyboard into the wrong spot many times, and it's a bit cumbersome not knowing whether the keyboard is currently open or not.showGamepadTextInputdoes work in that it opens the keyboard with a custom floating input element, but you are correct, since the callback is not implemented it is basically useless. In order to make it work, the callback needs to be implemented as well asGetEnteredGamepadTextLength. Since that function always needs to be called to get the result, I think it makes sense to automatically call that and pass it to theshowGamepadTextInputcallback in JS.
A good path forward could be to merge support for showFloatingGamepadTextInput (without callback, since it's still useful), and then focus on the callback use case and showGamepadTextInput support in a separate PR.
Thanks @cpojer! I will take a look at this and fix the missing points.
@dfabulich @cpojer just finished the API. Decided to use promises instead of callback because I think it makes sense since it would be used to control code flow and can only be called once.
Because I don't have a steam deck I couldn't test this change... you can help me on that?
I do have a Steam Deck but I don't have an easy way to build the artifacts without publishing. If you can provide me with a linux build of an electron app with an example I'm happy to test it right away.
I can do some testing later this week, but testing this API doesn't require a Steam Deck. You can test it using Steam Big Picture mode with any gamepad controller plugged into your PC, e.g. Xbox or PS5 controller.