fix: ios keyboard, composing input (#8471)
* fix: ios keyboard, composing input Signed-off-by: fufesou <linlong1266@gmail.com> * Incorrect changes Signed-off-by: fufesou <linlong1266@gmail.com> --------- Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
parent
f0dcc91907
commit
11bdd3cfcd
@ -55,6 +55,9 @@ class _RemotePageState extends State<RemotePage> {
|
|||||||
InputModel get inputModel => gFFI.inputModel;
|
InputModel get inputModel => gFFI.inputModel;
|
||||||
SessionID get sessionId => gFFI.sessionId;
|
SessionID get sessionId => gFFI.sessionId;
|
||||||
|
|
||||||
|
final TextEditingController _textController =
|
||||||
|
TextEditingController(text: initText);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@ -145,37 +148,59 @@ class _RemotePageState extends State<RemotePage> {
|
|||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle mobile virtual keyboard
|
void _handleIOSSoftKeyboardInput(String newValue) {
|
||||||
void handleSoftKeyboardInput(String newValue) {
|
|
||||||
var oldValue = _value;
|
var oldValue = _value;
|
||||||
_value = newValue;
|
_value = newValue;
|
||||||
if (isIOS) {
|
|
||||||
var i = newValue.length - 1;
|
var i = newValue.length - 1;
|
||||||
for (; i >= 0 && newValue[i] != '\1'; --i) {}
|
for (; i >= 0 && newValue[i] != '\1'; --i) {}
|
||||||
var j = oldValue.length - 1;
|
var j = oldValue.length - 1;
|
||||||
for (; j >= 0 && oldValue[j] != '\1'; --j) {}
|
for (; j >= 0 && oldValue[j] != '\1'; --j) {}
|
||||||
if (i < j) j = i;
|
if (i < j) j = i;
|
||||||
newValue = newValue.substring(j + 1);
|
var subNewValue = newValue.substring(j + 1);
|
||||||
oldValue = oldValue.substring(j + 1);
|
var subOldValue = oldValue.substring(j + 1);
|
||||||
|
|
||||||
|
// get common prefix of subNewValue and subOldValue
|
||||||
var common = 0;
|
var common = 0;
|
||||||
for (;
|
for (;
|
||||||
common < oldValue.length &&
|
common < subOldValue.length &&
|
||||||
common < newValue.length &&
|
common < subNewValue.length &&
|
||||||
newValue[common] == oldValue[common];
|
subNewValue[common] == subOldValue[common];
|
||||||
++common) {}
|
++common) {}
|
||||||
for (i = 0; i < oldValue.length - common; ++i) {
|
|
||||||
inputModel.inputKey('VK_BACK');
|
// get newStr from subNewValue
|
||||||
}
|
var newStr = "";
|
||||||
if (newValue.length > common) {
|
if (subNewValue.length > common) {
|
||||||
var s = newValue.substring(common);
|
newStr = subNewValue.substring(common);
|
||||||
if (s.length > 1) {
|
|
||||||
bind.sessionInputString(sessionId: sessionId, value: s);
|
|
||||||
} else {
|
|
||||||
inputChar(s);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the value to the old value and early return if is still composing. (1 && 2)
|
||||||
|
// 1. The composing range is valid
|
||||||
|
// 2. The new string is shorter than the composing range.
|
||||||
|
if (_textController.value.isComposingRangeValid) {
|
||||||
|
final composingLength = _textController.value.composing.end -
|
||||||
|
_textController.value.composing.start;
|
||||||
|
if (composingLength > newStr.length) {
|
||||||
|
_value = oldValue;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the different part in the old value.
|
||||||
|
for (i = 0; i < subOldValue.length - common; ++i) {
|
||||||
|
inputModel.inputKey('VK_BACK');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input the new string.
|
||||||
|
if (newStr.length > 1) {
|
||||||
|
bind.sessionInputString(sessionId: sessionId, value: newStr);
|
||||||
|
} else {
|
||||||
|
inputChar(newStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleNonIOSSoftKeyboardInput(String newValue) {
|
||||||
|
var oldValue = _value;
|
||||||
|
_value = newValue;
|
||||||
if (oldValue.isNotEmpty &&
|
if (oldValue.isNotEmpty &&
|
||||||
newValue.isNotEmpty &&
|
newValue.isNotEmpty &&
|
||||||
oldValue[0] == '\1' &&
|
oldValue[0] == '\1' &&
|
||||||
@ -214,6 +239,15 @@ class _RemotePageState extends State<RemotePage> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handle mobile virtual keyboard
|
||||||
|
void handleSoftKeyboardInput(String newValue) {
|
||||||
|
if (isIOS) {
|
||||||
|
_handleIOSSoftKeyboardInput(newValue);
|
||||||
|
} else {
|
||||||
|
_handleNonIOSSoftKeyboardInput(newValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void inputChar(String char) {
|
void inputChar(String char) {
|
||||||
if (char == '\n') {
|
if (char == '\n') {
|
||||||
char = 'VK_RETURN';
|
char = 'VK_RETURN';
|
||||||
@ -227,6 +261,7 @@ class _RemotePageState extends State<RemotePage> {
|
|||||||
gFFI.invokeMethod("enable_soft_keyboard", true);
|
gFFI.invokeMethod("enable_soft_keyboard", true);
|
||||||
// destroy first, so that our _value trick can work
|
// destroy first, so that our _value trick can work
|
||||||
_value = initText;
|
_value = initText;
|
||||||
|
_textController.text = _value;
|
||||||
setState(() => _showEdit = false);
|
setState(() => _showEdit = false);
|
||||||
_timer?.cancel();
|
_timer?.cancel();
|
||||||
_timer = Timer(kMobileDelaySoftKeyboard, () {
|
_timer = Timer(kMobileDelaySoftKeyboard, () {
|
||||||
@ -491,7 +526,7 @@ class _RemotePageState extends State<RemotePage> {
|
|||||||
autofocus: true,
|
autofocus: true,
|
||||||
focusNode: _mobileFocusNode,
|
focusNode: _mobileFocusNode,
|
||||||
maxLines: null,
|
maxLines: null,
|
||||||
initialValue: _value,
|
controller: _textController,
|
||||||
// trick way to make backspace work always
|
// trick way to make backspace work always
|
||||||
keyboardType: TextInputType.multiline,
|
keyboardType: TextInputType.multiline,
|
||||||
onChanged: handleSoftKeyboardInput,
|
onChanged: handleSoftKeyboardInput,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user