mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 282097 - Part 4: Create NativeKeyBindings for Cocoa. r=masayuki, r=smichaud
This commit is contained in:
parent
f4d2c62553
commit
6a5a431446
@ -52,6 +52,7 @@ CMMSRCS = \
|
||||
nsMacWebAppUtils.mm \
|
||||
GfxInfo.mm \
|
||||
WidgetTraceEvent.mm \
|
||||
NativeKeyBindings.mm \
|
||||
$(NULL)
|
||||
|
||||
ifeq (x86_64,$(TARGET_CPU))
|
||||
|
72
widget/cocoa/NativeKeyBindings.h
Normal file
72
widget/cocoa/NativeKeyBindings.h
Normal file
@ -0,0 +1,72 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 NativeKeyBindings_h_
|
||||
#define NativeKeyBindings_h_
|
||||
|
||||
#include "nsINativeKeyBindings.h"
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsDataHashtable.h"
|
||||
|
||||
// 8477f934-febf-4c79-b7fe-bb7f9ebb9b4f
|
||||
#define NS_NATIVEKEYBINDINGS_INPUT_CID \
|
||||
{ 0x8477f934, 0xfebf, 0x4c79, \
|
||||
{ 0xb7, 0xfe, 0xbb, 0x7f, 0x9e, 0xbb, 0x9b, 0x4f } }
|
||||
|
||||
// 13a6e56f-f00b-4e19-8cf6-1a51ee7cc4bf
|
||||
#define NS_NATIVEKEYBINDINGS_TEXTAREA_CID \
|
||||
{ 0x13a6e56f, 0xf00b, 0x4e19, \
|
||||
{ 0x8c, 0xf6, 0x1a, 0x51, 0xee, 0x7c, 0xc4, 0xbf } }
|
||||
|
||||
// 36bfbd29-4e02-40f4-8fff-094f1a9ec97c
|
||||
#define NS_NATIVEKEYBINDINGS_EDITOR_CID \
|
||||
{ 0x36bfbd29, 0x4e02, 0x40f4, \
|
||||
{ 0x8f, 0xff, 0x09, 0x4f, 0x1a, 0x9e, 0xc9, 0x7c } }
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
enum NativeKeyBindingsType
|
||||
{
|
||||
eNativeKeyBindingsType_Input,
|
||||
eNativeKeyBindingsType_TextArea,
|
||||
eNativeKeyBindingsType_Editor
|
||||
};
|
||||
|
||||
typedef nsDataHashtable<nsPtrHashKey<struct objc_selector>, const char *>
|
||||
SelectorCommandHashtable;
|
||||
|
||||
class NativeKeyBindings MOZ_FINAL : public nsINativeKeyBindings
|
||||
{
|
||||
public:
|
||||
NativeKeyBindings();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD Init(NativeKeyBindingsType aType);
|
||||
|
||||
// nsINativeKeyBindings
|
||||
NS_IMETHOD_(bool) KeyDown(const nsNativeKeyEvent& aEvent,
|
||||
DoCommandCallback aCallback,
|
||||
void* aCallbackData);
|
||||
|
||||
NS_IMETHOD_(bool) KeyPress(const nsNativeKeyEvent& aEvent,
|
||||
DoCommandCallback aCallback,
|
||||
void* aCallbackData);
|
||||
|
||||
NS_IMETHOD_(bool) KeyUp(const nsNativeKeyEvent& aEvent,
|
||||
DoCommandCallback aCallback,
|
||||
void* aCallbackData);
|
||||
|
||||
private:
|
||||
SelectorCommandHashtable mSelectorToCommand;
|
||||
}; // NativeKeyBindings
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* NativeKeyBindings_h_ */
|
290
widget/cocoa/NativeKeyBindings.mm
Normal file
290
widget/cocoa/NativeKeyBindings.mm
Normal file
@ -0,0 +1,290 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 "NativeKeyBindings.h"
|
||||
|
||||
#include "nsTArray.h"
|
||||
#include "nsCocoaUtils.h"
|
||||
#include "nsGUIEvent.h"
|
||||
#include "prlog.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::widget;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
PRLogModuleInfo* gNativeKeyBindingsLog = nullptr;
|
||||
#endif
|
||||
|
||||
NativeKeyBindings::NativeKeyBindings()
|
||||
{
|
||||
}
|
||||
|
||||
#define SEL_TO_COMMAND(aSel, aCommand) \
|
||||
mSelectorToCommand.Put( \
|
||||
reinterpret_cast<struct objc_selector *>(@selector(aSel)), aCommand)
|
||||
|
||||
NS_IMETHODIMP
|
||||
NativeKeyBindings::Init(NativeKeyBindingsType aType)
|
||||
{
|
||||
#ifdef PR_LOGGING
|
||||
if (!gNativeKeyBindingsLog) {
|
||||
gNativeKeyBindingsLog = PR_NewLogModule("NativeKeyBindings");
|
||||
}
|
||||
#endif
|
||||
|
||||
PR_LOG(gNativeKeyBindingsLog, PR_LOG_ALWAYS,
|
||||
("%p NativeKeyBindings::Init", this));
|
||||
|
||||
mSelectorToCommand.Init();
|
||||
|
||||
// Many selectors have a one-to-one mapping to a Gecko command. Those mappings
|
||||
// are registered in mSelectorToCommand.
|
||||
|
||||
// Selectors from NSResponder's "Responding to Action Messages" section and
|
||||
// from NSText's "Action Methods for Editing" section
|
||||
|
||||
// TODO: Improves correctness of left / right meaning
|
||||
// TODO: Add real paragraph motions
|
||||
|
||||
// SEL_TO_COMMAND(cancelOperation:, );
|
||||
// SEL_TO_COMMAND(capitalizeWord:, );
|
||||
// SEL_TO_COMMAND(centerSelectionInVisibleArea:, );
|
||||
// SEL_TO_COMMAND(changeCaseOfLetter:, );
|
||||
// SEL_TO_COMMAND(complete:, );
|
||||
SEL_TO_COMMAND(copy:, "cmd_copy");
|
||||
// SEL_TO_COMMAND(copyFont:, );
|
||||
// SEL_TO_COMMAND(copyRuler:, );
|
||||
SEL_TO_COMMAND(cut:, "cmd_cut");
|
||||
SEL_TO_COMMAND(delete:, "cmd_delete");
|
||||
SEL_TO_COMMAND(deleteBackward:, "cmd_deleteCharBackward");
|
||||
// SEL_TO_COMMAND(deleteBackwardByDecomposingPreviousCharacter:, );
|
||||
SEL_TO_COMMAND(deleteForward:, "cmd_deleteCharForward");
|
||||
|
||||
// TODO: deleteTo* selectors are also supposed to add text to a kill buffer
|
||||
SEL_TO_COMMAND(deleteToBeginningOfLine:, "cmd_deleteToBeginningOfLine");
|
||||
if (aType == eNativeKeyBindingsType_Input) {
|
||||
SEL_TO_COMMAND(deleteToBeginningOfParagraph:,
|
||||
"cmd_deleteToBeginningOfLine");
|
||||
}
|
||||
SEL_TO_COMMAND(deleteToEndOfLine:, "cmd_deleteToEndOfLine");
|
||||
if (aType == eNativeKeyBindingsType_Input) {
|
||||
SEL_TO_COMMAND(deleteToEndOfParagraph:, "cmd_deleteToEndOfLine");
|
||||
}
|
||||
// SEL_TO_COMMAND(deleteToMark:, );
|
||||
|
||||
SEL_TO_COMMAND(deleteWordBackward:, "cmd_deleteWordBackward");
|
||||
SEL_TO_COMMAND(deleteWordForward:, "cmd_deleteWordForward");
|
||||
// SEL_TO_COMMAND(indent:, );
|
||||
// SEL_TO_COMMAND(insertBacktab:, );
|
||||
// SEL_TO_COMMAND(insertContainerBreak:, );
|
||||
// SEL_TO_COMMAND(insertLineBreak:, );
|
||||
// SEL_TO_COMMAND(insertNewline:, );
|
||||
// SEL_TO_COMMAND(insertNewlineIgnoringFieldEditor:, );
|
||||
// SEL_TO_COMMAND(insertParagraphSeparator:, );
|
||||
// SEL_TO_COMMAND(insertTab:, );
|
||||
// SEL_TO_COMMAND(insertTabIgnoringFieldEditor:, );
|
||||
// SEL_TO_COMMAND(insertDoubleQuoteIgnoringSubstitution:, );
|
||||
// SEL_TO_COMMAND(insertSingleQuoteIgnoringSubstitution:, );
|
||||
// SEL_TO_COMMAND(lowercaseWord:, );
|
||||
SEL_TO_COMMAND(moveBackward:, "cmd_charPrevious");
|
||||
SEL_TO_COMMAND(moveBackwardAndModifySelection:, "cmd_selectCharPrevious");
|
||||
if (aType == eNativeKeyBindingsType_Input) {
|
||||
SEL_TO_COMMAND(moveDown:, "cmd_endLine");
|
||||
} else {
|
||||
SEL_TO_COMMAND(moveDown:, "cmd_lineNext");
|
||||
}
|
||||
SEL_TO_COMMAND(moveDownAndModifySelection:, "cmd_selectLineNext");
|
||||
SEL_TO_COMMAND(moveForward:, "cmd_charNext");
|
||||
SEL_TO_COMMAND(moveForwardAndModifySelection:, "cmd_selectCharNext");
|
||||
SEL_TO_COMMAND(moveLeft:, "cmd_charPrevious");
|
||||
SEL_TO_COMMAND(moveLeftAndModifySelection:, "cmd_selectCharPrevious");
|
||||
if (aType == eNativeKeyBindingsType_Input) {
|
||||
SEL_TO_COMMAND(moveParagraphBackwardAndModifySelection:,
|
||||
"cmd_selectBeginLine");
|
||||
SEL_TO_COMMAND(moveParagraphForwardAndModifySelection:,
|
||||
"cmd_selectEndLine");
|
||||
}
|
||||
SEL_TO_COMMAND(moveRight:, "cmd_charNext");
|
||||
SEL_TO_COMMAND(moveRightAndModifySelection:, "cmd_selectCharNext");
|
||||
SEL_TO_COMMAND(moveToBeginningOfDocument:, "cmd_moveTop");
|
||||
SEL_TO_COMMAND(moveToBeginningOfDocumentAndModifySelection:, "cmd_selectTop");
|
||||
SEL_TO_COMMAND(moveToBeginningOfLine:, "cmd_beginLine");
|
||||
SEL_TO_COMMAND(moveToBeginningOfLineAndModifySelection:,
|
||||
"cmd_selectBeginLine");
|
||||
if (aType == eNativeKeyBindingsType_Input) {
|
||||
SEL_TO_COMMAND(moveToBeginningOfParagraph:, "cmd_beginLine");
|
||||
SEL_TO_COMMAND(moveToBeginningOfParagraphAndModifySelection:,
|
||||
"cmd_selectBeginLine");
|
||||
}
|
||||
SEL_TO_COMMAND(moveToEndOfDocument:, "cmd_moveBottom");
|
||||
SEL_TO_COMMAND(moveToEndOfDocumentAndModifySelection:, "cmd_selectBottom");
|
||||
SEL_TO_COMMAND(moveToEndOfLine:, "cmd_endLine");
|
||||
SEL_TO_COMMAND(moveToEndOfLineAndModifySelection:, "cmd_selectEndLine");
|
||||
if (aType == eNativeKeyBindingsType_Input) {
|
||||
SEL_TO_COMMAND(moveToEndOfParagraph:, "cmd_endLine");
|
||||
SEL_TO_COMMAND(moveToEndOfParagraphAndModifySelection:,
|
||||
"cmd_selectEndLine");
|
||||
}
|
||||
SEL_TO_COMMAND(moveToLeftEndOfLine:, "cmd_beginLine");
|
||||
SEL_TO_COMMAND(moveToLeftEndOfLineAndModifySelection:, "cmd_selectBeginLine");
|
||||
SEL_TO_COMMAND(moveToRightEndOfLine:, "cmd_endLine");
|
||||
SEL_TO_COMMAND(moveToRightEndOfLineAndModifySelection:, "cmd_selectEndLine");
|
||||
if (aType == eNativeKeyBindingsType_Input) {
|
||||
SEL_TO_COMMAND(moveUp:, "cmd_beginLine");
|
||||
} else {
|
||||
SEL_TO_COMMAND(moveUp:, "cmd_linePrevious");
|
||||
}
|
||||
SEL_TO_COMMAND(moveUpAndModifySelection:, "cmd_selectLinePrevious");
|
||||
SEL_TO_COMMAND(moveWordBackward:, "cmd_wordPrevious");
|
||||
SEL_TO_COMMAND(moveWordBackwardAndModifySelection:, "cmd_selectWordPrevious");
|
||||
SEL_TO_COMMAND(moveWordForward:, "cmd_wordNext");
|
||||
SEL_TO_COMMAND(moveWordForwardAndModifySelection:, "cmd_selectWordNext");
|
||||
SEL_TO_COMMAND(moveWordLeft:, "cmd_wordPrevious");
|
||||
SEL_TO_COMMAND(moveWordLeftAndModifySelection:, "cmd_selectWordPrevious");
|
||||
SEL_TO_COMMAND(moveWordRight:, "cmd_wordNext");
|
||||
SEL_TO_COMMAND(moveWordRightAndModifySelection:, "cmd_selectWordNext");
|
||||
SEL_TO_COMMAND(pageDown:, "cmd_movePageDown");
|
||||
SEL_TO_COMMAND(pageDownAndModifySelection:, "cmd_selectPageDown");
|
||||
SEL_TO_COMMAND(pageUp:, "cmd_movePageUp");
|
||||
SEL_TO_COMMAND(pageUpAndModifySelection:, "cmd_selectPageUp");
|
||||
SEL_TO_COMMAND(paste:, "cmd_paste");
|
||||
// SEL_TO_COMMAND(pasteFont:, );
|
||||
// SEL_TO_COMMAND(pasteRuler:, );
|
||||
SEL_TO_COMMAND(scrollLineDown:, "cmd_scrollLineDown");
|
||||
SEL_TO_COMMAND(scrollLineUp:, "cmd_scrollLineUp");
|
||||
SEL_TO_COMMAND(scrollPageDown:, "cmd_scrollPageDown");
|
||||
SEL_TO_COMMAND(scrollPageUp:, "cmd_scrollPageUp");
|
||||
SEL_TO_COMMAND(scrollToBeginningOfDocument:, "cmd_scrollTop");
|
||||
SEL_TO_COMMAND(scrollToEndOfDocument:, "cmd_scrollBottom");
|
||||
SEL_TO_COMMAND(selectAll:, "cmd_selectAll");
|
||||
// selectLine: is complex, see KeyDown
|
||||
if (aType == eNativeKeyBindingsType_Input) {
|
||||
SEL_TO_COMMAND(selectParagraph:, "cmd_selectAll");
|
||||
}
|
||||
// SEL_TO_COMMAND(selectToMark:, );
|
||||
// selectWord: is complex, see KeyDown
|
||||
// SEL_TO_COMMAND(setMark:, );
|
||||
// SEL_TO_COMMAND(showContextHelp:, );
|
||||
// SEL_TO_COMMAND(supplementalTargetForAction:sender:, );
|
||||
// SEL_TO_COMMAND(swapWithMark:, );
|
||||
// SEL_TO_COMMAND(transpose:, );
|
||||
// SEL_TO_COMMAND(transposeWords:, );
|
||||
// SEL_TO_COMMAND(uppercaseWord:, );
|
||||
// SEL_TO_COMMAND(yank:, );
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#undef SEL_TO_COMMAND
|
||||
|
||||
NS_IMPL_ISUPPORTS1(NativeKeyBindings, nsINativeKeyBindings)
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
NativeKeyBindings::KeyDown(const nsNativeKeyEvent& aEvent,
|
||||
DoCommandCallback aCallback, void* aCallbackData)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
NativeKeyBindings::KeyPress(const nsNativeKeyEvent& aEvent,
|
||||
DoCommandCallback aCallback, void* aCallbackData)
|
||||
{
|
||||
PR_LOG(gNativeKeyBindingsLog, PR_LOG_ALWAYS,
|
||||
("%p NativeKeyBindings::KeyPress", this));
|
||||
|
||||
// Recover the current event, which should always be the key down we are
|
||||
// responding to.
|
||||
nsKeyEvent* geckoEvent = aEvent.mGeckoEvent;
|
||||
|
||||
MOZ_ASSERT(geckoEvent);
|
||||
|
||||
NSEvent* cocoaEvent = reinterpret_cast<NSEvent*>(geckoEvent->mNativeKeyEvent);
|
||||
|
||||
if (!cocoaEvent || [cocoaEvent type] != NSKeyDown) {
|
||||
PR_LOG(gNativeKeyBindingsLog, PR_LOG_ALWAYS,
|
||||
("%p NativeKeyBindings::KeyPress, no Cocoa key down event", this));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
PR_LOG(gNativeKeyBindingsLog, PR_LOG_ALWAYS,
|
||||
("%p NativeKeyBindings::KeyPress, interpreting", this));
|
||||
|
||||
nsAutoTArray<KeyBindingsCommand, 2> bindingCommands;
|
||||
nsCocoaUtils::GetCommandsFromKeyEvent(cocoaEvent, bindingCommands);
|
||||
|
||||
PR_LOG(gNativeKeyBindingsLog, PR_LOG_ALWAYS,
|
||||
("%p NativeKeyBindings::KeyPress, bindingCommands=%u",
|
||||
this, bindingCommands.Length()));
|
||||
|
||||
nsAutoTArray<const char*, 4> geckoCommands;
|
||||
|
||||
for (uint32_t i = 0; i < bindingCommands.Length(); i++) {
|
||||
SEL selector = bindingCommands[i].selector;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gNativeKeyBindingsLog, PR_LOG_ALWAYS)) {
|
||||
NSString* selectorString = NSStringFromSelector(selector);
|
||||
nsAutoString nsSelectorString;
|
||||
nsCocoaUtils::GetStringForNSString(selectorString, nsSelectorString);
|
||||
|
||||
PR_LOG(gNativeKeyBindingsLog, PR_LOG_ALWAYS,
|
||||
("%p NativeKeyBindings::KeyPress, selector=%s",
|
||||
this, ToNewCString(nsSelectorString)));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Try to find a simple mapping in the hashtable
|
||||
const char* commandStr = mSelectorToCommand.Get(
|
||||
reinterpret_cast<struct objc_selector*>(selector));
|
||||
|
||||
if (commandStr) {
|
||||
geckoCommands.AppendElement(commandStr);
|
||||
} else if (selector == @selector(selectLine:)) {
|
||||
// This is functional, but Cocoa's version is direction-less in that
|
||||
// selection direction is not determined until some future directed action
|
||||
// is taken. See bug 282097, comment 79 for more details.
|
||||
geckoCommands.AppendElement("cmd_beginLine");
|
||||
geckoCommands.AppendElement("cmd_selectEndLine");
|
||||
} else if (selector == @selector(selectWord:)) {
|
||||
// This is functional, but Cocoa's version is direction-less in that
|
||||
// selection direction is not determined until some future directed action
|
||||
// is taken. See bug 282097, comment 79 for more details.
|
||||
geckoCommands.AppendElement("cmd_wordPrevious");
|
||||
geckoCommands.AppendElement("cmd_selectWordNext");
|
||||
}
|
||||
}
|
||||
|
||||
if (geckoCommands.IsEmpty()) {
|
||||
PR_LOG(gNativeKeyBindingsLog, PR_LOG_ALWAYS,
|
||||
("%p NativeKeyBindings::KeyPress, handled=false", this));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < geckoCommands.Length(); i++) {
|
||||
const char* geckoCommand = geckoCommands[i];
|
||||
|
||||
PR_LOG(gNativeKeyBindingsLog, PR_LOG_ALWAYS,
|
||||
("%p NativeKeyBindings::KeyPress, command=%s",
|
||||
this, geckoCommand));
|
||||
|
||||
// Execute the Gecko command
|
||||
aCallback(geckoCommand, aCallbackData);
|
||||
}
|
||||
|
||||
PR_LOG(gNativeKeyBindingsLog, PR_LOG_ALWAYS,
|
||||
("%p NativeKeyBindings::KeyPress, handled=true", this));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
NativeKeyBindings::KeyUp(const nsNativeKeyEvent& aEvent,
|
||||
DoCommandCallback aCallback, void* aCallbackData)
|
||||
{
|
||||
return false;
|
||||
}
|
@ -777,6 +777,10 @@ TISInputSourceWrapper::InitKeyEvent(NSEvent *aNativeKeyEvent,
|
||||
|
||||
nsCocoaUtils::InitInputEvent(aKeyEvent, aNativeKeyEvent);
|
||||
|
||||
// This is used only while dispatching the event (which is a synchronous
|
||||
// call), so there is no need to retain and release this data.
|
||||
aKeyEvent.mNativeKeyEvent = aNativeKeyEvent;
|
||||
|
||||
aKeyEvent.refPoint = nsIntPoint(0, 0);
|
||||
|
||||
// If a keyboard layout override is set, we also need to force the keyboard
|
||||
|
@ -76,6 +76,58 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(GfxInfo, Init)
|
||||
}
|
||||
}
|
||||
|
||||
#include "NativeKeyBindings.h"
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
static nsresult
|
||||
NativeKeyBindingsConstructor(nsISupports* aOuter, REFNSIID aIID,
|
||||
void** aResult, NativeKeyBindingsType aType)
|
||||
{
|
||||
NativeKeyBindings* inst;
|
||||
|
||||
*aResult = NULL;
|
||||
if (NULL != aOuter) {
|
||||
return NS_ERROR_NO_AGGREGATION;
|
||||
}
|
||||
|
||||
inst = new NativeKeyBindings();
|
||||
NS_ADDREF(inst);
|
||||
nsresult rv = inst->Init(aType);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = inst->QueryInterface(aIID, aResult);
|
||||
}
|
||||
NS_RELEASE(inst);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
NativeKeyBindingsInputConstructor(nsISupports* aOuter, REFNSIID aIID,
|
||||
void** aResult)
|
||||
{
|
||||
return NativeKeyBindingsConstructor(aOuter, aIID, aResult,
|
||||
eNativeKeyBindingsType_Input);
|
||||
}
|
||||
|
||||
static nsresult
|
||||
NativeKeyBindingsTextAreaConstructor(nsISupports* aOuter, REFNSIID aIID,
|
||||
void** aResult)
|
||||
{
|
||||
return NativeKeyBindingsConstructor(aOuter, aIID, aResult,
|
||||
eNativeKeyBindingsType_TextArea);
|
||||
}
|
||||
|
||||
static nsresult
|
||||
NativeKeyBindingsEditorConstructor(nsISupports* aOuter, REFNSIID aIID,
|
||||
void** aResult)
|
||||
{
|
||||
return NativeKeyBindingsConstructor(aOuter, aIID, aResult,
|
||||
eNativeKeyBindingsType_Editor);
|
||||
}
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
NS_DEFINE_NAMED_CID(NS_WINDOW_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_POPUP_CID);
|
||||
@ -101,6 +153,9 @@ NS_DEFINE_NAMED_CID(NS_MACDOCKSUPPORT_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_MACWEBAPPUTILS_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_STANDALONENATIVEMENU_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_GFXINFO_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_NATIVEKEYBINDINGS_INPUT_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_NATIVEKEYBINDINGS_TEXTAREA_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_NATIVEKEYBINDINGS_EDITOR_CID);
|
||||
|
||||
|
||||
static const mozilla::Module::CIDEntry kWidgetCIDs[] = {
|
||||
@ -128,6 +183,12 @@ static const mozilla::Module::CIDEntry kWidgetCIDs[] = {
|
||||
{ &kNS_MACWEBAPPUTILS_CID, false, NULL, nsMacWebAppUtilsConstructor },
|
||||
{ &kNS_STANDALONENATIVEMENU_CID, false, NULL, nsStandaloneNativeMenuConstructor },
|
||||
{ &kNS_GFXINFO_CID, false, NULL, mozilla::widget::GfxInfoConstructor },
|
||||
{ &kNS_NATIVEKEYBINDINGS_INPUT_CID, false, NULL,
|
||||
mozilla::widget::NativeKeyBindingsInputConstructor },
|
||||
{ &kNS_NATIVEKEYBINDINGS_TEXTAREA_CID, false, NULL,
|
||||
mozilla::widget::NativeKeyBindingsTextAreaConstructor },
|
||||
{ &kNS_NATIVEKEYBINDINGS_EDITOR_CID, false, NULL,
|
||||
mozilla::widget::NativeKeyBindingsEditorConstructor },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@ -156,6 +217,10 @@ static const mozilla::Module::ContractIDEntry kWidgetContracts[] = {
|
||||
{ "@mozilla.org/widget/mac-web-app-utils;1", &kNS_MACWEBAPPUTILS_CID },
|
||||
{ "@mozilla.org/widget/standalonenativemenu;1", &kNS_STANDALONENATIVEMENU_CID },
|
||||
{ "@mozilla.org/gfx/info;1", &kNS_GFXINFO_CID },
|
||||
{ NS_NATIVEKEYBINDINGSINPUT_CONTRACTID, &kNS_NATIVEKEYBINDINGS_INPUT_CID },
|
||||
{ NS_NATIVEKEYBINDINGSTEXTAREA_CONTRACTID,
|
||||
&kNS_NATIVEKEYBINDINGS_TEXTAREA_CID },
|
||||
{ NS_NATIVEKEYBINDINGSEDITOR_CONTRACTID, &kNS_NATIVEKEYBINDINGS_EDITOR_CID },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
@ -23,21 +23,12 @@ enum NativeKeyBindingsType {
|
||||
#define NS_NATIVEKEYBINDINGSINPUT_CID \
|
||||
{0x5c337258, 0xa580, 0x472e, {0x86, 0x15, 0xf2, 0x77, 0xdd, 0xc5, 0xbb, 0x06}}
|
||||
|
||||
#define NS_NATIVEKEYBINDINGSINPUT_CONTRACTID \
|
||||
NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "input"
|
||||
|
||||
#define NS_NATIVEKEYBINDINGSTEXTAREA_CID \
|
||||
{0x2a898043, 0x180f, 0x4c8b, {0x8e, 0x54, 0x41, 0x0c, 0x7a, 0x54, 0x0f, 0x27}}
|
||||
|
||||
#define NS_NATIVEKEYBINDINGSTEXTAREA_CONTRACTID \
|
||||
NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "textarea"
|
||||
|
||||
#define NS_NATIVEKEYBINDINGSEDITOR_CID \
|
||||
{0xf916ebfb, 0x78ef, 0x464b, {0x94, 0xd0, 0xa6, 0xf2, 0xca, 0x32, 0x00, 0xae}}
|
||||
|
||||
#define NS_NATIVEKEYBINDINGSEDITOR_CONTRACTID \
|
||||
NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "editor"
|
||||
|
||||
class nsNativeKeyBindings MOZ_FINAL : public nsINativeKeyBindings
|
||||
{
|
||||
public:
|
||||
|
@ -15,6 +15,15 @@
|
||||
#define NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX \
|
||||
"@mozilla.org/widget/native-key-bindings;1?type="
|
||||
|
||||
#define NS_NATIVEKEYBINDINGSINPUT_CONTRACTID \
|
||||
NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "input"
|
||||
|
||||
#define NS_NATIVEKEYBINDINGSTEXTAREA_CONTRACTID \
|
||||
NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "textarea"
|
||||
|
||||
#define NS_NATIVEKEYBINDINGSEDITOR_CONTRACTID \
|
||||
NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "editor"
|
||||
|
||||
struct nsNativeKeyEvent
|
||||
{
|
||||
nsKeyEvent* mGeckoEvent; // see bug 406407 to see how this is used
|
||||
|
@ -79,6 +79,7 @@ MOCHITEST_CHROME_FILES += native_menus_window.xul \
|
||||
test_bug673301.xul \
|
||||
test_taskbar_progress.xul \
|
||||
test_secure_input.html \
|
||||
test_native_key_bindings_mac.html \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
|
154
widget/tests/test_native_key_bindings_mac.html
Normal file
154
widget/tests/test_native_key_bindings_mac.html
Normal file
@ -0,0 +1,154 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'/>
|
||||
<title>Native Key Bindings for Cocoa Test</title>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<script type="text/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script type="text/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/NativeKeyCodes.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="editable" contenteditable>
|
||||
|
||||
<p>Stretching attack nullam stuck in a tree zzz, suspendisse cras nec
|
||||
suspendisse lick suscipit. Nunc egestas amet litter box, nullam climb the
|
||||
curtains biting I don't like that food tristique biting sleep on your
|
||||
keyboard non. Lay down in your way cras nec tempus chase the red dot cras
|
||||
nec, pharetra pharetra eat the grass leap run orci turpis attack.
|
||||
Consectetur sleep in the sink eat I don't like that food, knock over the
|
||||
lamp catnip in viverra tail flick zzz meow etiam enim. Ac ac hiss shed
|
||||
everywhere kittens rhoncus, attack your ankles zzz iaculis kittens. Nullam
|
||||
pellentesque rip the couch iaculis rhoncus nibh, give me fish orci turpis
|
||||
purr sleep on your face quis nunc bibendum.</p>
|
||||
|
||||
<p>Neque jump on the table bat iaculis, adipiscing sleep on your keyboard
|
||||
jump vel justo shed everywhere suspendisse lick. Zzz enim faucibus
|
||||
hairball faucibus, pharetra sunbathe biting bat leap rip the couch attack.
|
||||
Tortor nibh in viverra quis hairball nam, vulputate adipiscing sleep on
|
||||
your keyboard purr knock over the lamp orci turpis. Vestibulum I don't
|
||||
like that food et chase the red dot, adipiscing neque bibendum rutrum
|
||||
accumsan quis rhoncus claw. Leap accumsan vehicula enim biting sleep on
|
||||
your face, pharetra nam accumsan egestas kittens sunbathe. Pharetra chase
|
||||
the red dot sniff non eat the grass, vulputate fluffy fur aliquam puking
|
||||
judging you.</p>
|
||||
|
||||
<p>Claw purr sollicitudin sollicitudin lay down in your way consectetur,
|
||||
pellentesque vehicula zzz orci turpis consectetur. I don't like that food
|
||||
rhoncus pellentesque sniff attack, rhoncus tortor attack your ankles
|
||||
iaculis scratched hiss vel. Tortor zzz tortor nullam rip the couch rutrum,
|
||||
bat enim ut leap hairball iaculis. Bibendum sunbathe elit suspendisse
|
||||
nibh, puking adipiscing sleep on your face sleep on your face zzz catnip.
|
||||
Judging you rutrum bat sunbathe sleep on your face, jump on the table leap
|
||||
tincidunt a faucibus sleep in the sink. Stuck in a tree tristique zzz hiss
|
||||
in viverra nullam, quis tortor pharetra attack.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/javascript;version=1.8">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
let editNode = document.getElementById("editable");
|
||||
|
||||
let utils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
|
||||
getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
|
||||
let layouts = {
|
||||
"US": 0,
|
||||
"Greek": 1,
|
||||
"German": 2,
|
||||
"Swedish": 3,
|
||||
"Dvorak-Qwerty": 4,
|
||||
"Thai": 5
|
||||
};
|
||||
|
||||
function synthesizeNativeKey(aLayout, aKeyCode, aModifiers, aSystemChars,
|
||||
aSystemUnmodifiedChars)
|
||||
{
|
||||
let modifiers = 0;
|
||||
if (aModifiers.capsLock) modifiers |= 0x01;
|
||||
if (aModifiers.numLock) modifiers |= 0x02;
|
||||
if (aModifiers.shift) modifiers |= 0x0100;
|
||||
if (aModifiers.shiftRight) modifiers |= 0x0200;
|
||||
if (aModifiers.ctrl) modifiers |= 0x0400;
|
||||
if (aModifiers.ctrlRight) modifiers |= 0x0800;
|
||||
if (aModifiers.alt) modifiers |= 0x1000;
|
||||
if (aModifiers.altRight) modifiers |= 0x2000;
|
||||
if (aModifiers.command) modifiers |= 0x4000;
|
||||
if (aModifiers.commandRight) modifiers |= 0x8000;
|
||||
if (aModifiers.help) modifiers |= 0x10000;
|
||||
if (aModifiers.function) modifiers |= 0x100000;
|
||||
if (aModifiers.numericKeyPad) modifiers |= 0x01000000;
|
||||
|
||||
utils.sendNativeKeyEvent(aLayout, aKeyCode, modifiers,
|
||||
aSystemChars, aSystemUnmodifiedChars);
|
||||
}
|
||||
|
||||
function testSelection(aAnchorOffset, aFocusOffset)
|
||||
{
|
||||
let selection = window.getSelection();
|
||||
|
||||
is(selection.anchorOffset, aAnchorOffset, "Incorrect anchor offset");
|
||||
is(selection.focusOffset, aFocusOffset, "Incorrect focus offset");
|
||||
}
|
||||
|
||||
function doTest()
|
||||
{
|
||||
editNode.focus();
|
||||
|
||||
// Move to beginning of line
|
||||
synthesizeNativeKey(layouts.US, MAC_VK_LeftArrow,
|
||||
{ctrl: true}, "\uf702", "\uf702");
|
||||
testSelection(0, 0);
|
||||
|
||||
// Move to end of line
|
||||
synthesizeNativeKey(layouts.US, MAC_VK_RightArrow,
|
||||
{ctrl: true}, "\uf703", "\uf703");
|
||||
testSelection(73, 73);
|
||||
|
||||
// Move down
|
||||
synthesizeNativeKey(layouts.US, MAC_VK_ANSI_N, {ctrl: true}, "n", "n");
|
||||
testSelection(140, 140);
|
||||
|
||||
// Move to beginning of line
|
||||
synthesizeNativeKey(layouts.US, MAC_VK_LeftArrow,
|
||||
{ctrl: true}, "\uf702", "\uf702");
|
||||
testSelection(73, 73);
|
||||
|
||||
// Move word right and modify selection
|
||||
synthesizeNativeKey(layouts.US, MAC_VK_RightArrow,
|
||||
{alt: true, shift: true}, "\uf703", "\uf703");
|
||||
testSelection(73, 84);
|
||||
|
||||
// Move word right
|
||||
synthesizeNativeKey(layouts.US, MAC_VK_RightArrow,
|
||||
{alt: true}, "\uf703", "\uf703");
|
||||
testSelection(84, 84);
|
||||
|
||||
// Move word right
|
||||
synthesizeNativeKey(layouts.US, MAC_VK_RightArrow,
|
||||
{alt: true}, "\uf703", "\uf703");
|
||||
testSelection(89, 89);
|
||||
|
||||
// Move down and modify selection
|
||||
synthesizeNativeKey(layouts.US, MAC_VK_DownArrow,
|
||||
{shift: true}, "\uf701", "\uf701");
|
||||
testSelection(89, 171);
|
||||
|
||||
// Move backward and modify selection
|
||||
synthesizeNativeKey(layouts.US, MAC_VK_ANSI_B,
|
||||
{ctrl: true, shift: true}, "B", "B");
|
||||
testSelection(89, 170);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForFocus(doTest);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
Loading…
Reference in New Issue
Block a user