/* 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 "ut_types.h" #include "ut_assert.h" #include "ut_string.h" #include "ut_debugmsg.h" #include "ev_EditBinding.h" #include "ev_EditEventMapper.h" #include "ev_EditMethod.h" #include "ev_NamedVirtualKey.h" #include "ev_BeOSKeyboard.h" #include "xap_BeOSApp.h" #include "xap_BeOSFrame.h" #define DPRINTF(x) EV_EditBits s_mapVirtualKeyCodeToNVK(int keyval, int modifiers, int charval, const char *bytes); UT_UCSChar s_getUCSChar(int keyval, int modifiers, int charval, const char *bytes); /**************************************************************/ /* EVENT FILTERING The user hit some key ... do the right thing */ class KeybdFilter: public BMessageFilter { public: KeybdFilter(XAP_BeOSApp * pBeOSApp, XAP_BeOSFrame * pBeOSFrame, EV_Keyboard *pEVKeyboard); filter_result Filter(BMessage *message, BHandler **target); private: XAP_BeOSApp *m_pBeOSApp; XAP_BeOSFrame *m_pBeOSFrame; EV_Keyboard *m_pEVKeyboard; }; KeybdFilter::KeybdFilter(XAP_BeOSApp * pBeOSApp, XAP_BeOSFrame * pBeOSFrame, EV_Keyboard *pEVKeyboard) : BMessageFilter(B_PROGRAMMED_DELIVERY, B_LOCAL_SOURCE) { m_pBeOSApp = pBeOSApp; m_pBeOSFrame = pBeOSFrame; m_pEVKeyboard = pEVKeyboard; } filter_result KeybdFilter::Filter(BMessage *message, BHandler **target) { //if (message->what != B_KEY_DOWN && message->what != B_KEY_UP) { if (message->what != B_KEY_DOWN) { return(B_DISPATCH_MESSAGE); } m_pBeOSFrame->getTopLevelWindow()->Lock(); bool result = ((ev_BeOSKeyboard*)m_pEVKeyboard)->keyPressEvent(m_pBeOSFrame->getCurrentView(), message); m_pBeOSFrame->getTopLevelWindow()->Unlock(); if( result == true) return(B_SKIP_MESSAGE); return(B_DISPATCH_MESSAGE); } /**************************************************************/ ev_BeOSKeyboard::ev_BeOSKeyboard(EV_EditEventMapper* pEEM) : EV_Keyboard(pEEM) { } ev_BeOSKeyboard::~ev_BeOSKeyboard(void) { } bool ev_BeOSKeyboard::synthesize(XAP_BeOSApp * pBeOSApp, XAP_BeOSFrame * pBeOSFrame) { UT_ASSERT(pBeOSFrame); be_Window *pBeWin; pBeWin = (be_Window*)pBeOSFrame->getTopLevelWindow(); UT_ASSERT(pBeWin); pBeWin->Lock(); pBeWin->m_pbe_DocView->AddFilter(new KeybdFilter(pBeOSApp, pBeOSFrame, this)); pBeWin->Unlock(); return true; } //Handle mapping bool ev_BeOSKeyboard::keyPressEvent(AV_View* pView, BMessage *msg) { EV_EditBits state = 0; EV_EditEventMapperResult result; EV_EditMethod * pEM; key_map *keymap; char *chars; get_key_map(&keymap, &chars); /* A typical keyboard message looks like: BMessage: what = _KYD (0x5f4b5944, or 1598773572) entry when, type=LLNG, c=1, size= 8, data[0]: entry modifiers, type=LONG, c=1, size= 4, data[0]: 0x0 entry key, type=LONG, c=1, size= 4, data[0]: 0x41 entry states, type=UBYT, c=1, size=16, entry raw_char, type=LONG, c=1, size= 4, data[0]: 0x68 entry byte, type=BYTE, c=1, size= 1, entry bytes, type=CSTR, c=1, size= 2, data[0]: */ int32 modifier; int32 keychar; int32 rawchar; int32 charindex; const char *bytes; msg->FindInt32("modifiers", &modifier); msg->FindInt32("key", &keychar); msg->FindInt32("raw_char", &rawchar); msg->FindString("bytes", &bytes); UT_DEBUGMSG(("Length %d \n", strlen(bytes))); for (int t=0; bytes[t]; t++) { UT_DEBUGMSG(("Byte[%d] = 0x%x \n",t, bytes[t])); } UT_DEBUGMSG(("Modifiers 0x%x keychar %c (0x%x) rawchar %c (0x%x)\n", modifier, keychar, keychar, rawchar, rawchar)); // CJP - If we want to 'BeOS'ize the menu's we need to map the command key to control // CJP - Is this safe? - Will we mess up any of the non-menu keyboard shortcuts? if( modifier & B_COMMAND_KEY ) { state |= EV_EMS_CONTROL; } if( modifier & B_COMMAND_KEY && modifier & B_CONTROL_KEY && modifier & B_OPTION_KEY) { state |= EV_EMS_ALT; } if( !(modifier & B_COMMAND_KEY) && modifier & B_OPTION_KEY ) state |= EV_EMS_ALT; else if( !(modifier & B_COMMAND_KEY) && modifier & B_CONTROL_KEY ) state |= EV_EMS_ALT; if (modifier & B_SHIFT_KEY) { state |= EV_EMS_SHIFT; } #if 0 if (modifier & B_CONTROL_KEY) { state |= EV_EMS_CONTROL; } if (modifier & B_OPTION_KEY) { state |= EV_EMS_ALT; } #endif if (s_mapVirtualKeyCodeToNVK(keychar, modifier, rawchar, bytes)) { EV_EditBits nvk = s_mapVirtualKeyCodeToNVK(keychar, modifier, rawchar, bytes); UT_DEBUGMSG(("VKC 0x%x ignore 0x%x \n", nvk, EV_NVK__IGNORE__)); //Trap Ten-Key Data UT_UCS4Char charData; bool ignore = false; if (!(modifier & B_SHIFT_KEY)) if (modifier & B_NUM_LOCK) { switch (keychar) { case 0x37: charData = 0x37;// Ten-Key 7 break; case 0x38: charData = 0x38;// Ten-Key 8 break; case 0x39: charData = 0x39;// Ten-Key 9 break; case 0x48: charData = 0x34;// Ten-Key 4 break; case 0x49: charData = 0x35;// Ten-Key 5 break; case 0x4a: charData = 0x36;// Ten-Key 6 break; case 0x58: charData = 0x31;// Ten-Key 1 break; case 0x59: charData = 0x32;// Ten-Key 2 break; case 0x5a: charData = 0x33;// Ten-Key 3 break; case 0x64: charData = 0x30;// Ten-Key 0 break; default: ignore = true; } if (!ignore) nvk = charData; } switch (nvk) { case EV_NVK__IGNORE__: return false; default: result = m_pEEM->Keystroke((UT_uint32)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); // no char data to offer if (charData < 0xff) invokeKeyboardMethod(pView,pEM, &charData,1); else invokeKeyboardMethod(pView,pEM,0,0); return true; case EV_EEMR_INCOMPLETE: return true; default: UT_ASSERT(0); return true; } } } else { UT_UCS4Char charData; charData = s_getUCSChar(keychar, modifier, rawchar, bytes); UT_DEBUGMSG(("AKC %c (0x%x) \n", charData, charData)); 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 true; 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); // no char data to offer invokeKeyboardMethod(pView,pEM,&charData,1); return true; case EV_EEMR_INCOMPLETE: return true; default: UT_ASSERT(0); return true; } } return false; } /* If the key is something special then it gets mapped to one of these key codes ... if it isn't a "special" key code, then we return 0 to indicate that we should attempt to get a regular key code out of the mapping with s_getKeyCode(). Otherwise we return with some sort of value ... */ EV_EditBits s_mapVirtualKeyCodeToNVK(int keyval, int modifiers, int charval, const char *bytes) { //Multibyte UTF-8 character stream if (strlen(bytes) > 1) { return(0); } switch (charval) { case B_BACKSPACE: //0x08 (same as '\\b') return(EV_NVK_BACKSPACE); //case B_ENTER: //0x0a (same as '\\n') case B_RETURN: //0x0a (synonym for B_ENTER) return(EV_NVK_RETURN); case B_SPACE: //0x20 (same as ' ') return(EV_NVK_SPACE); case B_TAB: //0x09 (same as '\\t') return(EV_NVK_TAB); case B_ESCAPE: //0x1b return(EV_NVK_ESCAPE); case B_LEFT_ARROW: //0x1c return(EV_NVK_LEFT); case B_RIGHT_ARROW: //0x1d return(EV_NVK_RIGHT); case B_UP_ARROW: //0x1e return(EV_NVK_UP); case B_DOWN_ARROW: //0x1f return(EV_NVK_DOWN); case B_INSERT: //0x05 return(EV_NVK_INSERT); case B_DELETE: //0x7f return(EV_NVK_DELETE); case B_HOME: //0x01 return(EV_NVK_HOME); case B_END: //0x04 return(EV_NVK_END); case B_PAGE_UP: //0x0b return(EV_NVK_PAGEUP); case B_PAGE_DOWN: //0x0c return(EV_NVK_PAGEDOWN); } if (charval == B_FUNCTION_KEY) { //0x10 switch(keyval) { case B_F1_KEY: return(EV_NVK_F1); case B_F2_KEY: return(EV_NVK_F2); case B_F3_KEY: return(EV_NVK_F3); case B_F4_KEY: return(EV_NVK_F4); case B_F5_KEY: return(EV_NVK_F5); case B_F6_KEY: return(EV_NVK_F6); case B_F7_KEY: return(EV_NVK_F7); case B_F8_KEY: return(EV_NVK_F8); case B_F9_KEY: return(EV_NVK_F9); case B_F10_KEY: return(EV_NVK_F10); case B_F11_KEY: return(EV_NVK_F11); case B_F12_KEY: return(EV_NVK_F12); //Goes all the way to EV_NVK_F34 } } //Everything else is a character return(0); //We ignore everything else return(EV_NVK__IGNORE__); } /* Turn a potential multibyte character into a single character. */ UT_UCSChar s_getUCSChar(int keyval, int modifiers, int charval, const char *bytes) { UT_UCSChar newchar; if (strlen(bytes) == 1) { newchar = bytes[0]; } else { newchar = UT_decodeUTF8char(bytes, strlen(bytes)); } return newchar; }