/* AbiSource Program Utilities * Copyright (C) 1998 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 "ut_assert.h" #include "ut_debugmsg.h" #include "ut_types.h" #include "ev_EditMethod.h" #include "ev_EditBinding.h" #include "ev_NamedVirtualKey.h" /*****************************************************************/ /*****************************************************************/ EV_EditBinding::EV_EditBinding(EV_EditBindingMap * pebm) { m_ebt = EV_EBT_PREFIX; u.m_pebm = pebm; } EV_EditBinding::EV_EditBinding(EV_EditMethod * pem) { m_ebt = EV_EBT_METHOD; u.m_pem = pem; } EV_EditBindingMap * EV_EditBinding::getMap(void) const { UT_ASSERT(m_ebt == EV_EBT_PREFIX); return u.m_pebm; } EV_EditMethod * EV_EditBinding::getMethod(void) const { UT_ASSERT(m_ebt == EV_EBT_METHOD); return u.m_pem; } /*****************************************************************/ /*****************************************************************/ class ev_EB_MouseTable { public: ev_EB_MouseTable() { memset(m_peb,0,sizeof(m_peb)); }; ~ev_EB_MouseTable() { for (UT_uint32 i=0; i < EV_COUNT_EMO; i++) for (UT_uint32 j=0; j < EV_COUNT_EMS; j++) for (UT_uint32 k=0; k< EV_COUNT_EMC; k++) if (m_peb[i][j][k]) delete m_peb[i][j][k]; } EV_EditBinding * m_peb[EV_COUNT_EMO][EV_COUNT_EMS][EV_COUNT_EMC]; }; class ev_EB_NVK_Table { public: ev_EB_NVK_Table() { memset(m_peb,0,sizeof(m_peb)); }; ~ev_EB_NVK_Table() { for (UT_sint32 i=0; i < static_cast(EV_COUNT_NVK); i++) for (UT_sint32 j=0; j < EV_COUNT_EMS; j++) if (m_peb[i][j]) delete m_peb[i][j]; } EV_EditBinding * m_peb[EV_COUNT_NVK][EV_COUNT_EMS]; }; class ev_EB_Char_Table { public: ev_EB_Char_Table() { memset(m_peb,0,sizeof(m_peb)); }; ~ev_EB_Char_Table() { for (UT_sint32 i=0; i < 256; i++) for (UT_sint32 j=0; j < EV_COUNT_EMS_NoShift; j++) if (m_peb[i][j]) delete m_peb[i][j]; } // TODO Note[1] we currently limit the range on regular (non-nvk) // TODO Note[1] keys to 256. This is probably OK for Latin1, but // TODO Note[1] will probably need to be re-addressed later. EV_EditBinding * m_peb[256][EV_COUNT_EMS_NoShift]; }; /*****************************************************************/ /*****************************************************************/ EV_EditBindingMap::EV_EditBindingMap(EV_EditMethodContainer * pemc) { UT_ASSERT(pemc); m_pemc = pemc; UT_sint32 i = 0; for (i=0; im_peb[n_emo][n_ems][n_emc-1]; } else if (EV_IsKeyboard(eb)) // a keyevent, find out what kind { if (eb & EV_EKP_NAMEDKEY) // a NVK { if (!m_pebNVK) return 0; // no bindings of anykind for nvk keys UT_uint32 n_nvk = EV_NVK_ToNumber(eb); UT_uint32 n_ems = EV_EMS_ToNumber(eb); return m_pebNVK->m_peb[n_nvk][n_ems]; } else // not a NVK -- regular char { if (!m_pebChar) return 0; // no bindings of anykind for non-nvk keys UT_uint32 n_evk = EV_EVK_ToNumber(eb); if (n_evk >= 256) { if ( n_evk >= 256 && (n_evk - 65280) < 256) n_evk -= 65280; // quick fix else { n_evk = 'a'; /* in hopes that there will be 'insertData' method assigned to plain 'a' */ } }; UT_uint32 n_ems = EV_EMS_ToNumberNoShift(eb); return m_pebChar->m_peb[n_evk][n_ems]; } } UT_ASSERT(0); return 0; } bool EV_EditBindingMap::setBinding(EV_EditBits eb, const char * szMethodName) { EV_EditMethod * pem = m_pemc->findEditMethodByName(szMethodName); if (!pem) { UT_DEBUGMSG(("Unknown method name [%s] in binding table.\n",szMethodName)); UT_ASSERT(pem); // TODO remove this and find a better way of doing a spelling-check... return false; } EV_EditBinding * peb = new EV_EditBinding(pem); if (!peb) return false; return setBinding(eb,peb); } bool EV_EditBindingMap::setBinding(EV_EditBits eb, EV_EditBinding * peb) { // this handles keyboard (nvk and char) and mouse. // return false if the given location is already bound. if (EV_IsMouse(eb)) // mouse { UT_uint32 n_emb = EV_EMB_ToNumber(eb)-1; class ev_EB_MouseTable * p = m_pebMT[n_emb]; if (!p) { m_pebMT[n_emb] = new ev_EB_MouseTable(); p = m_pebMT[n_emb]; if (!p) { delete peb; return false; } } UT_uint32 n_emo = EV_EMO_ToNumber(eb)-1; UT_uint32 n_ems = EV_EMS_ToNumber(eb); UT_uint32 n_emc = EV_EMC_ToNumber(eb); UT_return_val_if_fail(n_emc != 0, 0); if (p->m_peb[n_emo][n_ems][n_emc-1]) { delete peb; return false; } p->m_peb[n_emo][n_ems][n_emc-1] = peb; return true; } else if (EV_IsKeyboard(eb)) // a keyevent, find out what kind { if (eb & EV_EKP_NAMEDKEY) // nvk { if (!m_pebNVK) { m_pebNVK = new ev_EB_NVK_Table(); if (!m_pebNVK) { delete peb; return false; } } UT_uint32 n_nvk = EV_NVK_ToNumber(eb); UT_uint32 n_ems = EV_EMS_ToNumber(eb); if (m_pebNVK->m_peb[n_nvk][n_ems]) { delete peb; return false; } m_pebNVK->m_peb[n_nvk][n_ems] = peb; return true; } else // a non-nvk -- regular char { if (!m_pebChar) { m_pebChar = new ev_EB_Char_Table(); if (!m_pebChar) return false; } UT_uint32 n_evk = EV_EVK_ToNumber(eb); UT_ASSERT(n_evk < 256); // TODO see note [1] above. UT_uint32 n_ems = EV_EMS_ToNumberNoShift(eb); if (m_pebChar->m_peb[n_evk][n_ems]) { delete peb; return false; } m_pebChar->m_peb[n_evk][n_ems] = peb; return true; } } delete peb; UT_ASSERT(0); return 0; } bool EV_EditBindingMap::removeBinding(EV_EditBits eb) { // this handles keyboard (nvk and char) and mouse. // remove the binding from the map. // return true if binding updated. // we do not free the unreferenced binding. if (EV_IsMouse(eb)) // mouse { UT_uint32 n_emb = EV_EMB_ToNumber(eb)-1; class ev_EB_MouseTable * p = m_pebMT[n_emb]; if (!p) return false; UT_uint32 n_emo = EV_EMO_ToNumber(eb)-1; UT_uint32 n_ems = EV_EMS_ToNumber(eb); UT_uint32 n_emc = EV_EMC_ToNumber(eb); UT_return_val_if_fail(n_emc != 0, 0); p->m_peb[n_emo][n_ems][n_emc-1] = 0; return true; } else if (EV_IsKeyboard(eb)) // a keyevent, find out what kind { if (eb & EV_EKP_NAMEDKEY) // nvk { if (!m_pebNVK) return false; UT_uint32 n_nvk = EV_NVK_ToNumber(eb); UT_uint32 n_ems = EV_EMS_ToNumber(eb); m_pebNVK->m_peb[n_nvk][n_ems] = 0; return true; } else // a non-nvk -- regular char { if (!m_pebChar) return false; UT_uint32 n_evk = EV_EVK_ToNumber(eb); UT_ASSERT(n_evk < 256); // TODO see note [1] above. UT_uint32 n_ems = EV_EMS_ToNumberNoShift(eb); m_pebChar->m_peb[n_evk][n_ems] = 0; return true; } } UT_ASSERT(0); return 0; } const char * EV_EditBindingMap::getShortcutFor(const EV_EditMethod * pEM) const { UT_ASSERT(pEM); // lookup the keyboard shortcut bound to pEM, if any EV_EditModifierState ems = 0; EV_EditBinding * pEB; UT_sint32 i, j; char shortcut = 0; // search characters first bool bChar = false; /* we lookup the table in decreasing order to be able to catch lowercase BEFORE uppercase. Uppercase = Shift modifier. That is the rule */ for (i=255; (i >= 0) && !bChar; i--) for (j=0; j < EV_COUNT_EMS_NoShift; j++) if (m_pebChar->m_peb[i][j]) { // only check non-null entries pEB = m_pebChar->m_peb[i][j]; if ((pEB->getType() == EV_EBT_METHOD) && (pEB->getMethod() == pEM)) { // bingo bChar = true; shortcut = i; ems = EV_EMS_FromNumberNoShift(j); break; } } bool bNVK = false; if (!bChar) { // then search NVKs for (i=0; (i < static_cast(EV_COUNT_NVK)) && !bNVK; i++) for (j=0; j < EV_COUNT_EMS; j++) if (m_pebNVK->m_peb[i][j]) { // only check non-null entries pEB = m_pebNVK->m_peb[i][j]; if ((pEB->getType() == EV_EBT_METHOD) && (pEB->getMethod() == pEM)) { // bingo bNVK = true; shortcut = i; ems = EV_EMS_FromNumber(j); break; } } } if (!bChar && !bNVK) return NULL; // translate into displayable string static char buf[128]; memset(buf,0,NrElements(buf)); if (ems&EV_EMS_CONTROL) strcat(buf, "Ctrl+"); if (ems&EV_EMS_SHIFT) strcat(buf, "Shift+"); if (ems&EV_EMS_ALT) strcat(buf, "Alt+"); if (bChar) { if ((shortcut >= 'A') && (shortcut <= 'Z')) { /* always return an uppercase letter for the shortcut, unlike the mapper do */ if (!(ems&EV_EMS_SHIFT)) { strcat(buf, "Shift+"); } } else shortcut = toupper (shortcut); int len = strlen(buf); buf[len] = shortcut; } else { // translate NVK const char * szNVK = NULL; // TODO: look these up from table, rather than switch switch(EV_NamedKey(shortcut)) { case EV_NVK_DELETE: szNVK = "Del"; break; case EV_NVK_F1: szNVK = "F1"; break; case EV_NVK_F3: szNVK = "F3"; break; case EV_NVK_F4: szNVK = "F4"; break; case EV_NVK_F7: szNVK = "F7"; break; case EV_NVK_F10: szNVK = "F10"; break; case EV_NVK_F11: szNVK = "F11"; break; case EV_NVK_F12: szNVK = "F12"; break; default: szNVK = "unmapped NVK"; break; } strcat(buf, szNVK); } return buf; } bool EV_EditBindingMap::parseEditBinding(void) { /* TODO here we import a binding from a primitive ascii format ** TODO or XML syntax. */ return false; }