Bug 359638 accesskeys are incorrectly shifted again (i.e. accesskey=. is broken) and also for b=398264, b=401086, b=414130, b=427797, b=427932, b=427995 r=karlt+ere+josh, sr=roc, a1.9=mconnor

This commit is contained in:
masayuki@d-toybox.com 2008-04-14 21:16:24 -07:00
Родитель 8145c55c2b
Коммит f0d97b8c55
21 изменённых файлов: 671 добавлений и 257 удалений

Просмотреть файл

@ -57,6 +57,7 @@
#include "nsIScriptRuntime.h"
#include "nsIScriptGlobalObject.h"
#include "nsIDOMEvent.h"
#include "nsTArray.h"
struct nsNativeKeyEvent; // Don't include nsINativeKeyBindings.h here: it will force strange compilation error!
@ -124,6 +125,15 @@ struct EventNameMapping {
PRInt32 mType;
};
struct nsShortcutCandidate {
nsShortcutCandidate(PRUint32 aCharCode, PRBool aIgnoreShift) :
mCharCode(aCharCode), mIgnoreShift(aIgnoreShift)
{
}
PRUint32 mCharCode;
PRBool mIgnoreShift;
};
class nsContentUtils
{
public:
@ -1158,6 +1168,26 @@ public:
nsNativeKeyEvent* aNativeEvent,
PRBool aGetCharCode);
/**
* Get the candidates for accelkeys for aDOMEvent.
*
* @param aDOMEvent [in] the input event for accelkey handling.
* @param aCandidates [out] the candidate shortcut key combination list.
* the first item is most preferred.
*/
static void GetAccelKeyCandidates(nsIDOMEvent* aDOMEvent,
nsTArray<nsShortcutCandidate>& aCandidates);
/**
* Get the candidates for accesskeys for aDOMEvent.
*
* @param aNativeKeyEvent [in] the input event for accesskey handling.
* @param aCandidates [out] the candidate access key list.
* the first item is most preferred.
*/
static void GetAccessKeyCandidates(nsKeyEvent* aNativeKeyEvent,
nsTArray<PRUint32>& aCandidates);
/**
* Hide any XUL popups associated with aDocument, including any documents
* displayed in child frames.

Просмотреть файл

@ -3999,6 +3999,124 @@ nsContentUtils::DOMEventToNativeKeyEvent(nsIDOMEvent* aDOMEvent,
return PR_TRUE;
}
/* static */
void
nsContentUtils::GetAccelKeyCandidates(nsIDOMEvent* aDOMEvent,
nsTArray<nsShortcutCandidate>& aCandidates)
{
NS_PRECONDITION(aCandidates.IsEmpty(), "aCandidates must be empty");
nsAutoString eventType;
aDOMEvent->GetType(eventType);
// Don't process if aDOMEvent is not a keypress event.
if (!eventType.EqualsLiteral("keypress"))
return;
nsKeyEvent* nativeKeyEvent =
static_cast<nsKeyEvent*>(GetNativeEvent(aDOMEvent));
if (nativeKeyEvent) {
// nsShortcutCandidate::mCharCode is a candidate charCode.
// nsShoftcutCandidate::mIgnoreShift means the mCharCode should be tried to
// execute a command with/without shift key state. If this is TRUE, the
// shifted key state should be ignored. Otherwise, don't ignore the state.
// the priority of the charCodes are (shift key is not pressed):
// 0: charCode/PR_FALSE,
// 1: unshiftedCharCodes[0]/PR_FALSE, 2: unshiftedCharCodes[1]/PR_FALSE...
// the priority of the charCodes are (shift key is pressed):
// 0: charCode/PR_FALSE,
// 1: shiftedCharCodes[0]/PR_FALSE, 2: shiftedCharCodes[0]/PR_TRUE,
// 3: shiftedCharCodes[1]/PR_FALSE, 4: shiftedCharCodes[1]/PR_TRUE...
if (nativeKeyEvent->charCode) {
nsShortcutCandidate key(nativeKeyEvent->charCode, PR_FALSE);
aCandidates.AppendElement(key);
}
if (!nativeKeyEvent->isShift) {
for (PRUint32 i = 0;
i < nativeKeyEvent->alternativeCharCodes.Length(); ++i) {
PRUint32 ch =
nativeKeyEvent->alternativeCharCodes[0].mUnshiftedCharCode;
if (!ch || ch == nativeKeyEvent->charCode)
continue;
nsShortcutCandidate key(ch, PR_FALSE);
aCandidates.AppendElement(key);
}
} else {
for (PRUint32 i = 0;
i < nativeKeyEvent->alternativeCharCodes.Length(); ++i) {
PRUint32 ch = nativeKeyEvent->alternativeCharCodes[i].mShiftedCharCode;
if (!ch)
continue;
if (ch != nativeKeyEvent->charCode) {
nsShortcutCandidate key(ch, PR_FALSE);
aCandidates.AppendElement(key);
}
// If the char is an alphabet, the shift key state should not be
// ignored. E.g., Ctrl+Shift+C should not execute Ctrl+C.
// And checking the charCode is same as unshiftedCharCode too.
// E.g., for Ctrl+Shift+(Plus of Numpad) should not run Ctrl+Plus.
PRUint32 unshiftCh =
nativeKeyEvent->alternativeCharCodes[i].mUnshiftedCharCode;
if (ch == unshiftCh ||
(IS_IN_BMP(ch) && IS_IN_BMP(unshiftCh) &&
ToLowerCase(PRUnichar(ch)) == ToLowerCase(PRUnichar(unshiftCh))))
continue;
// Setting the alternative charCode candidates for retry without shift
// key state only when the shift key is pressed.
nsShortcutCandidate key(ch, PR_TRUE);
aCandidates.AppendElement(key);
}
}
} else {
nsCOMPtr<nsIDOMKeyEvent> key(do_QueryInterface(aDOMEvent));
PRUint32 charCode;
key->GetCharCode(&charCode);
if (charCode) {
nsShortcutCandidate key(charCode, PR_FALSE);
aCandidates.AppendElement(key);
}
}
}
/* static */
void
nsContentUtils::GetAccessKeyCandidates(nsKeyEvent* aNativeKeyEvent,
nsTArray<PRUint32>& aCandidates)
{
NS_PRECONDITION(aCandidates.IsEmpty(), "aCandidates must be empty");
// return the lower cased charCode candidates for access keys.
// the priority of the charCodes are:
// 0: charCode, 1: unshiftedCharCodes[0], 2: shiftedCharCodes[0]
// 3: unshiftedCharCodes[1], 4: shiftedCharCodes[1],...
if (aNativeKeyEvent->charCode) {
PRUint32 ch = aNativeKeyEvent->charCode;
if (IS_IN_BMP(ch))
ch = ToLowerCase(PRUnichar(ch));
aCandidates.AppendElement(ch);
}
for (PRUint32 i = 0;
i < aNativeKeyEvent->alternativeCharCodes.Length(); ++i) {
PRUint32 ch[2] =
{ aNativeKeyEvent->alternativeCharCodes[i].mUnshiftedCharCode,
aNativeKeyEvent->alternativeCharCodes[i].mShiftedCharCode };
for (PRUint32 j = 0; j < 2; ++j) {
if (!ch[j])
continue;
if (IS_IN_BMP(ch[j]))
ch[j] = ToLowerCase(PRUnichar(ch[j]));
// Don't append the charCode that was already appended.
if (aCandidates.IndexOf(ch[j]) == aCandidates.NoIndex)
aCandidates.AppendElement(ch[j]);
}
}
return;
}
/* static */
void
nsContentUtils::AddScriptBlocker()

Просмотреть файл

