Actually, I now have it working! So, my current version of UIEditBoxImpl-win32.cpp now lets me tab between fields and no longer has this problem. I’m working with 3.17, so I don’t think I want to do a pull request, but if anyone would like a copy of my edit, I can do that.
But actually, I simply modified the function thus. I simply added pThis->endAction = RETURN, because in my code where I support the TAB key, I look for TAB_TO_NEXT.
I need to clean this up, debugging/stepping wasn’t going too well, so I added a lot of CCLOG statements and found it.
LRESULT EditBoxImplWin::hookGLFWWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_COMMAND:
if (HIWORD(wParam) == EN_CHANGE) {
EditBoxImplWin* pThis = (EditBoxImplWin*)GetWindowLongPtrW((HWND)lParam, GWLP_USERDATA);
if (pThis && !pThis->_changedTextManually)
{
pThis->editBoxEditingChanged(pThis->getText());
pThis->_changedTextManually = false;
}
}
break;
case WM_LBUTTONDOWN:
// CCLOG("\nUIEditBox, WM_LBUTTONDOWN");
if (s_previousFocusWnd != s_hwndCocos) {
// CCLOG("WM_LBUTTONDOWN, entered block (s_previousFocusWnd != s_hwndCocos), before showWindow (hide)");
// added this so that I can manually override the _endAction on the current edit field
EditBoxImplWin* pThis = (EditBoxImplWin*)GetWindowLongPtrW(s_previousFocusWnd, GWLP_USERDATA);
if (pThis != nullptr)
pThis->_endAction = EditBoxDelegate::EditBoxEndAction::RETURN;
::ShowWindow(s_previousFocusWnd, SW_HIDE);
// CCLOG("WM_LBUTTONDOWN, *after* showWindow (hide)");
// EditBoxImplWin* pThis = (EditBoxImplWin*)GetWindowLongPtrW(s_previousFocusWnd, GWLP_USERDATA);
if (pThis!=nullptr && !pThis->_hasFocus)
{
// CCLOG("WM_LBUTTONDOWN, next block (pThis != nullptr)");
// next experiment with commenting out IsWindowVisible
// if (pThis->_editingMode && !IsWindowVisible(s_previousFocusWnd))
if (pThis->_editingMode) // && !IsWindowVisible(s_previousFocusWnd))
{
// CCLOG("WM_LBUTTONDOWN, inner block (pThis->_editingMode)");
pThis->editBoxEditingDidEnd(pThis->getText(), EditBoxDelegate::EditBoxEndAction::RETURN);
}
}
else
{
// CCLOG("WM_LBUTTONDOWN, else block (NOT pThis != nullptr)");
::PostMessageW(s_hwndCocos, WM_SETFOCUS, (WPARAM)s_previousFocusWnd, 0);
}
s_previousFocusWnd = s_hwndCocos;
}
break;
default:
break;
}
return ::CallWindowProcW(s_prevCocosWndProc, hwnd, uMsg, wParam, lParam);
}
I support tabbing here (the VK_TAB part)
void EditBoxImplWin::_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
// CCLOG("uMsg = %d, wParam = %d, lParam = %d", uMsg, wParam, lParam);
switch (uMsg)
{
case WM_CHAR:
if (wParam == VK_ESCAPE)
{
_hasFocus = false;
//when app enter background, this message also be called.
if (this->_editingMode && !::IsWindowVisible(hwnd))
{
_endAction = EditBoxDelegate::EditBoxEndAction::RETURN;
this->editBoxEditingDidEnd(this->getText(), _endAction);
}
}
else if (wParam == VK_RETURN || wParam == VK_TAB)
{
// KERRY BATTS - added "VK_TAB"
if (_editBoxInputMode != cocos2d::ui::EditBox::InputMode::ANY) {
if (s_previousFocusWnd != s_hwndCocos) {
switch (_keyboardReturnType)
{
case EditBox::KeyboardReturnType::DEFAULT:
_endAction = EditBoxDelegate::EditBoxEndAction::UNKNOWN;
break;
case EditBox::KeyboardReturnType::DONE:
_endAction = EditBoxDelegate::EditBoxEndAction::RETURN;
break;
case EditBox::KeyboardReturnType::SEND:
_endAction = EditBoxDelegate::EditBoxEndAction::RETURN;
break;
case EditBox::KeyboardReturnType::SEARCH:
_endAction = EditBoxDelegate::EditBoxEndAction::RETURN;
break;
case EditBox::KeyboardReturnType::GO:
_endAction = EditBoxDelegate::EditBoxEndAction::RETURN;
break;
case EditBox::KeyboardReturnType::NEXT:
_endAction = EditBoxDelegate::EditBoxEndAction::TAB_TO_NEXT;
break;
default:
_endAction = EditBoxDelegate::EditBoxEndAction::UNKNOWN;
break;
}
::ShowWindow(s_previousFocusWnd, SW_HIDE);
::SendMessageW(s_hwndCocos, WM_SETFOCUS, (WPARAM)s_previousFocusWnd, 0);
s_previousFocusWnd = s_hwndCocos;
}
}
}
break;
case WM_SETFOCUS:
if (hwnd != s_previousFocusWnd)
{
//CCLOG("\nWM_SETFOCUS, entered block");
::PostMessageW(hwnd, WM_ACTIVATE, (WPARAM)s_previousFocusWnd, 0);
::PostMessageW(hwnd, WM_SETCURSOR, (WPARAM)s_previousFocusWnd, 0);
s_previousFocusWnd = _hwndEdit;
_hasFocus = true;
this->_changedTextManually = false;
}
else
{
// CCLOG("\nWM_SETFOCUS, did NOT enter block");
}
break;
case WM_KILLFOCUS:
_hasFocus = false;
//when app enter background, this message also be called.
if (this->_editingMode && !::IsWindowVisible(hwnd))
{
// CCLOG("\nWM_KILLFOCUS, entered block");
this->editBoxEditingDidEnd(this->getText(), _endAction);
}
else
{
// CCLOG("\nWM_KILLFOCUS, did NOT enter block");
}
break;
default:
break;
}
}
and finally, I have my own EditBoxDelegate subclass that does this:
void PsfEditBoxDelegate::editBoxEditingDidEndWithAction(cocos2d::ui::EditBox *editBox, cocos2d::ui::EditBoxDelegate::EditBoxEndAction action)
{
updateDataFromEditBox(editBox);
// updateDataFromEditBoxes();
// CCLOG(“fired DidEndWithAction”);
if (action == cocos2d::ui::EditBoxDelegate::EditBoxEndAction::TAB_TO_NEXT)
{
EditBox *next = (EditBox *)editBox->getUserData();
if (next != nullptr)
{
editBox->closeKeyboard();
setFocus(next);
}
}
}
void PsfEditBoxDelegate::setFocus(cocos2d::ui::EditBox *editBox)
{
editBox->openKeyboard();
}