/* AbiSource Program Utilities * Copyright (C) 1998-2000 AbiSource, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include #include #include #include #include "ut_types.h" #include "ut_assert.h" #include "ev_EditBinding.h" #include "ev_EditEventMapper.h" #include "ev_EditMethod.h" #include "xav_View.h" #include "ev_NamedVirtualKey.h" #include "ev_UnixKeyboard.h" #include "ut_mbtowc.h" #include "ut_string_class.h" ////////////////////////////////////////////////////////////////// static EV_EditBits s_mapVirtualKeyCodeToNVK(guint keyval); static bool s_isVirtualKeyCode(guint keyval); static GdkModifierType s_getAltMask(void); ////////////////////////////////////////////////////////////////// // This is used to remember the modifier mask (GDK_MODx_MASK) that // is bound to the Alt keys. We load this once per session. // // TODO Figure out if GTK/GDK can send us a MappingNotify event. // TODO If so, recompute this value. // static GdkModifierType s_alt_mask = GDK_MODIFIER_MASK; // bogus value GdkModifierType ev_UnixKeyboard::getAltModifierMask(void) { return s_alt_mask; } ////////////////////////////////////////////////////////////////// ev_UnixKeyboard::ev_UnixKeyboard(EV_EditEventMapper* pEEM) : EV_Keyboard(pEEM) { if (s_alt_mask == GDK_MODIFIER_MASK) s_alt_mask = s_getAltMask(); } ev_UnixKeyboard::~ev_UnixKeyboard(void) { } bool ev_UnixKeyboard::keyPressEvent(AV_View* pView, GdkEventKey* e) { EV_EditBits state = 0; EV_EditEventMapperResult result; EV_EditMethod * pEM; UT_uint32 charData = e->keyval; if (e->state & GDK_SHIFT_MASK) state |= EV_EMS_SHIFT; if (e->state & GDK_CONTROL_MASK) { state |= EV_EMS_CONTROL; // Gdk does us the favour of working out a translated keyvalue for us, // but with the Ctrl keys, we do not want that -- see bug 9545 Display * display = GDK_DISPLAY(); KeySym sym = XKeycodeToKeysym(display, e->hardware_keycode, e->state & GDK_SHIFT_MASK ? 1 : 0); xxx_UT_DEBUGMSG(("ev_UnixKeyboard::keyPressEvent: keyval %d, hardware_keycode %d\n" " sym: 0x%x\n", e->keyval, e->hardware_keycode, sym)); charData = sym; } if (e->state & (s_alt_mask)) state |= EV_EMS_ALT; if (s_isVirtualKeyCode(charData)) { EV_EditBits nvk = s_mapVirtualKeyCodeToNVK(charData); switch (nvk) { case EV_NVK__IGNORE__: return false; default: result = m_pEEM->Keystroke(static_cast(EV_EKP_PRESS|state|nvk),&pEM); switch (result) { case EV_EEMR_BOGUS_START: // If it is a bogus key and we don't have a sequence in // progress, we should let the system handle it // (this lets things like ALT-F4 work). return false; case EV_EEMR_BOGUS_CONT: // If it is a bogus key but in the middle of a sequence, // we should silently eat it (this is to prevent things // like Control-X ALT-F4 from killing us -- if they want // to kill us, fine, but they shouldn't be in the middle // of a sequence). return true; case EV_EEMR_COMPLETE: UT_ASSERT(pEM); invokeKeyboardMethod(pView,pEM,0,0); // no char data to offer return true; case EV_EEMR_INCOMPLETE: return true; default: UT_ASSERT(0); return true; } } } else { // TODO: is this necessary? charData = gdk_keyval_to_unicode (charData); UT_UTF8String utf8 (static_cast(&charData), 1); return charDataEvent (pView, state, utf8.utf8_str(), utf8.byteLength()); } return false; } bool ev_UnixKeyboard::charDataEvent(AV_View* pView, EV_EditBits state, const char * text, size_t len) { EV_EditEventMapperResult result; EV_EditMethod * pEM; /* do some sanity checking, since: - delete_surrounding commits a 0 length string in some IMs - some IMs state a length of 1, while the text being "" (for example the Amharic IM for keystrokes that have no secondary character (eg. shift-R) */ if (!text || *text == '\0' || !len) return true; UT_UCS4String ucs (text, len); UT_uint32 charData = static_cast(ucs[0]); xxx_UT_DEBUGMSG(("DOM: charData: %d | length: %d | string: '%s'\n", charData, len, text)); if (charData == 32) charData = 'a'; // HACK!!! for space bar not working. investigate more.... if(charData>0xff || charData == 0) result = m_pEEM->Keystroke(EV_EKP_PRESS|state|'a',&pEM); else result = m_pEEM->Keystroke(EV_EKP_PRESS|state|charData,&pEM); switch (result) { case EV_EEMR_BOGUS_START: // If it is a bogus key and we don't have a sequence in // progress, we should let the system handle it // (this lets things like ALT-F4 work). return false; case EV_EEMR_BOGUS_CONT: // If it is a bogus key but in the middle of a sequence, // we should silently eat it (this is to prevent things // like Control-X ALT-F4 from killing us -- if they want // to kill us, fine, but they shouldn't be in the middle // of a sequence). return true; case EV_EEMR_COMPLETE: { UT_ASSERT(pEM); invokeKeyboardMethod(pView,pEM, ucs.ucs4_str(), static_cast(ucs.size())); return true; } case EV_EEMR_INCOMPLETE: return true; default: UT_ASSERT(0); return true; } return false; } // pulled in from gdk/gdkkeysyms.h static const EV_EditBits s_Table_NVK_0xff[] = { 0, // 00 0, // 01 0, // 02 0, // 03 0, // 04 0, // 05 0, // 06 0, // 07 EV_NVK_BACKSPACE, // GDK_Backspace 0xFF08 EV_NVK_TAB, // GDK_Tab 0xFF09 EV_NVK__IGNORE__, // GDK_Linefeed 0xFF0A EV_NVK__IGNORE__, // GDK_Clear 0xFF0B 0, // 0C EV_NVK_RETURN, // GDK_Return 0xFF0D 0, 0, 0, 0, 0, EV_NVK__IGNORE__, // GDK_Pause 0xFF13 EV_NVK__IGNORE__, // GDK_Scroll_Lock 0xFF14 EV_NVK__IGNORE__, // GDK_Sys_Req 0xFF15 0, 0, 0, 0, 0, EV_NVK_ESCAPE, // GDK_Escape 0xFF1B 0, 0, 0, 0, EV_NVK__IGNORE__, // GDK_Multi_key 0xFF20 EV_NVK__IGNORE__, // GDK_Kanji 0xFF21 EV_NVK__IGNORE__, // GDK_Muhenkan 0xFF22 EV_NVK__IGNORE__, // GDK_Henkan_Mode 0xFF23 EV_NVK__IGNORE__, // GDK_Henkan 0xFF23 EV_NVK__IGNORE__, // GDK_Romaji 0xFF24 EV_NVK__IGNORE__, // GDK_Hiragana 0xFF25 EV_NVK__IGNORE__, // GDK_Katakana 0xFF26 EV_NVK__IGNORE__, // GDK_Hiragana_Katakana 0xFF27 EV_NVK__IGNORE__, // GDK_Zenkaku 0xFF28 EV_NVK__IGNORE__, // GDK_Hankaku 0xFF29 EV_NVK__IGNORE__, // GDK_Zenkaku_Hankaku 0xFF2A EV_NVK__IGNORE__, // GDK_Touroku 0xFF2B EV_NVK__IGNORE__, // GDK_Massyo 0xFF2C EV_NVK__IGNORE__, // GDK_Kana_Lock 0xFF2D EV_NVK__IGNORE__, // GDK_Kana_Shift 0xFF2E EV_NVK__IGNORE__, // GDK_Eisu_Shift 0xFF2F EV_NVK__IGNORE__, // GDK_Eisu_toggle 0xFF30 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, EV_NVK_HOME, // GDK_Home 0xFF50 EV_NVK_LEFT, // GDK_Left 0xFF51 EV_NVK_UP, // GDK_Up 0xFF52 EV_NVK_RIGHT, // GDK_Right 0xFF53 EV_NVK_DOWN, // GDK_Down 0xFF54 EV_NVK_PAGEUP, // GDK_Page_Up 0xFF55 EV_NVK_PAGEDOWN, // GDK_Page_Down 0xFF56 EV_NVK_END, // GDK_End 0xFF57 EV_NVK__IGNORE__, // GDK_Begin 0xFF58 0, 0, 0, 0, 0, 0, 0, EV_NVK__IGNORE__, // GDK_Select 0xFF60 EV_NVK__IGNORE__, // GDK_Print 0xFF61 EV_NVK__IGNORE__, // GDK_Execute 0xFF62 EV_NVK_INSERT, // GDK_Insert 0xFF63 0, EV_NVK__IGNORE__, // GDK_Undo 0xFF65 EV_NVK__IGNORE__, // GDK_Redo 0xFF66 EV_NVK_MENU_SHORTCUT, // GDK_Menu 0xFF67 EV_NVK__IGNORE__, // GDK_Find 0xFF68 EV_NVK__IGNORE__, // GDK_Cancel 0xFF69 EV_NVK__IGNORE__, // GDK_Help 0xFF6A EV_NVK__IGNORE__, // GDK_Break 0xFF6B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, EV_NVK__IGNORE__, // GDK_script_switch 0xFF7E EV_NVK__IGNORE__, // GDK_Num_Lock 0xFF7F EV_NVK__IGNORE__, // GDK_KP_Space 0xFF80 0, 0, 0, 0, 0, 0, 0, 0, EV_NVK_TAB, // GDK_KP_Tab 0xFF89 0, 0, 0, EV_NVK_RETURN, // GDK_KP_Enter 0xFF8D 0, 0, 0, EV_NVK_F1, // GDK_KP_F1 0xFF91 EV_NVK_F2, // GDK_KP_F2 0xFF92 EV_NVK_F3, // GDK_KP_F3 0xFF93 EV_NVK_F4, // GDK_KP_F4 0xFF94 EV_NVK_HOME, // GDK_KP_Home 0xFF95 EV_NVK_LEFT, // GDK_KP_Left 0xFF96 EV_NVK_UP, // GDK_KP_Up 0xFF97 EV_NVK_RIGHT, // GDK_KP_Right 0xFF98 EV_NVK_DOWN, // GDK_KP_Down 0xFF99 EV_NVK_PAGEUP, // GDK_KP_Prior 0xFF9A EV_NVK_PAGEDOWN, // GDK_KP_Next 0xFF9B EV_NVK_END, // GDK_KP_End 0xFF9C EV_NVK_HOME, // GDK_KP_Begin 0xFF9D EV_NVK_INSERT, // GDK_KP_Insert 0xFF9E EV_NVK_DELETE, // GDK_KP_Delete 0xFF9F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // GDK_KP_Multiply 0xFFAA 0, // GDK_KP_Add 0xFFAB 0, // GDK_KP_Separator 0xFFAC 0, // GDK_KP_Subtract 0xFFAD 0, // GDK_KP_Decimal 0xFFAE 0, // GDK_KP_Divide 0xFFAF 0, // GDK_KP_0 0xFFB0 0, // GDK_KP_1 0xFFB1 0, // GDK_KP_2 0xFFB2 0, // GDK_KP_3 0xFFB3 0, // GDK_KP_4 0xFFB4 0, // GDK_KP_5 0xFFB5 0, // GDK_KP_6 0xFFB6 0, // GDK_KP_7 0xFFB7 0, // GDK_KP_8 0xFFB8 0, // GDK_KP_9 0xFFB9 0, 0, 0, 0, // GDK_KP_Equal 0xFFBD EV_NVK_F1, // GDK_F1 0xFFBE EV_NVK_F2, // GDK_F2 0xFFBF EV_NVK_F3, // GDK_F3 0xFFC0 EV_NVK_F4, // GDK_F4 0xFFC1 EV_NVK_F5, // GDK_F5 0xFFC2 EV_NVK_F6, // GDK_F6 0xFFC3 EV_NVK_F7, // GDK_F7 0xFFC4 EV_NVK_F8, // GDK_F8 0xFFC5 EV_NVK_F9, // GDK_F9 0xFFC6 EV_NVK_F10, // GDK_F10 0xFFC7 EV_NVK_F11, // GDK_F11 0xFFC8 EV_NVK_F12, // GDK_F12 0xFFC9 EV_NVK_F13, // GDK_F13 0xFFCA EV_NVK_F14, // GDK_F14 0xFFCB EV_NVK_F15, // GDK_F15 0xFFCC EV_NVK_F16, // GDK_F16 0xFFCD EV_NVK_F17, // GDK_F17 0xFFCE EV_NVK_F18, // GDK_F18 0xFFCF EV_NVK_F19, // GDK_F19 0xFFD0 EV_NVK_F20, // GDK_F20 0xFFD1 EV_NVK_F21, // GDK_F21 0xFFD2 EV_NVK_F22, // GDK_F22 0xFFD3 EV_NVK_F23, // GDK_F23 0xFFD4 EV_NVK_F24, // GDK_F24 0xFFD5 EV_NVK_F25, // GDK_F25 0xFFD6 EV_NVK_F26, // GDK_F26 0xFFD7 EV_NVK_F27, // GDK_F27 0xFFD8 EV_NVK_F28, // GDK_F28 0xFFD9 EV_NVK_F29, // GDK_F29 0xFFDA EV_NVK_F30, // GDK_F30 0xFFDB EV_NVK_F31, // GDK_F31 0xFFDC EV_NVK_F32, // GDK_F32 0xFFDD EV_NVK_F33, // GDK_F33 0xFFDE EV_NVK_F34, // GDK_F34 0xFFDF EV_NVK_F35, // GDK_F35 0xFFE0 EV_NVK__IGNORE__, // GDK_Shift_L 0xFFE1 EV_NVK__IGNORE__, // GDK_Shift_R 0xFFE2 EV_NVK__IGNORE__, // GDK_Control_L 0xFFE3 EV_NVK__IGNORE__, // GDK_Control_R 0xFFE4 EV_NVK__IGNORE__, // GDK_Caps_Lock 0xFFE5 EV_NVK__IGNORE__, // GDK_Shift_Lock 0xFFE6 EV_NVK__IGNORE__, // GDK_Meta_L 0xFFE7 EV_NVK__IGNORE__, // GDK_Meta_R 0xFFE8 EV_NVK__IGNORE__, // GDK_Alt_L 0xFFE9 EV_NVK__IGNORE__, // GDK_Alt_R 0xFFEA EV_NVK__IGNORE__, // GDK_Super_L 0xFFEB EV_NVK__IGNORE__, // GDK_Super_R 0xFFEC EV_NVK__IGNORE__, // GDK_Hyper_L 0xFFED EV_NVK_MENU_SHORTCUT, // GDK_Hyper_R 0xFFEE 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, EV_NVK_DELETE, // GDK_Delete 0xFFFF }; static const EV_EditBits s_Table_NVK_0xfe[] = // ISO 9995 Function and Modifier Keys { // see /usr/include/X11/keysymdef.h 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0xfe00 - 0xfe0f 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0xfe10 - 0xfe1f EV_NVK_TAB, // 0xfe20 left_tab 0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0xfe21 - 0xfe2f 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0xfe30 - 0xfe3f 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0xfe40 - 0xfe4f EV_NVK_DEAD_GRAVE, // 0xfe50 dead_grave EV_NVK_DEAD_ACUTE, // 0xfe51 dead_acute EV_NVK_DEAD_CIRCUMFLEX, // 0xfe52 dead_circumfex EV_NVK_DEAD_TILDE, // 0xfe53 dead_tilda EV_NVK_DEAD_MACRON, // 0xfe54 dead_macron EV_NVK_DEAD_BREVE, // 0xfe55 dead_breve EV_NVK_DEAD_ABOVEDOT, // 0xfe56 dead_abovedot EV_NVK_DEAD_DIAERESIS, // 0xfe57 dead_diaeresis 0, // 0xfe58 dead_abovering (not used) EV_NVK_DEAD_DOUBLEACUTE, // 0xfe59 dead_doubleacute EV_NVK_DEAD_CARON, // 0xfe5a dead_caron EV_NVK_DEAD_CEDILLA, // 0xfe5b dead_cedilla EV_NVK_DEAD_OGONEK, // 0xfe5c dead_ogonek EV_NVK_DEAD_IOTA, // 0xfe5d dead_iota 0,0, // 0xfe5e - 0xfe5f 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0xfe60 - 0xfe6f 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0xfe70 - 0xfe7f 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0xfe80 - 0xfe8f 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0xfe90 - 0xfe9f 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0xfea0 - 0xfeaf 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0xfeb0 - 0xfebf 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0xfec0 - 0xfecf 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0xfed0 - 0xfedf 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0xfee0 - 0xfeef 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0xfef0 - 0xfeff }; static bool s_isVirtualKeyCode(guint keyval) { // X11 has several segregated sets of keys // 0xff00 - 0xffff has most function keys and non-letter keys // 0xfe00 - 0xfeff has additional function keys // 0xfd00 - 0xfdff has 3270 terminal keys // 0x0000 - 0x00ff latin1 // 0x0100 - 0x01ff latin2 // ... and so on ... // // there is also a set of Hardware Vendor ranges defined. // these appear to have stuff in the high word. (see {ap_,DEC,HP,Sun}keysym.h) // for now, we will ignore these. if (keyval > 0x0000FFFF) return false; // was true before CJK patch // Causes immediate on keypress segfault?? if (keyval >= GDK_KP_0 && keyval <= GDK_KP_9 && keyval != GDK_KP_Enter) // number pad keys return false; if (keyval > 0xFE00) // see the above table return true; UT_ASSERT(keyval <= 0xFD00); // we don't what to do with 3270 keys if (keyval == 0x0020) // special handling for ASCII-Space return true; return false; } static EV_EditBits s_mapVirtualKeyCodeToNVK(guint keyval) { // map the given virtual key into a "named virtual key". // these are referenced by NVK_ symbol so that the cross // platform code can properly refer to them. // there is also a set of Hardware Vendor ranges defined. // these appear to have stuff in the high word. (see {ap_,DEC,HP,Sun}keysym.h) // for now, we will ignore these. if (keyval > 0x0000FFFF) return EV_NVK__IGNORE__; if (keyval > 0xFF00) return s_Table_NVK_0xff[keyval - 0xFF00]; if (keyval > 0xFE00) return s_Table_NVK_0xfe[keyval - 0xFE00]; if (keyval == 0x0020) return EV_NVK_SPACE; UT_ASSERT(0); return EV_NVK__IGNORE__; } ////////////////////////////////////////////////////////////////// // deal with keyboard mapping oddities ////////////////////////////////////////////////////////////////// static GdkModifierType s_getAltMask(void) { ////////////////////////////////////////////////////////////////// // find out what modifier mask XL_Alt_{L,R} are bound to. ////////////////////////////////////////////////////////////////// int alt_mask = 0; Display * display = GDK_DISPLAY(); KeyCode kcAltL = XKeysymToKeycode(display,XK_Alt_L); KeyCode kcAltR = XKeysymToKeycode(display,XK_Alt_R); XModifierKeymap * pModMap = XGetModifierMapping(display); int mkpm = pModMap->max_keypermod; int k,m; int mAltL=-1; int mAltR=-1; for (m=0; m<8; m++) { for (k=0; kmodifiermap[m*mkpm + k]; if (kcAltL && (code == kcAltL)) mAltL = m; if (kcAltR && (code == kcAltR)) mAltR = m; } } switch (mAltL) { default: // Should not happen... case -1: // Alt_L is not a modifier key ?? case 0: // Alt_L is mapped to SHIFT ?? case 1: // Alt_L is mapped to (Caps)LOCK ?? case 2: // Alt_L is mapped to CONTROL ?? break; // ... ignore this key. case 3: alt_mask |= GDK_MOD1_MASK; break; case 4: alt_mask |= GDK_MOD2_MASK; break; case 5: alt_mask |= GDK_MOD3_MASK; break; case 6: alt_mask |= GDK_MOD4_MASK; break; case 7: alt_mask |= GDK_MOD5_MASK; break; } switch (mAltR) { default: // Should not happen... case -1: // Alt_R is not a modifier key ?? case 0: // Alt_R is mapped to SHIFT ?? case 1: // Alt_R is mapped to (Caps)LOCK ?? case 2: // Alt_R is mapped to CONTROL ?? break; // ... ignore this key. case 3: alt_mask |= GDK_MOD1_MASK; break; case 4: alt_mask |= GDK_MOD2_MASK; break; case 5: alt_mask |= GDK_MOD3_MASK; break; case 6: alt_mask |= GDK_MOD4_MASK; break; case 7: alt_mask |= GDK_MOD5_MASK; break; } XFreeModifiermap(pModMap); if (!alt_mask) // if nothing set, fall back to MOD1 alt_mask = GDK_MOD1_MASK; return static_cast(alt_mask); }