From 086c044dc34dfc0f74fbe41f4ecb402b2cd34884 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 03:13:33 +0200 Subject: Merging upstream version 125.0.1. Signed-off-by: Daniel Baumann --- widget/uikit/TextInputHandler.mm | 254 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 254 insertions(+) create mode 100644 widget/uikit/TextInputHandler.mm (limited to 'widget/uikit/TextInputHandler.mm') diff --git a/widget/uikit/TextInputHandler.mm b/widget/uikit/TextInputHandler.mm new file mode 100644 index 0000000000..9a4a6ae226 --- /dev/null +++ b/widget/uikit/TextInputHandler.mm @@ -0,0 +1,254 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 sw=2 et tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "TextInputHandler.h" + +#import + +#include "mozilla/EventForwards.h" +#include "mozilla/Logging.h" +#include "mozilla/MiscEvents.h" +#include "mozilla/TextEventDispatcher.h" +#include "mozilla/TextEvents.h" +#include "mozilla/WidgetUtils.h" +#include "nsIWidget.h" +#include "nsObjCExceptions.h" +#include "nsString.h" +#include "nsWindow.h" + +mozilla::LazyLogModule gIMELog("TextInputHandler"); + +namespace mozilla::widget { + +static void GetStringForNSString(const NSString* aSrc, nsAString& aDist) { + NS_OBJC_BEGIN_TRY_IGNORE_BLOCK; + + if (!aSrc) { + aDist.Truncate(); + return; + } + + aDist.SetLength([aSrc length]); + [aSrc getCharacters:reinterpret_cast(aDist.BeginWriting()) + range:NSMakeRange(0, [aSrc length])]; + + NS_OBJC_END_TRY_IGNORE_BLOCK; +} + +NS_IMPL_ISUPPORTS(TextInputHandler, TextEventDispatcherListener, + nsISupportsWeakReference) + +TextInputHandler::TextInputHandler(nsWindow* aWidget) + : mWidget(aWidget), mDispatcher(aWidget->GetTextEventDispatcher()) {} + +nsresult TextInputHandler::NotifyIME(TextEventDispatcher* aTextEventDispatcher, + const IMENotification& aNotification) { + return NS_OK; +} + +IMENotificationRequests TextInputHandler::GetIMENotificationRequests() { + return IMENotificationRequests(); +} + +void TextInputHandler::OnRemovedFrom( + TextEventDispatcher* aTextEventDispatcher) {} + +void TextInputHandler::WillDispatchKeyboardEvent( + TextEventDispatcher* aTextEventDispatcher, + WidgetKeyboardEvent& aKeyboardEvent, uint32_t aIndexOfKeypress, + void* aData) {} + +bool TextInputHandler::InsertText(NSString* aText) { + nsString str; + GetStringForNSString(aText, str); + + MOZ_LOG(gIMELog, LogLevel::Info, + ("%p TextInputHandler::InsertText(aText=%s)", this, + NS_ConvertUTF16toUTF8(str).get())); + + if (Destroyed()) { + return false; + } + + if (str.Length() == 1) { + char16_t charCode = str[0]; + if (charCode == 0x0a) { + return EmulateKeyboardEvent(NS_VK_RETURN, KEY_NAME_INDEX_Enter, charCode); + } + if (charCode == 0x08) { + return EmulateKeyboardEvent(NS_VK_BACK, KEY_NAME_INDEX_Backspace, + charCode); + } + if (uint32_t keyCode = WidgetUtils::ComputeKeyCodeFromChar(charCode)) { + return EmulateKeyboardEvent(keyCode, KEY_NAME_INDEX_USE_STRING, charCode); + } + } + + nsEventStatus status = nsEventStatus_eIgnore; + RefPtr widget(mWidget); + if (!DispatchKeyDownEvent(NS_VK_PROCESSKEY, KEY_NAME_INDEX_Process, 0, + status)) { + return false; + } + if (Destroyed()) { + return false; + } + + mDispatcher->CommitComposition(status, &str, nullptr); + if (widget->Destroyed()) { + return false; + } + + DispatchKeyUpEvent(NS_VK_PROCESSKEY, KEY_NAME_INDEX_Process, 0, status); + + return true; +} + +bool TextInputHandler::HandleCommand(Command aCommand) { + MOZ_LOG(gIMELog, LogLevel::Info, + ("%p TextInputHandler::HandleCommand, aCommand=%s", this, + ToChar(aCommand))); + + if (Destroyed()) { + return false; + } + + if (aCommand != Command::DeleteCharBackward) { + return false; + } + + nsEventStatus status = nsEventStatus_eIgnore; + if (!DispatchKeyDownEvent(NS_VK_BACK, KEY_NAME_INDEX_Backspace, 0, status)) { + return true; + } + if (Destroyed() || status == nsEventStatus_eConsumeNoDefault) { + return true; + } + + // TODO: Focus check + + if (!DispatchKeyPressEvent(NS_VK_BACK, KEY_NAME_INDEX_Backspace, 0, status)) { + return true; + } + if (Destroyed() || status == nsEventStatus_eConsumeNoDefault) { + return true; + } + + // TODO: Focus check + + DispatchKeyUpEvent(NS_VK_BACK, KEY_NAME_INDEX_Backspace, 0, status); + + return true; +} + +static uint32_t ComputeKeyModifiers(uint32_t aCharCode) { + if (aCharCode >= 'A' && aCharCode <= 'Z') { + return MODIFIER_SHIFT; + } + return 0; +} + +static void InitKeyEvent(WidgetKeyboardEvent& aEvent, uint32_t aKeyCode, + KeyNameIndex aKeyNameIndex, char16_t aCharCode) { + aEvent.mKeyCode = aKeyCode; + aEvent.mIsRepeat = false; + aEvent.mKeyNameIndex = aKeyNameIndex; + // TODO(m_kato): + // How to get native key? Then, implement NativeKeyToDOM*.h for iOS + aEvent.mCodeNameIndex = CODE_NAME_INDEX_UNKNOWN; + if (aEvent.mKeyNameIndex == KEY_NAME_INDEX_USE_STRING) { + aEvent.mKeyValue = aCharCode; + } + aEvent.mModifiers = ComputeKeyModifiers(aCharCode); + aEvent.mLocation = eKeyLocationStandard; + aEvent.mTimeStamp = TimeStamp::Now(); +} + +bool TextInputHandler::DispatchKeyDownEvent(uint32_t aKeyCode, + KeyNameIndex aKeyNameIndex, + char16_t aCharCode, + nsEventStatus& aStatus) { + MOZ_ASSERT(aKeyCode); + MOZ_ASSERT(mWidget); + + WidgetKeyboardEvent keydownEvent(true, eKeyDown, mWidget); + InitKeyEvent(keydownEvent, aKeyCode, aKeyNameIndex, aCharCode); + nsresult rv = mDispatcher->BeginNativeInputTransaction(); + if (NS_FAILED(rv)) { + NS_WARNING("BeginNativeInputTransaction is failed"); + return false; + } + return mDispatcher->DispatchKeyboardEvent(eKeyDown, keydownEvent, aStatus); +} + +bool TextInputHandler::DispatchKeyUpEvent(uint32_t aKeyCode, + KeyNameIndex aKeyNameIndex, + char16_t aCharCode, + nsEventStatus& aStatus) { + MOZ_ASSERT(aKeyCode); + MOZ_ASSERT(mWidget); + + WidgetKeyboardEvent keyupEvent(true, eKeyUp, mWidget); + InitKeyEvent(keyupEvent, aKeyCode, aKeyNameIndex, aCharCode); + nsresult rv = mDispatcher->BeginNativeInputTransaction(); + if (NS_FAILED(rv)) { + NS_WARNING("BeginNativeInputTransaction is failed"); + return false; + } + return mDispatcher->DispatchKeyboardEvent(eKeyUp, keyupEvent, aStatus); +} + +bool TextInputHandler::DispatchKeyPressEvent(uint32_t aKeyCode, + KeyNameIndex aKeyNameIndex, + char16_t aCharCode, + nsEventStatus& aStatus) { + MOZ_ASSERT(aKeyCode); + MOZ_ASSERT(mWidget); + + WidgetKeyboardEvent keypressEvent(true, eKeyPress, mWidget); + InitKeyEvent(keypressEvent, aKeyCode, aKeyNameIndex, aCharCode); + nsresult rv = mDispatcher->BeginNativeInputTransaction(); + if (NS_FAILED(rv)) { + NS_WARNING("BeginNativeInputTransaction is failed"); + return false; + } + return mDispatcher->MaybeDispatchKeypressEvents(keypressEvent, aStatus); +} + +bool TextInputHandler::EmulateKeyboardEvent(uint32_t aKeyCode, + KeyNameIndex aKeyNameIndex, + char16_t aCharCode) { + MOZ_ASSERT(aCharCode); + + MOZ_LOG(gIMELog, LogLevel::Info, + ("%p TextInputHandler::EmulateKeyboardEvent(aKeyCode=%x, " + "aKeyNameIndex=%x, aCharCode=%x)", + this, aKeyCode, aKeyNameIndex, aCharCode)); + + nsEventStatus status = nsEventStatus_eIgnore; + if (!DispatchKeyDownEvent(aKeyCode, aKeyNameIndex, aCharCode, status)) { + return true; + } + if (Destroyed() || status == nsEventStatus_eConsumeNoDefault) { + return true; + } + // TODO: Focus check + + if (!DispatchKeyPressEvent(aKeyCode, aKeyNameIndex, aCharCode, status)) { + return true; + } + if (Destroyed() || status == nsEventStatus_eConsumeNoDefault) { + return true; + } + // TODO: Focus check + + DispatchKeyUpEvent(aKeyCode, aKeyNameIndex, aCharCode, status); + return true; +} + +void TextInputHandler::OnDestroyed() { mWidget = nullptr; } + +} // namespace mozilla::widget -- cgit v1.2.3