How do I open a keyboard overlay with Steamworks?

I have more than this, but this is the most important stuff:

var OnlineSubsystemSteamworks Steamworks;
local bool Success;
Steamworks = OnlineSubsystemSteamworks(class'GameEngine'.static.GetOnlineSubsystem());
Success = Steamworks.ShowKeyboardUI(0, EnterCharacterName_Localized, "", false, true, "", 64);

It always fails. (I also tried a loop to try all the possible LocalUserNum values from 0 through 255.)

Does OnlineSubsystemSteamworks.ShowKeyboardUI() do anything? I looked at it, and it’s not a native function and it’s empty.

Am I going to have to go into native code and get my own access to SteamUtils()->ShowGamepadTextInput() or SteamUtils()->ShowFloatingGamepadTextInput()?

Edit: In Steam, I have “Enable the Steam Overlay while in-game” and “Use the Big Picture Overlay when using a Steam Input enabled controller from the desktop” checked.

OK, a little progress here. I wrote my own UnrealScript wrapper for SteamUtils. I can get a text input window to appear when Steam Big Picture is active. I can only get Big Picture to work if I launch my game through the Steam client. I cannot find any way to launch the game with Big Picture activated, when launching from Visual Studio or a shortcut. Launching from the Steam client isn’t so bad, if I add my local development build exe as a non-Steam game, so I don’t have to upload every iteration through steamcmd just so I can test. But now it seems I can’t use my controller for some reason when launching through the Steam client as a non-Steam game. Ugh. There’s always something.

Now I need to figure out how to set up a callback to get the text when the text input window closes.

(Edit: Just to confirm there is a problem with the stock OnlineSubsystemSteamworks implementation, I tried using Steamworks.ShowKeyboardUI as shown in my first post, when launching from the Steam client. The keyboard overlay still does not appear even when Big Picture mode is active, when I launch from the Steam client.)

I ended up writing a dll to wrap the latest Steam SDK and linking with a DllBind (with the help of a knowledgeable modder), as the one included in UDK is old and doesn’t include many of the current features. This has allowed me to use the Steam Inventory Service and implement a system for weapon/clothing/item skins from the Steam store. Using DllBinds with the 64 bit executable is a bit tricky though, as you need to wrap the payload sent from US to the DLL to mimic that of the 64 bit structure.

@Nathaniel3W How did you manage to get access to SteamUtils(), or was that included in the old SDK and just not exposed through US?

I downloaded the latest Steamworks SDK and I had to make a new native class:

class SteamUtilsWrapper extends Object native;
var protected array<Object> ObjectsWaitingForCallback;
var string GamepadTextInput;
var bool TextInputWasCanceled;

// native function bool BOverlayNeedsPresent(); // No need to ever call this manually
native function int GetAppID();
native function byte GetCurrentBatteryPower();
native function int GetSecondsSinceAppActive();
native function int GetSecondsSinceComputerActive();
native function bool IsOverlayEnabled();
native function bool IsSteamChinaLauncher();
native function bool IsSteamInBigPictureMode();
native function bool IsSteamRunningOnSteamDeck();
native function SetOverlayNotificationInset(int nHorizontalInset, int nVerticalInset);
native function SetOverlayNotificationPosition(byte byteNotificationPosition);
native function bool ShowGamepadTextInput(byte eInputMode, byte eLineInputMode, string Description, int MaxChar, string ExistingText);
// native function bool ShowFloatingGamepadTextInput(byte eKeyboardMode, int nTextFieldXPosition, int nTextFieldYPosition, int nTextFieldWidth, int nTextFieldHeight); // only useful on Steam Deck
// native function WrapperRunCallbacks(); // The game engine runs this automatically.  No need to call it manually.

function bool WaitingForCallback()
	return ObjectsWaitingForCallback.Length > 0 ? true : false;

function AddToWaitForCallback(Object ObjectWaitingForCallback)
	if(TextInputDismissedInterface(ObjectWaitingForCallback) != none)

event NotifyTextInputCallbacks()
	local Object ObjectWaitingForCallback;

	foreach ObjectsWaitingForCallback(ObjectWaitingForCallback)
		if(TextInputDismissedInterface(ObjectWaitingForCallback) != none)
	ObjectsWaitingForCallback.Length = 0;

	#include "isteamutils.h" // ************************************************ Remember to cut/paste this to the top of RPGTacGameClasses.h
	#include "steam_api_common.h" // ************************************************ Remember to cut/paste this to the top of RPGTacGameClasses.h
	#include "steamclientpublic.h" // ************************************************ Remember to cut/paste this to the top of RPGTacGameClasses.h
	STEAM_CALLBACK( USteamUtilsWrapper, OnGamepadTextInputDismissed_t, GamepadTextInputDismissed_t );

Make that UScript class, build UScript which will make new header files, then move the #include statements to the top of the header (there’s a way to set up the Unreal Build Tool so that it automatically creates your headers with the #includes in the right place, but I never figured that out), then fill in your functions in the cpp file, and build the C++.

It took me a while to do all of that, mostly because I never learned C++. Now that I’ve done it all and I have working code, I think the code looks pretty simple. I don’t have any of the functionality you mentioned–I only really needed the text input window–but I think I could add more SteamUtils functions if I needed them.

Everything is working perfectly, except instantiating my SteamUtils object crashes the game when you’re running the 32 bit exe. I never figured out a way to know directly from UScript whether the game is 32 or 64 bit. So I added an option to my startup command (?win32=true) to tell the game whether I intended to run the 32 bit exe, and I look for that option before creating SteamUtils.

My 32-bit players just have to do without SteamUtils for now.

Thanks for the info @Nathaniel3. Very useful! :slight_smile: