mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-29 21:25:35 +00:00
Merge merge
This commit is contained in:
commit
0b9a7c075c
@ -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
|
||||
|
@ -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__ */
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user