This code was not tested and breaks in Release builds, reverting to restore
functionality of the nightly. All in-game menus do not work and generating
a world crashes.
This reverts commit a9be52c41a.
335 lines
9.7 KiB
C++
335 lines
9.7 KiB
C++
#include "stdafx.h"
|
|
#include "UI.h"
|
|
#include "UIScene_Keyboard.h"
|
|
|
|
#ifdef _WINDOWS64
|
|
// Global buffer that stores the text entered in the native keyboard scene.
|
|
// Callbacks retrieve it via Win64_GetKeyboardText() declared in UIStructs.h.
|
|
wchar_t g_Win64KeyboardResult[256] = {};
|
|
#endif
|
|
|
|
#define KEYBOARD_DONE_TIMER_ID 0
|
|
#define KEYBOARD_DONE_TIMER_TIME 100
|
|
|
|
UIScene_Keyboard::UIScene_Keyboard(int iPad, void *initData, UILayer *parentLayer) : UIScene(iPad, parentLayer)
|
|
{
|
|
// Setup all the Iggy references we need for this scene
|
|
initialiseMovie();
|
|
|
|
#ifdef _WINDOWS64
|
|
m_win64Callback = NULL;
|
|
m_win64CallbackParam = NULL;
|
|
m_win64TextBuffer = L"";
|
|
m_win64MaxChars = 25;
|
|
|
|
const wchar_t* titleText = L"Enter text";
|
|
const wchar_t* defaultText = L"";
|
|
|
|
m_bPCMode = false;
|
|
if (initData)
|
|
{
|
|
UIKeyboardInitData* kbData = (UIKeyboardInitData*)initData;
|
|
m_win64Callback = kbData->callback;
|
|
m_win64CallbackParam = kbData->lpParam;
|
|
if (kbData->title) titleText = kbData->title;
|
|
if (kbData->defaultText) defaultText = kbData->defaultText;
|
|
m_win64MaxChars = kbData->maxChars;
|
|
m_bPCMode = kbData->pcMode;
|
|
}
|
|
|
|
m_win64TextBuffer = defaultText;
|
|
|
|
m_EnterTextLabel.init(titleText);
|
|
m_KeyboardTextInput.init(defaultText, -1);
|
|
m_KeyboardTextInput.SetCharLimit(m_win64MaxChars);
|
|
|
|
// Clear any leftover typed characters from a previous keyboard session
|
|
g_KBMInput.ClearCharBuffer();
|
|
g_Win64KeyboardResult[0] = L'\0';
|
|
#else
|
|
m_EnterTextLabel.init(L"Enter Sign Text");
|
|
|
|
m_KeyboardTextInput.init(L"", -1);
|
|
m_KeyboardTextInput.SetCharLimit(15);
|
|
#endif
|
|
|
|
m_ButtonSpace.init(L"Space", -1);
|
|
m_ButtonCursorLeft.init(L"Cur L", -1);
|
|
m_ButtonCursorRight.init(L"Cur R", -1);
|
|
m_ButtonCaps.init(L"Caps", -1);
|
|
m_ButtonDone.init(L"Done", 0); // only the done button needs an id, the others will never call back!
|
|
m_ButtonSymbols.init(L"Symbols", -1);
|
|
m_ButtonBackspace.init(L"Backspace", -1);
|
|
|
|
// Initialise function keyboard Buttons and set alternative symbol button string
|
|
#ifdef _WINDOWS64
|
|
if (!m_bPCMode)
|
|
#endif
|
|
{
|
|
wstring label = L"Abc";
|
|
IggyStringUTF16 stringVal;
|
|
stringVal.string = (IggyUTF16*)label.c_str();
|
|
stringVal.length = label.length();
|
|
|
|
IggyDataValue result;
|
|
IggyDataValue value[1];
|
|
value[0].type = IGGY_DATATYPE_string_UTF16;
|
|
value[0].string16 = stringVal;
|
|
|
|
IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcInitFunctionButtons , 1 , value );
|
|
}
|
|
|
|
#ifdef _WINDOWS64
|
|
if (m_bPCMode)
|
|
{
|
|
// PC text-input mode: hide all on-screen buttons, user types with physical keyboard
|
|
|
|
// Hide the mapped function-row buttons
|
|
m_ButtonSpace.setVisible(false);
|
|
m_ButtonCursorLeft.setVisible(false);
|
|
m_ButtonCursorRight.setVisible(false);
|
|
m_ButtonCaps.setVisible(false);
|
|
m_ButtonSymbols.setVisible(false);
|
|
m_ButtonBackspace.setVisible(false);
|
|
|
|
// Hide the letter/number key grid (Flash-baked, not mapped as UIControls)
|
|
static const char* s_keyNames[] = {
|
|
"Button_q", "Button_w", "Button_e", "Button_r", "Button_t",
|
|
"Button_y", "Button_u", "Button_i", "Button_o", "Button_p",
|
|
"Button_a", "Button_s", "Button_d", "Button_f", "Button_g",
|
|
"Button_h", "Button_j", "Button_k", "Button_l", "Button_apostraphy",
|
|
"Button_z", "Button_x", "Button_c", "Button_v", "Button_b",
|
|
"Button_n", "Button_m", "Button_comma", "Button_stop", "Button_qmark",
|
|
"Button_0", "Button_1", "Button_2", "Button_3", "Button_4",
|
|
"Button_5", "Button_6", "Button_7", "Button_8", "Button_9"
|
|
};
|
|
IggyName nameVisible = registerFastName(L"visible");
|
|
IggyValuePath* root = IggyPlayerRootPath(getMovie());
|
|
for (int i = 0; i < (int)(sizeof(s_keyNames) / sizeof(s_keyNames[0])); ++i)
|
|
{
|
|
IggyValuePath keyPath;
|
|
if (IggyValuePathMakeNameRef(&keyPath, root, s_keyNames[i]))
|
|
IggyValueSetBooleanRS(&keyPath, nameVisible, NULL, false);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
m_bKeyboardDonePressed = false;
|
|
|
|
parentLayer->addComponent(iPad,eUIComponent_MenuBackground);
|
|
}
|
|
|
|
UIScene_Keyboard::~UIScene_Keyboard()
|
|
{
|
|
m_parentLayer->removeComponent(eUIComponent_MenuBackground);
|
|
}
|
|
|
|
wstring UIScene_Keyboard::getMoviePath()
|
|
{
|
|
if(app.GetLocalPlayerCount() > 1 && !m_parentLayer->IsFullscreenGroup())
|
|
{
|
|
return L"KeyboardSplit";
|
|
}
|
|
else
|
|
{
|
|
return L"Keyboard";
|
|
}
|
|
}
|
|
|
|
void UIScene_Keyboard::updateTooltips()
|
|
{
|
|
ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK, -1, -1);
|
|
}
|
|
|
|
bool UIScene_Keyboard::allowRepeat(int key)
|
|
{
|
|
// 4J - TomK - we want to allow X and Y repeats!
|
|
switch(key)
|
|
{
|
|
case ACTION_MENU_OK:
|
|
case ACTION_MENU_CANCEL:
|
|
case ACTION_MENU_A:
|
|
case ACTION_MENU_B:
|
|
case ACTION_MENU_PAUSEMENU:
|
|
//case ACTION_MENU_X:
|
|
//case ACTION_MENU_Y:
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
#ifdef _WINDOWS64
|
|
void UIScene_Keyboard::tick()
|
|
{
|
|
UIScene::tick();
|
|
|
|
// Sync our buffer from Flash so we pick up changes made via controller/on-screen buttons.
|
|
// Without this, switching between controller and keyboard would use stale text.
|
|
const wchar_t* flashText = m_KeyboardTextInput.getLabel();
|
|
if (flashText)
|
|
m_win64TextBuffer = flashText;
|
|
|
|
// Accumulate physical keyboard chars into our own buffer, then push to Flash via setLabel.
|
|
// This bypasses Iggy's focus system (char events only route to the focused element).
|
|
// The char buffer is cleared on open so Enter/clicks from the triggering action don't leak in.
|
|
wchar_t ch;
|
|
bool changed = false;
|
|
while (g_KBMInput.ConsumeChar(ch))
|
|
{
|
|
if (ch == 0x08) // backspace
|
|
{
|
|
if (!m_win64TextBuffer.empty())
|
|
{
|
|
m_win64TextBuffer.pop_back();
|
|
changed = true;
|
|
}
|
|
}
|
|
else if (ch == 0x0D) // enter - confirm
|
|
{
|
|
if (!m_bKeyboardDonePressed)
|
|
{
|
|
addTimer(KEYBOARD_DONE_TIMER_ID, KEYBOARD_DONE_TIMER_TIME);
|
|
m_bKeyboardDonePressed = true;
|
|
}
|
|
}
|
|
else if ((int)m_win64TextBuffer.length() < m_win64MaxChars)
|
|
{
|
|
m_win64TextBuffer += ch;
|
|
changed = true;
|
|
}
|
|
}
|
|
|
|
if (changed)
|
|
m_KeyboardTextInput.setLabel(m_win64TextBuffer.c_str(), true /*instant*/);
|
|
}
|
|
#endif
|
|
|
|
void UIScene_Keyboard::handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled)
|
|
{
|
|
IggyDataValue result;
|
|
IggyResult out;
|
|
|
|
if(repeat || pressed)
|
|
{
|
|
switch(key)
|
|
{
|
|
case ACTION_MENU_CANCEL:
|
|
#ifdef _WINDOWS64
|
|
{
|
|
// Cache before navigateBack() destroys this scene
|
|
int(*cb)(LPVOID, const bool) = m_win64Callback;
|
|
LPVOID cbParam = m_win64CallbackParam;
|
|
navigateBack();
|
|
if (cb)
|
|
cb(cbParam, false);
|
|
}
|
|
#else
|
|
navigateBack();
|
|
#endif
|
|
handled = true;
|
|
break;
|
|
case ACTION_MENU_X: // X
|
|
out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcBackspaceButtonPressed, 0 , NULL );
|
|
handled = true;
|
|
break;
|
|
case ACTION_MENU_PAGEUP: // LT
|
|
out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcSymbolButtonPressed, 0 , NULL );
|
|
handled = true;
|
|
break;
|
|
case ACTION_MENU_Y: // Y
|
|
out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcSpaceButtonPressed, 0 , NULL );
|
|
handled = true;
|
|
break;
|
|
case ACTION_MENU_STICK_PRESS: // LS
|
|
out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcCapsButtonPressed, 0 , NULL );
|
|
handled = true;
|
|
break;
|
|
case ACTION_MENU_LEFT_SCROLL: // LB
|
|
out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcCursorLeftButtonPressed, 0 , NULL );
|
|
handled = true;
|
|
break;
|
|
case ACTION_MENU_RIGHT_SCROLL: // RB
|
|
out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcCursorRightButtonPressed, 0 , NULL );
|
|
handled = true;
|
|
break;
|
|
case ACTION_MENU_PAUSEMENU: // Start
|
|
if(!m_bKeyboardDonePressed)
|
|
{
|
|
out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcDoneButtonPressed, 0 , NULL );
|
|
|
|
// kick off done timer
|
|
addTimer(KEYBOARD_DONE_TIMER_ID,KEYBOARD_DONE_TIMER_TIME);
|
|
m_bKeyboardDonePressed = true;
|
|
}
|
|
handled = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch(key)
|
|
{
|
|
case ACTION_MENU_OK:
|
|
case ACTION_MENU_LEFT:
|
|
case ACTION_MENU_RIGHT:
|
|
case ACTION_MENU_UP:
|
|
case ACTION_MENU_DOWN:
|
|
sendInputToMovie(key, repeat, pressed, released);
|
|
handled = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void UIScene_Keyboard::handlePress(F64 controlId, F64 childId)
|
|
{
|
|
if((int)controlId == 0)
|
|
{
|
|
// Done has been pressed. At this point we can query for the input string and pass it on to wherever it is needed.
|
|
// we can not query for m_KeyboardTextInput.getLabel() here because we're in an iggy callback so we need to wait a frame.
|
|
if(!m_bKeyboardDonePressed)
|
|
{
|
|
// kick off done timer
|
|
addTimer(KEYBOARD_DONE_TIMER_ID,KEYBOARD_DONE_TIMER_TIME);
|
|
m_bKeyboardDonePressed = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void UIScene_Keyboard::handleTimerComplete(int id)
|
|
{
|
|
if(id == KEYBOARD_DONE_TIMER_ID)
|
|
{
|
|
// remove timer
|
|
killTimer(KEYBOARD_DONE_TIMER_ID);
|
|
|
|
// we're done here!
|
|
KeyboardDonePressed();
|
|
}
|
|
}
|
|
|
|
void UIScene_Keyboard::KeyboardDonePressed()
|
|
{
|
|
#ifdef _WINDOWS64
|
|
// Use getLabel() here — this is a timer callback (not an Iggy callback) so it's safe.
|
|
// getLabel() reflects both physical keyboard input (pushed via setLabel) and
|
|
// on-screen button input (set directly by Flash ActionScript).
|
|
const wchar_t* finalText = m_KeyboardTextInput.getLabel();
|
|
app.DebugPrintf("UI Keyboard - DONE - [%ls]\n", finalText);
|
|
|
|
// Store the typed text so callbacks can retrieve it via Win64_GetKeyboardText()
|
|
wcsncpy_s(g_Win64KeyboardResult, 256, finalText, _TRUNCATE);
|
|
|
|
// Cache callback and param before navigateBack() which destroys this scene
|
|
int(*cb)(LPVOID, const bool) = m_win64Callback;
|
|
LPVOID cbParam = m_win64CallbackParam;
|
|
|
|
// Navigate back so the scene stack is restored before the callback runs
|
|
navigateBack();
|
|
|
|
// Fire callback: bRes=true means confirmed
|
|
if (cb)
|
|
cb(cbParam, true);
|
|
#else
|
|
app.DebugPrintf("UI Keyboard - DONE - [%ls]\n", m_KeyboardTextInput.getLabel());
|
|
navigateBack();
|
|
#endif
|
|
} |