aboutsummaryrefslogtreecommitdiff
path: root/src/Keys.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/Keys.cc')
-rw-r--r--src/Keys.cc251
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;
94using std::string; 94using std::string;
95using std::vector; 95using std::vector;
96using std::ifstream; 96using std::ifstream;
97using std::pair;
97 98
98Keys::Keys(): 99Keys::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
111void Keys::deleteTree() { 112void 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*/
296bool Keys::doAction(XKeyEvent &ke) { 269bool 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/** 317void Keys::keyMode(string keyMode) {
349 Merges two chains and binds new keys
350 @return true on success else false.
351*/
352bool 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
398void 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
325void 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
406Keys::t_key::t_key(unsigned int key_, unsigned int mod_, FbTk::RefCount<FbTk::Command> command) { 334Keys::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
418Keys::t_key::~t_key() { 346Keys::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}