1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sw=2 et tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "TextInputHandler.h"
9 #import <UIKit/UIKit.h>
11 #include "mozilla/EventForwards.h"
12 #include "mozilla/Logging.h"
13 #include "mozilla/MacStringHelpers.h"
14 #include "mozilla/MiscEvents.h"
15 #include "mozilla/TextEventDispatcher.h"
16 #include "mozilla/TextEvents.h"
17 #include "mozilla/WidgetUtils.h"
18 #include "nsIWidget.h"
19 #include "nsObjCExceptions.h"
23 mozilla::LazyLogModule gIMELog("TextInputHandler");
25 namespace mozilla::widget {
27 NS_IMPL_ISUPPORTS(TextInputHandler, TextEventDispatcherListener,
28 nsISupportsWeakReference)
30 TextInputHandler::TextInputHandler(nsWindow* aWidget)
31 : mWidget(aWidget), mDispatcher(aWidget->GetTextEventDispatcher()) {}
33 nsresult TextInputHandler::NotifyIME(TextEventDispatcher* aTextEventDispatcher,
34 const IMENotification& aNotification) {
38 IMENotificationRequests TextInputHandler::GetIMENotificationRequests() {
39 return IMENotificationRequests();
42 void TextInputHandler::OnRemovedFrom(
43 TextEventDispatcher* aTextEventDispatcher) {}
45 void TextInputHandler::WillDispatchKeyboardEvent(
46 TextEventDispatcher* aTextEventDispatcher,
47 WidgetKeyboardEvent& aKeyboardEvent, uint32_t aIndexOfKeypress,
50 bool TextInputHandler::InsertText(NSString* aText) {
52 CopyNSStringToXPCOMString(aText, str);
54 MOZ_LOG(gIMELog, LogLevel::Info,
55 ("%p TextInputHandler::InsertText(aText=%s)", this,
56 NS_ConvertUTF16toUTF8(str).get()));
62 if (str.Length() == 1) {
63 char16_t charCode = str[0];
64 if (charCode == 0x0a) {
65 return EmulateKeyboardEvent(NS_VK_RETURN, KEY_NAME_INDEX_Enter, charCode);
67 if (charCode == 0x08) {
68 return EmulateKeyboardEvent(NS_VK_BACK, KEY_NAME_INDEX_Backspace,
71 if (uint32_t keyCode = WidgetUtils::ComputeKeyCodeFromChar(charCode)) {
72 return EmulateKeyboardEvent(keyCode, KEY_NAME_INDEX_USE_STRING, charCode);
76 nsEventStatus status = nsEventStatus_eIgnore;
77 RefPtr<nsWindow> widget(mWidget);
78 if (!DispatchKeyDownEvent(NS_VK_PROCESSKEY, KEY_NAME_INDEX_Process, 0,
86 mDispatcher->CommitComposition(status, &str, nullptr);
87 if (widget->Destroyed()) {
91 DispatchKeyUpEvent(NS_VK_PROCESSKEY, KEY_NAME_INDEX_Process, 0, status);
96 bool TextInputHandler::HandleCommand(Command aCommand) {
97 MOZ_LOG(gIMELog, LogLevel::Info,
98 ("%p TextInputHandler::HandleCommand, aCommand=%s", this,
105 if (aCommand != Command::DeleteCharBackward) {
109 nsEventStatus status = nsEventStatus_eIgnore;
110 if (!DispatchKeyDownEvent(NS_VK_BACK, KEY_NAME_INDEX_Backspace, 0, status)) {
113 if (Destroyed() || status == nsEventStatus_eConsumeNoDefault) {
119 if (!DispatchKeyPressEvent(NS_VK_BACK, KEY_NAME_INDEX_Backspace, 0, status)) {
122 if (Destroyed() || status == nsEventStatus_eConsumeNoDefault) {
128 DispatchKeyUpEvent(NS_VK_BACK, KEY_NAME_INDEX_Backspace, 0, status);
133 static uint32_t ComputeKeyModifiers(uint32_t aCharCode) {
134 if (aCharCode >= 'A' && aCharCode <= 'Z') {
135 return MODIFIER_SHIFT;
140 static void InitKeyEvent(WidgetKeyboardEvent& aEvent, uint32_t aKeyCode,
141 KeyNameIndex aKeyNameIndex, char16_t aCharCode) {
142 aEvent.mKeyCode = aKeyCode;
143 aEvent.mIsRepeat = false;
144 aEvent.mKeyNameIndex = aKeyNameIndex;
146 // How to get native key? Then, implement NativeKeyToDOM*.h for iOS
147 aEvent.mCodeNameIndex = CODE_NAME_INDEX_UNKNOWN;
148 if (aEvent.mKeyNameIndex == KEY_NAME_INDEX_USE_STRING) {
149 aEvent.mKeyValue = aCharCode;
151 aEvent.mModifiers = ComputeKeyModifiers(aCharCode);
152 aEvent.mLocation = eKeyLocationStandard;
153 aEvent.mTimeStamp = TimeStamp::Now();
156 bool TextInputHandler::DispatchKeyDownEvent(uint32_t aKeyCode,
157 KeyNameIndex aKeyNameIndex,
159 nsEventStatus& aStatus) {
160 MOZ_ASSERT(aKeyCode);
163 WidgetKeyboardEvent keydownEvent(true, eKeyDown, mWidget);
164 InitKeyEvent(keydownEvent, aKeyCode, aKeyNameIndex, aCharCode);
165 nsresult rv = mDispatcher->BeginNativeInputTransaction();
167 NS_WARNING("BeginNativeInputTransaction is failed");
170 return mDispatcher->DispatchKeyboardEvent(eKeyDown, keydownEvent, aStatus);
173 bool TextInputHandler::DispatchKeyUpEvent(uint32_t aKeyCode,
174 KeyNameIndex aKeyNameIndex,
176 nsEventStatus& aStatus) {
177 MOZ_ASSERT(aKeyCode);
180 WidgetKeyboardEvent keyupEvent(true, eKeyUp, mWidget);
181 InitKeyEvent(keyupEvent, aKeyCode, aKeyNameIndex, aCharCode);
182 nsresult rv = mDispatcher->BeginNativeInputTransaction();
184 NS_WARNING("BeginNativeInputTransaction is failed");
187 return mDispatcher->DispatchKeyboardEvent(eKeyUp, keyupEvent, aStatus);
190 bool TextInputHandler::DispatchKeyPressEvent(uint32_t aKeyCode,
191 KeyNameIndex aKeyNameIndex,
193 nsEventStatus& aStatus) {
194 MOZ_ASSERT(aKeyCode);
197 WidgetKeyboardEvent keypressEvent(true, eKeyPress, mWidget);
198 InitKeyEvent(keypressEvent, aKeyCode, aKeyNameIndex, aCharCode);
199 nsresult rv = mDispatcher->BeginNativeInputTransaction();
201 NS_WARNING("BeginNativeInputTransaction is failed");
204 return mDispatcher->MaybeDispatchKeypressEvents(keypressEvent, aStatus);
207 bool TextInputHandler::EmulateKeyboardEvent(uint32_t aKeyCode,
208 KeyNameIndex aKeyNameIndex,
209 char16_t aCharCode) {
210 MOZ_ASSERT(aCharCode);
212 MOZ_LOG(gIMELog, LogLevel::Info,
213 ("%p TextInputHandler::EmulateKeyboardEvent(aKeyCode=%x, "
214 "aKeyNameIndex=%x, aCharCode=%x)",
215 this, aKeyCode, aKeyNameIndex, aCharCode));
217 nsEventStatus status = nsEventStatus_eIgnore;
218 if (!DispatchKeyDownEvent(aKeyCode, aKeyNameIndex, aCharCode, status)) {
221 if (Destroyed() || status == nsEventStatus_eConsumeNoDefault) {
226 if (!DispatchKeyPressEvent(aKeyCode, aKeyNameIndex, aCharCode, status)) {
229 if (Destroyed() || status == nsEventStatus_eConsumeNoDefault) {
234 DispatchKeyUpEvent(aKeyCode, aKeyNameIndex, aCharCode, status);
238 void TextInputHandler::OnDestroyed() { mWidget = nullptr; }
240 } // namespace mozilla::widget