diff options
Diffstat (limited to 'src/Keys.cc')
-rw-r--r-- | src/Keys.cc | 95 |
1 files changed, 72 insertions, 23 deletions
diff --git a/src/Keys.cc b/src/Keys.cc index e7b7acd..dbcff67 100644 --- a/src/Keys.cc +++ b/src/Keys.cc | |||
@@ -114,6 +114,7 @@ Keys::Keys(): | |||
114 | 114 | ||
115 | Keys::~Keys() { | 115 | Keys::~Keys() { |
116 | ungrabKeys(); | 116 | ungrabKeys(); |
117 | ungrabButtons(); | ||
117 | deleteTree(); | 118 | deleteTree(); |
118 | } | 119 | } |
119 | 120 | ||
@@ -140,6 +141,23 @@ void Keys::ungrabKeys() { | |||
140 | FbTk::KeyUtil::ungrabKeys(*it); | 141 | FbTk::KeyUtil::ungrabKeys(*it); |
141 | } | 142 | } |
142 | 143 | ||
144 | void Keys::grabButton(unsigned int button, unsigned int mod) { | ||
145 | std::list<Window>::iterator it = m_window_list.begin(); | ||
146 | std::list<Window>::iterator it_end = m_window_list.end(); | ||
147 | |||
148 | for (; it != it_end; ++it) | ||
149 | FbTk::KeyUtil::grabButton(button, mod, *it, | ||
150 | ButtonPressMask|ButtonReleaseMask); | ||
151 | } | ||
152 | |||
153 | void Keys::ungrabButtons() { | ||
154 | std::list<Window>::iterator it = m_window_list.begin(); | ||
155 | std::list<Window>::iterator it_end = m_window_list.end(); | ||
156 | |||
157 | for (; it != it_end; ++it) | ||
158 | FbTk::KeyUtil::ungrabButtons(*it); | ||
159 | } | ||
160 | |||
143 | /** | 161 | /** |
144 | Load and grab keys | 162 | Load and grab keys |
145 | TODO: error checking | 163 | TODO: error checking |
@@ -152,7 +170,7 @@ bool Keys::load(const char *filename) { | |||
152 | //free memory of previous grabs | 170 | //free memory of previous grabs |
153 | deleteTree(); | 171 | deleteTree(); |
154 | 172 | ||
155 | m_map["default:"] = new t_key(0,0); | 173 | m_map["default:"] = new t_key(0,0,0,0); |
156 | 174 | ||
157 | FbTk::App::instance()->sync(false); | 175 | FbTk::App::instance()->sync(false); |
158 | 176 | ||
@@ -211,6 +229,7 @@ bool Keys::addBinding(const string &linebuffer) { | |||
211 | return true; // still a valid line. | 229 | return true; // still a valid line. |
212 | 230 | ||
213 | unsigned int key = 0, mod = 0; | 231 | unsigned int key = 0, mod = 0; |
232 | int type = 0, context = 0; | ||
214 | size_t argc = 0; | 233 | size_t argc = 0; |
215 | t_key *current_key=m_map["default:"]; | 234 | t_key *current_key=m_map["default:"]; |
216 | t_key *first_new_keylist = current_key, *first_new_key=0; | 235 | t_key *first_new_keylist = current_key, *first_new_key=0; |
@@ -219,7 +238,7 @@ bool Keys::addBinding(const string &linebuffer) { | |||
219 | argc++; | 238 | argc++; |
220 | keyspace_t::iterator it = m_map.find(val[0]); | 239 | keyspace_t::iterator it = m_map.find(val[0]); |
221 | if (it == m_map.end()) | 240 | if (it == m_map.end()) |
222 | m_map[val[0]] = new t_key(0,0); | 241 | m_map[val[0]] = new t_key(0,0,0,0); |
223 | current_key = m_map[val[0]]; | 242 | current_key = m_map[val[0]]; |
224 | } | 243 | } |
225 | // for each argument | 244 | // for each argument |
@@ -230,41 +249,53 @@ bool Keys::addBinding(const string &linebuffer) { | |||
230 | int tmpmod = FbTk::KeyUtil::getModifier(val[argc].c_str()); | 249 | int tmpmod = FbTk::KeyUtil::getModifier(val[argc].c_str()); |
231 | if(tmpmod) | 250 | if(tmpmod) |
232 | mod |= tmpmod; //If it's a modifier | 251 | mod |= tmpmod; //If it's a modifier |
252 | else if (strcasecmp("ondesktop", val[argc].c_str()) == 0) | ||
253 | context |= ON_DESKTOP; | ||
233 | else if (strcasecmp("NONE",val[argc].c_str())) { | 254 | else if (strcasecmp("NONE",val[argc].c_str())) { |
255 | // check if it's a mouse button | ||
256 | if (!strcasecmp(val[argc].substr(0,5).c_str(), "mouse") && | ||
257 | val[argc].length() > 5) { | ||
258 | type = ButtonPress; | ||
259 | key = atoi(val[argc].substr(5,val[argc].length()-5).c_str()); | ||
234 | // keycode covers the following three two-byte cases: | 260 | // keycode covers the following three two-byte cases: |
235 | // 0x - hex | 261 | // 0x - hex |
236 | // +[1-9] - number between +1 and +9 | 262 | // +[1-9] - number between +1 and +9 |
237 | // numbers 10 and above | 263 | // numbers 10 and above |
238 | // | 264 | // |
239 | if (val[argc].size() > 1 && (isdigit(val[argc][0]) && | 265 | } else if (val[argc].size() > 1 && (isdigit(val[argc][0]) && |
240 | (isdigit(val[argc][1]) || val[argc][1] == 'x') || | 266 | (isdigit(val[argc][1]) || val[argc][1] == 'x') || |
241 | val[argc][0] == '+' && isdigit(val[argc][1])) ) { | 267 | val[argc][0] == '+' && isdigit(val[argc][1])) ) { |
242 | 268 | ||
243 | key = strtoul(val[argc].c_str(), NULL, 0); | 269 | key = strtoul(val[argc].c_str(), NULL, 0); |
270 | type = KeyPress; | ||
244 | 271 | ||
245 | if (errno == EINVAL || errno == ERANGE) | 272 | if (errno == EINVAL || errno == ERANGE) |
246 | key = 0; | 273 | key = 0; |
247 | 274 | ||
248 | } else // convert from string symbol | 275 | } else { // convert from string symbol |
249 | key = FbTk::KeyUtil::getKey(val[argc].c_str()); | 276 | key = FbTk::KeyUtil::getKey(val[argc].c_str()); |
277 | type = KeyPress; | ||
278 | } | ||
250 | 279 | ||
251 | if (key == 0) | 280 | if (key == 0) |
252 | return false; | 281 | return false; |
253 | if (!first_new_key) { | 282 | if (!first_new_key) { |
254 | first_new_keylist = current_key; | 283 | first_new_keylist = current_key; |
255 | current_key = current_key->find(key, mod); | 284 | current_key = current_key->find(type, mod, key, context); |
256 | if (!current_key) { | 285 | if (!current_key) { |
257 | first_new_key = new t_key(key, mod); | 286 | first_new_key = new t_key(type, mod, key, context); |
258 | current_key = first_new_key; | 287 | current_key = first_new_key; |
259 | } else if (*current_key->m_command) // already being used | 288 | } else if (*current_key->m_command) // already being used |
260 | return false; | 289 | return false; |
261 | } else { | 290 | } else { |
262 | t_key *temp_key = new t_key(key, mod); | 291 | t_key *temp_key = new t_key(type, mod, key, context); |
263 | current_key->keylist.push_back(temp_key); | 292 | current_key->keylist.push_back(temp_key); |
264 | current_key = temp_key; | 293 | current_key = temp_key; |
265 | } | 294 | } |
266 | mod = 0; | 295 | mod = 0; |
267 | key = 0; | 296 | key = 0; |
297 | type = 0; | ||
298 | context = 0; | ||
268 | } | 299 | } |
269 | 300 | ||
270 | } else { // parse command line | 301 | } else { // parse command line |
@@ -291,36 +322,43 @@ bool Keys::addBinding(const string &linebuffer) { | |||
291 | } | 322 | } |
292 | 323 | ||
293 | // return true if bound to a command, else false | 324 | // return true if bound to a command, else false |
294 | bool Keys::doAction(XKeyEvent &ke) { | 325 | bool Keys::doAction(int type, unsigned int mods, unsigned int key) { |
295 | |||
296 | ke.state = FbTk::KeyUtil::instance().cleanMods(ke.state); | ||
297 | 326 | ||
298 | static t_key* next_key = m_keylist; | 327 | static t_key* next_key = m_keylist; |
299 | if (!next_key) | 328 | if (!next_key) |
300 | next_key = m_keylist; | 329 | next_key = m_keylist; |
301 | t_key *temp_key = next_key->find(ke); | ||
302 | 330 | ||
331 | mods = FbTk::KeyUtil::instance().cleanMods(mods); | ||
332 | // at the moment, any key/button that gets here is on root window | ||
333 | // context will need to be added as an argument to doAction, though | ||
334 | t_key *temp_key = next_key->find(type, mods, key, ON_DESKTOP|GLOBAL); | ||
303 | 335 | ||
304 | // need to save this for emacs-style keybindings | 336 | // need to save this for emacs-style keybindings |
305 | static t_key *saved_keymode = 0; | 337 | static t_key *saved_keymode = 0; |
306 | 338 | ||
339 | // grab "None Escape" to exit keychain in the middle | ||
340 | unsigned int esc = FbTk::KeyUtil::getKey("Escape"); | ||
341 | |||
307 | if (temp_key && temp_key->keylist.size()) { // emacs-style | 342 | if (temp_key && temp_key->keylist.size()) { // emacs-style |
308 | saved_keymode = m_keylist; | 343 | if (!saved_keymode) |
344 | saved_keymode = m_keylist; | ||
309 | next_key = temp_key; | 345 | next_key = temp_key; |
310 | setKeyMode(next_key); | 346 | setKeyMode(next_key); |
311 | // grab "None Escape" to exit keychain in the middle | ||
312 | unsigned int esc = FbTk::KeyUtil::getKey("Escape"); | ||
313 | grabKey(esc,0); | 347 | grabKey(esc,0); |
314 | return true; | 348 | return true; |
315 | } | 349 | } |
316 | if (!temp_key || *temp_key->m_command == 0) { | 350 | if (!temp_key || *temp_key->m_command == 0) { |
317 | next_key = 0; | 351 | if (type == KeyPress && key == esc && mods == 0) { |
318 | if (saved_keymode) { | 352 | // if we're in the middle of an emacs-style keychain, exit it |
319 | setKeyMode(saved_keymode); | 353 | next_key = 0; |
320 | saved_keymode = 0; | 354 | if (saved_keymode) { |
355 | setKeyMode(saved_keymode); | ||
356 | saved_keymode = 0; | ||
357 | } | ||
321 | } | 358 | } |
322 | return false; | 359 | return false; |
323 | } | 360 | } |
361 | |||
324 | temp_key->m_command->execute(); | 362 | temp_key->m_command->execute(); |
325 | if (saved_keymode) { | 363 | if (saved_keymode) { |
326 | if (next_key == m_keylist) // don't reset keymode if command changed it | 364 | if (next_key == m_keylist) // don't reset keymode if command changed it |
@@ -349,22 +387,33 @@ void Keys::keyMode(string keyMode) { | |||
349 | 387 | ||
350 | void Keys::setKeyMode(t_key *keyMode) { | 388 | void Keys::setKeyMode(t_key *keyMode) { |
351 | ungrabKeys(); | 389 | ungrabKeys(); |
390 | ungrabButtons(); | ||
352 | keylist_t::iterator it = keyMode->keylist.begin(); | 391 | keylist_t::iterator it = keyMode->keylist.begin(); |
353 | keylist_t::iterator it_end = keyMode->keylist.end(); | 392 | keylist_t::iterator it_end = keyMode->keylist.end(); |
354 | for (; it != it_end; ++it) | 393 | for (; it != it_end; ++it) { |
355 | grabKey((*it)->key,(*it)->mod); | 394 | if ((*it)->type == KeyPress) |
395 | grabKey((*it)->key,(*it)->mod); | ||
396 | else if ((*it)->context == GLOBAL) | ||
397 | grabButton((*it)->key,(*it)->mod); | ||
398 | // we must use root window's event mask to get ON_DESKTOP events | ||
399 | } | ||
356 | m_keylist = keyMode; | 400 | m_keylist = keyMode; |
357 | } | 401 | } |
358 | 402 | ||
359 | Keys::t_key::t_key(unsigned int key_, unsigned int mod_, FbTk::RefCount<FbTk::Command> command) { | 403 | Keys::t_key::t_key(int type_, unsigned int mod_, unsigned int key_, |
404 | int context_, FbTk::RefCount<FbTk::Command> command) { | ||
360 | key = key_; | 405 | key = key_; |
361 | mod = mod_; | 406 | mod = mod_; |
407 | type = type_; | ||
408 | context = context_ ? context_ : GLOBAL; | ||
362 | m_command = command; | 409 | m_command = command; |
363 | } | 410 | } |
364 | 411 | ||
365 | Keys::t_key::t_key(t_key *k) { | 412 | Keys::t_key::t_key(t_key *k) { |
366 | key = k->key; | 413 | key = k->key; |
367 | mod = k->mod; | 414 | mod = k->mod; |
415 | type = k->type; | ||
416 | context = k->context; | ||
368 | m_command = k->m_command; | 417 | m_command = k->m_command; |
369 | } | 418 | } |
370 | 419 | ||