Merge merge

This commit is contained in:
Phil Ringnalda 2012-02-21 23:38:00 -08:00
commit 0b9a7c075c
5 changed files with 1035 additions and 438 deletions

View File

@ -22,6 +22,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Masayuki Nakano <masayuki@d-toybox.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -37,6 +38,10 @@
*
* ***** END LICENSE BLOCK ***** */
#include "prlog.h"
#include "nsGtkKeyUtils.h"
#include <gdk/gdkkeysyms.h>
#ifndef GDK_Sleep
#define GDK_Sleep 0x1008ff2f
@ -49,22 +54,25 @@
#include "nsGUIEvent.h"
#include "keysym2ucs.h"
#ifdef PR_LOGGING
PRLogModuleInfo* gKeymapWrapperLog = nsnull;
#endif // PR_LOGGING
#include "mozilla/Util.h"
using namespace mozilla;
namespace mozilla {
namespace widget {
#define MAX_UNICODE 0x10FFFF
struct nsKeyConverter {
int vkCode; // Platform independent key code
int keysym; // GDK keysym key code
struct KeyPair {
PRUint32 DOMKeyCode;
guint GDKKeyval;
};
//
// Netscape keycodes are defined in widget/public/nsGUIEvent.h
// GTK keycodes are defined in <gdk/gdkkeysyms.h>
//
struct nsKeyConverter nsKeycodes[] = {
static const KeyPair kKeyPairs[] = {
{ NS_VK_CANCEL, GDK_Cancel },
{ NS_VK_BACK, GDK_BackSpace },
{ NS_VK_TAB, GDK_Tab },
@ -183,15 +191,385 @@ struct nsKeyConverter nsKeycodes[] = {
};
// map Sun Keyboard special keysyms on to NS_VK keys
struct nsKeyConverter nsSunKeycodes[] = {
static const KeyPair kSunKeyPairs[] = {
{NS_VK_F11, 0x1005ff10 }, //Sun F11 key generates SunF36(0x1005ff10) keysym
{NS_VK_F12, 0x1005ff11 } //Sun F12 key generates SunF37(0x1005ff11) keysym
};
int
GdkKeyCodeToDOMKeyCode(int aKeysym)
#define MOZ_MODIFIER_KEYS "MozKeymapWrapper"
KeymapWrapper* KeymapWrapper::sInstance = nsnull;
#ifdef PR_LOGGING
static const char* GetBoolName(bool aBool)
{
unsigned int i;
return aBool ? "TRUE" : "FALSE";
}
/* static */ const char*
KeymapWrapper::GetModifierName(Modifier aModifier)
{
switch (aModifier) {
case CAPS_LOCK: return "CapsLock";
case NUM_LOCK: return "NumLock";
case SCROLL_LOCK: return "ScrollLock";
case SHIFT: return "Shift";
case CTRL: return "Ctrl";
case ALT: return "Alt";
case SUPER: return "Super";
case HYPER: return "Hyper";
case META: return "Meta";
case ALTGR: return "AltGr";
case NOT_MODIFIER: return "NotModifier";
default: return "InvalidValue";
}
}
#endif // PR_LOGGING
/* static */ KeymapWrapper::Modifier
KeymapWrapper::GetModifierForGDKKeyval(guint aGdkKeyval)
{
switch (aGdkKeyval) {
case GDK_Caps_Lock: return CAPS_LOCK;
case GDK_Num_Lock: return NUM_LOCK;
case GDK_Scroll_Lock: return SCROLL_LOCK;
case GDK_Shift_L:
case GDK_Shift_R: return SHIFT;
case GDK_Control_L:
case GDK_Control_R: return CTRL;
case GDK_Alt_L:
case GDK_Alt_R: return ALT;
case GDK_Super_L:
case GDK_Super_R: return SUPER;
case GDK_Hyper_L:
case GDK_Hyper_R: return HYPER;
case GDK_Meta_L:
case GDK_Meta_R: return META;
case GDK_ISO_Level3_Shift:
case GDK_Mode_switch: return ALTGR;
default: return NOT_MODIFIER;
}
}
guint
KeymapWrapper::GetModifierMask(Modifier aModifier) const
{
switch (aModifier) {
case CAPS_LOCK:
return GDK_LOCK_MASK;
case NUM_LOCK:
return mModifierMasks[INDEX_NUM_LOCK];
case SCROLL_LOCK:
return mModifierMasks[INDEX_SCROLL_LOCK];
case SHIFT:
return GDK_SHIFT_MASK;
case CTRL:
return GDK_CONTROL_MASK;
case ALT:
return mModifierMasks[INDEX_ALT];
case SUPER:
return mModifierMasks[INDEX_SUPER];
case HYPER:
return mModifierMasks[INDEX_HYPER];
case META:
return mModifierMasks[INDEX_META];
case ALTGR:
return mModifierMasks[INDEX_ALTGR];
default:
return 0;
}
}
KeymapWrapper::ModifierKey*
KeymapWrapper::GetModifierKey(guint aHardwareKeycode)
{
for (PRUint32 i = 0; i < mModifierKeys.Length(); i++) {
ModifierKey& key = mModifierKeys[i];
if (key.mHardwareKeycode == aHardwareKeycode) {
return &key;
}
}
return nsnull;
}
/* static */ KeymapWrapper*
KeymapWrapper::GetInstance()
{
if (sInstance) {
sInstance->Init();
return sInstance;
}
sInstance = new KeymapWrapper();
return sInstance;
}
KeymapWrapper::KeymapWrapper() :
mInitialized(false), mGdkKeymap(gdk_keymap_get_default())
{
#ifdef PR_LOGGING
if (!gKeymapWrapperLog) {
gKeymapWrapperLog = PR_NewLogModule("KeymapWrapperWidgets");
}
PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
("KeymapWrapper(%p): Constructor, mGdkKeymap=%p",
this, mGdkKeymap));
#endif // PR_LOGGING
g_signal_connect(mGdkKeymap, "keys-changed",
(GCallback)OnKeysChanged, this);
// This is necessary for catching the destroying timing.
g_object_weak_ref(G_OBJECT(mGdkKeymap),
(GWeakNotify)OnDestroyKeymap, this);
Init();
}
void
KeymapWrapper::Init()
{
if (mInitialized) {
return;
}
mInitialized = true;
PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
("KeymapWrapper(%p): Init, mGdkKeymap=%p",
this, mGdkKeymap));
mModifierKeys.Clear();
memset(mModifierMasks, 0, sizeof(mModifierMasks));
InitBySystemSettings();
PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
("KeymapWrapper(%p): Init, CapsLock=0x%X, NumLock=0x%X, "
"ScrollLock=0x%X, AltGr=0x%X, Shift=0x%X, Ctrl=0x%X, Alt=0x%X, "
"Meta=0x%X, Super=0x%X, Hyper=0x%X",
this,
GetModifierMask(CAPS_LOCK), GetModifierMask(NUM_LOCK),
GetModifierMask(SCROLL_LOCK), GetModifierMask(ALTGR),
GetModifierMask(SHIFT), GetModifierMask(CTRL),
GetModifierMask(ALT), GetModifierMask(META),
GetModifierMask(SUPER), GetModifierMask(HYPER)));
}
void
KeymapWrapper::InitBySystemSettings()
{
PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
("KeymapWrapper(%p): InitBySystemSettings, mGdkKeymap=%p",
this, mGdkKeymap));
Display* display =
gdk_x11_display_get_xdisplay(gdk_display_get_default());
int min_keycode = 0;
int max_keycode = 0;
XDisplayKeycodes(display, &min_keycode, &max_keycode);
int keysyms_per_keycode = 0;
KeySym* xkeymap = XGetKeyboardMapping(display, min_keycode,
max_keycode - min_keycode + 1,
&keysyms_per_keycode);
if (!xkeymap) {
PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
("KeymapWrapper(%p): InitBySystemSettings, "
"Failed due to null xkeymap", this));
return;
}
XModifierKeymap* xmodmap = XGetModifierMapping(display);
if (!xmodmap) {
PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
("KeymapWrapper(%p): InitBySystemSettings, "
"Failed due to null xmodmap", this));
XFree(xkeymap);
return;
}
PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
("KeymapWrapper(%p): InitBySystemSettings, min_keycode=%d, "
"max_keycode=%d, keysyms_per_keycode=%d, max_keypermod=%d",
this, min_keycode, max_keycode, keysyms_per_keycode,
xmodmap->max_keypermod));
// The modifiermap member of the XModifierKeymap structure contains 8 sets
// of max_keypermod KeyCodes, one for each modifier in the order Shift,
// Lock, Control, Mod1, Mod2, Mod3, Mod4, and Mod5.
// Only nonzero KeyCodes have meaning in each set, and zero KeyCodes are
// ignored.
// Note that two or more modifiers may use one modifier flag. E.g.,
// on Ubuntu 10.10, Alt and Meta share the Mod1 in default settings.
// And also Super and Hyper share the Mod4.
const PRUint32 map_size = 8 * xmodmap->max_keypermod;
for (PRUint32 i = 0; i < map_size; i++) {
KeyCode keycode = xmodmap->modifiermap[i];
PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
("KeymapWrapper(%p): InitBySystemSettings, "
" i=%d, keycode=0x%08X",
this, i, keycode));
if (!keycode || keycode < min_keycode || keycode > max_keycode) {
continue;
}
ModifierKey* modifierKey = GetModifierKey(keycode);
if (!modifierKey) {
modifierKey = mModifierKeys.AppendElement(ModifierKey(keycode));
}
const KeySym* syms =
xkeymap + (keycode - min_keycode) * keysyms_per_keycode;
const PRUint32 bit = i / xmodmap->max_keypermod;
modifierKey->mMask |= 1 << bit;
for (PRInt32 j = 0; j < keysyms_per_keycode; j++) {
Modifier modifier = GetModifierForGDKKeyval(syms[j]);
PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
("KeymapWrapper(%p): InitBySystemSettings, "
" bit=%d, j=%d, syms[j]=%s(0x%X), modifier=%s",
this, bit, j, gdk_keyval_name(syms[j]), syms[j],
GetModifierName(modifier)));
ModifierIndex index;
switch (modifier) {
case NUM_LOCK:
index = INDEX_NUM_LOCK;
break;
case SCROLL_LOCK:
index = INDEX_SCROLL_LOCK;
break;
case ALT:
index = INDEX_ALT;
break;
case SUPER:
index = INDEX_SUPER;
break;
case HYPER:
index = INDEX_HYPER;
break;
case META:
index = INDEX_META;
break;
case ALTGR:
index = INDEX_ALTGR;
break;
default:
// NOTE: We always use GDK_SHIFT_MASK, GDK_CONTROL_MASK and
// GDK_LOCK_MASK for SHIFT, CTRL and CAPS_LOCK.
// This is standard manners of GTK application.
continue;
}
mModifierMasks[index] |= 1 << bit;
}
}
XFreeModifiermap(xmodmap);
XFree(xkeymap);
}
KeymapWrapper::~KeymapWrapper()
{
PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
("KeymapWrapper(%p): Destructor", this));
}
/* static */ void
KeymapWrapper::OnDestroyKeymap(KeymapWrapper* aKeymapWrapper,
GdkKeymap *aGdkKeymap)
{
PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
("KeymapWrapper: OnDestroyKeymap, aGdkKeymap=%p, aKeymapWrapper=%p",
aGdkKeymap, aKeymapWrapper));
MOZ_ASSERT(aKeymapWrapper == sInstance,
"Desroying unexpected instance");
delete sInstance;
sInstance = nsnull;
}
/* static */ void
KeymapWrapper::OnKeysChanged(GdkKeymap *aGdkKeymap,
KeymapWrapper* aKeymapWrapper)
{
PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
("KeymapWrapper: OnKeysChanged, aGdkKeymap=%p, aKeymapWrapper=%p",
aGdkKeymap, aKeymapWrapper));
MOZ_ASSERT(sInstance == aKeymapWrapper,
"This instance must be the singleton instance");
// We cannot reintialize here becasue we don't have GdkWindow which is using
// the GdkKeymap. We'll reinitialize it when next GetInstance() is called.
sInstance->mInitialized = false;
}
/* static */ guint
KeymapWrapper::GetCurrentModifierState()
{
GdkModifierType modifiers;
gdk_display_get_pointer(gdk_display_get_default(),
NULL, NULL, NULL, &modifiers);
return static_cast<guint>(modifiers);
}
/* static */ bool
KeymapWrapper::AreModifiersCurrentlyActive(Modifiers aModifiers)
{
guint modifierState = GetCurrentModifierState();
return AreModifiersActive(aModifiers, modifierState);
}
/* static */ bool
KeymapWrapper::AreModifiersActive(Modifiers aModifiers,
guint aModifierState)
{
NS_ENSURE_TRUE(aModifiers, false);
KeymapWrapper* keymapWrapper = GetInstance();
for (PRUint32 i = 0; i < sizeof(Modifier) * 8 && aModifiers; i++) {
Modifier modifier = static_cast<Modifier>(1 << i);
if (!(aModifiers & modifier)) {
continue;
}
if (!(aModifierState & keymapWrapper->GetModifierMask(modifier))) {
return false;
}
aModifiers &= ~modifier;
}
return true;
}
/* static */ void
KeymapWrapper::InitInputEvent(nsInputEvent& aInputEvent,
guint aModifierState)
{
KeymapWrapper* keymapWrapper = GetInstance();
aInputEvent.isShift =
keymapWrapper->AreModifiersActive(SHIFT, aModifierState);
aInputEvent.isControl =
keymapWrapper->AreModifiersActive(CTRL, aModifierState);
aInputEvent.isAlt =
keymapWrapper->AreModifiersActive(ALT, aModifierState);
// XXX DOM Meta key should be TRUE only on Mac. We need to discuss this
// issue later.
aInputEvent.isMeta = false;
PR_LOG(gKeymapWrapperLog, PR_LOG_DEBUG,
("KeymapWrapper(%p): InitInputEvent, aModifierState=0x%08X "
"aKeyEvent={ isShift=%s, isControl=%s, isAlt=%s, isMeta=%s }",
keymapWrapper, aModifierState,
GetBoolName(aInputEvent.isShift), GetBoolName(aInputEvent.isControl),
GetBoolName(aInputEvent.isAlt), GetBoolName(aInputEvent.isMeta)));
}
/* static */ PRUint32
KeymapWrapper::ComputeDOMKeyCode(const GdkEventKey* aGdkKeyEvent)
{
guint keyval = aGdkKeyEvent->keyval;
// First, try to handle alphanumeric input, not listed in nsKeycodes:
// most likely, more letters will be getting typed in than things in
@ -199,132 +577,410 @@ GdkKeyCodeToDOMKeyCode(int aKeysym)
// since X has different key symbols for upper and lowercase letters and
// mozilla does not, convert gdk's to mozilla's
if (aKeysym >= GDK_a && aKeysym <= GDK_z)
return aKeysym - GDK_a + NS_VK_A;
if (aKeysym >= GDK_A && aKeysym <= GDK_Z)
return aKeysym - GDK_A + NS_VK_A;
if (keyval >= GDK_a && keyval <= GDK_z) {
return keyval - GDK_a + NS_VK_A;
}
if (keyval >= GDK_A && keyval <= GDK_Z) {
return keyval - GDK_A + NS_VK_A;
}
// numbers
if (aKeysym >= GDK_0 && aKeysym <= GDK_9)
return aKeysym - GDK_0 + NS_VK_0;
if (keyval >= GDK_0 && keyval <= GDK_9) {
return keyval - GDK_0 + NS_VK_0;
}
// keypad numbers
if (aKeysym >= GDK_KP_0 && aKeysym <= GDK_KP_9)
return aKeysym - GDK_KP_0 + NS_VK_NUMPAD0;
if (keyval >= GDK_KP_0 && keyval <= GDK_KP_9) {
return keyval - GDK_KP_0 + NS_VK_NUMPAD0;
}
// If the keyval indicates it's a modifier key, we should use unshifted
// key's modifier keyval.
if (GetModifierForGDKKeyval(keyval)) {
KeymapWrapper* keymapWrapper = GetInstance();
GdkKeymapKey key;
key.keycode = aGdkKeyEvent->hardware_keycode;
key.group = aGdkKeyEvent->group;
key.level = 0;
guint unshiftedKeyval =
gdk_keymap_lookup_key(keymapWrapper->mGdkKeymap, &key);
// But if the unshifted keyval isn't a modifier key, we shouldn't use
// it. E.g., Japanese keyboard layout's Shift + Eisu-Toggle key is
// CapsLock. This is an actual rare case, Windows uses different
// keycode for a physical key for different shift key state.
if (GetModifierForGDKKeyval(unshiftedKeyval)) {
keyval = unshiftedKeyval;
}
}
// map Sun Keyboard special keysyms
for (i = 0; i < ArrayLength(nsSunKeycodes); i++) {
if (nsSunKeycodes[i].keysym == aKeysym)
return(nsSunKeycodes[i].vkCode);
for (PRUint32 i = 0; i < ArrayLength(kSunKeyPairs); i++) {
if (kSunKeyPairs[i].GDKKeyval == keyval) {
return kSunKeyPairs[i].DOMKeyCode;
}
}
// misc other things
for (i = 0; i < ArrayLength(nsKeycodes); i++) {
if (nsKeycodes[i].keysym == aKeysym)
return(nsKeycodes[i].vkCode);
for (PRUint32 i = 0; i < ArrayLength(kKeyPairs); i++) {
if (kKeyPairs[i].GDKKeyval == keyval) {
return kKeyPairs[i].DOMKeyCode;
}
}
// function keys
if (aKeysym >= GDK_F1 && aKeysym <= GDK_F24)
return aKeysym - GDK_F1 + NS_VK_F1;
if (keyval >= GDK_F1 && keyval <= GDK_F24) {
return keyval - GDK_F1 + NS_VK_F1;
}
return((int)0);
return 0;
}
int
DOMKeyCodeToGdkKeyCode(int aKeysym)
/* static */ guint
KeymapWrapper::GuessGDKKeyval(PRUint32 aDOMKeyCode)
{
unsigned int i;
// First, try to handle alphanumeric input, not listed in nsKeycodes:
// most likely, more letters will be getting typed in than things in
// the key list, so we will look through these first.
if (aKeysym >= NS_VK_A && aKeysym <= NS_VK_Z)
// gdk and DOM both use the ASCII codes for these keys.
return aKeysym;
if (aDOMKeyCode >= NS_VK_A && aDOMKeyCode <= NS_VK_Z) {
// gdk and DOM both use the ASCII codes for these keys.
return aDOMKeyCode;
}
// numbers
if (aKeysym >= NS_VK_0 && aKeysym <= NS_VK_9)
// gdk and DOM both use the ASCII codes for these keys.
return aKeysym - GDK_0 + NS_VK_0;
if (aDOMKeyCode >= NS_VK_0 && aDOMKeyCode <= NS_VK_9) {
// gdk and DOM both use the ASCII codes for these keys.
return aDOMKeyCode - NS_VK_0 + GDK_0;
}
// keypad numbers
if (aKeysym >= NS_VK_NUMPAD0 && aKeysym <= NS_VK_NUMPAD9)
return aKeysym - NS_VK_NUMPAD0 + GDK_KP_0;
if (aDOMKeyCode >= NS_VK_NUMPAD0 && aDOMKeyCode <= NS_VK_NUMPAD9) {
return aDOMKeyCode - NS_VK_NUMPAD0 + GDK_KP_0;
}
// misc other things
for (i = 0; i < ArrayLength(nsKeycodes); ++i) {
if (nsKeycodes[i].vkCode == aKeysym) {
return nsKeycodes[i].keysym;
}
for (PRUint32 i = 0; i < ArrayLength(kKeyPairs); ++i) {
if (kKeyPairs[i].DOMKeyCode == aDOMKeyCode) {
return kKeyPairs[i].GDKKeyval;
}
}
// function keys
if (aKeysym >= NS_VK_F1 && aKeysym <= NS_VK_F9)
return aKeysym - NS_VK_F1 + GDK_F1;
if (aDOMKeyCode >= NS_VK_F1 && aDOMKeyCode <= NS_VK_F9) {
return aDOMKeyCode - NS_VK_F1 + GDK_F1;
}
return 0;
}
// Convert gdk key event keyvals to char codes if printable, 0 otherwise
PRUint32 nsConvertCharCodeToUnicode(GdkEventKey* aEvent)
/* static */ void
KeymapWrapper::InitKeyEvent(nsKeyEvent& aKeyEvent,
GdkEventKey* aGdkKeyEvent)
{
KeymapWrapper* keymapWrapper = GetInstance();
aKeyEvent.keyCode = ComputeDOMKeyCode(aGdkKeyEvent);
// NOTE: The state of given key event indicates adjacent state of
// modifier keys. E.g., even if the event is Shift key press event,
// the bit for Shift is still false. By the same token, even if the
// event is Shift key release event, the bit for Shift is still true.
// Unfortunately, gdk_keyboard_get_modifiers() returns current modifier
// state. It means if there're some pending modifier key press or
// key release events, the result isn't what we want.
// Temporarily, we should compute the state only when the key event
// is GDK_KEY_PRESS.
// XXX If we could know the modifier keys state at the key release event,
// we should cut out changingMask from modifierState.
guint modifierState = aGdkKeyEvent->state;
if (aGdkKeyEvent->is_modifier && aGdkKeyEvent->type == GDK_KEY_PRESS) {
ModifierKey* modifierKey =
keymapWrapper->GetModifierKey(aGdkKeyEvent->hardware_keycode);
if (modifierKey) {
// If new modifier key is pressed, add the pressed mod mask.
modifierState |= modifierKey->mMask;
}
}
InitInputEvent(aKeyEvent, modifierState);
PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
("KeymapWrapper(%p): InitKeyEvent, modifierState=0x%08X "
"aGdkKeyEvent={ type=%s, keyval=%s(0x%X), state=0x%08X, "
"hardware_keycode=0x%08X, is_modifier=%s } "
"aKeyEvent={ message=%s, isShift=%s, isControl=%s, "
"isAlt=%s, isMeta=%s }",
keymapWrapper, modifierState,
((aGdkKeyEvent->type == GDK_KEY_PRESS) ?
"GDK_KEY_PRESS" : "GDK_KEY_RELEASE"),
gdk_keyval_name(aGdkKeyEvent->keyval),
aGdkKeyEvent->keyval, aGdkKeyEvent->state,
aGdkKeyEvent->hardware_keycode,
GetBoolName(aGdkKeyEvent->is_modifier),
((aKeyEvent.message == NS_KEY_DOWN) ? "NS_KEY_DOWN" :
(aKeyEvent.message == NS_KEY_PRESS) ? "NS_KEY_PRESS" :
"NS_KEY_UP"),
GetBoolName(aKeyEvent.isShift), GetBoolName(aKeyEvent.isControl),
GetBoolName(aKeyEvent.isAlt), GetBoolName(aKeyEvent.isMeta)));
if (aKeyEvent.message == NS_KEY_PRESS) {
keymapWrapper->InitKeypressEvent(aKeyEvent, aGdkKeyEvent);
}
// The transformations above and in gdk for the keyval are not invertible
// so link to the GdkEvent (which will vanish soon after return from the
// event callback) to give plugins access to hardware_keycode and state.
// (An XEvent would be nice but the GdkEvent is good enough.)
aKeyEvent.pluginEvent = (void *)aGdkKeyEvent;
aKeyEvent.time = aGdkKeyEvent->time;
}
/* static */ PRUint32
KeymapWrapper::GetCharCodeFor(const GdkEventKey *aGdkKeyEvent)
{
// Anything above 0xf000 is considered a non-printable
// Exception: directly encoded UCS characters
if (aEvent->keyval > 0xf000 && (aEvent->keyval & 0xff000000) != 0x01000000) {
if (aGdkKeyEvent->keyval > 0xf000 &&
(aGdkKeyEvent->keyval & 0xff000000) != 0x01000000) {
// Keypad keys are an exception: they return a value different
// from their non-keypad equivalents, but mozilla doesn't distinguish.
switch (aEvent->keyval)
{
case GDK_KP_Space:
return ' ';
case GDK_KP_Equal:
return '=';
case GDK_KP_Multiply:
return '*';
case GDK_KP_Add:
return '+';
case GDK_KP_Separator:
return ',';
case GDK_KP_Subtract:
return '-';
case GDK_KP_Decimal:
return '.';
case GDK_KP_Divide:
return '/';
case GDK_KP_0:
return '0';
case GDK_KP_1:
return '1';
case GDK_KP_2:
return '2';
case GDK_KP_3:
return '3';
case GDK_KP_4:
return '4';
case GDK_KP_5:
return '5';
case GDK_KP_6:
return '6';
case GDK_KP_7:
return '7';
case GDK_KP_8:
return '8';
case GDK_KP_9:
return '9';
}
// non-printables
return 0;
switch (aGdkKeyEvent->keyval) {
case GDK_KP_Space: return ' ';
case GDK_KP_Equal: return '=';
case GDK_KP_Multiply: return '*';
case GDK_KP_Add: return '+';
case GDK_KP_Separator: return ',';
case GDK_KP_Subtract: return '-';
case GDK_KP_Decimal: return '.';
case GDK_KP_Divide: return '/';
case GDK_KP_0: return '0';
case GDK_KP_1: return '1';
case GDK_KP_2: return '2';
case GDK_KP_3: return '3';
case GDK_KP_4: return '4';
case GDK_KP_5: return '5';
case GDK_KP_6: return '6';
case GDK_KP_7: return '7';
case GDK_KP_8: return '8';
case GDK_KP_9: return '9';
default: return 0; // non-printables
}
}
static const long MAX_UNICODE = 0x10FFFF;
// we're supposedly printable, let's try to convert
long ucs = keysym2ucs(aEvent->keyval);
if ((ucs != -1) && (ucs < MAX_UNICODE))
return ucs;
long ucs = keysym2ucs(aGdkKeyEvent->keyval);
if ((ucs != -1) && (ucs < MAX_UNICODE)) {
return ucs;
}
// I guess we couldn't convert
return 0;
}
PRUint32
KeymapWrapper::GetCharCodeFor(const GdkEventKey *aGdkKeyEvent,
guint aModifierState,
gint aGroup)
{
guint keyval;
if (!gdk_keymap_translate_keyboard_state(mGdkKeymap,
aGdkKeyEvent->hardware_keycode,
GdkModifierType(aModifierState),
aGroup, &keyval, NULL, NULL, NULL)) {
return 0;
}
GdkEventKey tmpEvent = *aGdkKeyEvent;
tmpEvent.state = aModifierState;
tmpEvent.keyval = keyval;
tmpEvent.group = aGroup;
return GetCharCodeFor(&tmpEvent);
}
gint
KeymapWrapper::GetKeyLevel(GdkEventKey *aGdkKeyEvent)
{
gint level;
if (!gdk_keymap_translate_keyboard_state(mGdkKeymap,
aGdkKeyEvent->hardware_keycode,
GdkModifierType(aGdkKeyEvent->state),
aGdkKeyEvent->group, NULL, NULL, &level, NULL)) {
return -1;
}
return level;
}
/* static */ PRBool
KeymapWrapper::IsBasicLatinLetterOrNumeral(PRUint32 aCharCode)
{
return (aCharCode >= 'a' && aCharCode <= 'z') ||
(aCharCode >= 'A' && aCharCode <= 'Z') ||
(aCharCode >= '0' && aCharCode <= '9');
}
void
KeymapWrapper::InitKeypressEvent(nsKeyEvent& aKeyEvent,
GdkEventKey* aGdkKeyEvent)
{
NS_ENSURE_TRUE(aKeyEvent.message == NS_KEY_PRESS, );
aKeyEvent.charCode = GetCharCodeFor(aGdkKeyEvent);
if (!aKeyEvent.charCode) {
PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
("KeymapWrapper(%p): InitKeypressEvent, "
"keyCode=0x%02X, charCode=0x%08X",
this, aKeyEvent.keyCode, aKeyEvent.charCode));
return;
}
// If the event causes inputting a character, keyCode must be zero.
aKeyEvent.keyCode = 0;
// If Ctrl or Alt or Meta is pressed, we need to append the key details
// for handling shortcut key. Otherwise, we have no additional work.
if (!aKeyEvent.isControl && !aKeyEvent.isAlt && !aKeyEvent.isMeta) {
PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
("KeymapWrapper(%p): InitKeypressEvent, "
"keyCode=0x%02X, charCode=0x%08X",
this, aKeyEvent.keyCode, aKeyEvent.charCode));
return;
}
gint level = GetKeyLevel(aGdkKeyEvent);
if (level != 0 && level != 1) {
PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
("KeymapWrapper(%p): InitKeypressEvent, "
"keyCode=0x%02X, charCode=0x%08X, level=%d",
this, aKeyEvent.keyCode, aKeyEvent.charCode, level));
return;
}
guint baseState = aGdkKeyEvent->state &
~(GetModifierMask(SHIFT) | GetModifierMask(CTRL) |
GetModifierMask(ALT) | GetModifierMask(META) |
GetModifierMask(SUPER) | GetModifierMask(HYPER));
// 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(aGdkKeyEvent, baseState, aGdkKeyEvent->group);
PRBool isLatin = (altCharCodes.mUnshiftedCharCode <= 0xFF);
// shifted charcode of current keyboard layout.
altCharCodes.mShiftedCharCode =
GetCharCodeFor(aGdkKeyEvent,
baseState | GetModifierMask(SHIFT),
aGdkKeyEvent->group);
isLatin = isLatin && (altCharCodes.mShiftedCharCode <= 0xFF);
if (altCharCodes.mUnshiftedCharCode || altCharCodes.mShiftedCharCode) {
aKeyEvent.alternativeCharCodes.AppendElement(altCharCodes);
}
// If current keyboard layout can input Latin characters, we don't need
// more information.
if (isLatin) {
PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
("KeymapWrapper(%p): InitKeypressEvent, keyCode=0x%02X, "
"charCode=0x%08X, level=%d, altCharCodes={ "
"mUnshiftedCharCode=0x%08X, mShiftedCharCode=0x%08X }",
this, aKeyEvent.keyCode, aKeyEvent.charCode, level,
altCharCodes.mUnshiftedCharCode, altCharCodes.mShiftedCharCode));
return;
}
// Next, find Latin inputtable keyboard layout.
GdkKeymapKey *keys;
gint count;
gint minGroup = -1;
if (gdk_keymap_get_entries_for_keyval(mGdkKeymap, 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) {
PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
("KeymapWrapper(%p): InitKeypressEvent, "
"Latin keyboard layout isn't found: "
"keyCode=0x%02X, charCode=0x%08X, level=%d, "
"altCharCodes={ mUnshiftedCharCode=0x%08X, "
"mShiftedCharCode=0x%08X }",
this, aKeyEvent.keyCode, aKeyEvent.charCode, level,
altCharCodes.mUnshiftedCharCode, altCharCodes.mShiftedCharCode));
return;
}
nsAlternativeCharCode altLatinCharCodes(0, 0);
PRUint32 unmodifiedCh =
aKeyEvent.isShift ? altCharCodes.mShiftedCharCode :
altCharCodes.mUnshiftedCharCode;
// unshifted charcode of found keyboard layout.
PRUint32 ch = GetCharCodeFor(aGdkKeyEvent, baseState, minGroup);
altLatinCharCodes.mUnshiftedCharCode =
IsBasicLatinLetterOrNumeral(ch) ? ch : 0;
// shifted charcode of found keyboard layout.
ch = GetCharCodeFor(aGdkKeyEvent,
baseState | GetModifierMask(SHIFT),
minGroup);
altLatinCharCodes.mShiftedCharCode =
IsBasicLatinLetterOrNumeral(ch) ? ch : 0;
if (altLatinCharCodes.mUnshiftedCharCode ||
altLatinCharCodes.mShiftedCharCode) {
aKeyEvent.alternativeCharCodes.AppendElement(altLatinCharCodes);
}
// If the charCode is not Latin, and the level is 0 or 1, we should
// replace the charCode to Latin char if Alt and Meta keys are not
// pressed. (Alt should be sent the localized char for accesskey
// like handling of Web Applications.)
ch = aKeyEvent.isShift ? altLatinCharCodes.mShiftedCharCode :
altLatinCharCodes.mUnshiftedCharCode;
if (ch && !(aKeyEvent.isAlt || aKeyEvent.isMeta) &&
aKeyEvent.charCode == unmodifiedCh) {
aKeyEvent.charCode = ch;
}
PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
("KeymapWrapper(%p): InitKeypressEvent, "
"keyCode=0x%02X, charCode=0x%08X, level=%d, minGroup=%d, "
"altCharCodes={ mUnshiftedCharCode=0x%08X, "
"mShiftedCharCode=0x%08X } "
"altLatinCharCodes={ mUnshiftedCharCode=0x%08X, "
"mShiftedCharCode=0x%08X }",
this, aKeyEvent.keyCode, aKeyEvent.charCode, level, minGroup,
altCharCodes.mUnshiftedCharCode, altCharCodes.mShiftedCharCode,
altLatinCharCodes.mUnshiftedCharCode,
altLatinCharCodes.mShiftedCharCode));
}
/* static */ bool
KeymapWrapper::IsKeyPressEventNecessary(GdkEventKey* aGdkKeyEvent)
{
// If this is a modifier key event, we shouldn't send keypress event.
switch (ComputeDOMKeyCode(aGdkKeyEvent)) {
case NS_VK_SHIFT:
case NS_VK_CONTROL:
case NS_VK_META:
case NS_VK_ALT:
case NS_VK_CAPS_LOCK:
case NS_VK_NUM_LOCK:
case NS_VK_SCROLL_LOCK:
return false;
default:
return true;
}
}
} // namespace widget
} // namespace mozilla

