mirror of https://github.com/axmolengine/axmol.git
Prevent excessive calls to deleteBackward method which may cause crashes on Android (#2248)
* Pass the number of characters to delete from a TextField * Include TextFieldEx.h reference in axmoil-ui.h * Remove logging calls used for testing * Update parameter name
This commit is contained in:
parent
1e8fbb991d
commit
c37bcf8977
|
@ -24,6 +24,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "2d/TextFieldTTF.h"
|
#include "2d/TextFieldTTF.h"
|
||||||
|
|
||||||
#include "base/Director.h"
|
#include "base/Director.h"
|
||||||
|
@ -310,7 +312,7 @@ void TextFieldTTF::insertText(const char* text, size_t len)
|
||||||
detachWithIME();
|
detachWithIME();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextFieldTTF::deleteBackward()
|
void TextFieldTTF::deleteBackward(size_t numChars)
|
||||||
{
|
{
|
||||||
size_t len = _inputText.length();
|
size_t len = _inputText.length();
|
||||||
if (!len)
|
if (!len)
|
||||||
|
@ -319,23 +321,33 @@ void TextFieldTTF::deleteBackward()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the delete byte number
|
// Length of characters to delete is based on input editor, but the actual
|
||||||
size_t deleteLen = 1; // default, erase 1 byte
|
// length of the displayed text may be less
|
||||||
|
numChars = std::min(numChars, len);
|
||||||
|
|
||||||
while (0x80 == (0xC0 & _inputText.at(len - deleteLen)))
|
size_t totalDeleteLen = 0;
|
||||||
|
for (auto i = 0; i < numChars; ++i)
|
||||||
{
|
{
|
||||||
++deleteLen;
|
// get the delete byte number
|
||||||
|
size_t deleteLen = 1; // default, erase 1 byte
|
||||||
|
|
||||||
|
// Calculate the actual number of bytes to delete for a specific character
|
||||||
|
while (0x80 == (0xC0 & _inputText.at(len - totalDeleteLen - deleteLen)))
|
||||||
|
{
|
||||||
|
++deleteLen;
|
||||||
|
}
|
||||||
|
totalDeleteLen += deleteLen;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_delegate &&
|
if (_delegate &&
|
||||||
_delegate->onTextFieldDeleteBackward(this, _inputText.c_str() + len - deleteLen, static_cast<int>(deleteLen)))
|
_delegate->onTextFieldDeleteBackward(this, _inputText.c_str() + len - totalDeleteLen, static_cast<int>(totalDeleteLen)))
|
||||||
{
|
{
|
||||||
// delegate doesn't want to delete backwards
|
// delegate doesn't want to delete backwards
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if all text deleted, show placeholder string
|
// if all text deleted, show placeholder string
|
||||||
if (len <= deleteLen)
|
if (len <= totalDeleteLen)
|
||||||
{
|
{
|
||||||
_inputText = "";
|
_inputText = "";
|
||||||
_charCount = 0;
|
_charCount = 0;
|
||||||
|
@ -362,7 +374,7 @@ void TextFieldTTF::deleteBackward()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::string text(_inputText.c_str(), len - deleteLen);
|
std::string text(_inputText.c_str(), len - totalDeleteLen);
|
||||||
setString(text);
|
setString(text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -261,7 +261,7 @@ protected:
|
||||||
virtual void didAttachWithIME() override;
|
virtual void didAttachWithIME() override;
|
||||||
virtual void didDetachWithIME() override;
|
virtual void didDetachWithIME() override;
|
||||||
virtual void insertText(const char* text, size_t len) override;
|
virtual void insertText(const char* text, size_t len) override;
|
||||||
virtual void deleteBackward() override;
|
virtual void deleteBackward(size_t numChars) override;
|
||||||
virtual std::string_view getContentText() override;
|
virtual std::string_view getContentText() override;
|
||||||
virtual void controlKey(EventKeyboard::KeyCode keyCode) override;
|
virtual void controlKey(EventKeyboard::KeyCode keyCode) override;
|
||||||
|
|
||||||
|
|
|
@ -124,7 +124,7 @@ protected:
|
||||||
* @js NA
|
* @js NA
|
||||||
* @lua NA
|
* @lua NA
|
||||||
*/
|
*/
|
||||||
virtual void deleteBackward() {}
|
virtual void deleteBackward(size_t numChars) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief Called by IMEDispatcher after the user press control key.
|
@brief Called by IMEDispatcher after the user press control key.
|
||||||
|
|
|
@ -222,7 +222,7 @@ void IMEDispatcher::dispatchInsertText(const char* text, size_t len)
|
||||||
} while (0);
|
} while (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IMEDispatcher::dispatchDeleteBackward()
|
void IMEDispatcher::dispatchDeleteBackward(int numChars)
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
@ -231,7 +231,7 @@ void IMEDispatcher::dispatchDeleteBackward()
|
||||||
// there is no delegate attached to IME
|
// there is no delegate attached to IME
|
||||||
AX_BREAK_IF(!_impl->_delegateWithIme);
|
AX_BREAK_IF(!_impl->_delegateWithIme);
|
||||||
|
|
||||||
_impl->_delegateWithIme->deleteBackward();
|
_impl->_delegateWithIme->deleteBackward(numChars);
|
||||||
} while (0);
|
} while (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ public:
|
||||||
* @brief Dispatches the delete-backward operation.
|
* @brief Dispatches the delete-backward operation.
|
||||||
* @lua NA
|
* @lua NA
|
||||||
*/
|
*/
|
||||||
void dispatchDeleteBackward();
|
void dispatchDeleteBackward(int numChars);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Dispatches the press control key operation.
|
* @brief Dispatches the press control key operation.
|
||||||
|
|
|
@ -1220,7 +1220,7 @@ void GLViewImpl::onGLFWKeyCallback(GLFWwindow* /*window*/, int key, int /*scanco
|
||||||
switch (g_keyCodeMap[key])
|
switch (g_keyCodeMap[key])
|
||||||
{
|
{
|
||||||
case EventKeyboard::KeyCode::KEY_BACKSPACE:
|
case EventKeyboard::KeyCode::KEY_BACKSPACE:
|
||||||
IMEDispatcher::sharedDispatcher()->dispatchDeleteBackward();
|
IMEDispatcher::sharedDispatcher()->dispatchDeleteBackward(1);
|
||||||
break;
|
break;
|
||||||
case EventKeyboard::KeyCode::KEY_HOME:
|
case EventKeyboard::KeyCode::KEY_HOME:
|
||||||
case EventKeyboard::KeyCode::KEY_KP_HOME:
|
case EventKeyboard::KeyCode::KEY_KP_HOME:
|
||||||
|
|
|
@ -458,11 +458,11 @@ public class AxmolGLSurfaceView extends GLSurfaceView {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteBackward() {
|
public void deleteBackward(int numChars) {
|
||||||
this.queueEvent(new Runnable() {
|
this.queueEvent(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
AxmolGLSurfaceView.this.mRenderer.handleDeleteBackward();
|
AxmolGLSurfaceView.this.mRenderer.handleDeleteBackward(numChars);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,15 +176,15 @@ public class AxmolRenderer implements GLSurfaceView.Renderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native void nativeInsertText(final String text);
|
private static native void nativeInsertText(final String text);
|
||||||
private static native void nativeDeleteBackward();
|
private static native void nativeDeleteBackward(final int numChars);
|
||||||
private static native String nativeGetContentText();
|
private static native String nativeGetContentText();
|
||||||
|
|
||||||
public void handleInsertText(final String text) {
|
public void handleInsertText(final String text) {
|
||||||
AxmolRenderer.nativeInsertText(text);
|
AxmolRenderer.nativeInsertText(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleDeleteBackward() {
|
public void handleDeleteBackward(final int numChars) {
|
||||||
AxmolRenderer.nativeDeleteBackward();
|
AxmolRenderer.nativeDeleteBackward(numChars);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getContentText() {
|
public String getContentText() {
|
||||||
|
|
|
@ -90,8 +90,8 @@ public class TextInputWrapper implements TextWatcher, OnEditorActionListener {
|
||||||
new_i += 1;
|
new_i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; old_i < this.mText.length(); ++old_i) {
|
if (old_i < this.mText.length()) {
|
||||||
this.mGLSurfaceView.deleteBackward();
|
this.mGLSurfaceView.deleteBackward(this.mText.length() - old_i);
|
||||||
}
|
}
|
||||||
|
|
||||||
int nModified = s.length() - new_i;
|
int nModified = s.length() - new_i;
|
||||||
|
@ -118,13 +118,13 @@ public class TextInputWrapper implements TextWatcher, OnEditorActionListener {
|
||||||
if (this.mGLSurfaceView.getEditText() == pTextView && this.isFullScreenEdit()) {
|
if (this.mGLSurfaceView.getEditText() == pTextView && this.isFullScreenEdit()) {
|
||||||
// user press the action button, delete all old text and insert new text
|
// user press the action button, delete all old text and insert new text
|
||||||
if (null != mOriginText) {
|
if (null != mOriginText) {
|
||||||
for (int i = this.mOriginText.length(); i > 0; i--) {
|
if (!this.mOriginText.isEmpty()) {
|
||||||
this.mGLSurfaceView.deleteBackward();
|
this.mGLSurfaceView.deleteBackward(this.mOriginText.length());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String text = pTextView.getText().toString();
|
String text = pTextView.getText().toString();
|
||||||
|
|
||||||
if (text != null) {
|
if (text != null) {
|
||||||
/* If user input nothing, translate "\n" to engine. */
|
/* If user input nothing, translate "\n" to engine. */
|
||||||
if ( text.compareTo("") == 0) {
|
if ( text.compareTo("") == 0) {
|
||||||
|
@ -135,16 +135,16 @@ public class TextInputWrapper implements TextWatcher, OnEditorActionListener {
|
||||||
text += '\n';
|
text += '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final String insertText = text;
|
final String insertText = text;
|
||||||
this.mGLSurfaceView.insertText(insertText);
|
this.mGLSurfaceView.insertText(insertText);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pActionID == EditorInfo.IME_ACTION_DONE) {
|
if (pActionID == EditorInfo.IME_ACTION_DONE) {
|
||||||
this.mGLSurfaceView.requestFocus();
|
this.mGLSurfaceView.requestFocus();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,9 +70,9 @@ JNIEXPORT void JNICALL Java_org_axmol_lib_AxmolRenderer_nativeInsertText(JNIEnv*
|
||||||
ax::IMEDispatcher::sharedDispatcher()->dispatchInsertText(pszText, strlen(pszText));
|
ax::IMEDispatcher::sharedDispatcher()->dispatchInsertText(pszText, strlen(pszText));
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_org_axmol_lib_AxmolRenderer_nativeDeleteBackward(JNIEnv*, jclass)
|
JNIEXPORT void JNICALL Java_org_axmol_lib_AxmolRenderer_nativeDeleteBackward(JNIEnv*, jclass, jint numChars)
|
||||||
{
|
{
|
||||||
ax::IMEDispatcher::sharedDispatcher()->dispatchDeleteBackward();
|
ax::IMEDispatcher::sharedDispatcher()->dispatchDeleteBackward(numChars);
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jstring JNICALL Java_org_axmol_lib_AxmolRenderer_nativeGetContentText(JNIEnv* env, jclass)
|
JNIEXPORT jstring JNICALL Java_org_axmol_lib_AxmolRenderer_nativeGetContentText(JNIEnv* env, jclass)
|
||||||
|
|
|
@ -98,7 +98,7 @@ THE SOFTWARE.
|
||||||
[self.myMarkedText release];
|
[self.myMarkedText release];
|
||||||
self.myMarkedText = nil;
|
self.myMarkedText = nil;
|
||||||
}
|
}
|
||||||
ax::IMEDispatcher::sharedDispatcher()->dispatchDeleteBackward();
|
ax::IMEDispatcher::sharedDispatcher()->dispatchDeleteBackward(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)insertText:(nonnull NSString*)text
|
- (void)insertText:(nonnull NSString*)text
|
||||||
|
|
|
@ -112,7 +112,7 @@ void KeyboardEvent::execute()
|
||||||
//Director::getInstance()()->getKeypadDispatcher()->dispatchKeypadMSG(kTypeBackClicked);
|
//Director::getInstance()()->getKeypadDispatcher()->dispatchKeypadMSG(kTypeBackClicked);
|
||||||
break;
|
break;
|
||||||
case AxmolKeyEvent::Back:
|
case AxmolKeyEvent::Back:
|
||||||
IMEDispatcher::sharedDispatcher()->dispatchDeleteBackward();
|
IMEDispatcher::sharedDispatcher()->dispatchDeleteBackward(1);
|
||||||
break;
|
break;
|
||||||
case AxmolKeyEvent::Enter:
|
case AxmolKeyEvent::Enter:
|
||||||
IMEDispatcher::sharedDispatcher()->dispatchInsertText("\n", 1);
|
IMEDispatcher::sharedDispatcher()->dispatchInsertText("\n", 1);
|
||||||
|
|
|
@ -304,7 +304,7 @@ void KeyBoardWinRT::OnWinRTKeyboardEvent(WinRTKeyboardEventType type, KeyEventAr
|
||||||
switch (keyCode)
|
switch (keyCode)
|
||||||
{
|
{
|
||||||
case EventKeyboard::KeyCode::KEY_BACKSPACE:
|
case EventKeyboard::KeyCode::KEY_BACKSPACE:
|
||||||
IMEDispatcher::sharedDispatcher()->dispatchDeleteBackward();
|
IMEDispatcher::sharedDispatcher()->dispatchDeleteBackward(1);
|
||||||
break;
|
break;
|
||||||
case EventKeyboard::KeyCode::KEY_HOME:
|
case EventKeyboard::KeyCode::KEY_HOME:
|
||||||
case EventKeyboard::KeyCode::KEY_KP_HOME:
|
case EventKeyboard::KeyCode::KEY_KP_HOME:
|
||||||
|
|
|
@ -617,7 +617,7 @@ void TextFieldEx::insertText(const char* text, size_t len)
|
||||||
this->closeIME();
|
this->closeIME();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextFieldEx::deleteBackward()
|
void TextFieldEx::deleteBackward(size_t numChars)
|
||||||
{
|
{
|
||||||
if (!_editable || !this->_enabled || 0 == _charCount)
|
if (!_editable || !this->_enabled || 0 == _charCount)
|
||||||
{
|
{
|
||||||
|
@ -634,23 +634,33 @@ void TextFieldEx::deleteBackward()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the delete byte number
|
// Length of characters to delete is based on input editor, but the actual
|
||||||
size_t deleteLen = 1; // default, erase 1 byte
|
// length of the displayed text may be less
|
||||||
|
numChars = std::min(numChars, len);
|
||||||
|
|
||||||
while (0x80 == (0xC0 & _inputText.at(_insertPos - deleteLen)))
|
size_t totalDeleteLen = 0;
|
||||||
|
for (auto i = 0; i < numChars; ++i)
|
||||||
{
|
{
|
||||||
++deleteLen;
|
// get the delete byte number
|
||||||
|
size_t deleteLen = 1; // default, erase 1 byte
|
||||||
|
|
||||||
|
// Calculate the actual number of bytes to delete for a specific character
|
||||||
|
while (0x80 == (0xC0 & _inputText.at(_insertPos - totalDeleteLen - deleteLen)))
|
||||||
|
{
|
||||||
|
++deleteLen;
|
||||||
|
}
|
||||||
|
totalDeleteLen += deleteLen;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (_delegate && _delegate->onTextFieldDeleteBackward(this, _inputText.c_str() + len - deleteLen,
|
// if (_delegate && _delegate->onTextFieldDeleteBackward(this, _inputText.c_str() + len - deleteLen,
|
||||||
// static_cast<int>(deleteLen)))
|
// static_cast<int>(deleteLen)))
|
||||||
//{
|
//{
|
||||||
// // delegate doesn't wan't to delete backwards
|
// // delegate doesn't want to delete backwards
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// if all text deleted, show placeholder string
|
// if all text deleted, show placeholder string
|
||||||
if (len <= deleteLen)
|
if (len <= totalDeleteLen)
|
||||||
{
|
{
|
||||||
__moveCursor(-1);
|
__moveCursor(-1);
|
||||||
|
|
||||||
|
@ -670,7 +680,7 @@ void TextFieldEx::deleteBackward()
|
||||||
|
|
||||||
// set new input text
|
// set new input text
|
||||||
std::string text = _inputText; // (inputText.c_str(), len - deleteLen);
|
std::string text = _inputText; // (inputText.c_str(), len - deleteLen);
|
||||||
text.erase(_insertPos - deleteLen, deleteLen);
|
text.erase(_insertPos - totalDeleteLen, totalDeleteLen);
|
||||||
|
|
||||||
__moveCursor(-1);
|
__moveCursor(-1);
|
||||||
|
|
||||||
|
|
|
@ -140,7 +140,7 @@ protected:
|
||||||
bool canAttachWithIME() override;
|
bool canAttachWithIME() override;
|
||||||
bool canDetachWithIME() override;
|
bool canDetachWithIME() override;
|
||||||
|
|
||||||
void deleteBackward() override;
|
void deleteBackward(size_t numChars) override;
|
||||||
std::string_view getContentText() override;
|
std::string_view getContentText() override;
|
||||||
|
|
||||||
void handleDeleteKeyEvent();
|
void handleDeleteKeyEvent();
|
||||||
|
|
|
@ -40,6 +40,7 @@ THE SOFTWARE.
|
||||||
#include "ui/UIListView.h"
|
#include "ui/UIListView.h"
|
||||||
#include "ui/UISlider.h"
|
#include "ui/UISlider.h"
|
||||||
#include "ui/UITextField.h"
|
#include "ui/UITextField.h"
|
||||||
|
#include "ui/UITextFieldEx.h"
|
||||||
#include "ui/UITextBMFont.h"
|
#include "ui/UITextBMFont.h"
|
||||||
#include "ui/UIPageView.h"
|
#include "ui/UIPageView.h"
|
||||||
#include "ui/UIHelper.h"
|
#include "ui/UIHelper.h"
|
||||||
|
|
Loading…
Reference in New Issue