home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Linux / Divers / lyx-0.13.2.tar.gz / lyx-0.13.2.tar / lyx-0.13.2 / src / kbmap.C < prev    next >
C/C++ Source or Header  |  1998-04-23  |  17KB  |  664 lines

  1. /* This file is part of
  2.  * ======================================================
  3.  * 
  4.  *          LyX, The Document Processor
  5.  *      
  6.  *        Copyright (C) 1995 Matthias Ettrich
  7.  *          Copyright (C) 1995-1998 The LyX Team.
  8.  *
  9.  *======================================================*/
  10.  
  11. #include <config.h>
  12. #include <string.h>
  13. #include <stdio.h>
  14. #include "gettext.h"
  15.  
  16. //     $Id: kbmap.C,v 1.1.1.1 1998/04/23 16:02:51 larsbj Exp $    
  17.  
  18. #if !defined(lint) && !defined(WITH_WARNINGS)
  19. static char vcid[] = "$Id: kbmap.C,v 1.1.1.1 1998/04/23 16:02:51 larsbj Exp $";
  20. #endif /* lint */
  21.  
  22. #ifdef __GNUG__
  23. #pragma implementation
  24. #endif
  25.  
  26. #include "kbmap.h"
  27. #include "error.h"
  28.  
  29. // The only modifiers that we handle. We want to throw away things
  30. // like NumLock. 
  31. enum { ModsMask = ShiftMask | ControlMask | Mod1Mask};
  32.  
  33.  
  34. // === static functions ===================================================
  35.  
  36.  
  37. /* ---F+------------------------------------------------------------------ *\
  38.    Function  : printKeysym
  39.    Called by : kb_sequence::print and printKeyMap. RVDK_PATCH_5
  40.    Purpose   : prints a keysym, including modifiers.
  41.    Parameters: key    - keysym
  42.                mod    - modifiers
  43.    Returns   : string if ok, "" otherwise.
  44. \* ---F------------------------------------------------------------------- */
  45.  
  46. static
  47. LString printKeysym( KeySym key, unsigned int mod )
  48. {
  49.     LString str;
  50.     
  51.     mod &= ModsMask;
  52.     if ( mod & ShiftMask ) 
  53.         str += "S-";
  54.     if ( mod & ControlMask ) 
  55.         str += "C-";
  56.     if ( mod & Mod1Mask ) 
  57.         str += "M-";
  58.  
  59.     str += XKeysymToString(key);
  60.  
  61.     return str;
  62. }
  63.  
  64.  
  65. /* ---F+------------------------------------------------------------------ *\
  66.    Function  : printKeyTab
  67.    Called by : kb_keymap::print
  68.    Purpose   : print the keysyms found in the given key table. RVDK_PATCH_5
  69.    Parameters: tabPt  - keytable pointer
  70.    Returns   : printed string.
  71. \* ---F------------------------------------------------------------------- */
  72.  
  73.  
  74. static
  75. LString printKeyTab( kb_key *tabPt)
  76. {
  77.     LString str;
  78.     
  79.     /* -------> Print each of the slots into buf. */
  80.     for( ; (tabPt->code & 0xffff) != NoSymbol; tabPt++) {
  81.         
  82.         str += printKeysym( tabPt->code, tabPt->mod &ModsMask);
  83.         str += ' ';
  84.     }
  85.     return str;
  86. }
  87.  
  88.  
  89. // === kb_sequence methods ================================================
  90.  
  91.  
  92.  
  93. /* ---F+------------------------------------------------------------------ *\
  94.     Function  : kb_sequence::addkey
  95.     Called by : [user]
  96.     Purpose   : add a key to the sequence, look up in map and return action
  97.     Parameters: key  - keysym of key
  98.                 mod  - modifier mask
  99.                 nmod - modifier veto mask (unused now)
  100.     Returns   : action or -1 if error (no map defined or key not found)
  101. \* ---F------------------------------------------------------------------- */
  102.  
  103. int kb_sequence::addkey(KeySym key, unsigned int mod, unsigned int nmod /*=0*/)
  104. {
  105.     if(length<0) length=0;
  106.  
  107.     if(length+1 >= size) {
  108.         unsigned int *nseq = new unsigned int[size+KB_PREALLOC];
  109.         size += KB_PREALLOC;
  110.         memcpy(nseq, sequence, length*sizeof(unsigned int));
  111.         if(sequence != staticseq) delete sequence;
  112.         sequence = nseq;
  113.         nseq = new unsigned int[size];
  114.         memcpy(nseq, modifiers, length*sizeof(unsigned int));
  115.         if(modifiers != staticmod) delete modifiers;
  116.         modifiers = nseq;
  117.     }
  118.  
  119.     modifiers[length]  = mod + (nmod<<16);
  120.     sequence[length++] = key;
  121.    
  122.     if(curmap)
  123.         return curmap->lookup(key, mod, this);
  124.     
  125.     return -1;
  126. }
  127.  
  128.  
  129. /* ---F+------------------------------------------------------------------ *\
  130.     Function  : kb_sequence::parse
  131.     Called by : [user]
  132.     Purpose   : parse a string that holds a key sequence and add the keys
  133.     Parameters: s - string holding the key sequence
  134.     Returns   : 0 - if ok, error pos if error
  135.     Note      : Keys must be separated with whitespace;
  136.                 Use the keysym names used by XStringToKeysym
  137.                 Prefixes are S-, C-, M- for shift, control, meta
  138. \* ---F------------------------------------------------------------------- */
  139.  
  140. int kb_sequence::parse(LString const &s)
  141. {
  142.     int i = 0;
  143.     unsigned int mod = 0, nmod = 0;
  144.     KeySym key = 0;
  145.     
  146.     if(s.empty()) return 1;
  147.     
  148.     while (i < s.length()) {
  149.         if(((unsigned char) s[i]) <= ' ') {
  150.             i++;
  151.             continue;
  152.         }
  153.         
  154.         if(i+1 < s.length() && s[i+1]=='-')    { 
  155.             switch(s[i]) {
  156.             case 's': case 'S':
  157.                 mod |= ShiftMask;
  158.                 i+=2;
  159.                 continue;
  160.             case 'c': case 'C':
  161.                 mod |= ControlMask;
  162.                 i+=2;
  163.                 continue;
  164.             case 'm': case 'M':
  165.                 mod |= Mod1Mask;
  166.                 i+=2;
  167.                 continue;
  168.             default:
  169.                 return i+1;
  170.             }
  171.         } else if(i+2 < s.length() && s[i]=='~' && s[i+2]=='-') {
  172.             switch(s[i+1]) {
  173.             case 's': case 'S':
  174.                 nmod |= ShiftMask;
  175.                 i+=3;
  176.                 continue;
  177.             case 'c': case 'C':
  178.                 nmod |= ControlMask;
  179.                 i+=3;
  180.                 continue;
  181.             case 'm': case 'M':
  182.                 nmod |= Mod1Mask;
  183.                 i+=3;
  184.                 continue;
  185.             default:
  186.                 return i+2;
  187.             }
  188.         } else {
  189.             LString buf;
  190.             int j;
  191.             for(j = i; j < s.length() 
  192.                    && ((unsigned char)s[j]) > ' '; j++)
  193.                 buf += s[j];
  194.             
  195.             key = XStringToKeysym(buf.c_str());
  196.             if(key == NoSymbol) {
  197.                 lyxerr.debug("kbmap.C: No such keysym: "
  198.                          + buf,Error::KBMAP);
  199.                 return j;
  200.             }
  201.             i = j;
  202.             
  203.             addkey(key, mod, nmod);
  204.             mod = 0;
  205.             nmod = 0;
  206.         }
  207.     }
  208.     return 0;
  209. }
  210.  
  211.  
  212. /* ---F+------------------------------------------------------------------ *\
  213.     Function  : kb_sequence::print
  214.     Called by : [user]
  215.     Purpose   : print the currently defined sequence into a string
  216.     Parameters: when_defined  - only  print when sequence is real: length > 0.
  217.     Returns   : string
  218. \* ---F------------------------------------------------------------------- */
  219.  
  220. LString kb_sequence::print(bool when_defined) const
  221. {
  222.     LString str, str2;
  223.     int l = length;
  224.     if ( l<0 && !when_defined ) l = -l;
  225.     
  226.     for(int i = 0; i < l; i++) {
  227.         str2 = printKeysym( sequence[i], 
  228.                     modifiers[i] & ModsMask);
  229.         if (str2.empty())
  230.             return LString();
  231.  
  232.         str += str2;
  233.         str += ' ';
  234.     }
  235.  
  236.     return str;
  237. }
  238.  
  239.  
  240. /* ---F+------------------------------------------------------------------ *\
  241.     Function  : kb_sequence::printOptions
  242.     Called by : [user]
  243.     Purpose   : print the available key options from the current state in the
  244.                 sequence. RVDK_PATCH_5
  245.     Parameters: (none)
  246.     Returns   : string
  247. \* ---F------------------------------------------------------------------- */
  248.  
  249. LString kb_sequence::printOptions() const
  250. {
  251.     if ( !curmap ) 
  252.         return print(true);
  253.  
  254.     return print(true) + _("   options: ") + curmap->print();
  255. }
  256.  
  257.  
  258. /* ---F+------------------------------------------------------------------ *\
  259.     Function  : kb_sequence::delseq
  260.     Called by : [user]
  261.     Purpose   : mark the sequence as deleted
  262.     Parameters: none
  263.     Returns   : nothing
  264. \* ---F------------------------------------------------------------------- */
  265.  
  266. void kb_sequence::delseq()
  267. {
  268.     // negative length marks sequence as deleted, but we can still
  269.     // print() it or retrieve the last char using getiso()
  270.     length = -length;
  271. }
  272.  
  273.  
  274. /* ---F+------------------------------------------------------------------ *\
  275.    Function  : kb_sequence::getsym
  276.    Called by : [user], getiso
  277.    Purpose   : get the keysym of the last key in sequence
  278.    Parameters: none
  279.    Returns   : keysym
  280. \* ---F------------------------------------------------------------------- */
  281.  
  282. KeySym kb_sequence::getsym()
  283. {
  284.     int l = length;
  285.     if(l==0) return NoSymbol;
  286.     if(l<0) l = -l;
  287.     return sequence[l-1];
  288. }
  289.  
  290.  
  291. /* ---F+------------------------------------------------------------------ *\
  292.     Function  : kb_sequence::getiso
  293.     Called by : [user]
  294.     Purpose   : return iso character code of last key, if any
  295.     Parameters: none
  296.     Returns   : iso code or 0 if none
  297. \* ---F------------------------------------------------------------------- */
  298.  
  299. char kb_sequence::getiso()
  300. {
  301.     int c = getsym();
  302.     
  303.     if(c > 0xff)
  304.         return '\0';
  305.     return (char)c;
  306. }
  307.  
  308.  
  309. /* ---F+------------------------------------------------------------------ *\
  310.     Function  : kb_sequence::reset
  311.     Called by : [user]
  312.     Purpose   : reset sequence to initial state. RVDK_PATCH_5
  313.     Parameters: none
  314.     Returns   : void
  315. \* ---F------------------------------------------------------------------- */
  316.  
  317. void kb_sequence::reset()
  318. {
  319.     delseq();
  320.     curmap = stdmap;
  321.     if ( length > 0 ) length = -length;
  322. }
  323.  
  324.  
  325. // === kb_keymap methods ==================================================
  326.  
  327. // This binds a key to an action
  328. int kb_keymap::bind(LString const &seq, int action)
  329. {
  330.     kb_sequence k;
  331.  
  332.     int res = k.parse(seq);
  333.     if (!res) {
  334.         defkey(&k, action);
  335.     } else
  336.         lyxerr.debug(LString("Parse error at position ") + res +
  337.                  " in key sequence '" + seq + "'.", Error::KBMAP);
  338.     return res;
  339. }
  340.  
  341.  
  342. /* ---F+------------------------------------------------------------------ *\
  343.     Function  : kb_keymap::lookup
  344.     Called by : [user], kb_sequence::add()
  345.     Purpose   : look up a key press in a given keymap
  346.     Parameters: key - the keysym of the key press
  347.                 mod - the modifier mask of the keypress
  348.                 seq - the key-sequence retrieved so far
  349.     Returns   : user defined action; 0 for prefix key, -1 if key not found
  350. \* ---F------------------------------------------------------------------- */
  351.  
  352. int kb_keymap::lookup(KeySym key, unsigned int mod, kb_sequence *seq)
  353. {
  354.     unsigned int hashval, ksym, msk1, msk0;
  355.     kb_key *tab;
  356.  
  357.     //suppress modifier bits we do not handle
  358.     mod &= ModsMask;
  359.  
  360.     if(!table) {
  361.         // error - no keymap defined:
  362.         seq->curmap = seq->stdmap;
  363.         seq->delseq();
  364.         return -1;
  365.     }
  366.  
  367.     if(size < 0) {               // --- if hash table ---
  368.         hashval = ((key&0xff) ^ ((key>>8)&0xff)) % KB_HASHSIZE;
  369.         tab = htable[hashval];
  370.         if(!tab) {
  371.             seq->curmap = seq->stdmap;
  372.             seq->delseq();
  373.             return -1;
  374.         }
  375.     } else                       // --- else: linear list ---
  376.         tab = table;
  377.  
  378.     // --- now search the list of keys ---
  379.  
  380.     for( ; (tab->code & 0xffff) != NoSymbol; tab++) {
  381.         ksym =  tab->code;
  382.         msk1 =  tab->mod      & 0xffff;
  383.         msk0 = (tab->mod>>16) & 0xffff;
  384.  
  385.         if(ksym == key && (mod&~msk0) == msk1) {
  386.             // match found:
  387.             if(tab->table) {
  388.                  // this is a prefix key - set new map
  389.                 seq->curmap = tab->table;
  390.                 return 0;
  391.             } else {
  392.                   // final key - reset map
  393.                 seq->curmap = seq->stdmap;
  394.                 seq->delseq();
  395.                 return tab->action; // ... and return action
  396.             }
  397.         }
  398.     }
  399.     
  400.     // error - key not found:
  401.     seq->curmap = seq->stdmap;
  402.     seq->delseq();
  403.     return -1;
  404. }
  405.  
  406.  
  407. /* ---F+------------------------------------------------------------------ *\
  408.     Function  : kb_keymap::print
  409.     Called by : [user]
  410.     Purpose   : Prints all the available keysyms. RVDK_PATCH_5
  411.     Parameters: (none)
  412.     Returns   : string
  413. \* ---F------------------------------------------------------------------- */
  414.  
  415. LString kb_keymap::print() const
  416. {
  417.     LString str;
  418.     
  419.     if ( !table ) 
  420.         return LString();
  421.    
  422.     // Hash table. Process each of its slots recursively and return. 
  423.     if ( size < 0 ) {   
  424.         for ( int ix = 0; ix < KB_HASHSIZE ; ix++ ) {
  425.             if ( htable[ix] ) 
  426.                 str +=  printKeyTab(htable[ix]);
  427.         }
  428.     } else {
  429.         /* -------> Normal table. */
  430.         str += printKeyTab(table); 
  431.     }
  432.     return str;
  433. }
  434.  
  435.  
  436. /* ---F+------------------------------------------------------------------ *\
  437.     Function  : kb_keymap::defkey
  438.     Called by : [user]
  439.     Purpose   : define an action for a key sequence
  440.     Parameters: seq    - the key sequence
  441.                 action - the action to be defined
  442.                 idx    - recursion depth
  443.     Returns   : 0 if ok.
  444. \* ---F------------------------------------------------------------------- */
  445.  
  446. int kb_keymap::defkey(kb_sequence *seq, int action, int idx /*=0*/)
  447. {
  448.     int      tsize;
  449.     unsigned int code, modmsk;
  450.     kb_key  *tab, **ptab;
  451.  
  452.     code = seq->sequence[idx];
  453.     modmsk = seq->modifiers[idx];
  454.     if(code == NoSymbol) return -1;
  455.  
  456.     // --- get list------------------------------------------------------
  457.     if(!table) {
  458.         // If we don't have any yet, make an empty one
  459.         table = new kb_key[KB_PREALLOC];
  460.         table[0].code = NoSymbol;
  461.         tab   =  table;
  462.         ptab  = &table;
  463.         size  = KB_PREALLOC;
  464.     } else if(size<0) {
  465.         // Hash table.
  466.         int hashval = (code&0xffff);
  467.         hashval = ((hashval&0xff) ^ ((hashval>>8)&0xff)) % KB_HASHSIZE;
  468.         tab  = htable[hashval];
  469.         ptab = htable+hashval;
  470.         if(!tab) {
  471.             tab = new kb_key[KB_PREALLOC];
  472.             tab[0].code = NoSymbol;
  473.             *ptab = tab;
  474.         }
  475.     } else {
  476.         tab  =  table;
  477.         ptab = &table;
  478.     }
  479.  
  480.     // --- check if key is already there --------------------------------
  481.  
  482.     kb_key *t;
  483.     for(t = tab, tsize=1; t->code != NoSymbol; t++, tsize++) {
  484.         if(code == t->code && modmsk == t->mod) { 
  485.             // -- overwrite binding ---
  486.             if(idx+1 == seq->length) {
  487.                 lyxerr.debug("Warning: New binding for `" 
  488.                          + seq->print(true) + 
  489.                          "' is overriding old binding...", 
  490.                          Error::KEY);
  491.  
  492.                 if(t->table) {
  493.                     delete t->table;
  494.                     t->table = 0;
  495.                 }
  496.                 t->action = action;
  497.                 return 0;
  498.             } else if (!t->table) {
  499.                 lyxerr.print("Error: New binding for `" 
  500.                     + seq->print(true) + 
  501.                     "' is overriding old binding...");
  502.                 return -1;
  503.             } else
  504.                 return t->table->defkey(seq, action, idx+1);
  505.         }
  506.     }
  507.  
  508.     // --- extend list if necessary -------------------------------------
  509.  
  510.     if(tsize % KB_PREALLOC == 0) {
  511.         kb_key *nt = new kb_key[tsize+KB_PREALLOC];
  512.         // Set to NULL as table is used uninitialised later (thornley)
  513.         nt[tsize].table = NULL;
  514.         memcpy(nt, tab, tsize*sizeof(kb_key));
  515.         *ptab = nt;
  516.         delete[] tab;
  517.         tab = nt;
  518.         if(size>=0) size = tsize+KB_PREALLOC;
  519.     }
  520.  
  521.     // --- add action ---------------------------------------------------
  522.  
  523.     tab[tsize--].code = NoSymbol;
  524.     tab[tsize].code = code;
  525.     tab[tsize].mod  = modmsk;
  526.     kb_key *newone = &tab[tsize];
  527.     
  528.     // --- convert list to hash table if necessary ----------------------
  529.  
  530.     if(size>=0 && tsize>=32) {
  531.         kb_key *oldtab = tab;
  532.         kb_key **nht = new kb_key*[KB_HASHSIZE];
  533.         for(int i = 0; i < KB_HASHSIZE; i++)
  534.             nht[i] = 0;
  535.         htable = nht;
  536.         size   = -KB_HASHSIZE;
  537.         
  538.         // --- copy old keys to new hash table ---
  539.         int hashval;
  540.         for(kb_key *tu = oldtab; tu->code != NoSymbol; tu++){
  541.             // copy values from oldtab to htable
  542.             hashval = (tu->code&0xffff);
  543.             hashval = ((hashval&0xff) ^ ((hashval>>8)&0xff)) % KB_HASHSIZE;
  544.             tab  = htable[hashval];
  545.             
  546.             if(!tab){
  547.                 htable[hashval] = tab = new kb_key[KB_PREALLOC];
  548.                 tab->code = NoSymbol;
  549.             }
  550.             int ts = 1;
  551.             for(kb_key *tt = tab; tt->code != NoSymbol; tt++)
  552.                 ts++;
  553.             if(ts % KB_PREALLOC == 0){
  554.                 // extend table
  555.                 kb_key *nt = new kb_key[ts+KB_PREALLOC];
  556.                 memcpy(nt, tab, ts*sizeof(kb_key));
  557.                 htable[hashval] = nt;
  558.                 delete[] tab;
  559.                 tab = nt;
  560.             }
  561.             tab[ts--].code = NoSymbol;
  562.             tab[ts].code   = tu->code;
  563.             tab[ts].mod    = tu->mod;
  564.             tab[ts].action = tu->action;
  565.             tab[ts].table  = tu->table;
  566.             
  567.             if(tu == newone)
  568.                 newone = &tab[ts];
  569.         }
  570.         delete[] oldtab;
  571.     }
  572.     
  573.     // --- define rest of sequence --------------------------------------
  574.  
  575.     if(idx+1 == seq->length) {
  576.         newone->action = action;
  577.         newone->table  = 0;
  578.         return 0;
  579.     } else {
  580.         newone->table = new kb_keymap;
  581.         int res = newone->table->defkey(seq, action, idx+1);
  582.         return res;
  583.     }
  584. }
  585.  
  586.  
  587. /* ---F+------------------------------------------------------------------ *\
  588.     Function  : kb_keymap::~kb_keymap
  589.     Called by : [destructor]
  590.     Purpose   : free keymap and its descendents
  591.     Parameters: none
  592.     Returns   : nothing
  593. \* ---F------------------------------------------------------------------- */
  594.  
  595. kb_keymap::~kb_keymap()
  596. {
  597.     if(!table) return;
  598.     if(size<0) {
  599.         for(int i=0; i < KB_HASHSIZE; i++) {
  600.             if(htable[i]) {
  601.                 for(kb_key *t = htable[i]; t->code != NoSymbol; t++)
  602.                     if(t->table)
  603.                         delete t->table;
  604.                 delete htable[i];
  605.             }
  606.         }
  607.         delete htable;
  608.     } else {
  609.         for(kb_key *t = table; t->code != NoSymbol; t++)
  610.             if(t->table)
  611.                 delete t->table;
  612.         delete table;
  613.     }
  614. }
  615.  
  616. LString keyname(kb_key k) {
  617.     return printKeysym(k.code, k.mod);
  618. }
  619.  
  620. // Finds a key for a keyaction, if possible
  621. LString kb_keymap::findbinding(int act) const {
  622.     LString res;
  623.     if (!table)
  624.         return res;
  625.  
  626.     if (size<0) {
  627.         for(int i=0; i < KB_HASHSIZE; i++) {
  628.             if(htable[i]) {
  629.                 for(kb_key *t = htable[i]; t->code != NoSymbol; t++) {
  630.                     if(t->table) {
  631.                         LString suffix = t->table->findbinding(act);
  632.                         suffix.strip(' ');
  633.                         suffix.strip(']');
  634.                         suffix.frontStrip('[');
  635.                         if (!suffix.empty()) {
  636.                             res += "[" + keyname(*t) + " " + suffix + "] ";
  637.                         }
  638.                     } else if (t->action == act) {
  639.                         res += "[" + keyname(*t) + "] ";
  640.                     }
  641.                 }
  642.             }
  643.         }
  644.     } else {
  645.         for(kb_key *t = table; t->code != NoSymbol; t++) {
  646.             if(t->table) {
  647.                 LString suffix = t->table->findbinding(act);
  648.                 suffix.strip(' ');
  649.                 suffix.strip(']');
  650.                 suffix.frontStrip('[');
  651.                 if (!suffix.empty()) {
  652.                     res += "[" + keyname(*t) + " " + suffix + "] ";
  653.                 }
  654.             } else if (t->action == act) {
  655.                 res += "[" + keyname(*t) + "] ";
  656.             }
  657.         }
  658.     }
  659.     return res;
  660. }
  661.  
  662.  
  663. /* === End of File: kbmap.C ============================================== */
  664.