View File

@ -39,8 +39,257 @@
#ifndef __nsGdkKeyUtils_h__
#define __nsGdkKeyUtils_h__
int GdkKeyCodeToDOMKeyCode (int aKeysym);
int DOMKeyCodeToGdkKeyCode (int aKeysym);
PRUint32 nsConvertCharCodeToUnicode (GdkEventKey* aEvent);
#include "nsEvent.h"
#include "nsTArray.h"
#include <gdk/gdk.h>
namespace mozilla {
namespace widget {
/**
* KeymapWrapper is a wrapper class of GdkKeymap. GdkKeymap doesn't support
* all our needs, therefore, we need to access lower level APIs.
* But such code is usually complex and might be slow. Against such issues,
* we should cache some information.
*
* This class provides only static methods. The methods is using internal
* singleton instance which is initialized by default GdkKeymap. When the
* GdkKeymap is destroyed, the singleton instance will be destroyed.
*/
class KeymapWrapper
{
public:
/**
* Compute an our DOM keycode from a GDK keyval.
*/
static PRUint32 ComputeDOMKeyCode(const GdkEventKey* aGdkKeyEvent);
/**
* Returns a GDK keyval which is related to the aDOMKeyCode. However,
* it may not be same as original value since there are some lost
* information.
*/
static guint GuessGDKKeyval(PRUint32 aDOMKeyCode);
/**
* Modifier is list of modifiers which we support in widget level.
*/
enum Modifier {
NOT_MODIFIER = 0x0000,
CAPS_LOCK = 0x0001,
NUM_LOCK = 0x0002,
SCROLL_LOCK = 0x0004,
SHIFT = 0x0008,
CTRL = 0x0010,
ALT = 0x0020,
SUPER = 0x0040,
HYPER = 0x0080,
META = 0x0100,
ALTGR = 0x0200
};
/**
* Modifiers is used for combination of Modifier.
* E.g., |Modifiers modifiers = (SHIFT | CTRL);| means Shift and Ctrl.
*/
typedef PRUint32 Modifiers;
/**
* GetCurrentModifierState() returns current modifier key state.
* The "current" means actual state of hardware keyboard when this is
* called. I.e., if some key events are not still dispatched by GDK,
* the state may mismatch with GdkEventKey::state.
*
* @return Current modifier key state.
*/
static guint GetCurrentModifierState();
/**
* AreModifiersCurrentlyActive() checks the "current" modifier state
* on aGdkWindow with the keymap of the singleton instance.
*
* @param aModifiers One or more of Modifier values except
* NOT_MODIFIER.
* @return TRUE if all of modifieres in aModifiers are
* active. Otherwise, FALSE.
*/
static bool AreModifiersCurrentlyActive(Modifiers aModifiers);
/**
* AreModifiersActive() just checks whether aModifierState indicates
* all modifiers in aModifiers are active or not.
*
* @param aModifiers One or more of Modifier values except
* NOT_MODIFIER.
* @param aModifierState GDK's modifier states.
* @return TRUE if aGdkModifierType indecates all of
* modifiers in aModifier are active.
* Otherwise, FALSE.
*/
static bool AreModifiersActive(Modifiers aModifiers,
guint aModifierState);
/**
* InitInputEvent() initializes the aInputEvent with aModifierState.
*/
static void InitInputEvent(nsInputEvent& aInputEvent,
guint aModifierState);
/**
* InitKeyEvent() intializes aKeyEvent's modifier key related members
* and keycode related values.
*
* @param aKeyEvent It's an nsKeyEvent which needs to be
* initialized.
* @param aGdkKeyEvent A native GDK key event.
*/
static void InitKeyEvent(nsKeyEvent& aKeyEvent, GdkEventKey* aGdkKeyEvent);
/**
* IsKeyPressEventNecessary() returns TRUE when aGdkKeyEvent should cause
* a DOM keypress event. Otherwise, FALSE.
*/
static bool IsKeyPressEventNecessary(GdkEventKey* aGdkKeyEvent);
protected:
/**
* GetInstance() returns a KeymapWrapper instance.
*
* @return A singleton instance of KeymapWrapper.
*/
static KeymapWrapper* GetInstance();
KeymapWrapper();
~KeymapWrapper();
bool mInitialized;
/**
* Initializing methods.
*/
void Init();
void InitBySystemSettings();
/**
* mModifierKeys stores each hardware key information.
*/
struct ModifierKey {
guint mHardwareKeycode;
guint mMask;
ModifierKey(guint aHardwareKeycode) :
mHardwareKeycode(aHardwareKeycode), mMask(0)
{
}
};
nsTArray<ModifierKey> mModifierKeys;
/**
* GetModifierKey() returns modifier key information of the hardware
* keycode. If the key isn't a modifier key, returns NULL.
*/
ModifierKey* GetModifierKey(guint aHardwareKeycode);
/**
* mModifierMasks is bit masks for each modifier. The index should be one
* of ModifierIndex values.
*/
enum ModifierIndex {
INDEX_NUM_LOCK,
INDEX_SCROLL_LOCK,
INDEX_ALT,
INDEX_SUPER,
INDEX_HYPER,
INDEX_META,
INDEX_ALTGR,
COUNT_OF_MODIFIER_INDEX
};
guint mModifierMasks[COUNT_OF_MODIFIER_INDEX];
guint GetModifierMask(Modifier aModifier) const;
/**
* @param aGdkKeyval A GDK defined modifier key value such as
* GDK_Shift_L.
* @return Returns Modifier values for aGdkKeyval.
* If the given key code isn't a modifier key,
* returns NOT_MODIFIER.
*/
static Modifier GetModifierForGDKKeyval(guint aGdkKeyval);
#ifdef PR_LOGGING
static const char* GetModifierName(Modifier aModifier);
#endif // PR_LOGGING
/**
* mGdkKeymap is a wrapped instance by this class.
*/
GdkKeymap* mGdkKeymap;
/**
* Pointer of the singleton instance.
*/
static KeymapWrapper* sInstance;
/**
* Signal handlers.
*/
static void OnKeysChanged(GdkKeymap* aKeymap, KeymapWrapper* aKeymapWrapper);
static void OnDestroyKeymap(KeymapWrapper* aKeymapWrapper,
GdkKeymap *aGdkKeymap);
/**
* GetCharCodeFor() Computes what character is inputted by the key event
* with aModifierState and aGroup.
*
* @param aGdkKeyEvent Native key event, must not be NULL.
* @param aModifierState Combination of GdkModifierType which you
* want to test with aGdkKeyEvent.
* @param aGroup Set group in the mGdkKeymap.
* @return charCode which is inputted by aGdkKeyEvent.
* If failed, this returns 0.
*/
static PRUint32 GetCharCodeFor(const GdkEventKey *aGdkKeyEvent);
PRUint32 GetCharCodeFor(const GdkEventKey *aGdkKeyEvent,
guint aModifierState,
gint aGroup);
/**
* GetKeyLevel() returns level of the aGdkKeyEvent in mGdkKeymap.
*
* @param aGdkKeyEvent Native key event, must not be NULL.
* @return Using level. Typically, this is 0 or 1.
* If failed, this returns -1.
*/
gint GetKeyLevel(GdkEventKey *aGdkKeyEvent);
/**
* IsBasicLatinLetterOrNumeral() Checks whether the aCharCode is an
* alphabet or a numeric character in ASCII.
*
* @param aCharCode Charcode which you want to test.
* @return TRUE if aCharCode is an alphabet or a numeric
* in ASCII range. Otherwise, FALSE.
*/
static PRBool IsBasicLatinLetterOrNumeral(PRUint32 aCharCode);
/**
* InitKeypressEvent() intializes keyCode, charCode and
* alternativeCharCodes of keypress event.
*
* @param aKeyEvent An NS_KEY_PRESS event, must not be NULL.
* The modifier related members and keyCode must
* be initialized already.
* @param aGdkKeyEvent A native key event which causes dispatching
* aKeyEvent.
*/
void InitKeypressEvent(nsKeyEvent& aKeyEvent, GdkEventKey* aGdkKeyEvent);
};
} // namespace widget
} // namespace mozilla
#endif /* __nsGdkKeyUtils_h__ */

