Backed out changeset b71c8c052463 (bug 1943846) for causing mass failures. CLOSED...
[gecko.git] / widget / uikit / TextInputHandler.mm
blob3ee3573b838af2918d6a486ed613cb98d3b64825
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"
20 #include "nsString.h"
21 #include "nsWindow.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) {
35   return NS_OK;
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,
48     void* aData) {}
50 bool TextInputHandler::InsertText(NSString* aText) {
51   nsString str;
52   CopyNSStringToXPCOMString(aText, str);
54   MOZ_LOG(gIMELog, LogLevel::Info,
55           ("%p TextInputHandler::InsertText(aText=%s)", this,
56            NS_ConvertUTF16toUTF8(str).get()));
58   if (Destroyed()) {
59     return false;
60   }
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);
66     }
67     if (charCode == 0x08) {
68       return EmulateKeyboardEvent(NS_VK_BACK, KEY_NAME_INDEX_Backspace,
69                                   charCode);
70     }
71     if (uint32_t keyCode = WidgetUtils::ComputeKeyCodeFromChar(charCode)) {
72       return EmulateKeyboardEvent(keyCode, KEY_NAME_INDEX_USE_STRING, charCode);
73     }
74   }
76   nsEventStatus status = nsEventStatus_eIgnore;
77   RefPtr<nsWindow> widget(mWidget);
78   if (!DispatchKeyDownEvent(NS_VK_PROCESSKEY, KEY_NAME_INDEX_Process, 0,
79                             status)) {
80     return false;
81   }
82   if (Destroyed()) {
83     return false;
84   }
86   mDispatcher->CommitComposition(status, &str, nullptr);
87   if (widget->Destroyed()) {
88     return false;
89   }
91   DispatchKeyUpEvent(NS_VK_PROCESSKEY, KEY_NAME_INDEX_Process, 0, status);
93   return true;
96 bool TextInputHandler::HandleCommand(Command aCommand) {
97   MOZ_LOG(gIMELog, LogLevel::Info,
98           ("%p   TextInputHandler::HandleCommand, aCommand=%s", this,
99            ToChar(aCommand)));
101   if (Destroyed()) {
102     return false;
103   }
105   if (aCommand != Command::DeleteCharBackward) {
106     return false;
107   }
109   nsEventStatus status = nsEventStatus_eIgnore;
110   if (!DispatchKeyDownEvent(NS_VK_BACK, KEY_NAME_INDEX_Backspace, 0, status)) {
111     return true;
112   }
113   if (Destroyed() || status == nsEventStatus_eConsumeNoDefault) {
114     return true;
115   }
117   // TODO: Focus check
119   if (!DispatchKeyPressEvent(NS_VK_BACK, KEY_NAME_INDEX_Backspace, 0, status)) {
120     return true;
121   }
122   if (Destroyed() || status == nsEventStatus_eConsumeNoDefault) {
123     return true;
124   }
126   // TODO: Focus check
128   DispatchKeyUpEvent(NS_VK_BACK, KEY_NAME_INDEX_Backspace, 0, status);
130   return true;
133 static uint32_t ComputeKeyModifiers(uint32_t aCharCode) {
134   if (aCharCode >= 'A' && aCharCode <= 'Z') {
135     return MODIFIER_SHIFT;
136   }
137   return 0;
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;
145   // TODO(m_kato):
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;
150   }
151   aEvent.mModifiers = ComputeKeyModifiers(aCharCode);
152   aEvent.mLocation = eKeyLocationStandard;
153   aEvent.mTimeStamp = TimeStamp::Now();
156 bool TextInputHandler::DispatchKeyDownEvent(uint32_t aKeyCode,
157                                             KeyNameIndex aKeyNameIndex,
158                                             char16_t aCharCode,
159                                             nsEventStatus& aStatus) {
160   MOZ_ASSERT(aKeyCode);
161   MOZ_ASSERT(mWidget);
163   WidgetKeyboardEvent keydownEvent(true, eKeyDown, mWidget);
164   InitKeyEvent(keydownEvent, aKeyCode, aKeyNameIndex, aCharCode);
165   nsresult rv = mDispatcher->BeginNativeInputTransaction();
166   if (NS_FAILED(rv)) {
167     NS_WARNING("BeginNativeInputTransaction is failed");
168     return false;
169   }
170   return mDispatcher->DispatchKeyboardEvent(eKeyDown, keydownEvent, aStatus);
173 bool TextInputHandler::DispatchKeyUpEvent(uint32_t aKeyCode,
174                                           KeyNameIndex aKeyNameIndex,
175                                           char16_t aCharCode,
176                                           nsEventStatus& aStatus) {
177   MOZ_ASSERT(aKeyCode);
178   MOZ_ASSERT(mWidget);
180   WidgetKeyboardEvent keyupEvent(true, eKeyUp, mWidget);
181   InitKeyEvent(keyupEvent, aKeyCode, aKeyNameIndex, aCharCode);
182   nsresult rv = mDispatcher->BeginNativeInputTransaction();
183   if (NS_FAILED(rv)) {
184     NS_WARNING("BeginNativeInputTransaction is failed");
185     return false;
186   }
187   return mDispatcher->DispatchKeyboardEvent(eKeyUp, keyupEvent, aStatus);
190 bool TextInputHandler::DispatchKeyPressEvent(uint32_t aKeyCode,
191                                              KeyNameIndex aKeyNameIndex,
192                                              char16_t aCharCode,
193                                              nsEventStatus& aStatus) {
194   MOZ_ASSERT(aKeyCode);
195   MOZ_ASSERT(mWidget);
197   WidgetKeyboardEvent keypressEvent(true, eKeyPress, mWidget);
198   InitKeyEvent(keypressEvent, aKeyCode, aKeyNameIndex, aCharCode);
199   nsresult rv = mDispatcher->BeginNativeInputTransaction();
200   if (NS_FAILED(rv)) {
201     NS_WARNING("BeginNativeInputTransaction is failed");
202     return false;
203   }
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)) {
219     return true;
220   }
221   if (Destroyed() || status == nsEventStatus_eConsumeNoDefault) {
222     return true;
223   }
224   // TODO: Focus check
226   if (!DispatchKeyPressEvent(aKeyCode, aKeyNameIndex, aCharCode, status)) {
227     return true;
228   }
229   if (Destroyed() || status == nsEventStatus_eConsumeNoDefault) {
230     return true;
231   }
232   // TODO: Focus check
234   DispatchKeyUpEvent(aKeyCode, aKeyNameIndex, aCharCode, status);
235   return true;
238 void TextInputHandler::OnDestroyed() { mWidget = nullptr; }
240 }  // namespace mozilla::widget