240 lines
7.4 KiB
Text
240 lines
7.4 KiB
Text
/* -*- 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/MacStringHelpers.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 {
|
|
|
|
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;
|
|
CopyNSStringToXPCOMString(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
|