@ -1441,7 +1441,7 @@ GetAccessModifierMask(nsISupports* aDocShell)
}
static PRBool
IsAccessKeyTarget(nsIContent* aContent, nsIFrame* aFrame, nsString& aKey)
IsAccessKeyTarget(nsIContent* aContent, nsIFrame* aFrame, nsAString& aKey)
{
if (!aFrame)
return PR_FALSE;
@ -1465,6 +1465,45 @@ IsAccessKeyTarget(nsIContent* aContent, nsIFrame* aFrame, nsString& aKey)
return PR_FALSE;
}
PRBool
nsEventStateManager::ExecuteAccessKey(nsTArray<PRUint32>& aAccessCharCodes,
PRBool aIsTrustedEvent)
{
PRInt32 count, start = -1;
if (mCurrentFocus) {
start = mAccessKeys.IndexOf(mCurrentFocus);
if (start == -1 && mCurrentFocus->GetBindingParent())
start = mAccessKeys.IndexOf(mCurrentFocus->GetBindingParent());
}
nsIContent *content;
nsIFrame *frame;
PRInt32 length = mAccessKeys.Count();
for (PRUint32 i = 0; i < aAccessCharCodes.Length(); ++i) {
PRUint32 ch = aAccessCharCodes[i];
nsAutoString accessKey;
AppendUCS4ToUTF16(ch, accessKey);
for (count = 1; count <= length; ++count) {
content = mAccessKeys[(start + count) % length];
frame = mPresContext->PresShell()->GetPrimaryFrameFor(content);
if (IsAccessKeyTarget(content, frame, accessKey)) {
PRBool shouldActivate = sKeyCausesActivation;
while (shouldActivate && ++count <= length) {
nsIContent *oc = mAccessKeys[(start + count) % length];
nsIFrame *of = mPresContext->PresShell()->GetPrimaryFrameFor(oc);
if (IsAccessKeyTarget(oc, of, accessKey))
shouldActivate = PR_FALSE;
}
if (shouldActivate)
content->PerformAccesskey(shouldActivate, aIsTrustedEvent);
else if (frame && frame->IsFocusable())
ChangeFocusWith(content, eEventFocusedByKey);
return PR_TRUE;
}
}
}
return PR_FALSE;
}
void
nsEventStateManager::HandleAccessKey(nsPresContext* aPresContext,
nsKeyEvent *aEvent,
@ -1476,37 +1515,15 @@ nsEventStateManager::HandleAccessKey(nsPresContext* aPresContext,
nsCOMPtr<nsISupports> pcContainer = aPresContext->GetContainer();
// Alt or other accesskey modifier is down, we may need to do an accesskey
PRInt32 length = mAccessKeys.Count();
if (length > 0 && aModifierMask == GetAccessModifierMask(pcContainer)) {
if (mAccessKeys.Count() > 0 &&
aModifierMask == GetAccessModifierMask(pcContainer)) {
// Someone registered an accesskey. Find and activate it.
nsAutoString accKey(aEvent->charCode);
PRInt32 count, start = -1;
if (mCurrentFocus) {
start = mAccessKeys.IndexOf(mCurrentFocus);
if (start == -1 && mCurrentFocus->GetBindingParent())
start = mAccessKeys.IndexOf(mCurrentFocus->GetBindingParent());
}
nsIContent *content;
nsIFrame *frame;
for (count = 1; count <= length; ++count) {
content = mAccessKeys[(start + count) % length];
frame = mPresContext->PresShell()->GetPrimaryFrameFor(content);
if (IsAccessKeyTarget(content, frame, accKey)) {
PRBool shouldActivate = sKeyCausesActivation;
while (shouldActivate && ++count <= length) {
nsIContent *oc = mAccessKeys[(start + count) % length];
nsIFrame *of = mPresContext->PresShell()->GetPrimaryFrameFor(oc);
if (IsAccessKeyTarget(oc, of, accKey))
shouldActivate = PR_FALSE;
}
if (shouldActivate)
content->PerformAccesskey(shouldActivate,
NS_IS_TRUSTED_EVENT(aEvent));
else if (frame && frame->IsFocusable())
ChangeFocusWith(content, eEventFocusedByKey);
*aStatus = nsEventStatus_eConsumeNoDefault;
break;
}
PRBool isTrusted = NS_IS_TRUSTED_EVENT(aEvent);
nsAutoTArray<PRUint32, 10> accessCharCodes;
nsContentUtils::GetAccessKeyCandidates(aEvent, accessCharCodes);
if (ExecuteAccessKey(accessCharCodes, isTrusted)) {
*aStatus = nsEventStatus_eConsumeNoDefault;
return;
}
}

Просмотреть файл

@ -268,6 +268,9 @@ protected:
ProcessingAccessKeyState aAccessKeyState,
PRInt32 aModifierMask);
PRBool ExecuteAccessKey(nsTArray<PRUint32>& aAccessCharCodes,
PRBool aIsTrustedEvent);
//---------------------------------------------
// DocShell Focus Traversal Methods
//---------------------------------------------

Просмотреть файл

@ -49,7 +49,9 @@
#include "nsGkAtoms.h"
#include "nsXBLPrototypeHandler.h"
#include "nsIDOMNSEvent.h"
#include "nsGUIEvent.h"
#include "nsContentUtils.h"
#include "nsUnicharUtils.h"
nsXBLEventHandler::nsXBLEventHandler(nsXBLPrototypeHandler* aHandler)
: mProtoHandler(aHandler)
@ -119,6 +121,36 @@ nsXBLKeyEventHandler::~nsXBLKeyEventHandler()
NS_IMPL_ISUPPORTS1(nsXBLKeyEventHandler, nsIDOMEventListener)
PRBool
nsXBLKeyEventHandler::ExecuteMatchedHandlers(nsIDOMKeyEvent* aKeyEvent,
PRUint32 aCharCode,
PRBool aIgnoreShiftKey)
{
nsCOMPtr<nsIDOMNSEvent> domNSEvent = do_QueryInterface(aKeyEvent);
PRBool trustedEvent = PR_FALSE;
if (domNSEvent)
domNSEvent->GetIsTrusted(&trustedEvent);
nsCOMPtr<nsIDOMEventTarget> target;
aKeyEvent->GetCurrentTarget(getter_AddRefs(target));
nsCOMPtr<nsPIDOMEventTarget> piTarget = do_QueryInterface(target);
PRBool executed = PR_FALSE;
for (PRUint32 i = 0; i < mProtoHandlers.Count(); ++i) {
nsXBLPrototypeHandler* handler = static_cast<nsXBLPrototypeHandler*>
(mProtoHandlers[i]);
PRBool hasAllowUntrustedAttr = handler->HasAllowUntrustedAttr();
if ((trustedEvent ||
(hasAllowUntrustedAttr && handler->AllowUntrustedEvents()) ||
(!hasAllowUntrustedAttr && !mIsBoundToChrome)) &&
handler->KeyEventMatched(aKeyEvent, aCharCode, aIgnoreShiftKey)) {
handler->ExecuteHandler(piTarget, aKeyEvent);
executed = PR_TRUE;
}
}
return executed;
}
NS_IMETHODIMP
nsXBLKeyEventHandler::HandleEvent(nsIDOMEvent* aEvent)
{
@ -133,31 +165,21 @@ nsXBLKeyEventHandler::HandleEvent(nsIDOMEvent* aEvent)
return NS_OK;
}
nsCOMPtr<nsIDOMEventTarget> target;
aEvent->GetCurrentTarget(getter_AddRefs(target));
nsCOMPtr<nsPIDOMEventTarget> piTarget = do_QueryInterface(target);
nsCOMPtr<nsIDOMKeyEvent> key(do_QueryInterface(aEvent));
nsCOMPtr<nsIDOMNSEvent> domNSEvent = do_QueryInterface(aEvent);
PRBool trustedEvent = PR_FALSE;
if (domNSEvent) {
domNSEvent->GetIsTrusted(&trustedEvent);
nsAutoTArray<nsShortcutCandidate, 10> accessKeys;
nsContentUtils::GetAccelKeyCandidates(aEvent, accessKeys);
if (accessKeys.IsEmpty()) {
ExecuteMatchedHandlers(key, 0, PR_FALSE);
return NS_OK;
}
PRUint32 i;
for (i = 0; i < count; ++i) {
nsXBLPrototypeHandler* handler = static_cast<nsXBLPrototypeHandler*>
(mProtoHandlers[i]);
PRBool hasAllowUntrustedAttr = handler->HasAllowUntrustedAttr();
if ((trustedEvent ||
(hasAllowUntrustedAttr && handler->AllowUntrustedEvents()) ||
(!hasAllowUntrustedAttr && !mIsBoundToChrome)) &&
handler->KeyEventMatched(key)) {
handler->ExecuteHandler(piTarget, aEvent);
}
for (PRUint32 i = 0; i < accessKeys.Length(); ++i) {
if (ExecuteMatchedHandlers(key, accessKeys[i].mCharCode,
accessKeys[i].mIgnoreShift))
return NS_OK;
}
return NS_OK;
}

Просмотреть файл

@ -46,6 +46,7 @@
class nsIAtom;
class nsIContent;
class nsIDOM3EventTarget;
class nsIDOMKeyEvent;
class nsPIDOMEventTarget;
class nsXBLPrototypeHandler;
@ -121,6 +122,8 @@ public:
}
private:
nsXBLKeyEventHandler();
PRBool ExecuteMatchedHandlers(nsIDOMKeyEvent* aEvent, PRUint32 aCharCode,
PRBool aIgnoreShiftKey);
nsVoidArray mProtoHandlers;
nsCOMPtr<nsIAtom> mEventType;

Просмотреть файл

@ -596,7 +596,9 @@ nsXBLPrototypeHandler::GetController(nsPIDOMEventTarget* aTarget)
}
PRBool
nsXBLPrototypeHandler::KeyEventMatched(nsIDOMKeyEvent* aKeyEvent)
nsXBLPrototypeHandler::KeyEventMatched(nsIDOMKeyEvent* aKeyEvent,
PRUint32 aCharCode,
PRBool aIgnoreShiftKey)
{
if (mDetail == -1)
return PR_TRUE; // No filters set up. It's generic.
@ -605,8 +607,12 @@ nsXBLPrototypeHandler::KeyEventMatched(nsIDOMKeyEvent* aKeyEvent)
PRUint32 code;
if (mMisc) {
aKeyEvent->GetCharCode(&code);
code = ToLowerCase(PRUnichar(code));
if (aCharCode)
code = aCharCode;
else
aKeyEvent->GetCharCode(&code);
if (IS_IN_BMP(code))
code = ToLowerCase(PRUnichar(code));
}
else
aKeyEvent->GetKeyCode(&code);
@ -614,7 +620,7 @@ nsXBLPrototypeHandler::KeyEventMatched(nsIDOMKeyEvent* aKeyEvent)
if (code != PRUint32(mDetail))
return PR_FALSE;
return ModifiersMatchMask(aKeyEvent);
return ModifiersMatchMask(aKeyEvent, aIgnoreShiftKey);
}
PRBool
@ -992,7 +998,8 @@ nsXBLPrototypeHandler::ReportKeyConflict(const PRUnichar* aKey, const PRUnichar*
}
PRBool
nsXBLPrototypeHandler::ModifiersMatchMask(nsIDOMUIEvent* aEvent)
nsXBLPrototypeHandler::ModifiersMatchMask(nsIDOMUIEvent* aEvent,
PRBool aIgnoreShiftKey)
{
nsCOMPtr<nsIDOMKeyEvent> key(do_QueryInterface(aEvent));
nsCOMPtr<nsIDOMMouseEvent> mouse(do_QueryInterface(aEvent));
@ -1004,7 +1011,7 @@ nsXBLPrototypeHandler::ModifiersMatchMask(nsIDOMUIEvent* aEvent)
return PR_FALSE;
}
if (mKeyMask & cShiftMask) {
if (mKeyMask & cShiftMask && !aIgnoreShiftKey) {
key ? key->GetShiftKey(&keyPresent) : mouse->GetShiftKey(&keyPresent);
if (keyPresent != ((mKeyMask & cShift) != 0))
return PR_FALSE;

Просмотреть файл

@ -91,14 +91,19 @@ public:
~nsXBLPrototypeHandler();
PRBool KeyEventMatched(nsIDOMKeyEvent* aKeyEvent);
// if aCharCode is not zero, it is used instead of the charCode of aKeyEvent.
PRBool KeyEventMatched(nsIDOMKeyEvent* aKeyEvent,
PRUint32 aCharCode = 0,
PRBool aIgnoreShiftKey = PR_FALSE);
inline PRBool KeyEventMatched(nsIAtom* aEventType,
nsIDOMKeyEvent* aEvent)
nsIDOMKeyEvent* aEvent,
PRUint32 aCharCode = 0,
PRBool aIgnoreShiftKey = PR_FALSE)
{
if (aEventType != mEventName)
return PR_FALSE;
return KeyEventMatched(aEvent);
return KeyEventMatched(aEvent, aCharCode, aIgnoreShiftKey);
}
PRBool MouseEventMatched(nsIDOMMouseEvent* aMouseEvent);
@ -171,7 +176,8 @@ protected:
void ReportKeyConflict(const PRUnichar* aKey, const PRUnichar* aModifiers, nsIContent* aElement, const char *aMessageName);
void GetEventType(nsAString& type);
PRBool ModifiersMatchMask(nsIDOMUIEvent* aEvent);
PRBool ModifiersMatchMask(nsIDOMUIEvent* aEvent,
PRBool aIgnoreShiftKey = PR_FALSE);
nsresult DispatchXBLCommand(nsPIDOMEventTarget* aTarget, nsIDOMEvent* aEvent);
nsresult DispatchXULKeyCommand(nsIDOMEvent* aEvent);
nsresult EnsureEventHandler(nsIScriptGlobalObject* aGlobal,

Просмотреть файл

@ -70,6 +70,7 @@
#include "nsIPresShell.h"
#include "nsIPrivateDOMEvent.h"
#include "nsISelectionController.h"
#include "nsGUIEvent.h"
static nsINativeKeyBindings *sNativeEditorBindings = nsnull;
@ -216,6 +217,16 @@ BuildHandlerChain(nsIContent* aContent, nsXBLPrototypeHandler** aResult)
nsIContent *key = aContent->GetChildAt(j);
if (key->NodeInfo()->Equals(nsGkAtoms::key, kNameSpaceID_XUL)) {
// Check whether the key element has empty value at key/char attribute.
// Such element is used by localizers for alternative shortcut key
// definition on the locale. See bug 426501.
nsAutoString valKey, valChar;
PRBool attrExists =
key->GetAttr(kNameSpaceID_None, nsGkAtoms::key, valKey) ||
key->GetAttr(kNameSpaceID_None, nsGkAtoms::charcode, valChar);
if (attrExists && valKey.IsEmpty() && valChar.IsEmpty())
continue;
nsXBLPrototypeHandler* handler = new nsXBLPrototypeHandler(key);
if (!handler)
@ -405,11 +416,13 @@ nsresult nsXBLWindowKeyHandler::KeyPress(nsIDOMEvent* aKeyEvent)
//
PRBool
nsXBLWindowKeyHandler::EventMatched(nsXBLPrototypeHandler* inHandler,
nsIAtom* inEventType, nsIDOMEvent* inEvent)
nsIAtom* inEventType, nsIDOMEvent* inEvent,
PRUint32 aCharCode, PRBool aIgnoreShiftKey)
{
nsCOMPtr<nsIDOMKeyEvent> keyEvent(do_QueryInterface(inEvent));
if (keyEvent)
return inHandler->KeyEventMatched(inEventType, keyEvent);
return inHandler->KeyEventMatched(inEventType, keyEvent, aCharCode,
aIgnoreShiftKey);
return PR_FALSE;
}
@ -458,7 +471,7 @@ nsXBLWindowKeyHandler::IsEditor()
}
//
// WalkHandlersInternal
// WalkHandlersInternal and WalkHandlersAndExecute
//
// Given a particular DOM event and a pointer to the first handler in the list,
// scan through the list to find something to handle the event and then make it
@ -468,10 +481,34 @@ nsresult
nsXBLWindowKeyHandler::WalkHandlersInternal(nsIDOMEvent* aEvent,
nsIAtom* aEventType,
nsXBLPrototypeHandler* aHandler)
{
nsAutoTArray<nsShortcutCandidate, 10> accessKeys;
nsContentUtils::GetAccelKeyCandidates(aEvent, accessKeys);
if (accessKeys.IsEmpty()) {
WalkHandlersAndExecute(aEvent, aEventType, aHandler, 0, PR_FALSE);
return NS_OK;
}
for (PRUint32 i = 0; i < accessKeys.Length(); ++i) {
nsShortcutCandidate &key = accessKeys[i];
if (WalkHandlersAndExecute(aEvent, aEventType, aHandler,
key.mCharCode, key.mIgnoreShift))
return NS_OK;
}
return NS_OK;
}
PRBool
nsXBLWindowKeyHandler::WalkHandlersAndExecute(nsIDOMEvent* aEvent,
nsIAtom* aEventType,
nsXBLPrototypeHandler* aHandler,
PRUint32 aCharCode,
PRBool aIgnoreShiftKey)
{
nsresult rv;
nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aEvent));
// Try all of the handlers until we find one that matches the event.
for (nsXBLPrototypeHandler *currHandler = aHandler; currHandler;
currHandler = currHandler->GetNextHandler()) {
@ -482,7 +519,8 @@ nsXBLWindowKeyHandler::WalkHandlersInternal(nsIDOMEvent* aEvent,
return NS_OK;
}
if (!EventMatched(currHandler, aEventType, aEvent))
if (!EventMatched(currHandler, aEventType, aEvent,
aCharCode, aIgnoreShiftKey))
continue; // try the next one
// Before executing this handler, check that it's not disabled,
@ -541,11 +579,11 @@ nsXBLWindowKeyHandler::WalkHandlersInternal(nsIDOMEvent* aEvent,
rv = currHandler->ExecuteHandler(piTarget, aEvent);
if (NS_SUCCEEDED(rv)) {
return NS_OK;
return PR_TRUE;
}
}
return NS_OK;
return PR_FALSE;
}
already_AddRefed<nsIDOMElement>

Просмотреть файл

@ -80,13 +80,19 @@ protected:
nsIAtom* aEventType,
nsXBLPrototypeHandler* aHandler);
// walk the handlers for aEvent, aCharCode and aIgnoreShiftKey
PRBool WalkHandlersAndExecute(nsIDOMEvent* aEvent, nsIAtom* aEventType,
nsXBLPrototypeHandler* aHandler,
PRUint32 aCharCode, PRBool aIgnoreShiftKey);
// lazily load the handlers. Overridden to handle being attached
// to a particular element rather than the document
nsresult EnsureHandlers(PRBool *aIsEditor);
// check if the given handler cares about the given key event
PRBool EventMatched(nsXBLPrototypeHandler* inHandler, nsIAtom* inEventType,
nsIDOMEvent* inEvent);
nsIDOMEvent* inEvent, PRUint32 aCharCode,
PRBool aIgnoreShiftKey);
// are we working with editor or browser?
PRBool IsEditor() ;

