123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444 |
- /****************************************************************************
- Copyright (c) 2010-2012 cocos2d-x.org
- Copyright (c) 2013 Jozef Pridavok
- Copyright (c) 2013-2017 zilongshanren
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos2d-x.org
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
- #include "ui/UIEditBox/UIEditBoxImpl-win32.h"
- #include "platform/CCPlatformConfig.h"
- #if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
- #include "ui/UIEditBox/UIEditBox.h"
- #include <tchar.h>
- #include <stdio.h>
- #include "2d/CCLabel.h"
- #include "base/CCDirector.h"
- #include "base/ccUTF8.h"
- #include <Commctrl.h>
- #include <windows.h>
- #include "ui/UIHelper.h"
- NS_CC_BEGIN
- namespace ui {
- bool EditBoxImplWin::s_isInitialized = false;
- int EditBoxImplWin::s_editboxChildID = 100;
- HWND EditBoxImplWin::s_previousFocusWnd = 0;
- WNDPROC EditBoxImplWin::s_prevCocosWndProc = 0;
- HINSTANCE EditBoxImplWin::s_hInstance = 0;
- HWND EditBoxImplWin::s_hwndCocos = 0;
- void EditBoxImplWin::lazyInit()
- {
- s_hwndCocos = cocos2d::Director::getInstance()->getOpenGLView()->getWin32Window();
- LONG style = ::GetWindowLongW(s_hwndCocos, GWL_STYLE);
- ::SetWindowLongW(s_hwndCocos, GWL_STYLE, style | WS_CLIPCHILDREN);
- s_isInitialized = true;
- s_previousFocusWnd = s_hwndCocos;
- s_hInstance = ::GetModuleHandleW(nullptr);
- s_prevCocosWndProc = (WNDPROC)SetWindowLongPtrW(s_hwndCocos, GWL_WNDPROC, (LONG_PTR)hookGLFWWindowProc);
- }
- EditBoxImpl* __createSystemEditBox(EditBox* pEditBox)
- {
- return new (std::nothrow) EditBoxImplWin(pEditBox);
- }
- EditBoxImplWin::EditBoxImplWin(EditBox* pEditText)
- : EditBoxImplCommon(pEditText),
- _changedTextManually(false),
- _hasFocus(false),
- _endAction(EditBoxDelegate::EditBoxEndAction::UNKNOWN)
- {
- if (!s_isInitialized)
- {
- lazyInit();
- }
- s_editboxChildID++;
- }
- EditBoxImplWin::~EditBoxImplWin()
- {
- this->cleanupEditCtrl();
- }
- bool EditBoxImplWin::isEditing()
- {
- return false;
- }
- void EditBoxImplWin::cleanupEditCtrl()
- {
- if (_hwndEdit)
- {
- SetWindowLongPtrW(_hwndEdit, GWL_WNDPROC, (LONG_PTR)_prevWndProc);
- ::DestroyWindow(_hwndEdit);
- _hasFocus = false;
- _changedTextManually = false;
- _editingMode = false;
- _hwndEdit = NULL;
- }
- }
- void EditBoxImplWin::createEditCtrl(bool singleLine)
- {
- this->cleanupEditCtrl();
- if (!_hwndEdit)
- {
- _hwndEdit = ::CreateWindowExW(
- WS_EX_CLIENTEDGE, L"EDIT", // predefined class
- NULL, // no window title
- WS_CHILD | ES_LEFT | WS_BORDER | WS_EX_TRANSPARENT | WS_TABSTOP | ES_AUTOHSCROLL | (singleLine ? 0 : ES_MULTILINE),
- 0,
- 0,
- 0,
- 0, // set size in WM_SIZE message
- s_hwndCocos, // parent window
- (HMENU)s_editboxChildID, // edit control ID
- s_hInstance,
- this); // pointer not needed
- SetWindowLongPtrW(_hwndEdit, GWL_USERDATA, (LONG_PTR)this);
- _prevWndProc = (WNDPROC)SetWindowLongPtrW(_hwndEdit, GWL_WNDPROC, (LONG_PTR)WindowProc);
- ::SendMessageW(_hwndEdit, EM_LIMITTEXT, this->_maxLength, 0);
- s_previousFocusWnd = s_hwndCocos;
- this->setNativeFont(this->getNativeDefaultFontName(), this->_fontSize);
- this->setNativeText(this->_text.c_str());
- }
- }
- void EditBoxImplWin::createNativeControl(const Rect& frame)
- {
- this->createEditCtrl(false);
- }
- void EditBoxImplWin::setNativeFont(const char* pFontName, int fontSize)
- {
- auto glView = Director::getInstance()->getOpenGLView();
- HFONT hFont = ::CreateFontW(static_cast<int>(fontSize * glView->getScaleX()), 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS,
- CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, VARIABLE_PITCH, L"Arial");
- ::SendMessageW(_hwndEdit, // Handle of edit control
- WM_SETFONT, // Message to change the font
- (WPARAM)hFont, // handle of the font
- MAKELPARAM(TRUE, 0) // Redraw text
- );
- }
- void EditBoxImplWin::setNativeFontColor(const Color4B& color)
- {
- //not implemented yet
- }
- void EditBoxImplWin::setNativePlaceholderFont(const char* pFontName, int fontSize)
- {
- //not implemented yet
- }
- void EditBoxImplWin::setNativePlaceholderFontColor(const Color4B& color)
- {
- //not implemented yet
- }
- void EditBoxImplWin::setNativeInputMode(EditBox::InputMode inputMode)
- {
- if (_editBoxInputMode == cocos2d::ui::EditBox::InputMode::ANY)
- {
- this->createEditCtrl(false);
- }
- else if (_editBoxInputMode == cocos2d::ui::EditBox::InputMode::NUMERIC
- || _editBoxInputMode == cocos2d::ui::EditBox::InputMode::DECIMAL
- || _editBoxInputMode == cocos2d::ui::EditBox::InputMode::PHONE_NUMBER)
- {
- this->createEditCtrl(true);
- ::SetWindowLongW(_hwndEdit, GWL_STYLE, ::GetWindowLongW(_hwndEdit, GWL_STYLE) | ES_NUMBER);
- }
- else
- {
- this->createEditCtrl(true);
- }
- if (this->_editBoxInputFlag != cocos2d::ui::EditBox::InputFlag::PASSWORD)
- {
- ::PostMessageW(_hwndEdit, EM_SETPASSWORDCHAR, (WPARAM)0, (LPARAM)0);
- }
- }
- void EditBoxImplWin::setNativeInputFlag(EditBox::InputFlag inputFlag)
- {
- if (inputFlag == EditBox::InputFlag::PASSWORD)
- {
- this->createEditCtrl(true);
- }
- else
- {
- if (_editBoxInputMode != cocos2d::ui::EditBox::InputMode::ANY)
- {
- this->createEditCtrl(true);
- if (inputFlag == EditBox::InputFlag::INITIAL_CAPS_ALL_CHARACTERS)
- {
- ::SetWindowLongW(_hwndEdit, GWL_STYLE, ::GetWindowLongW(_hwndEdit, GWL_STYLE) | ES_UPPERCASE);
- }
- // Clear the password style
- ::PostMessageW(_hwndEdit, EM_SETPASSWORDCHAR, (WPARAM)0, (LPARAM)0);
- }
- }
- }
- void EditBoxImplWin::setNativeReturnType(EditBox::KeyboardReturnType returnType)
- {
- //not implemented yet
- }
- void EditBoxImplWin::setNativeTextHorizontalAlignment(TextHAlignment alignment)
- {
- LONG style = ::GetWindowLongW(_hwndEdit, GWL_STYLE);
- switch (alignment)
- {
- case TextHAlignment::LEFT:
- style = (style & ~ES_CENTER & ~ES_RIGHT) | ES_LEFT;
- break;
- case TextHAlignment::CENTER:
- style = (style & ~ES_LEFT & ~ES_RIGHT) | ES_CENTER;
- break;
- case TextHAlignment::RIGHT:
- style = (style & ~ES_LEFT & ~ES_CENTER) | ES_RIGHT;
- break;
- }
- ::SetWindowLongW(_hwndEdit, GWL_STYLE, style);
- }
- void EditBoxImplWin::setNativeText(const char* pText)
- {
- std::u16string utf16Result;
- std::string text(pText);
- cocos2d::StringUtils::UTF8ToUTF16(text, utf16Result);
- this->_changedTextManually = true;
- ::SetWindowTextW(_hwndEdit, (LPCWSTR)utf16Result.c_str());
- int textLen = text.size();
- ::SendMessageW(_hwndEdit, EM_SETSEL, textLen, textLen);
- if (_editBoxInputMode == cocos2d::ui::EditBox::InputMode::ANY)
- {
- ::SendMessageW(_hwndEdit, EM_SCROLLCARET, 0, 0);
- }
- }
- void EditBoxImplWin::setNativePlaceHolder(const char* pText)
- {
- //not implemented yet
- }
- void EditBoxImplWin::setNativeVisible(bool visible)
- {
- if (visible)
- {
- ::ShowWindow(_hwndEdit, SW_SHOW);
- }
- else
- {
- ::ShowWindow(_hwndEdit, SW_HIDE);
- }
- }
- void EditBoxImplWin::updateNativeFrame(const Rect& rect)
- {
- ::SetWindowPos(
- _hwndEdit,
- HWND_NOTOPMOST,
- rect.origin.x,
- rect.origin.y,
- rect.size.width,
- rect.size.height,
- SWP_NOZORDER);
- }
- const char* EditBoxImplWin::getNativeDefaultFontName()
- {
- return "Arial";
- }
- void EditBoxImplWin::nativeOpenKeyboard()
- {
- ::PostMessageW(_hwndEdit, WM_SETFOCUS, (WPARAM)s_previousFocusWnd, 0);
- // s_previousFocusWnd = hwndEdit;
- this->editBoxEditingDidBegin();
- auto rect = ui::Helper::convertBoundingBoxToScreen(_editBox);
- this->updateNativeFrame(rect);
- }
- void EditBoxImplWin::nativeCloseKeyboard()
- {
- //don't need to implement
- }
- void EditBoxImplWin::setNativeMaxLength(int maxLength)
- {
- ::SendMessageW(_hwndEdit, EM_LIMITTEXT, maxLength, 0);
- }
- void EditBoxImplWin::_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
- {
- switch (uMsg)
- {
- case WM_CHAR:
- if (wParam == VK_RETURN)
- {
- 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)
- {
- ::PostMessageW(hwnd, WM_ACTIVATE, (WPARAM)s_previousFocusWnd, 0);
- ::PostMessageW(hwnd, WM_SETCURSOR, (WPARAM)s_previousFocusWnd, 0);
- s_previousFocusWnd = _hwndEdit;
- _hasFocus = true;
- this->_changedTextManually = false;
- }
- break;
- case WM_KILLFOCUS:
- _hasFocus = false;
- //when app enter background, this message also be called.
- if (this->_editingMode && !::IsWindowVisible(hwnd))
- {
- this->editBoxEditingDidEnd(this->getText(), _endAction);
- }
- break;
- default:
- break;
- }
- }
- std::string EditBoxImplWin::getText() const
- {
- std::u16string wstrResult;
- std::string utf8Result;
- int inputLength = ::GetWindowTextLengthW(_hwndEdit);
- wstrResult.resize(inputLength);
- ::GetWindowTextW(_hwndEdit, (LPWSTR)&wstrResult[0], inputLength + 1);
- bool conversionResult = cocos2d::StringUtils::UTF16ToUTF8(wstrResult, utf8Result);
- if (!conversionResult)
- {
- CCLOG("warning, editbox input text conversion error.");
- }
- return std::move(utf8Result);
- }
- 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:
- if (s_previousFocusWnd != s_hwndCocos) {
- ::ShowWindow(s_previousFocusWnd, SW_HIDE);
- EditBoxImplWin* pThis = (EditBoxImplWin*)GetWindowLongPtrW(s_previousFocusWnd, GWLP_USERDATA);
- if (pThis!=nullptr && !pThis->_hasFocus)
- {
- if (pThis->_editingMode && !IsWindowVisible(s_previousFocusWnd))
- {
- pThis->editBoxEditingDidEnd(pThis->getText());
- }
- }
- else
- {
- ::PostMessageW(s_hwndCocos, WM_SETFOCUS, (WPARAM)s_previousFocusWnd, 0);
- }
- s_previousFocusWnd = s_hwndCocos;
- }
- break;
- default:
- break;
- }
- return ::CallWindowProcW(s_prevCocosWndProc, hwnd, uMsg, wParam, lParam);
- }
- LRESULT EditBoxImplWin::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
- {
- EditBoxImplWin* pThis = (EditBoxImplWin*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
- if (pThis)
- {
- pThis->_WindowProc(hwnd, uMsg, wParam, lParam);
- }
- return ::CallWindowProcW(pThis->_prevWndProc, hwnd, uMsg, wParam, lParam);
- }
- }
- NS_CC_END
- #endif /* (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) */
|