diff options
Diffstat (limited to 'src/Keys.cc')
-rw-r--r-- | src/Keys.cc | 251 |
1 files changed, 87 insertions, 164 deletions
diff --git a/src/Keys.cc b/src/Keys.cc index b1f6763..2404a0a 100644 --- a/src/Keys.cc +++ b/src/Keys.cc | |||
@@ -94,6 +94,7 @@ using std::endl; | |||
94 | using std::string; | 94 | using std::string; |
95 | using std::vector; | 95 | using std::vector; |
96 | using std::ifstream; | 96 | using std::ifstream; |
97 | using std::pair; | ||
97 | 98 | ||
98 | Keys::Keys(): | 99 | Keys::Keys(): |
99 | m_display(FbTk::App::instance()->display()) | 100 | m_display(FbTk::App::instance()->display()) |
@@ -109,14 +110,8 @@ Keys::~Keys() { | |||
109 | 110 | ||
110 | /// Destroys the keytree | 111 | /// Destroys the keytree |
111 | void Keys::deleteTree() { | 112 | void Keys::deleteTree() { |
112 | for (keyspace_t::iterator map_it = m_map.begin(); map_it != m_map.end(); ++map_it) { | 113 | for (keyspace_t::iterator map_it = m_map.begin(); map_it != m_map.end(); ++map_it) |
113 | keylist_t::iterator it = map_it->second->begin(); | ||
114 | const keylist_t::iterator it_end = map_it->second->end(); | ||
115 | for ( ; it != it_end; it++) | ||
116 | delete *it; | ||
117 | map_it->second->clear(); | ||
118 | delete map_it->second; | 114 | delete map_it->second; |
119 | } | ||
120 | m_map.clear(); | 115 | m_map.clear(); |
121 | } | 116 | } |
122 | 117 | ||
@@ -129,13 +124,10 @@ bool Keys::load(const char *filename) { | |||
129 | if (!filename) | 124 | if (!filename) |
130 | return false; | 125 | return false; |
131 | 126 | ||
132 | //ungrab all keys | ||
133 | FbTk::KeyUtil::ungrabKeys(); | ||
134 | |||
135 | //free memory of previous grabs | 127 | //free memory of previous grabs |
136 | deleteTree(); | 128 | deleteTree(); |
137 | 129 | ||
138 | m_map["default:"] = new keylist_t; | 130 | m_map["default:"] = new t_key(0,0); |
139 | 131 | ||
140 | FbTk::App::instance()->sync(false); | 132 | FbTk::App::instance()->sync(false); |
141 | 133 | ||
@@ -144,21 +136,25 @@ bool Keys::load(const char *filename) { | |||
144 | if (!infile) | 136 | if (!infile) |
145 | return false; // faild to open file | 137 | return false; // faild to open file |
146 | 138 | ||
147 | m_current_line = 0;//current line, so we can tell the user where the fault is | 139 | unsigned int current_line = 0;//so we can tell the user where the fault is |
148 | 140 | ||
149 | while (!infile.eof()) { | 141 | while (!infile.eof()) { |
150 | string linebuffer; | 142 | string linebuffer; |
151 | 143 | ||
152 | getline(infile, linebuffer); | 144 | getline(infile, linebuffer); |
153 | 145 | ||
154 | m_current_line++; | 146 | current_line++; |
155 | 147 | ||
156 | addBinding(linebuffer); | 148 | if (!addBinding(linebuffer)) { |
149 | cerr<<_FB_CONSOLETEXT(Keys, InvalidKeyMod, | ||
150 | "Keys: Invalid key/modifier on line", | ||
151 | "A bad key/modifier string was found on line (number following)")<<" "<< | ||
152 | current_line<<"): "<<linebuffer<<endl; | ||
153 | } | ||
157 | } // end while eof | 154 | } // end while eof |
158 | 155 | ||
159 | m_current_line = 0; | ||
160 | m_filename = filename; | 156 | m_filename = filename; |
161 | m_keylist = m_map["default:"]; | 157 | keyMode("default"); |
162 | return true; | 158 | return true; |
163 | } | 159 | } |
164 | 160 | ||
@@ -189,16 +185,16 @@ bool Keys::addBinding(const string &linebuffer) { | |||
189 | return true; // still a valid line. | 185 | return true; // still a valid line. |
190 | 186 | ||
191 | unsigned int key = 0, mod = 0; | 187 | unsigned int key = 0, mod = 0; |
192 | t_key *current_key=0, *last_key=0; | ||
193 | size_t argc = 0; | 188 | size_t argc = 0; |
194 | string keyMode = "default:"; | 189 | t_key *current_key=m_map["default:"]; |
190 | t_key *first_new_keylist = current_key, *first_new_key=0; | ||
195 | 191 | ||
196 | if (val[0][val[0].length()-1] == ':') { | 192 | if (val[0][val[0].length()-1] == ':') { |
197 | argc++; | 193 | argc++; |
198 | keyspace_t::iterator it = m_map.find(val[0]); | 194 | keyspace_t::iterator it = m_map.find(val[0]); |
199 | if (it == m_map.end()) | 195 | if (it == m_map.end()) |
200 | m_map[val[0]] = new keylist_t; | 196 | m_map[val[0]] = new t_key(0,0); |
201 | keyMode = val[0]; | 197 | current_key = m_map[val[0]]; |
202 | } | 198 | } |
203 | _FB_USES_NLS; | 199 | _FB_USES_NLS; |
204 | // for each argument | 200 | // for each argument |
@@ -209,9 +205,7 @@ bool Keys::addBinding(const string &linebuffer) { | |||
209 | int tmpmod = FbTk::KeyUtil::getModifier(val[argc].c_str()); | 205 | int tmpmod = FbTk::KeyUtil::getModifier(val[argc].c_str()); |
210 | if(tmpmod) | 206 | if(tmpmod) |
211 | mod |= tmpmod; //If it's a modifier | 207 | mod |= tmpmod; //If it's a modifier |
212 | else if (strcasecmp("NONE",val[argc].c_str()) == 0) | 208 | else if (strcasecmp("NONE",val[argc].c_str())) { |
213 | mod = 0; | ||
214 | else { | ||
215 | // keycode covers the following three two-byte cases: | 209 | // keycode covers the following three two-byte cases: |
216 | // 0x - hex | 210 | // 0x - hex |
217 | // +[1-9] - number between +1 and +9 | 211 | // +[1-9] - number between +1 and +9 |
@@ -229,111 +223,86 @@ bool Keys::addBinding(const string &linebuffer) { | |||
229 | } else // convert from string symbol | 223 | } else // convert from string symbol |
230 | key = FbTk::KeyUtil::getKey(val[argc].c_str()); | 224 | key = FbTk::KeyUtil::getKey(val[argc].c_str()); |
231 | 225 | ||
232 | if (key == 0) { | 226 | if (key == 0) |
233 | cerr<<_FB_CONSOLETEXT(Keys, InvalidKeyMod, | ||
234 | "Keys: Invalid key/modifier on line", | ||
235 | "A bad key/modifier string was found on line (number following)")<<" "<< | ||
236 | m_current_line<<"): "<<linebuffer<<endl; | ||
237 | return false; | 227 | return false; |
238 | } | 228 | if (!first_new_key) { |
239 | if (!current_key) { | 229 | first_new_keylist = current_key; |
240 | current_key = new t_key(key, mod); | 230 | current_key = current_key->find(key, mod); |
241 | last_key = current_key; | 231 | if (!current_key) { |
232 | first_new_key = new t_key(key, mod); | ||
233 | current_key = first_new_key; | ||
234 | } else if (*current_key->m_command) // already being used | ||
235 | return false; | ||
242 | } else { | 236 | } else { |
243 | t_key *temp_key = new t_key(key, mod); | 237 | t_key *temp_key = new t_key(key, mod); |
244 | last_key->keylist.push_back(temp_key); | 238 | current_key->keylist.push_back(temp_key); |
245 | last_key = temp_key; | 239 | current_key = temp_key; |
246 | } | 240 | } |
241 | mod = 0; | ||
242 | key = 0; | ||
247 | } | 243 | } |
248 | 244 | ||
249 | } else { // parse command line | 245 | } else { // parse command line |
250 | if (last_key == 0) { | 246 | if (!first_new_key) |
251 | cerr<<_FB_CONSOLETEXT(Keys, BadLine, "Keys: Error on line", "Error on line (number following)")<<": "<<m_current_line<<endl; | ||
252 | cerr<<"> "<<linebuffer<<endl; | ||
253 | return false; | 247 | return false; |
254 | } | ||
255 | bool ret_val = true; | ||
256 | const char *str = | ||
257 | FbTk::StringUtil::strcasestr(linebuffer.c_str(), | ||
258 | val[argc].c_str() + 1); // +1 to skip ':' | ||
259 | if (str == 0) { | ||
260 | cerr<<_FB_CONSOLETEXT(Keys, BadLine, "Keys: Error on line", "Error on line (number following)")<<": "<<m_current_line<<endl; | ||
261 | cerr<<"> "<<linebuffer<<endl; | ||
262 | ret_val = false; | ||
263 | } else { | ||
264 | |||
265 | last_key->m_command = CommandParser::instance().parseLine(str); | ||
266 | |||
267 | if (*last_key->m_command == 0) { | ||
268 | cerr<<_FB_CONSOLETEXT(Keys, BadLine, "Keys: Error on line", "Error on line (number following)")<<": "<<m_current_line<<endl; | ||
269 | cerr<<"> "<<linebuffer<<endl; | ||
270 | } else { | ||
271 | // need to change keymode here so it doesn't get changed by CommandParser | ||
272 | m_keylist = m_map[keyMode]; | ||
273 | // Add the keychain to list | ||
274 | if (!mergeTree(current_key)) { | ||
275 | cerr<<_FB_CONSOLETEXT(Keys, BadMerge, "Keys: Failed to merge keytree!", "relatively technical error message. Key bindings are stored in a tree structure")<<endl; | ||
276 | ret_val = false; | ||
277 | } | ||
278 | } | ||
279 | } | ||
280 | delete current_key; | ||
281 | current_key = 0; | ||
282 | last_key = 0; | ||
283 | 248 | ||
284 | return ret_val; | 249 | const char *str = FbTk::StringUtil::strcasestr(linebuffer.c_str(), |
250 | val[argc].c_str() + 1); // +1 to skip ':' | ||
251 | if (str) | ||
252 | current_key->m_command = CommandParser::instance().parseLine(str); | ||
285 | 253 | ||
254 | if (!str || *current_key->m_command == 0 || mod) { | ||
255 | delete first_new_key; | ||
256 | return false; | ||
257 | } | ||
258 | |||
259 | // success | ||
260 | first_new_keylist->keylist.push_back(first_new_key); | ||
261 | return true; | ||
286 | } // end if | 262 | } // end if |
287 | } // end for | 263 | } // end for |
288 | 264 | ||
289 | return false; | 265 | return false; |
290 | } | 266 | } |
291 | 267 | ||
292 | 268 | // return true if bound to a command, else false | |
293 | /** | ||
294 | @return the KeyAction of the XKeyEvent; return false if not bound | ||
295 | */ | ||
296 | bool Keys::doAction(XKeyEvent &ke) { | 269 | bool Keys::doAction(XKeyEvent &ke) { |
297 | 270 | ||
298 | ke.state = FbTk::KeyUtil::instance().cleanMods(ke.state); | 271 | ke.state = FbTk::KeyUtil::instance().cleanMods(ke.state); |
299 | 272 | ||
300 | static struct t_key* next_key = 0; | 273 | static t_key* next_key = m_keylist; |
301 | 274 | if (!next_key) | |
302 | if (!next_key) { | 275 | next_key = m_keylist; |
303 | bool retval = false; | ||
304 | // need a local keylist, in case m_command->execute() changes it | ||
305 | keylist_t *keylist = m_keylist; | ||
306 | for (size_t i = 0; i < keylist->size(); i++) { | ||
307 | if (*(*keylist)[i] == ke) { | ||
308 | if ((*keylist)[i]->keylist.size()) { | ||
309 | next_key = (*keylist)[i]; | ||
310 | return true; //still counts as being grabbed | ||
311 | } | ||
312 | if (*(*keylist)[i]->m_command != 0) { | ||
313 | (*keylist)[i]->m_command->execute(); | ||
314 | retval = true; | ||
315 | } | ||
316 | } | ||
317 | } | ||
318 | return retval; | ||
319 | } | ||
320 | t_key *temp_key = next_key->find(ke); | 276 | t_key *temp_key = next_key->find(ke); |
321 | if (temp_key) { | 277 | |
322 | if (temp_key->keylist.size()) { | 278 | |
323 | next_key = temp_key; | 279 | // need to save this for emacs-style keybindings |
324 | return true; | 280 | static t_key *saved_keymode = 0; |
325 | } | 281 | |
326 | next_key = 0; | 282 | if (temp_key && temp_key->keylist.size()) { // emacs-style |
327 | if (*temp_key->m_command == 0) | 283 | saved_keymode = m_keylist; |
328 | return false; | 284 | next_key = temp_key; |
329 | temp_key->m_command->execute(); | 285 | setKeyMode(next_key); |
286 | // grab "None Escape" to exit keychain in the middle | ||
287 | unsigned int esc = FbTk::KeyUtil::getKey("Escape"); | ||
288 | FbTk::KeyUtil::grabKey(esc,0); | ||
330 | return true; | 289 | return true; |
331 | } | 290 | } |
332 | temp_key = next_key; | 291 | if (!temp_key || *temp_key->m_command == 0) { |
333 | next_key = 0; | 292 | next_key = 0; |
334 | if (*temp_key->m_command == 0) | 293 | if (saved_keymode) { |
294 | setKeyMode(saved_keymode); | ||
295 | saved_keymode = 0; | ||
296 | } | ||
335 | return false; | 297 | return false; |
298 | } | ||
336 | temp_key->m_command->execute(); | 299 | temp_key->m_command->execute(); |
300 | if (saved_keymode) { | ||
301 | if (next_key == m_keylist) // don't reset keymode if command changed it | ||
302 | setKeyMode(saved_keymode); | ||
303 | saved_keymode = 0; | ||
304 | } | ||
305 | next_key = 0; | ||
337 | return true; | 306 | return true; |
338 | } | 307 | } |
339 | 308 | ||
@@ -345,62 +314,21 @@ bool Keys::reconfigure(const char *filename) { | |||
345 | return load(filename); | 314 | return load(filename); |
346 | } | 315 | } |
347 | 316 | ||
348 | /** | 317 | void Keys::keyMode(string keyMode) { |
349 | Merges two chains and binds new keys | ||
350 | @return true on success else false. | ||
351 | */ | ||
352 | bool Keys::mergeTree(t_key *newtree, t_key *basetree) { | ||
353 | size_t baselist_i = 0; | ||
354 | if (basetree==0) { | ||
355 | for (; baselist_i<m_keylist->size(); baselist_i++) { | ||
356 | if ((*m_keylist)[baselist_i]->mod == newtree->mod && | ||
357 | (*m_keylist)[baselist_i]->key == newtree->key) { | ||
358 | if (newtree->keylist.size() && *(*m_keylist)[baselist_i]->m_command == 0) { | ||
359 | //assumes the newtree only have one branch | ||
360 | return mergeTree(newtree->keylist[0], (*m_keylist)[baselist_i]); | ||
361 | } else | ||
362 | break; | ||
363 | } | ||
364 | } | ||
365 | |||
366 | if (baselist_i == m_keylist->size()) { | ||
367 | FbTk::KeyUtil::grabKey(newtree->key, newtree->mod); | ||
368 | m_keylist->push_back(new t_key(newtree)); | ||
369 | if (newtree->keylist.size()) | ||
370 | return mergeTree(newtree->keylist[0], m_keylist->back()); | ||
371 | return true; | ||
372 | } | ||
373 | |||
374 | } else { | ||
375 | for (; baselist_i<basetree->keylist.size(); baselist_i++) { | ||
376 | if (basetree->keylist[baselist_i]->mod == newtree->mod && | ||
377 | basetree->keylist[baselist_i]->key == newtree->key) { | ||
378 | if (newtree->keylist.size()) { | ||
379 | //assumes the newtree only have on branch | ||
380 | return mergeTree(newtree->keylist[0], basetree->keylist[baselist_i]); | ||
381 | } else | ||
382 | return false; | ||
383 | } | ||
384 | } | ||
385 | //if it wasn't in the list grab the key and add it to the list | ||
386 | if (baselist_i==basetree->keylist.size()) { | ||
387 | FbTk::KeyUtil::grabKey(newtree->key, newtree->mod); | ||
388 | basetree->keylist.push_back(new t_key(newtree)); | ||
389 | if (newtree->keylist.size()) | ||
390 | return mergeTree(newtree->keylist[0], basetree->keylist.back()); | ||
391 | return true; | ||
392 | } | ||
393 | } | ||
394 | |||
395 | return false; | ||
396 | } | ||
397 | |||
398 | void Keys::keyMode(string keyMode = "default") { | ||
399 | keyspace_t::iterator it = m_map.find(keyMode + ":"); | 318 | keyspace_t::iterator it = m_map.find(keyMode + ":"); |
400 | if (it == m_map.end()) | 319 | if (it == m_map.end()) |
401 | m_keylist = m_map["default:"]; | 320 | setKeyMode(m_map["default:"]); |
402 | else | 321 | else |
403 | m_keylist = it->second; | 322 | setKeyMode(it->second); |
323 | } | ||
324 | |||
325 | void Keys::setKeyMode(t_key *keyMode) { | ||
326 | FbTk::KeyUtil::ungrabKeys(); | ||
327 | keylist_t::iterator it = keyMode->keylist.begin(); | ||
328 | keylist_t::iterator it_end = keyMode->keylist.end(); | ||
329 | for (; it != it_end; ++it) | ||
330 | FbTk::KeyUtil::grabKey((*it)->key,(*it)->mod); | ||
331 | m_keylist = keyMode; | ||
404 | } | 332 | } |
405 | 333 | ||
406 | Keys::t_key::t_key(unsigned int key_, unsigned int mod_, FbTk::RefCount<FbTk::Command> command) { | 334 | Keys::t_key::t_key(unsigned int key_, unsigned int mod_, FbTk::RefCount<FbTk::Command> command) { |
@@ -416,12 +344,7 @@ Keys::t_key::t_key(t_key *k) { | |||
416 | } | 344 | } |
417 | 345 | ||
418 | Keys::t_key::~t_key() { | 346 | Keys::t_key::~t_key() { |
419 | while (!keylist.empty()) { | 347 | for (keylist_t::iterator list_it = keylist.begin(); list_it != keylist.end(); ++list_it) |
420 | t_key *k = keylist.back(); | 348 | delete *list_it; |
421 | if (k != 0) { // make sure we don't have a bad key pointer | 349 | keylist.clear(); |
422 | delete k; | ||
423 | keylist.pop_back(); | ||
424 | } | ||
425 | } | ||
426 | |||
427 | } | 350 | } |