forked from mozilla/gecko-dev
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Bug 1844905 - Part 3. Basic keyboard support. r=masayuki
Implement UIKeyInput protocol to simple basic input. When implementing UITextInput, we need to consider to share cocoa's code. Differential Revision: https://phabricator.services.mozilla.com/D184286
- Loading branch information
Showing
6 changed files
with
434 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/* -*- 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/. */ | ||
|
||
#ifndef TextInputHandler_h_ | ||
#define TextInputHandler_h_ | ||
|
||
#import <UIKit/UITextInput.h> | ||
|
||
#include "mozilla/EventForwards.h" | ||
#include "mozilla/TextEventDispatcherListener.h" | ||
#include "mozilla/widget/IMEData.h" | ||
#include "nsCOMPtr.h" | ||
|
||
class nsWindow; | ||
|
||
namespace mozilla::widget { | ||
class TextEventDispatcher; | ||
|
||
// This is the temporary input class. When implementing UITextInpt protocol, we | ||
// should share this class with Cocoa's version. | ||
class TextInputHandler final : public TextEventDispatcherListener { | ||
public: | ||
TextInputHandler(nsWindow* aWidget); | ||
TextInputHandler() = delete; | ||
|
||
NS_DECL_ISUPPORTS | ||
|
||
NS_IMETHOD NotifyIME(TextEventDispatcher* aTextEventDispatcher, | ||
const IMENotification& aNotification) override; | ||
NS_IMETHOD_(IMENotificationRequests) GetIMENotificationRequests() override; | ||
NS_IMETHOD_(void) OnRemovedFrom(TextEventDispatcher* aTextEventDispatcher) override; | ||
NS_IMETHOD_(void) | ||
WillDispatchKeyboardEvent(TextEventDispatcher* aTextEventDispatcher, | ||
WidgetKeyboardEvent& aKeyboardEvent, uint32_t aIndexOfKeypress, | ||
void* aData) override; | ||
|
||
// UIKeyInput delegation | ||
bool InsertText(NSString* aText); | ||
bool HandleCommand(Command aCommand); | ||
|
||
void OnDestroyed(); | ||
|
||
private: | ||
virtual ~TextInputHandler() = default; | ||
|
||
bool DispatchKeyDownEvent(uint32_t aKeyCode, KeyNameIndex aKeyNameIndex, char16_t aCharCode, | ||
nsEventStatus& aStatus); | ||
bool DispatchKeyUpEvent(uint32_t aKeyCode, KeyNameIndex aKeyNameIndex, char16_t aCharCode, | ||
nsEventStatus& aStatus); | ||
bool DispatchKeyPressEvent(uint32_t aKeyCode, KeyNameIndex aKeyNameIndex, char16_t aCharCode, | ||
nsEventStatus& aStatus); | ||
|
||
bool EmulateKeyboardEvent(uint32_t aKeyCode, KeyNameIndex aKeyNameIndex, char16_t charCode); | ||
|
||
bool Destroyed() { return !mWidget; } | ||
|
||
nsWindow* mWidget; // weak ref | ||
RefPtr<TextEventDispatcher> mDispatcher; | ||
}; | ||
|
||
} // namespace mozilla::widget | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <UIKit/UIKit.h> | ||
|
||
#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<unichar*>(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<nsWindow> 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.