| 4379 | } |
| 4380 | |
| 4381 | void Document::processKeystrokeAction(const Action *action, Okular::FormField *ff, const QVariant &newValue, int prevCursorPos, int prevAnchorPos) |
| 4382 | { |
| 4383 | if (action->actionType() != Action::Script) { |
| 4384 | qCDebug(OkularCoreDebug) << "Unsupported action type" << action->actionType() << "for keystroke."; |
| 4385 | return; |
| 4386 | } |
| 4387 | // Lookup the page of the FormFieldText |
| 4388 | int foundPage = d->findFieldPageNumber(ff); |
| 4389 | |
| 4390 | if (foundPage == -1) { |
| 4391 | qCDebug(OkularCoreDebug) << "Could not find page for formfield!"; |
| 4392 | return; |
| 4393 | } |
| 4394 | |
| 4395 | std::shared_ptr<Event> event = Event::createKeystrokeEvent(ff, d->m_pagesVector[foundPage]); |
| 4396 | |
| 4397 | /* Set the selStart and selEnd event properties |
| 4398 | |
| 4399 | QString using UTF-16 counts a code point as made up of 1 or 2 16-bit code units. |
| 4400 | |
| 4401 | When encoded using 2 code units, the units are referred to as surrogate pairs. |
| 4402 | selectionStart() and selectionEnd() methods evaluate prevCursorPos and prevAnchorPos based on code units during selection. |
| 4403 | |
| 4404 | While this unit-based evaluation is suitable for detecting changes, for providing consistency with Adobe Reader for values of selStart and selEnd, |
| 4405 | it would be best to evaluate in terms of code points rather than the code units. |
| 4406 | |
| 4407 | To correct the values of selStart and selEnd accordingly, we iterate over the code units. If a surrogate pair is encountered, then selStart and |
| 4408 | selEnd are accordingly decremented. |
| 4409 | */ |
| 4410 | int selStart = std::min(prevCursorPos, prevAnchorPos); |
| 4411 | int selEnd = std::max(prevCursorPos, prevAnchorPos); |
| 4412 | int codeUnit; |
| 4413 | int initialSelStart = selStart; |
| 4414 | int initialSelEnd = selEnd; |
| 4415 | QString inputString = ff->value().toString(); |
| 4416 | for (codeUnit = 0; codeUnit < initialSelStart && codeUnit < inputString.size(); codeUnit++) { |
| 4417 | if (inputString.at(codeUnit).isHighSurrogate()) { |
| 4418 | // skip the low surrogate and decrement selStart and selEnd |
| 4419 | codeUnit++; |
| 4420 | selStart--; |
| 4421 | selEnd--; |
| 4422 | } |
| 4423 | } |
| 4424 | for (; codeUnit < initialSelEnd && codeUnit < inputString.size(); codeUnit++) { |
| 4425 | if (inputString.at(codeUnit).isHighSurrogate()) { |
| 4426 | // skip the low surrogate and decrement selEnd |
| 4427 | codeUnit++; |
| 4428 | selEnd--; |
| 4429 | } |
| 4430 | } |
| 4431 | std::u32string oldUcs4 = inputString.toStdU32String(); |
| 4432 | std::u32string newUcs4 = newValue.toString().toStdU32String(); |
| 4433 | // It is necessary to count size in terms of code points rather than code units for deletion. |
| 4434 | if (oldUcs4.size() - newUcs4.size() == 1 && selStart == selEnd) { |
| 4435 | // consider a one character removal as selection of that character and then its removal. |
| 4436 | selStart--; |
| 4437 | } |
| 4438 | event->setSelStart(selStart); |