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