Просмотреть файл

@ -64,6 +64,8 @@
#include "nsISound.h"
#include "nsWidgetsCID.h"
#endif
#include "nsContentUtils.h"
#include "nsUTF8Utils.h"
//
@ -209,8 +211,17 @@ nsMenuBarFrame::FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent)
{
PRUint32 charCode;
aKeyEvent->GetCharCode(&charCode);
if (!charCode) // no character was pressed so just return
return nsnull;
nsAutoTArray<PRUint32, 10> accessKeys;
nsEvent* nativeEvent = nsContentUtils::GetNativeEvent(aKeyEvent);
nsKeyEvent* nativeKeyEvent = static_cast<nsKeyEvent*>(nativeEvent);
if (nativeKeyEvent)
nsContentUtils::GetAccessKeyCandidates(nativeKeyEvent, accessKeys);
if (accessKeys.IsEmpty() && charCode)
accessKeys.AppendElement(charCode);
if (accessKeys.IsEmpty())
return nsnull; // no character was pressed so just return
// Enumerate over our list of frames.
nsIFrame* immediateParent = nsnull;
@ -218,29 +229,39 @@ nsMenuBarFrame::FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent)
if (!immediateParent)
immediateParent = this;
// Find a most preferred accesskey which should be returned.
nsIFrame* foundMenu = nsnull;
PRUint32 foundIndex = accessKeys.NoIndex;
nsIFrame* currFrame = immediateParent->GetFirstChild(nsnull);
while (currFrame) {
nsIContent* current = currFrame->GetContent();
// See if it's a menu item.
if (nsXULPopupManager::IsValidMenuItem(PresContext(), current, PR_FALSE)) {
// Get the shortcut attribute.
nsAutoString shortcutKey;
current->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, shortcutKey);
if (!shortcutKey.IsEmpty()) {
// We've got something.
PRUnichar letter = PRUnichar(charCode); // throw away the high-zero-fill
if ( shortcutKey.Equals(Substring(&letter, &letter+1),
nsCaseInsensitiveStringComparator()) ) {
// We match!
return (currFrame->GetType() == nsGkAtoms::menuFrame) ?
static_cast<nsMenuFrame *>(currFrame) : nsnull;
ToLowerCase(shortcutKey);
nsAutoString::const_iterator start, end;
shortcutKey.BeginReading(start);
shortcutKey.EndReading(end);
PRUint32 ch = UTF16CharEnumerator::NextChar(start, end);
PRUint32 index = accessKeys.IndexOf(ch);
if (index != accessKeys.NoIndex &&
(foundIndex == kNotFound || index < foundIndex)) {
foundMenu = currFrame;
foundIndex = index;
}
}
}
currFrame = currFrame->GetNextSibling();
}
if (foundMenu) {
return (foundMenu->GetType() == nsGkAtoms::menuFrame) ?
static_cast<nsMenuFrame *>(foundMenu) : nsnull;
}
// didn't find a matching menu item
#ifdef XP_WIN

