]> git.lyx.org Git - lyx.git/blob - src/kbmap.C
8c11970cdb43809b93d30bcd911e636546254b35
[lyx.git] / src / kbmap.C
1 /* This file is part of
2  * ====================================================== 
3  * 
4  *           LyX, The Document Processor
5  *       
6  *           Copyright 1995 Matthias Ettrich
7  *           Copyright 1995-2000 The LyX Team.
8  *
9  * ====================================================== */
10
11 #include <config.h>
12
13 #include <cstring>
14 #include <X11/Xlib.h>
15
16 #ifdef __GNUG__
17 #pragma implementation
18 #endif
19
20 #include "kbmap.h"
21 #include "kbsequence.h"
22 #include "debug.h"
23
24 // The only modifiers that we handle. We want to throw away things
25 // like NumLock. 
26 enum { ModsMask = ShiftMask | ControlMask | Mod1Mask };
27
28
29 // === static functions =================================================== 
30
31
32 /* ---F+------------------------------------------------------------------ *\
33    Function  : printKeysym
34    Called by : kb_sequence::print and printKeyMap. RVDK_PATCH_5
35    Purpose   : prints a keysym, including modifiers.
36    Parameters: key    - keysym
37                mod    - modifiers
38                buf    - string where the result goes
39                maxlen - length of string (including '\0')
40    Returns   : length of printed string if ok, 0 otherwise.
41 \* ---F------------------------------------------------------------------- */
42 void printKeysym(unsigned int key, unsigned int mod, string & buf)
43 {
44         mod &= ModsMask;
45
46         char * s = XKeysymToString(key);
47         
48         if (mod & ShiftMask) buf += "S-";
49         if (mod & ControlMask) buf += "C-";
50         if (mod & Mod1Mask) buf += "M-";
51         if (s) buf += s;
52 }
53
54
55 /* ---F+------------------------------------------------------------------ *\
56    Function  : printKeyTab
57    Called by : kb_keymap::print
58    Purpose   : print the keysyms found in the given key table. RVDK_PATCH_5
59    Parameters: tabPt  - keytable pointer
60                buf    - string where the result goes
61                maxLen - length of string (including '\0')
62    Returns   : length of printed string.
63 \* ---F------------------------------------------------------------------- */
64
65 void kb_keymap::printKey(kb_key const & key, string & buf)
66 {
67         printKeysym(key.code, key.mod & 0xffff, buf);
68 }
69
70
71 // This binds a key to an action
72 int kb_keymap::bind(char const * seq, int action)
73 {
74         kb_sequence k;
75
76         int res = k.parse(seq);
77         if (!res) {
78                 defkey(&k, action);
79         } else
80                 lyxerr[Debug::KBMAP] << "Parse error at position " << res
81                                      << " in key sequence '" << seq << "'."
82                                      << endl;
83         return res;
84 }
85
86
87 /* ---F+------------------------------------------------------------------ *\
88     Function  : kb_keymap::lookup
89     Called by : [user], kb_sequence::add()
90     Purpose   : look up a key press in a given keymap
91     Parameters: key - the keysym of the key press
92                 mod - the modifier mask of the keypress
93                 seq - the key-sequence retrieved so far
94     Returns   : user defined action; 0 for prefix key, -1 if key not found
95 \* ---F------------------------------------------------------------------- */
96
97 int kb_keymap::lookup(unsigned int key,
98                       unsigned int mod, kb_sequence * seq) const
99 {
100         if (table.empty()) {
101                 seq->curmap = seq->stdmap;
102                 seq->delseq();
103                 return -1;
104         }
105
106         unsigned int msk1, msk0;
107         //suppress modifier bits we do not handle
108         mod &= ModsMask;
109
110         for (Table::const_iterator cit = table.begin();
111              cit != table.end(); ++cit) {
112                 msk1 = (*cit).mod & 0xffff;
113                 msk0 = ((*cit).mod >> 16) & 0xffff;
114                 if ((*cit).code == key && (mod & ~msk0) == msk1) {
115                         // math found:
116                         if ((*cit).table) {
117                                 // this is a prefix key - set new map
118                                 seq->curmap = (*cit).table;
119                                 return 0;
120                         } else {
121                                 // final key - reset map
122                                 seq->curmap = seq->stdmap;
123                                 seq->delseq();
124                                 return (*cit).action;
125                         }
126                 }
127         }
128
129         // error - key not found:
130         seq->curmap = seq->stdmap;
131         seq->delseq();
132         return -1;
133 }
134
135
136 /* ---F+------------------------------------------------------------------ *\
137     Function  : kb_keymap::print
138     Called by : [user]
139     Purpose   : Prints all the available keysyms. RVDK_PATCH_5
140     Parameters: buf    - string where output goes.
141                maxLen - available length in string, including `\0'.
142     Returns   : updated maxLen.
143 \* ---F------------------------------------------------------------------- */
144
145 void kb_keymap::print(string & buf) const
146 {
147         for (Table::const_iterator cit = table.begin();
148              cit != table.end(); ++cit) {
149                 printKey((*cit), buf);
150                 buf += ' ';
151         }
152 }
153
154
155 /* ---F+------------------------------------------------------------------ *\
156     Function  : kb_keymap::defkey
157     Called by : [user]
158     Purpose   : define an action for a key sequence
159     Parameters: seq    - the key sequence
160                 action - the action to be defined
161                 idx    - recursion depth
162     Returns   : 0 if ok.
163 \* ---F------------------------------------------------------------------- */
164
165 int kb_keymap::defkey(kb_sequence * seq, int action, int idx /*= 0*/)
166 {
167         unsigned int code = seq->sequence[idx];
168         if(code == NoSymbol) return -1;
169
170         unsigned int modmsk = seq->modifiers[idx];
171
172         // --- check if key is already there --------------------------------
173         if (table.size() != 0) // without this I get strange crashes
174         for (Table::iterator it = table.begin(); it != table.end(); ++it) {
175                 if (code == (*it).code && modmsk == (*it).mod) {
176                         // overwrite binding
177                         if (idx + 1 == seq->length) {
178                                 string buf;
179                                 seq->print(buf, true);
180                                 lyxerr[Debug::KEY]
181                                         << "Warning: New binding for '"
182                                         << buf
183                                         << "' is overriding old binding..."
184                                         << endl;
185                                 if((*it).table) {
186                                         delete (*it).table;
187                                         (*it).table = 0;
188                                 }
189                                 (*it).action = action;
190                                 return 0;
191                         } else if (!(*it).table) {
192                                 string buf;
193                                 seq->print(buf, true);
194                                 lyxerr << "Error: New binding for '" << buf
195                                        << "' is overriding old binding..."
196                                        << endl;
197                                 return -1;
198                         } else {
199                                 return (*it).table->defkey(seq, action,
200                                                            idx + 1);
201                         }
202                 }
203         }
204
205         Table::iterator newone = table.insert(table.end(), kb_key());
206         (*newone).code = code;
207         (*newone).mod = modmsk;
208         if (idx + 1 == seq->length) {
209                 (*newone).action = action;
210                 (*newone).table = 0;
211                 return 0;
212         } else {
213                 (*newone).table = new kb_keymap;
214                 return (*newone).table->defkey(seq, action, idx + 1);
215         }
216 }
217
218
219 /* ---F+------------------------------------------------------------------ *\
220     Function  : kb_keymap::~kb_keymap
221     Called by : [destructor]
222     Purpose   : free keymap and its descendents
223     Parameters: none
224     Returns   : nothing
225 \* ---F------------------------------------------------------------------- */
226
227 kb_keymap::~kb_keymap()
228 {
229         // This could be done by a destructor in kb_key.
230         for(Table::iterator it = table.begin(); it != table.end(); ++it) {
231                 delete (*it).table;
232         }
233 }
234
235
236 string kb_keymap::keyname(kb_key const & k)
237 {
238         string buf;
239         printKeysym(k.code, k.mod, buf);
240         return buf;
241 }
242
243
244 // Finds a key for a keyaction, if possible
245 string kb_keymap::findbinding(int act) const
246 {
247         string res;
248         if (table.empty()) return res;
249
250         for(Table::const_iterator cit = table.begin();
251             cit != table.end(); ++cit) {
252                 if ((*cit).table) {
253                         string suffix = (*cit).table->findbinding(act);
254                         suffix = strip(suffix, ' ');
255                         suffix = strip(suffix, ']');
256                         suffix = frontStrip(suffix, '[');
257                         if (!suffix.empty()) {
258                                 res += "[" + keyname((*cit)) + " "
259                                         + suffix + "] ";
260                         }
261                 } else if ((*cit).action == act) {
262                         res += "[" + keyname((*cit)) + "] ";
263                 }
264         }
265         return res;
266 }
267
268 /* === End of File: kbmap.C ============================================== */