-
-
Notifications
You must be signed in to change notification settings - Fork 70
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add utils.showFloatingGamepadTextInput() #113
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,12 @@ use napi_derive::napi; | |
|
||
#[napi] | ||
pub mod utils { | ||
use napi::bindgen_prelude::{FromNapiValue, ToNapiValue}; | ||
use steamworks::FloatingGamepadTextInputMode as kFloatingGamepadTextInputMode; | ||
use steamworks::GamepadTextInputLineMode as kGamepadTextInputLineMode; | ||
use steamworks::GamepadTextInputMode as kGamepadTextInputMode; | ||
use tokio::sync::oneshot; | ||
|
||
#[napi] | ||
pub fn get_app_id() -> u32 { | ||
let client = crate::client::get_client(); | ||
|
@@ -19,4 +25,110 @@ pub mod utils { | |
let client = crate::client::get_client(); | ||
client.utils().is_steam_running_on_steam_deck() | ||
} | ||
|
||
#[napi] | ||
pub enum GamepadTextInputMode { | ||
Normal, | ||
Password, | ||
} | ||
|
||
#[napi] | ||
pub enum GamepadTextInputLineMode { | ||
SingleLine, | ||
MultipleLines, | ||
} | ||
|
||
/// @returns the entered text, or null if cancelled or could not show the input | ||
#[napi] | ||
pub async fn show_gamepad_text_input( | ||
input_mode: GamepadTextInputMode, | ||
input_line_mode: GamepadTextInputLineMode, | ||
description: String, | ||
max_characters: u32, | ||
existing_text: Option<String>, | ||
) -> Option<String> { | ||
let client = crate::client::get_client(); | ||
|
||
let (tx, rx) = oneshot::channel(); | ||
let mut tx = Some(tx); | ||
|
||
let opened = client.utils().show_gamepad_text_input( | ||
match input_mode { | ||
GamepadTextInputMode::Normal => kGamepadTextInputMode::Normal, | ||
GamepadTextInputMode::Password => kGamepadTextInputMode::Password, | ||
}, | ||
match input_line_mode { | ||
GamepadTextInputLineMode::SingleLine => kGamepadTextInputLineMode::SingleLine, | ||
GamepadTextInputLineMode::MultipleLines => kGamepadTextInputLineMode::MultipleLines, | ||
}, | ||
&description, | ||
max_characters, | ||
existing_text.as_deref(), | ||
move |dismissed_data| { | ||
if let Some(tx) = tx.take() { | ||
let text = client | ||
.utils() | ||
.get_entered_gamepad_text_input(&dismissed_data); | ||
tx.send(text).unwrap(); | ||
} | ||
}, | ||
); | ||
|
||
if opened { | ||
rx.await.unwrap() | ||
} else { | ||
None | ||
} | ||
} | ||
|
||
#[napi] | ||
pub enum FloatingGamepadTextInputMode { | ||
SingleLine, | ||
MultipleLines, | ||
Email, | ||
Numeric, | ||
} | ||
|
||
/// @returns true if the floating keyboard was shown, otherwise, false | ||
#[napi] | ||
pub async fn show_floating_gamepad_text_input( | ||
keyboard_mode: FloatingGamepadTextInputMode, | ||
x: i32, | ||
y: i32, | ||
width: i32, | ||
height: i32, | ||
) -> bool { | ||
let client = crate::client::get_client(); | ||
|
||
let (tx, rx) = oneshot::channel(); | ||
let mut tx = Some(tx); | ||
|
||
let opened = client.utils().show_floating_gamepad_text_input( | ||
match keyboard_mode { | ||
FloatingGamepadTextInputMode::SingleLine => { | ||
kFloatingGamepadTextInputMode::SingleLine | ||
} | ||
FloatingGamepadTextInputMode::MultipleLines => { | ||
kFloatingGamepadTextInputMode::MultipleLines | ||
} | ||
FloatingGamepadTextInputMode::Email => kFloatingGamepadTextInputMode::Email, | ||
FloatingGamepadTextInputMode::Numeric => kFloatingGamepadTextInputMode::Numeric, | ||
}, | ||
x, | ||
y, | ||
width, | ||
height, | ||
move || { | ||
if let Some(tx) = tx.take() { | ||
tx.send(true).unwrap(); | ||
} | ||
}, | ||
); | ||
|
||
if opened { | ||
rx.await.unwrap() | ||
} else { | ||
false | ||
} | ||
Comment on lines
+121
to
+132
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I'm understanding the docs correctly, this function will immediately return Let me know if I'm missing something. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can't see a real use case where you will need both, I think the promise way maes more sense on JS and can benefit the consumer for a more fluid code flow. What do you think? |
||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if there is no result here? The Promise will never resolve, right?
Looking further at the docs, this function returns true if "big picture overlay is running" but I'm wondering if that's a docs mistake and it returns true/false if the keyboard was opened or not similar to the floating text input function (or if it kinda means the same in this case, anyway).
Since the two new functions can be called without showing the gamepad, there is one more wrinkle in the Promise based API: Technically, promises are expected to be resolved at some point in the future, but if the gamepad doesn't open or doesn't exist, the Promise will never be handled. This is kinda ok-ish when using the Promise API, but it's very confusing when using async/await since the code block will just get stuck:
Most likely this is fine if it's documented. One thing to keep in mind is that this behavior is likely attached to input elements and is called repeatedly. Without knowing whether the gamepad can/is ever shown on the platform that it is being called on it will create a lot of dangling promises in memory that will stay unresolved for the duration of the app runtime.
Now, this might be an acceptable trade-off for you, but I wanted to bring it up anyway for consideration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so, the memory management will drop the promise and unsign the callback as soon as the function returns something.
The idea is to always resolve the promise, either with the text input or with an undefined state, meaning the text input could not be shown or was cancelled. Example impl:
I think it means the same thing 🤔