View File

@ -49,6 +49,7 @@
#include <gdk/gdk.h>
using namespace mozilla;
using namespace mozilla::widget;
static nsINativeKeyBindings::DoCommandCallback gCurrentCallback;
static void *gCurrentCallbackData;
@ -282,7 +283,7 @@ nsNativeKeyBindings::KeyPress(const nsNativeKeyEvent& aEvent,
if (aEvent.charCode != 0)
keyCode = gdk_unicode_to_keyval(aEvent.charCode);
else
keyCode = DOMKeyCodeToGdkKeyCode(aEvent.keyCode);
keyCode = KeymapWrapper::GuessGDKKeyval(aEvent.keyCode);
if (KeyPressInternal(aEvent, aCallback, aCallbackData, keyCode))
return true;

View File

@ -174,8 +174,6 @@ static GdkWindow *get_inner_gdk_window (GdkWindow *aWindow,
gint *retx, gint *rety);
static inline bool is_context_menu_key(const nsKeyEvent& inKeyEvent);
static void key_event_to_context_menu_event(nsMouseEvent &aEvent,
GdkEventKey *aGdkEvent);
static int is_parent_ungrab_enter(GdkEventCrossing *aEvent);
static int is_parent_grab_leave(GdkEventCrossing *aEvent);
@ -271,14 +269,6 @@ static void drag_data_received_event_cb(GtkWidget *aWidget,
guint32 aTime,
gpointer aData);
static GdkModifierType gdk_keyboard_get_modifiers();
#ifdef MOZ_X11
static bool gdk_keyboard_get_modmap_masks(Display* aDisplay,
PRUint32* aCapsLockMask,
PRUint32* aNumLockMask,
PRUint32* aScrollLockMask);
#endif /* MOZ_X11 */
/* initialization static functions */
static nsresult initialize_prefs (void);
@ -476,59 +466,6 @@ nsWindow::CommonCreate(nsIWidget *aParent, bool aListenForResizes)
mCreated = true;
}
void
nsWindow::InitKeyEvent(nsKeyEvent &aEvent, GdkEventKey *aGdkEvent)
{
aEvent.keyCode = GdkKeyCodeToDOMKeyCode(aGdkEvent->keyval);
// NOTE: The state of given key event indicates adjacent state of
// modifier keys. E.g., even if the event is Shift key press event,
// the bit for Shift is still false. By the same token, even if the
// event is Shift key release event, the bit for Shift is still true.
// Unfortunately, gdk_keyboard_get_modifiers() returns current modifier
// state. It means if there're some pending modifier key press or
// key release events, the result isn't what we want.
// Temporarily, we should compute the state only when the key event
// is GDK_KEY_PRESS.
guint modifierState = aGdkEvent->state;
guint changingMask = 0;
switch (aEvent.keyCode) {
case NS_VK_SHIFT:
changingMask = GDK_SHIFT_MASK;
break;
case NS_VK_CONTROL:
changingMask = GDK_CONTROL_MASK;
break;
case NS_VK_ALT:
changingMask = GDK_MOD1_MASK;
break;
case NS_VK_META:
changingMask = GDK_MOD4_MASK;
break;
}
if (changingMask != 0) {
// This key event is caused by pressing or releasing a modifier key.
if (aGdkEvent->type == GDK_KEY_PRESS) {
// If new modifier key is pressed, add the pressed mod mask.
modifierState |= changingMask;
} else {
// XXX If we could know the modifier keys state at the key release
// event, we should cut out changingMask from modifierState.
}
}
aEvent.isShift = (modifierState & GDK_SHIFT_MASK) != 0;
aEvent.isControl = (modifierState & GDK_CONTROL_MASK) != 0;
aEvent.isAlt = (modifierState & GDK_MOD1_MASK) != 0;
aEvent.isMeta = (modifierState & GDK_MOD4_MASK) != 0;
// The transformations above and in gdk for the keyval are not invertible
// so link to the GdkEvent (which will vanish soon after return from the
// event callback) to give plugins access to hardware_keycode and state.
// (An XEvent would be nice but the GdkEvent is good enough.)
aEvent.pluginEvent = (void *)aGdkEvent;
aEvent.time = aGdkEvent->time;
}
void
nsWindow::DispatchResizeEvent(nsIntRect &aRect, nsEventStatus &aStatus)
{
@ -2033,7 +1970,7 @@ nsWindow::HasPendingInputEvent()
// Paint flashing code (disabled for cairo - see below)
#define CAPS_LOCK_IS_ON \
(gdk_keyboard_get_modifiers() & GDK_LOCK_MASK)
(KeymapWrapper::AreModifiersCurrentlyActive(KeymapWrapper::CAPS_LOCK))
#define WANT_PAINT_FLASHING \
(debug_WantPaintFlashing() && CAPS_LOCK_IS_ON)
@ -2617,29 +2554,20 @@ nsWindow::OnMotionNotifyEvent(GtkWidget *aWidget, GdkEventMotion *aEvent)
mLastMotionPressure = pressure;
event.pressure = mLastMotionPressure;
guint modifierState;
if (synthEvent) {
#ifdef MOZ_X11
event.refPoint.x = nscoord(xevent.xmotion.x);
event.refPoint.y = nscoord(xevent.xmotion.y);
event.isShift = (xevent.xmotion.state & GDK_SHIFT_MASK)
? true : false;
event.isControl = (xevent.xmotion.state & GDK_CONTROL_MASK)
? true : false;
event.isAlt = (xevent.xmotion.state & GDK_MOD1_MASK)
? true : false;
modifierState = xevent.xmotion.state;
event.time = xevent.xmotion.time;
#else
event.refPoint.x = nscoord(aEvent->x);
event.refPoint.y = nscoord(aEvent->y);
event.isShift = (aEvent->state & GDK_SHIFT_MASK)
? true : false;
event.isControl = (aEvent->state & GDK_CONTROL_MASK)
? true : false;
event.isAlt = (aEvent->state & GDK_MOD1_MASK)
? true : false;
modifierState = aEvent->state;
event.time = aEvent->time;
#endif /* MOZ_X11 */
@ -2654,16 +2582,13 @@ nsWindow::OnMotionNotifyEvent(GtkWidget *aWidget, GdkEventMotion *aEvent)
event.refPoint = point - WidgetToScreenOffset();
}
event.isShift = (aEvent->state & GDK_SHIFT_MASK)
? true : false;
event.isControl = (aEvent->state & GDK_CONTROL_MASK)
? true : false;
event.isAlt = (aEvent->state & GDK_MOD1_MASK)
? true : false;
modifierState = aEvent->state;
event.time = aEvent->time;
}
KeymapWrapper::InitInputEvent(event, modifierState);
nsEventStatus status;
DispatchEvent(&event, status);
}
@ -2736,10 +2661,7 @@ nsWindow::InitButtonEvent(nsMouseEvent &aEvent,
aEvent.refPoint = point - WidgetToScreenOffset();
}
aEvent.isShift = (aGdkEvent->state & GDK_SHIFT_MASK) != 0;
aEvent.isControl = (aGdkEvent->state & GDK_CONTROL_MASK) != 0;
aEvent.isAlt = (aGdkEvent->state & GDK_MOD1_MASK) != 0;
aEvent.isMeta = (aGdkEvent->state & GDK_MOD4_MASK) != 0;
KeymapWrapper::InitInputEvent(aEvent, aGdkEvent->state);
aEvent.time = aGdkEvent->time;
@ -2823,10 +2745,7 @@ nsWindow::OnButtonPressEvent(GtkWidget *aWidget, GdkEventButton *aEvent)
// XXX Why is this delta value different from the scroll event?
event.delta = (aEvent->button == 6) ? -2 : 2;
event.isShift = (aEvent->state & GDK_SHIFT_MASK) != 0;
event.isControl = (aEvent->state & GDK_CONTROL_MASK) != 0;
event.isAlt = (aEvent->state & GDK_MOD1_MASK) != 0;
event.isMeta = (aEvent->state & GDK_MOD4_MASK) != 0;
KeymapWrapper::InitInputEvent(event, aEvent->state);
event.time = aEvent->time;
@ -2999,54 +2918,12 @@ nsWindow::DispatchContentCommandEvent(PRInt32 aMsg)
return TRUE;
}
static PRUint32
GetCharCodeFor(const GdkEventKey *aEvent, guint aShiftState,
gint aGroup)
{
guint keyval;
GdkKeymap *keymap = gdk_keymap_get_default();
if (gdk_keymap_translate_keyboard_state(keymap, aEvent->hardware_keycode,
GdkModifierType(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;
GdkKeymap *keymap = gdk_keymap_get_default();
if (!gdk_keymap_translate_keyboard_state(keymap,
aEvent->hardware_keycode,
GdkModifierType(aEvent->state),
aEvent->group,
NULL, NULL, &level, NULL))
return -1;
return level;
}
static bool
IsBasicLatinLetterOrNumeral(PRUint32 aChar)
{
return (aChar >= 'a' && aChar <= 'z') ||
(aChar >= 'A' && aChar <= 'Z') ||
(aChar >= '0' && aChar <= '9');
}
static bool
IsCtrlAltTab(GdkEventKey *aEvent)
{
return aEvent->keyval == GDK_Tab &&
aEvent->state & GDK_CONTROL_MASK && aEvent->state & GDK_MOD1_MASK;
KeymapWrapper::AreModifiersActive(
KeymapWrapper::CTRL | KeymapWrapper::ALT, aEvent->state);
}
bool
@ -3063,7 +2940,7 @@ nsWindow::DispatchKeyDownEvent(GdkEventKey *aEvent, bool *aCancelled)
// send the key down event
nsEventStatus status;
nsKeyEvent downEvent(true, NS_KEY_DOWN, this);
InitKeyEvent(downEvent, aEvent);
KeymapWrapper::InitKeyEvent(downEvent, aEvent);
DispatchEvent(&downEvent, status);
*aCancelled = (status == nsEventStatus_eConsumeNoDefault);
return true;
@ -3120,14 +2997,7 @@ nsWindow::OnKeyPressEvent(GtkWidget *aWidget, GdkEventKey *aEvent)
// TODO: Instead of selectively excluding some keys from NS_KEY_PRESS events,
// we should instead selectively include (as per MSDN spec; no official
// spec covers KeyPress events).
if (aEvent->keyval == GDK_Shift_L
|| aEvent->keyval == GDK_Shift_R
|| aEvent->keyval == GDK_Control_L
|| aEvent->keyval == GDK_Control_R
|| aEvent->keyval == GDK_Alt_L
|| aEvent->keyval == GDK_Alt_R
|| aEvent->keyval == GDK_Meta_L
|| aEvent->keyval == GDK_Meta_R) {
if (!KeymapWrapper::IsKeyPressEventNecessary(aEvent)) {
return TRUE;
}
@ -3168,89 +3038,11 @@ nsWindow::OnKeyPressEvent(GtkWidget *aWidget, GdkEventKey *aEvent)
#endif /* MOZ_X11 */
nsKeyEvent event(true, NS_KEY_PRESS, this);
InitKeyEvent(event, aEvent);
KeymapWrapper::InitKeyEvent(event, aEvent);
if (isKeyDownCancelled) {
// If prevent default set for onkeydown, do the same for onkeypress
event.flags |= NS_EVENT_FLAG_NO_DEFAULT;
}
event.charCode = nsConvertCharCodeToUnicode(aEvent);
if (event.charCode) {
event.keyCode = 0;
gint level = GetKeyLevel(aEvent);
if ((event.isControl || event.isAlt || event.isMeta) &&
(level == 0 || level == 1)) {
guint baseState =
aEvent->state & ~(GDK_SHIFT_MASK | GDK_CONTROL_MASK |
GDK_MOD1_MASK | GDK_MOD4_MASK);
// 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, baseState, aEvent->group);
bool isLatin = (altCharCodes.mUnshiftedCharCode <= 0xFF);
// shifted charcode of current keyboard layout.
altCharCodes.mShiftedCharCode =
GetCharCodeFor(aEvent, baseState | GDK_SHIFT_MASK,
aEvent->group);
isLatin = isLatin && (altCharCodes.mShiftedCharCode <= 0xFF);
if (altCharCodes.mUnshiftedCharCode ||
altCharCodes.mShiftedCharCode) {
event.alternativeCharCodes.AppendElement(altCharCodes);
}
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) {
PRUint32 unmodifiedCh =
event.isShift ? altCharCodes.mShiftedCharCode :
altCharCodes.mUnshiftedCharCode;
// unshifted charcode of found keyboard layout.
PRUint32 ch =
GetCharCodeFor(aEvent, baseState, minGroup);
altCharCodes.mUnshiftedCharCode =
IsBasicLatinLetterOrNumeral(ch) ? ch : 0;
// shifted charcode of found keyboard layout.
ch = GetCharCodeFor(aEvent, baseState | GDK_SHIFT_MASK,
minGroup);
altCharCodes.mShiftedCharCode =
IsBasicLatinLetterOrNumeral(ch) ? ch : 0;
if (altCharCodes.mUnshiftedCharCode ||
altCharCodes.mShiftedCharCode) {
event.alternativeCharCodes.AppendElement(altCharCodes);
}
// If the charCode is not Latin, and the level is 0 or 1,
// we should replace the charCode to Latin char if Alt and
// Meta keys are not pressed. (Alt should be sent the
// localized char for accesskey like handling of Web
// Applications.)
ch = event.isShift ? altCharCodes.mShiftedCharCode :
altCharCodes.mUnshiftedCharCode;
if (ch && !(event.isAlt || event.isMeta) &&
event.charCode == unmodifiedCh) {
event.charCode = ch;
}
}
}
}
}
// before we dispatch a key, check if it's the context menu key.
// If so, send a context menu key event instead.
@ -3258,7 +3050,11 @@ nsWindow::OnKeyPressEvent(GtkWidget *aWidget, GdkEventKey *aEvent)
nsMouseEvent contextMenuEvent(true, NS_CONTEXTMENU, this,
nsMouseEvent::eReal,
nsMouseEvent::eContextMenuKey);
key_event_to_context_menu_event(contextMenuEvent, aEvent);
contextMenuEvent.refPoint = nsIntPoint(0, 0);
contextMenuEvent.time = aEvent->time;
contextMenuEvent.clickCount = 1;
KeymapWrapper::InitInputEvent(contextMenuEvent, aEvent->state);
DispatchEvent(&contextMenuEvent, status);
}
else {
@ -3298,7 +3094,7 @@ nsWindow::OnKeyReleaseEvent(GtkWidget *aWidget, GdkEventKey *aEvent)
// send the key event as a key up event
nsKeyEvent event(true, NS_KEY_UP, this);
InitKeyEvent(event, aEvent);
KeymapWrapper::InitKeyEvent(event, aEvent);
nsEventStatus status;
DispatchEvent(&event, status);
@ -3352,10 +3148,7 @@ nsWindow::OnScrollEvent(GtkWidget *aWidget, GdkEventScroll *aEvent)
event.refPoint = point - WidgetToScreenOffset();
}
event.isShift = (aEvent->state & GDK_SHIFT_MASK) != 0;
event.isControl = (aEvent->state & GDK_CONTROL_MASK) != 0;
event.isAlt = (aEvent->state & GDK_MOD1_MASK) != 0;
event.isMeta = (aEvent->state & GDK_MOD4_MASK) != 0;
KeymapWrapper::InitInputEvent(event, aEvent->state);
event.time = aEvent->time;
@ -6128,12 +5921,8 @@ void
nsWindow::InitDragEvent(nsDragEvent &aEvent)
{
// set the keyboard modifiers
GdkModifierType state = (GdkModifierType)0;
gdk_display_get_pointer(gdk_display_get_default(), NULL, NULL, NULL, &state);
aEvent.isShift = (state & GDK_SHIFT_MASK) ? true : false;
aEvent.isControl = (state & GDK_CONTROL_MASK) ? true : false;
aEvent.isAlt = (state & GDK_MOD1_MASK) ? true : false;
aEvent.isMeta = false; // GTK+ doesn't support the meta key
guint modifierState = KeymapWrapper::GetCurrentModifierState();
KeymapWrapper::InitInputEvent(aEvent, modifierState);
}
// This will update the drag action based on the information in the
@ -6317,19 +6106,6 @@ is_context_menu_key(const nsKeyEvent& aKeyEvent)
!aKeyEvent.isControl && !aKeyEvent.isMeta && !aKeyEvent.isAlt));
}
static void
key_event_to_context_menu_event(nsMouseEvent &aEvent,
GdkEventKey *aGdkEvent)
{
aEvent.refPoint = nsIntPoint(0, 0);
aEvent.isShift = false;
aEvent.isControl = false;
aEvent.isAlt = false;
aEvent.isMeta = false;
aEvent.time = aGdkEvent->time;
aEvent.clickCount = 1;
}
static int
is_parent_ungrab_enter(GdkEventCrossing *aEvent)
{
@ -6347,76 +6123,6 @@ is_parent_grab_leave(GdkEventCrossing *aEvent)
(GDK_NOTIFY_VIRTUAL == aEvent->detail));
}
static GdkModifierType
gdk_keyboard_get_modifiers()
{
GdkModifierType m = (GdkModifierType) 0;
gdk_window_get_pointer(NULL, NULL, NULL, &m);
return m;
}
#ifdef MOZ_X11
// Get the modifier masks for GDK_Caps_Lock, GDK_Num_Lock and GDK_Scroll_Lock.
// Return true on success, false on error.
static bool
gdk_keyboard_get_modmap_masks(Display* aDisplay,
PRUint32* aCapsLockMask,
PRUint32* aNumLockMask,
PRUint32* aScrollLockMask)
{
*aCapsLockMask = 0;
*aNumLockMask = 0;
*aScrollLockMask = 0;
int min_keycode = 0;
int max_keycode = 0;
XDisplayKeycodes(aDisplay, &min_keycode, &max_keycode);
int keysyms_per_keycode = 0;
KeySym* xkeymap = XGetKeyboardMapping(aDisplay, min_keycode,
max_keycode - min_keycode + 1,
&keysyms_per_keycode);
if (!xkeymap) {
return false;
}
XModifierKeymap* xmodmap = XGetModifierMapping(aDisplay);
if (!xmodmap) {
XFree(xkeymap);
return false;
}
/*
The modifiermap member of the XModifierKeymap structure contains 8 sets
of max_keypermod KeyCodes, one for each modifier in the order Shift,
Lock, Control, Mod1, Mod2, Mod3, Mod4, and Mod5.
Only nonzero KeyCodes have meaning in each set, and zero KeyCodes are ignored.
*/
const unsigned int map_size = 8 * xmodmap->max_keypermod;
for (unsigned int i = 0; i < map_size; i++) {
KeyCode keycode = xmodmap->modifiermap[i];
if (!keycode || keycode < min_keycode || keycode > max_keycode)
continue;
const KeySym* syms = xkeymap + (keycode - min_keycode) * keysyms_per_keycode;
const unsigned int mask = 1 << (i / xmodmap->max_keypermod);
for (int j = 0; j < keysyms_per_keycode; j++) {
switch (syms[j]) {
case GDK_Caps_Lock: *aCapsLockMask |= mask; break;
case GDK_Num_Lock: *aNumLockMask |= mask; break;
case GDK_Scroll_Lock: *aScrollLockMask |= mask; break;
}
}
}
XFreeModifiermap(xmodmap);
XFree(xkeymap);
return true;
}
#endif /* MOZ_X11 */
#ifdef ACCESSIBILITY
void
nsWindow::CreateRootAccessible()
@ -6554,30 +6260,17 @@ nsWindow::GetToggledKeyState(PRUint32 aKeyCode, bool* aLEDState)
{
NS_ENSURE_ARG_POINTER(aLEDState);
#ifdef MOZ_X11
GdkModifierType modifiers = gdk_keyboard_get_modifiers();
PRUint32 capsLockMask, numLockMask, scrollLockMask;
bool foundMasks = gdk_keyboard_get_modmap_masks(
GDK_WINDOW_XDISPLAY(mGdkWindow),
&capsLockMask, &numLockMask, &scrollLockMask);
if (!foundMasks)
return NS_ERROR_NOT_IMPLEMENTED;
PRUint32 mask = 0;
KeymapWrapper::Modifiers modifier;
switch (aKeyCode) {
case NS_VK_CAPS_LOCK: mask = capsLockMask; break;
case NS_VK_NUM_LOCK: mask = numLockMask; break;
case NS_VK_SCROLL_LOCK: mask = scrollLockMask; break;
case NS_VK_CAPS_LOCK: modifier = KeymapWrapper::CAPS_LOCK; break;
case NS_VK_NUM_LOCK: modifier = KeymapWrapper::NUM_LOCK; break;
case NS_VK_SCROLL_LOCK: modifier = KeymapWrapper::SCROLL_LOCK; break;
default: return NS_ERROR_INVALID_ARG;
}
if (mask == 0)
return NS_ERROR_NOT_IMPLEMENTED;
*aLEDState = (modifiers & mask) != 0;
*aLEDState =
KeymapWrapper::AreModifiersCurrentlyActive(modifier);
return NS_OK;
#else
return NS_ERROR_NOT_IMPLEMENTED;
#endif /* MOZ_X11 */
}
#if defined(MOZ_X11) && defined(MOZ_WIDGET_GTK2)

View File

@ -114,8 +114,6 @@ public:
void CommonCreate(nsIWidget *aParent, bool aListenForResizes);
// event handling code
void InitKeyEvent(nsKeyEvent &aEvent, GdkEventKey *aGdkEvent);
void DispatchActivateEvent(void);
void DispatchDeactivateEvent(void);
void DispatchResizeEvent(nsIntRect &aRect, nsEventStatus &aStatus);