Просмотреть файл

@ -234,14 +234,22 @@ nsMenuBarListener::KeyPress(nsIDOMEvent* aKeyEvent)
keyEvent->GetKeyCode(&keyCode);
keyEvent->GetCharCode(&charCode);
PRBool hasAccessKeyCandidates = charCode != 0;
if (!hasAccessKeyCandidates) {
nsEvent* nativeEvent = nsContentUtils::GetNativeEvent(aKeyEvent);
nsKeyEvent* nativeKeyEvent = static_cast<nsKeyEvent*>(nativeEvent);
if (nativeKeyEvent) {
nsAutoTArray<PRUint32, 10> keys;
nsContentUtils::GetAccessKeyCandidates(nativeKeyEvent, keys);
hasAccessKeyCandidates = !keys.IsEmpty();
}
}
// Clear the access key flag unless we are pressing the access key.
if (keyCode != (PRUint32)mAccessKey)
mAccessKeyDown = PR_FALSE;
// If charCode == 0, then it is not a printable character.
// Don't attempt to handle accesskey for non-printable characters.
if (IsAccessKeyPressed(keyEvent) && charCode)
{
if (IsAccessKeyPressed(keyEvent) && hasAccessKeyCandidates) {
// Do shortcut navigation.
// A letter was pressed. We want to see if a shortcut gets matched. If
// so, we'll know the menu got activated.

Просмотреть файл

@ -56,6 +56,7 @@
#include "nsIDOMKeyEvent.h"
#include "nsWeakPtr.h"
#include "nsIWidget.h"
#include "nsTArray.h"
class nsIRenderingContext;
class nsIRegion;
@ -700,6 +701,16 @@ public:
* Keyboard event
*/
struct nsAlternativeCharCode {
nsAlternativeCharCode(PRUint32 aUnshiftedCharCode,
PRUint32 aShiftedCharCode) :
mUnshiftedCharCode(aUnshiftedCharCode), mShiftedCharCode(aShiftedCharCode)
{
}
PRUint32 mUnshiftedCharCode;
PRUint32 mShiftedCharCode;
};
class nsKeyEvent : public nsInputEvent
{
public:
@ -713,6 +724,9 @@ public:
PRUint32 keyCode;
/// OS translated Unicode char
PRUint32 charCode;
// OS translated Unicode chars which are used for accesskey and accelkey
// handling. The handlers will try from first character to last character.
nsTArray<nsAlternativeCharCode> alternativeCharCodes;
// indicates whether the event signifies a printable character
PRBool isChar;
};

Просмотреть файл

@ -3879,17 +3879,73 @@ static PRBool IsNormalCharInputtingEvent(const nsKeyEvent& aEvent)
outGeckoEvent->charCode = 0;
outGeckoEvent->keyCode = 0; // not set for key press events
NSString* unmodifiedChars = [aKeyEvent charactersIgnoringModifiers];
if ([unmodifiedChars length] > 0)
outGeckoEvent->charCode = [unmodifiedChars characterAtIndex:0];
NSString* chars = [aKeyEvent characters];
if ([chars length] > 0)
outGeckoEvent->charCode = [chars characterAtIndex:0];
// convert control-modified charCode to raw charCode (with appropriate case)
if (outGeckoEvent->isControl && outGeckoEvent->charCode <= 26)
outGeckoEvent->charCode += (outGeckoEvent->isShift) ? ('A' - 1) : ('a' - 1);
// gecko also wants charCode to be in the appropriate case
if (outGeckoEvent->isShift && (outGeckoEvent->charCode >= 'a' && outGeckoEvent->charCode <= 'z'))
outGeckoEvent->charCode -= 32; // convert to uppercase
// If Ctrl or Command is pressed, we should set shiftCharCode and
// unshiftCharCode for accessKeys and accelKeys.
if ((outGeckoEvent->isControl || outGeckoEvent->isMeta) &&
!outGeckoEvent->isAlt) {
SInt16 keyLayoutID =
::GetScriptVariable(::GetScriptManagerVariable(smKeyScript),
smScriptKeys);
Handle handle = ::GetResource('uchr', keyLayoutID);
PRUint32 unshiftedChar = 0;
PRUint32 shiftedChar = 0;
PRUint32 shiftedCmdChar = 0;
if (handle) {
UInt32 kbType = ::LMGetKbdType();
UInt32 deadKeyState = 0;
UniCharCount len;
UniChar chars[1];
OSStatus err;
err = ::UCKeyTranslate((UCKeyboardLayout*)*handle,
[aKeyEvent keyCode],
kUCKeyActionDown, 0,
kbType, 0, &deadKeyState, 1, &len, chars);
if (noErr == err && len > 0)
unshiftedChar = chars[0];
deadKeyState = 0;
err = ::UCKeyTranslate((UCKeyboardLayout*)*handle, [aKeyEvent keyCode],
kUCKeyActionDown, shiftKey >> 8,
kbType, 0, &deadKeyState, 1, &len, chars);
if (noErr == err && len > 0)
shiftedChar = chars[0];
deadKeyState = 0;
err = ::UCKeyTranslate((UCKeyboardLayout*)*handle, [aKeyEvent keyCode],
kUCKeyActionDown, (cmdKey | shiftKey) >> 8,
kbType, 0, &deadKeyState, 1, &len, chars);
if (noErr == err && len > 0)
shiftedCmdChar = chars[0];
} else if (handle = (char**)::GetScriptManagerVariable(smKCHRCache)) {
UInt32 state = 0;
UInt32 keyCode = [aKeyEvent keyCode];
unshiftedChar = ::KeyTranslate(handle, keyCode, &state) & charCodeMask;
keyCode = [aKeyEvent keyCode] | shiftKey;
shiftedChar = ::KeyTranslate(handle, keyCode, &state) & charCodeMask;
keyCode = [aKeyEvent keyCode] | shiftKey | cmdKey;
shiftedCmdChar = ::KeyTranslate(handle, keyCode, &state) & charCodeMask;
}
// If the current keyboad layout is switchable by Cmd key
// (e.g., Dvorak-QWERTY layout), we should not append the alternative
// char codes to unshiftedCharCodes and shiftedCharCodes.
// Because then, the alternative char codes might execute wrong item.
// Therefore, we should check whether the unshiftedChar and shiftedCmdChar
// are same. Because Cmd+Shift+'foo' returns unshifted 'foo'. So, they
// should be same for this case.
// Note that we cannot support the combination of Cmd and Shift needed
// char. (E.g., Cmd++ in US keyboard layout.)
if ((unshiftedChar || shiftedChar) &&
(!outGeckoEvent->isMeta || unshiftedChar == shiftedCmdChar)) {
nsAlternativeCharCode altCharCodes(unshiftedChar, shiftedChar);
outGeckoEvent->alternativeCharCodes.AppendElement(altCharCodes);
}
}
}
else {
NSString* characters = nil;

Просмотреть файл

@ -280,6 +280,47 @@ nsNativeKeyBindings::KeyPress(const nsNativeKeyEvent& aEvent,
else
keyCode = DOMKeyCodeToGdkKeyCode(aEvent.keyCode);
if (KeyPressInternal(aEvent, aCallback, aCallbackData, keyCode))
return PR_TRUE;
nsKeyEvent *nativeKeyEvent = static_cast<nsKeyEvent*>(aEvent.nativeEvent);
if (!nativeKeyEvent || nativeKeyEvent->eventStructType != NS_KEY_EVENT &&
nativeKeyEvent->message != NS_KEY_PRESS)
return PR_FALSE;
for (PRUint32 i = 0; i < nativeKeyEvent->alternativeCharCodes.Length(); ++i) {
PRUint32 ch = nativeKeyEvent->isShift ?
nativeKeyEvent->alternativeCharCodes[i].mShiftedCharCode :
nativeKeyEvent->alternativeCharCodes[i].mUnshiftedCharCode;
if (ch && ch != aEvent.charCode) {
keyCode = gdk_unicode_to_keyval(ch);
if (KeyPressInternal(aEvent, aCallback, aCallbackData, keyCode))
return PR_TRUE;
}
}
/* gtk_bindings_activate_event is preferable, but it has unresolved bug: http://bugzilla.gnome.org/show_bug.cgi?id=162726
Also gtk_bindings_activate may work with some non-shortcuts operations (todo: check it)
See bugs 411005 406407
Code, which should be used after fixing http://bugzilla.gnome.org/show_bug.cgi?id=162726:
const nsGUIEvent *guiEvent = static_cast<nsGUIEvent*>(aEvent.nativeEvent);
if (guiEvent &&
(guiEvent->message == NS_KEY_PRESS || guiEvent->message == NS_KEY_UP || guiEvent->message == NS_KEY_DOWN) &&
guiEvent->nativeMsg)
gtk_bindings_activate_event(GTK_OBJECT(mNativeTarget),
static_cast<GdkEventKey*>(guiEvent->nativeMsg));
*/
return PR_FALSE;
}
PRBool
nsNativeKeyBindings::KeyPressInternal(const nsNativeKeyEvent& aEvent,
DoCommandCallback aCallback,
void *aCallbackData,
PRUint32 aKeyCode)
{
int modifiers = 0;
if (aEvent.altKey)
modifiers |= GDK_MOD1_MASK;
@ -295,20 +336,8 @@ nsNativeKeyBindings::KeyPress(const nsNativeKeyEvent& aEvent,
gHandled = PR_FALSE;
gtk_bindings_activate(GTK_OBJECT(mNativeTarget),
keyCode, GdkModifierType(modifiers));
aKeyCode, GdkModifierType(modifiers));
/* gtk_bindings_activate_event is preferable, but it has unresolved bug: http://bugzilla.gnome.org/show_bug.cgi?id=162726
Also gtk_bindings_activate may work with some non-shortcuts operations (todo: check it)
See bugs 411005 406407
Code, which should be used after fixing http://bugzilla.gnome.org/show_bug.cgi?id=162726:
const nsGUIEvent *guiEvent = static_cast<nsGUIEvent*>(aEvent.nativeEvent);
if (guiEvent &&
(guiEvent->message == NS_KEY_PRESS || guiEvent->message == NS_KEY_UP || guiEvent->message == NS_KEY_DOWN) &&
guiEvent->nativeMsg)
gtk_bindings_activate_event(GTK_OBJECT(mNativeTarget),
static_cast<GdkEventKey*>(guiEvent->nativeMsg));
*/
gCurrentCallback = nsnull;
gCurrentCallbackData = nsnull;

Просмотреть файл

@ -93,6 +93,11 @@ public:
private:
~nsNativeKeyBindings() NS_HIDDEN;
PRBool KeyPressInternal(const nsNativeKeyEvent& aEvent,
DoCommandCallback aCallback,
void *aCallbackData,
PRUint32 aKeyCode);
GtkWidget *mNativeTarget;
};

Просмотреть файл

@ -2276,14 +2276,6 @@ nsWindow::OnContainerFocusOutEvent(GtkWidget *aWidget, GdkEventFocus *aEvent)
LOGFOCUS(("Done with container focus out [%p]\n", (void *)this));
}
inline PRBool
is_latin_shortcut_key(guint aKeyval)
{
return ((GDK_0 <= aKeyval && aKeyval <= GDK_9) ||
(GDK_A <= aKeyval && aKeyval <= GDK_Z) ||
(GDK_a <= aKeyval && aKeyval <= GDK_z));
}
PRBool
nsWindow::DispatchCommandEvent(nsIAtom* aCommand)
{
@ -2293,6 +2285,45 @@ nsWindow::DispatchCommandEvent(nsIAtom* aCommand)
return TRUE;
}
static PRUint32
GetCharCodeFor(const GdkEventKey *aEvent, GdkModifierType aShiftState,
gint aGroup)
{
guint keyval;
if (gdk_keymap_translate_keyboard_state(NULL,
aEvent->hardware_keycode,
aShiftState, aGroup,
&keyval, NULL, NULL, NULL)) {
GdkEventKey tmpEvent = *aEvent;
tmpEvent.state = guint(aShiftState);
tmpEvent.keyval = keyval;
tmpEvent.group = aGroup;
return nsConvertCharCodeToUnicode(&tmpEvent);
}
return 0;
}
static gint
GetKeyLevel(GdkEventKey *aEvent)
{
gint level;
if (!gdk_keymap_translate_keyboard_state(NULL,
aEvent->hardware_keycode,
GdkModifierType(aEvent->state),
aEvent->group,
NULL, NULL, &level, NULL))
return -1;
return level;
}
static PRBool
IsBasicLatinLetterOrNumeral(PRUint32 aChar)
{
return (aChar >= 'a' && aChar <= 'z') ||
(aChar >= 'A' && aChar <= 'Z') ||
(aChar >= '0' && aChar <= '9');
}
gboolean
nsWindow::OnKeyPressEvent(GtkWidget *aWidget, GdkEventKey *aEvent)
{
@ -2382,91 +2413,60 @@ nsWindow::OnKeyPressEvent(GtkWidget *aWidget, GdkEventKey *aEvent)
event.charCode = nsConvertCharCodeToUnicode(aEvent);
if (event.charCode) {
event.keyCode = 0;
// if the control, meta, or alt key is down, then we should leave
// the isShift flag alone (probably not a printable character)
// if none of the other modifier keys are pressed then we need to
// clear isShift so the character can be inserted in the editor
if (event.isControl || event.isAlt || event.isMeta) {
GdkEventKey tmpEvent = *aEvent;
// Fix for bug 69230:
// if modifier key is pressed and key pressed is not latin character,
// we should try other keyboard layouts to find out correct latin
// character corresponding to pressed key;
// that way shortcuts like Ctrl+C will work no matter what
// keyboard layout is selected
// We don't try to fix up punctuation accelerators here,
// because their location differs between latin layouts
if (!is_latin_shortcut_key(event.charCode)) {
// We have a non-latin char, try other keyboard groups
GdkKeymapKey *keys;
guint *keyvals;
gint n_entries;
PRUint32 latinCharCode;
gint level;
if (gdk_keymap_translate_keyboard_state(NULL,
tmpEvent.hardware_keycode,
(GdkModifierType)tmpEvent.state,
tmpEvent.group,
NULL, NULL, &level, NULL)
&& gdk_keymap_get_entries_for_keycode(NULL,
tmpEvent.hardware_keycode,
&keys, &keyvals,
&n_entries)) {
gint n;
for (n=0; n<n_entries; n++) {
if (keys[n].group == tmpEvent.group) {
// Skip keys from the same group
continue;
}
if (keys[n].level != level) {
// Allow only same level keys
continue;
}
if (is_latin_shortcut_key(keyvals[n])) {
// Latin character found
if (event.isShift)
tmpEvent.keyval = gdk_keyval_to_upper(keyvals[n]);
else
tmpEvent.keyval = gdk_keyval_to_lower(keyvals[n]);
tmpEvent.group = keys[n].group;
latinCharCode = nsConvertCharCodeToUnicode(&tmpEvent);
if (latinCharCode) {
event.charCode = latinCharCode;
break;
}
}
}
g_free(keys);
g_free(keyvals);
}
gint level = GetKeyLevel(aEvent);
if ((event.isControl || event.isAlt || event.isMeta) &&
(level == 0 || level == 1)) {
// We shold send both shifted char and unshifted char,
// all keyboard layout users can use all keys.
// Don't change event.charCode. On some keyboard layouts,
// ctrl/alt/meta keys are used for inputting some characters.
nsAlternativeCharCode altCharCodes(0, 0);
// unshifted charcode of current keyboard layout.
altCharCodes.mUnshiftedCharCode =
GetCharCodeFor(aEvent, GdkModifierType(0), aEvent->group);
PRBool isLatin = (altCharCodes.mUnshiftedCharCode <= 0xFF);
// shifted charcode of current keyboard layout.
altCharCodes.mShiftedCharCode =
GetCharCodeFor(aEvent, GDK_SHIFT_MASK, aEvent->group);
isLatin = isLatin && (altCharCodes.mShiftedCharCode <= 0xFF);
if (altCharCodes.mUnshiftedCharCode ||
altCharCodes.mShiftedCharCode) {
event.alternativeCharCodes.AppendElement(altCharCodes);
}
// make Ctrl+uppercase functional as same as Ctrl+lowercase
// when Ctrl+uppercase(eg.Ctrl+C) is pressed,convert the charCode
// from uppercase to lowercase(eg.Ctrl+c),so do Alt and Meta Key
// It is hack code for bug 61355, there is same code snip for
// Windows platform in widget/src/windows/nsWindow.cpp: See bug 16486
// Note: if Shift is pressed at the same time, do not to_lower()
// Because Ctrl+Shift has different function with Ctrl
if (!event.isShift &&
event.charCode >= GDK_A &&
event.charCode <= GDK_Z)
event.charCode = gdk_keyval_to_lower(event.charCode);
// Keep the characters unshifted for shortcuts and accesskeys and
// make sure that numbers are always passed as such (among others:
// bugs 50255 and 351310)
if (!event.isControl && event.isShift &&
(event.charCode < GDK_0 || event.charCode > GDK_9)) {
GdkKeymapKey k = { tmpEvent.hardware_keycode, tmpEvent.group, 0 };
tmpEvent.keyval = gdk_keymap_lookup_key(gdk_keymap_get_default(), &k);
PRUint32 unshiftedCharCode = nsConvertCharCodeToUnicode(&tmpEvent);
if (unshiftedCharCode)
event.charCode = unshiftedCharCode;
}
if (!isLatin) {
// Next, find latin inputtable keyboard layout.
GdkKeymapKey *keys;
gint count;
gint minGroup = -1;
if (gdk_keymap_get_entries_for_keyval(NULL, GDK_a,
&keys, &count)) {
// find the minimum number group for latin inputtable layout
for (gint i = 0; i < count && minGroup != 0; ++i) {
if (keys[i].level != 0 && keys[i].level != 1)
continue;
if (minGroup >= 0 && keys[i].group > minGroup)
continue;
minGroup = keys[i].group;
}
g_free(keys);
}
if (minGroup >= 0) {
// unshifted charcode of found keyboard layout.
PRUint32 ch =
GetCharCodeFor(aEvent, GdkModifierType(0), minGroup);
altCharCodes.mUnshiftedCharCode =
IsBasicLatinLetterOrNumeral(ch) ? ch : 0;
// shifted charcode of found keyboard layout.
ch = GetCharCodeFor(aEvent, GDK_SHIFT_MASK, minGroup);
altCharCodes.mShiftedCharCode =
IsBasicLatinLetterOrNumeral(ch) ? ch : 0;
if (altCharCodes.mUnshiftedCharCode ||
altCharCodes.mShiftedCharCode) {
event.alternativeCharCodes.AppendElement(altCharCodes);
}
}
}
}
}

Просмотреть файл

@ -324,6 +324,30 @@ PRUint32 KeyboardLayout::GetUniChars (PRUint16* aUniChars, PRUint8* aShiftStates
#endif
}
PRUint32
KeyboardLayout::GetUniCharsWithShiftState(PRUint8 aVirtualKey,
PRUint8 aShiftStates,
PRUint16* aUniChars,
PRUint32 aMaxChars) const
{
#ifndef WINCE
PRInt32 key = GetKeyIndex(aVirtualKey);
if (key < 0)
return 0;
PRUint8 finalShiftState;
PRUint16 uniChars[5];
PRUint32 numOfBaseChars =
mVirtualKeys[key].GetUniChars(aShiftStates, uniChars, &finalShiftState);
PRUint32 chars = PR_MIN(numOfBaseChars, aMaxChars);
memcpy(aUniChars, uniChars, chars * sizeof (PRUint16));
return chars;
#else
return 0;
#endif
}
void KeyboardLayout::LoadLayout ()
{
#ifndef WINCE

Просмотреть файл

@ -180,6 +180,9 @@ public:
void LoadLayout ();
void OnKeyDown (PRUint8 aVirtualKey);
PRUint32 GetUniChars (PRUint16* aUniChars, PRUint8* aShiftStates, PRUint32 aMaxChars) const;
PRUint32 GetUniCharsWithShiftState(PRUint8 aVirtualKey, PRUint8 aShiftStates,
PRUint16* aUniChars,
PRUint32 aMaxChars) const;
};
#endif

Просмотреть файл

@ -3040,7 +3040,10 @@ UINT nsWindow::MapFromNativeToDOM(UINT aNativeKeyCode)
// OnKey
//
//-------------------------------------------------------------------------
PRBool nsWindow::DispatchKeyEvent(PRUint32 aEventType, WORD aCharCode, UINT aVirtualCharCode,
PRBool nsWindow::DispatchKeyEvent(PRUint32 aEventType, WORD aCharCode,
PRUint32 aUnshiftedCharCode,
PRUint32 aShiftedCharCode,
UINT aVirtualCharCode,
LPARAM aKeyData, PRUint32 aFlags)
{
nsKeyEvent event(PR_TRUE, aEventType, this);
@ -3050,6 +3053,10 @@ PRBool nsWindow::DispatchKeyEvent(PRUint32 aEventType, WORD aCharCode, UINT aVir
event.flags |= aFlags;
event.charCode = aCharCode;
if (aUnshiftedCharCode || aShiftedCharCode) {
nsAlternativeCharCode altCharCodes(aUnshiftedCharCode, aShiftedCharCode);
event.alternativeCharCodes.AppendElement(altCharCodes);
}
event.keyCode = aVirtualCharCode;
#ifdef KE_DEBUG
@ -3133,7 +3140,7 @@ BOOL nsWindow::OnKeyDown(UINT aVirtualKeyCode, UINT aScanCode, LPARAM aKeyData)
//printf("In OnKeyDown virt: %d scan: %d\n", DOMKeyCode, aScanCode);
#endif
BOOL noDefault = DispatchKeyEvent(NS_KEY_DOWN, 0, DOMKeyCode, aKeyData);
BOOL noDefault = DispatchKeyEvent(NS_KEY_DOWN, 0, 0, 0, DOMKeyCode, aKeyData);
// If we won't be getting a WM_CHAR, WM_SYSCHAR or WM_DEADCHAR, synthesize a keypress
// for almost all keys
@ -3233,9 +3240,13 @@ BOOL nsWindow::OnKeyDown(UINT aVirtualKeyCode, UINT aScanCode, LPARAM aKeyData)
if (gKbdLayout.IsDeadKey ())
return PR_FALSE;
PRUint8 shiftStates [5];
PRUint16 uniChars [5];
PRUint8 shiftStates[5];
PRUint16 uniChars[5];
PRUint16 shiftedChars[5] = {0, 0, 0, 0, 0};
PRUint16 unshiftedChars[5] = {0, 0, 0, 0, 0};
PRUint32 numOfUniChars = 0;
PRUint32 numOfShiftedChars = 0;
PRUint32 numOfUnshiftedChars = 0;
PRUint32 numOfShiftStates = 0;
switch (aVirtualKeyCode) {
@ -3258,67 +3269,55 @@ BOOL nsWindow::OnKeyDown(UINT aVirtualKeyCode, UINT aScanCode, LPARAM aKeyData)
numOfUniChars = 1;
break;
default:
if (KeyboardLayout::IsPrintableCharKey (aVirtualKeyCode))
numOfUniChars = numOfShiftStates = gKbdLayout.GetUniChars (uniChars, shiftStates, NS_ARRAY_LENGTH (uniChars));
if (KeyboardLayout::IsPrintableCharKey(aVirtualKeyCode)) {
numOfUniChars = numOfShiftStates =
gKbdLayout.GetUniChars(uniChars, shiftStates,
NS_ARRAY_LENGTH(uniChars));
}
if (mIsControlDown ^ mIsAltDown)
{
// XXX
// For both Alt+key and Ctrl+key combinations we return the latin characters A..Z and
// numbers 0..9, ignoring the real characters returned by active keyboard layout.
// This is required to make sure that all shortcut keys (e.g. Ctrl+c, Ctrl+1, Alt+f)
// work the same way no matter what keyboard layout you are using.
if ((NS_VK_0 <= DOMKeyCode && DOMKeyCode <= NS_VK_9) ||
(NS_VK_A <= DOMKeyCode && DOMKeyCode <= NS_VK_Z))
{
uniChars [0] = DOMKeyCode;
numOfUniChars = 1;
numOfShiftStates = 0;
// For letters take the Shift state into account
if (!mIsShiftDown &&
NS_VK_A <= DOMKeyCode && DOMKeyCode <= NS_VK_Z)
uniChars [0] += 0x20;
}
else if (!anyCharMessagesRemoved && DOMKeyCode != aVirtualKeyCode) {
switch (DOMKeyCode) {
case NS_VK_ADD:
uniChars [0] = '+'; numOfUniChars = 1; break;
case NS_VK_SUBTRACT:
uniChars [0] = '-'; numOfUniChars = 1; break;
case NS_VK_SEMICOLON:
// XXXmnakano I don't know whether this is correct.
uniChars [0] = ';';
uniChars [1] = ':';
numOfUniChars = 2;
break;
default:
NS_ERROR("implement me!");
}
}
if (mIsControlDown ^ mIsAltDown) {
numOfUnshiftedChars =
gKbdLayout.GetUniCharsWithShiftState(aVirtualKeyCode, 0,
unshiftedChars, NS_ARRAY_LENGTH(unshiftedChars));
numOfShiftedChars =
gKbdLayout.GetUniCharsWithShiftState(aVirtualKeyCode, eShift,
shiftedChars, NS_ARRAY_LENGTH(shiftedChars));
}
}
if (numOfUniChars)
{
for (PRUint32 cnt = 0; cnt < numOfUniChars; cnt++)
{
if (cnt < numOfShiftStates)
{
// If key in combination with Alt and/or Ctrl produces a different character than without them
// then do not report these flags because it is separate keyboard layout shift state.
// If dead-key and base character does not produce a valid composite character then both produced
// dead-key character and following base character may have different modifier flags, too.
mIsShiftDown = (shiftStates [cnt] & eShift) != 0;
mIsControlDown = (shiftStates [cnt] & eCtrl) != 0;
mIsAltDown = (shiftStates [cnt] & eAlt) != 0;
if (numOfUniChars > 0 || numOfShiftedChars > 0 || numOfUnshiftedChars > 0) {
PRUint32 num = PR_MAX(numOfUniChars,
PR_MAX(numOfShiftedChars, numOfUnshiftedChars));
PRUint32 skipUniChars = num - numOfUniChars;
PRUint32 skipShiftedChars = num - numOfShiftedChars;
PRUint32 skipUnshiftedChars = num - numOfUnshiftedChars;
UINT keyCode = numOfUniChars == 0 ? DOMKeyCode : 0;
for (PRUint32 cnt = 0; cnt < num; cnt++) {
PRUint16 uniChar, shiftedChar, unshiftedChar;
uniChar = shiftedChar = unshiftedChar = 0;
if (skipUniChars <= cnt) {
if (cnt - skipUniChars < numOfShiftStates) {
// If key in combination with Alt and/or Ctrl produces a different
// character than without them then do not report these flags
// because it is separate keyboard layout shift state. If dead-key
// and base character does not produce a valid composite character
// then both produced dead-key character and following base
// character may have different modifier flags, too.
mIsShiftDown = (shiftStates[cnt - skipUniChars] & eShift) != 0;
mIsControlDown = (shiftStates[cnt - skipUniChars] & eCtrl) != 0;
mIsAltDown = (shiftStates[cnt - skipUniChars] & eAlt) != 0;
}
uniChar = uniChars[cnt - skipUniChars];
}
DispatchKeyEvent(NS_KEY_PRESS, uniChars [cnt], 0, aKeyData, extraFlags);
if (skipShiftedChars <= cnt)
shiftedChar = shiftedChars[cnt - skipShiftedChars];
if (skipUnshiftedChars <= cnt)
unshiftedChar = unshiftedChars[cnt - skipUnshiftedChars];
DispatchKeyEvent(NS_KEY_PRESS, uniChar, unshiftedChar,
shiftedChar, keyCode, aKeyData, extraFlags);
}
} else
DispatchKeyEvent(NS_KEY_PRESS, 0, DOMKeyCode, aKeyData, extraFlags);
DispatchKeyEvent(NS_KEY_PRESS, 0, 0, 0, DOMKeyCode, aKeyData, extraFlags);
return noDefault;
}
@ -3335,7 +3334,7 @@ BOOL nsWindow::OnKeyUp( UINT aVirtualKeyCode, UINT aScanCode, LPARAM aKeyData)
#endif
aVirtualKeyCode = sIMEIsComposing ? aVirtualKeyCode : MapFromNativeToDOM(aVirtualKeyCode);
BOOL result = DispatchKeyEvent(NS_KEY_UP, 0, aVirtualKeyCode, aKeyData);
BOOL result = DispatchKeyEvent(NS_KEY_UP, 0, 0, 0, aVirtualKeyCode, aKeyData);
return result;
}
@ -3412,7 +3411,8 @@ BOOL nsWindow::OnChar(UINT charCode, LPARAM keyData, PRUint32 aFlags)
uniChar = towlower(uniChar);
}
PRBool result = DispatchKeyEvent(NS_KEY_PRESS, uniChar, charCode, 0, aFlags);
PRBool result = DispatchKeyEvent(NS_KEY_PRESS, uniChar, 0, 0,
charCode, 0, aFlags);
mIsAltDown = saveIsAltDown;
mIsControlDown = saveIsControlDown;
return result;
@ -6535,7 +6535,7 @@ BOOL nsWindow::OnIMEChar(BYTE aByte1, BYTE aByte2, LPARAM aKeyState)
// We need to return TRUE here so that Windows doesn't
// send two WM_CHAR msgs
DispatchKeyEvent(NS_KEY_PRESS, uniChar, 0, 0);
DispatchKeyEvent(NS_KEY_PRESS, uniChar, 0, 0, 0, 0);
return PR_TRUE;
}
@ -6815,7 +6815,7 @@ BOOL nsWindow::OnIMENotify(WPARAM aIMN, LPARAM aData, LRESULT *oResult)
mIsControlDown = PR_FALSE;
mIsAltDown = PR_TRUE;
DispatchKeyEvent(NS_KEY_PRESS, 0, 192, 0); // XXX hack hack hack
DispatchKeyEvent(NS_KEY_PRESS, 0, 0, 0, 192, 0); // XXX hack hack hack
if (aIMN == IMN_SETOPENSTATUS)
sIMEIsStatusChanged = PR_TRUE;
}

Просмотреть файл

@ -331,8 +331,12 @@ protected:
nsRect& aEventResult,
nsRect& aResult);
virtual PRBool DispatchKeyEvent(PRUint32 aEventType, WORD aCharCode, UINT aVirtualCharCode,
LPARAM aKeyCode, PRUint32 aFlags = 0);
virtual PRBool DispatchKeyEvent(PRUint32 aEventType, WORD aCharCode,
PRUint32 aUnshiftedCharCode,
PRUint32 aShiftedCharCodes,
UINT aVirtualCharCode,
LPARAM aKeyCode,
PRUint32 aFlags = 0);
virtual PRBool DispatchFocus(PRUint32 aEventType, PRBool isMozWindowTakingFocus);
virtual PRBool OnScroll(UINT scrollCode, int cPos);