binder.cpp (23472B)
1 // Copyright (c) 2003 - 2009 Anselm R Garbe <anselm@garbe.us> 2 // Copyright (c) 2003 - 2004 Marcel Manthe <schneegloeckchen at gmx.li> 3 // See LICENSE for license details. 4 5 extern "C" { 6 #include <assert.h> 7 } 8 9 #include <sstream> 10 #include <string> 11 #include "wmi.h" 12 13 #include "binder.h" 14 15 #include "action.h" 16 #include "box.h" 17 #include "client.h" 18 #include "container.h" 19 #include "cursors.h" 20 #include "expander.h" 21 #include "frame.h" 22 #include "inputbar.h" 23 #include "kernel.h" 24 #include "logger.h" 25 #include "monitor.h" 26 #include "shortcut.h" 27 #include "thing.h" 28 #include "util.h" 29 #include "workspace.h" 30 #include "xcore.h" 31 32 33 Binder::Binder() { 34 actionBindings_ = KERNEL->actionBindings(); 35 initLockModifiers(); 36 #ifdef POSIX_REGEX 37 temp_pattern_="uninitalized"; 38 regex_prepare(); 39 #endif 40 } 41 42 Binder::~Binder() { 43 } 44 45 void Binder::grabShortcut(Shortcut *shortcut, Window window) { 46 47 // update keysym definitions of the action 48 if (shortcut->button()) { 49 XCORE->grabButton(window, shortcut->modMask(), 50 shortcut->button()); 51 52 if (shortcut->modMask() == AnyModifier) { 53 return; 54 } 55 if (numLockMask_) { 56 XCORE->grabButton(window, shortcut->modMask() | numLockMask_, 57 shortcut->button()); 58 XCORE->grabButton(window, shortcut->modMask() | numLockMask_ 59 | LockMask, shortcut->button()); 60 } 61 if (scrollLockMask_) { 62 XCORE->grabButton(window, shortcut->modMask() | scrollLockMask_, 63 shortcut->button()); 64 XCORE->grabButton(window, shortcut->modMask() | scrollLockMask_ 65 | LockMask, shortcut->button()); 66 } 67 if (numLockMask_ && scrollLockMask_) { 68 XCORE->grabButton(window, shortcut->modMask() | numLockMask_ 69 | scrollLockMask_, shortcut->button()); 70 XCORE->grabButton(window, shortcut->modMask() | numLockMask_ 71 | scrollLockMask_ | LockMask, shortcut->button()); 72 } 73 } 74 else if (shortcut->keyCode()) { 75 XCORE->grabKey(window, shortcut->modMask(), 76 shortcut->keyCode()); 77 78 if (shortcut->modMask() == AnyModifier) { 79 return; 80 } 81 if (numLockMask_) { 82 XCORE->grabKey(window, shortcut->modMask() | numLockMask_, 83 shortcut->keyCode()); 84 XCORE->grabKey(window, shortcut->modMask() | numLockMask_ 85 | LockMask, shortcut->keyCode()); 86 } 87 if (scrollLockMask_) { 88 XCORE->grabKey(window, shortcut->modMask() | scrollLockMask_, 89 shortcut->keyCode()); 90 XCORE->grabKey(window, shortcut->modMask() | scrollLockMask_ 91 | LockMask, shortcut->keyCode()); 92 } 93 if (numLockMask_ && scrollLockMask_) { 94 XCORE->grabKey(window, shortcut->modMask() | numLockMask_ 95 | scrollLockMask_, shortcut->keyCode()); 96 XCORE->grabKey(window, shortcut->modMask() | numLockMask_ 97 | scrollLockMask_ | LockMask, shortcut->keyCode()); 98 } 99 } 100 } 101 102 void Binder::ungrabShortcut(Shortcut *shortcut, Window window) { 103 104 if (shortcut->button()) { 105 XCORE->ungrabButton(window, shortcut->modMask(), shortcut->button()); 106 107 if (shortcut->modMask() == AnyModifier) { 108 return; 109 } 110 if (numLockMask_) { 111 XCORE->ungrabButton(window, shortcut->modMask() | numLockMask_, 112 shortcut->button()); 113 XCORE->ungrabButton(window, shortcut->modMask() | numLockMask_ 114 | LockMask, shortcut->button()); 115 } 116 if (scrollLockMask_) { 117 XCORE->ungrabButton(window, shortcut->modMask() | scrollLockMask_, 118 shortcut->button()); 119 XCORE->ungrabButton(window, shortcut->modMask() | scrollLockMask_ 120 | LockMask, shortcut->button()); 121 } 122 if (numLockMask_ && scrollLockMask_) { 123 XCORE->ungrabButton(window, shortcut->modMask() | numLockMask_ 124 | scrollLockMask_, shortcut->button()); 125 XCORE->ungrabButton(window, shortcut->modMask() | numLockMask_ 126 | scrollLockMask_ | LockMask, shortcut->button()); 127 } 128 } 129 else { 130 XCORE->ungrabKey(window, shortcut->modMask(), 131 shortcut->keyCode()); 132 133 if (shortcut->modMask() == AnyModifier) { 134 return; 135 } 136 if (numLockMask_) { 137 XCORE->ungrabKey(window, shortcut->modMask() | numLockMask_, 138 shortcut->keyCode()); 139 XCORE->ungrabKey(window, shortcut->modMask() | numLockMask_ 140 | LockMask, shortcut->keyCode()); 141 } 142 if (scrollLockMask_) { 143 XCORE->ungrabKey(window, shortcut->modMask() | scrollLockMask_, 144 shortcut->keyCode()); 145 XCORE->ungrabKey(window, shortcut->modMask() | scrollLockMask_ 146 | LockMask, shortcut->keyCode()); 147 } 148 if (numLockMask_ && scrollLockMask_) { 149 XCORE->ungrabKey(window, shortcut->modMask() | numLockMask_ 150 | scrollLockMask_, shortcut->keyCode()); 151 XCORE->ungrabKey(window, shortcut->modMask() | numLockMask_ 152 | scrollLockMask_ | LockMask, shortcut->keyCode()); 153 } 154 } 155 } 156 157 void Binder::initKeys(Window window) { 158 159 for (MBindings::iterator it = actionBindings_->begin(); 160 it != actionBindings_->end(); it++) 161 { 162 Action *action = (*it).second; 163 LOGDEBUG("initKeys: " + action->id()); 164 if (action->listenOn()) { 165 grabShortcut(action->listenOn(), window); 166 } 167 } 168 } 169 170 string Binder::prettyPrintKeyBindings() { 171 172 ostringstream oss; 173 for (MBindings::iterator it = actionBindings_->begin(); 174 it != actionBindings_->end(); it++) 175 { 176 Action *action = (*it).second; 177 Shortcut *shortcut = action->shortcut(); 178 Shortcut *tmp = action->shortcut(); 179 if (shortcut) { 180 oss.width(35); 181 oss.fill(' '); 182 oss << action->id() << " = "; 183 } 184 while (tmp) { 185 oss.width(0); 186 if (tmp->button()) { 187 oss << Util::stringForModMask(tmp->modMask()) 188 << Util::stringForButton(tmp->button()); 189 } 190 else { 191 oss << Util::stringForModMask(tmp->modMask()) 192 << XCORE->keyCodeToString(tmp->keyCode()); 193 } 194 tmp = tmp->next(); 195 if (tmp) { 196 oss << " :: "; 197 } 198 } 199 if (shortcut) { 200 oss << "\n"; 201 } 202 } 203 204 string result = oss.str(); 205 if (result == "") { 206 result = "no key bindings defined\n"; 207 } 208 return result; 209 } 210 211 void Binder::handleButton(Window window, XButtonEvent *event) 212 { 213 LOGDEBUG("handle button press event"); 214 handleShortcut(window, event->state, 0, event->button); 215 } 216 217 void Binder::handleShortcut(Window window, unsigned long modMask, 218 KeyCode keyCode, unsigned int button) 219 { 220 LOGDEBUG("handle shortcut event"); 221 LAction grabbedActions; 222 // only gets in here for the first part of a shortcut, thus 223 // create a list of all shortcuts which are listened for 224 for (MBindings::iterator it = actionBindings_->begin(); 225 it != actionBindings_->end(); it++) 226 { 227 Action *action = (*it).second; 228 Shortcut *shortcut = action->listenOn(); 229 230 if (shortcut && 231 (modMask == shortcut->modMask()) && 232 (keyCode == shortcut->keyCode()) && 233 (button == shortcut->button())) 234 { 235 if (shortcut->next()) { 236 action->setListenOn(shortcut->next()); 237 grabbedActions.push_back(action); 238 } 239 else { 240 grabbedActions.clear(); 241 LOGDEBUG("handle shortcut performs action '" 242 + action->id() + "'"); 243 if (action->promptsCount() > 0) { 244 KERNEL->focusedMonitor()->inputBar()->runArgument(action); 245 // action will be performed by argument processing 246 } 247 else { 248 action->perform(); 249 } 250 break; 251 } 252 } 253 } 254 if (grabbedActions.size()) { 255 Shortcut shortcut(modMask, keyCode, 0, button); 256 // now the magic occurs 257 handleShortcutChains(window, &shortcut, &grabbedActions); 258 } 259 // reset listen on info 260 for (MBindings::iterator it = actionBindings_->begin(); 261 it != actionBindings_->end(); it++) 262 { 263 Action *action = (*it).second; 264 if (action->shortcut()) { 265 // already grabbed 266 action->setListenOn(action->shortcut()); 267 } 268 } 269 } 270 271 void Binder::handleShortcutChains(Window window, Shortcut *prefix, 272 LAction *grabbedActions) 273 { 274 string sequence = 275 " " + Util::stringForModMask(prefix->modMask()) 276 + XCORE->keyCodeToString(prefix->keyCode()) + " ::"; 277 Box *box = KERNEL->focusedMonitor()->box(); 278 box->setText(sequence); 279 box->show(); 280 box->illuminate(); 281 282 XCORE->grabKeyboard(window); 283 284 bool isDoubleShortcut = false; 285 unsigned long modMask; 286 KeyCode keyCode; 287 Action *action = 0; 288 while (grabbedActions->size()) { 289 // fetch new key stroke 290 nextKeystroke(&modMask, &keyCode); 291 292 if ((prefix->modMask() == modMask) && 293 (prefix->keyCode() == keyCode)) 294 { 295 isDoubleShortcut = true; 296 break; 297 } 298 prefix->setModMask(modMask); 299 prefix->setKeyCode(keyCode); 300 sequence += " " + Util::stringForModMask(modMask) 301 + XCORE->keyCodeToString(keyCode) + " ::"; 302 box->setText(sequence); 303 box->illuminate(); 304 for (LAction::iterator it = grabbedActions->begin(); 305 it != grabbedActions->end(); ) 306 { 307 action = *it; 308 Shortcut *shortcut = action->listenOn(); 309 if (shortcut && 310 (modMask == shortcut->modMask()) && 311 (keyCode == shortcut->keyCode())) 312 { 313 // iterates next 314 it++; 315 if (shortcut->next()) { 316 action->setListenOn(shortcut->next()); 317 } 318 else { 319 grabbedActions->clear(); // escape condition 320 break; 321 } 322 } 323 else { 324 // iterates next 325 it = grabbedActions->erase(it); 326 } 327 action = 0; 328 } 329 } 330 XCORE->ungrabKeyboard(); 331 box->hide(); 332 if (action) { 333 334 LOGDEBUG("handle shortcut performs action '" 335 + action->id() + "'"); 336 if (action->promptsCount() > 0) { 337 KERNEL->focusedMonitor()->inputBar()->runArgument(action); 338 // action will be performed by argument processing 339 } 340 else { 341 action->perform(); 342 } 343 } 344 else if (isDoubleShortcut) { 345 emulateKeyPress(modMask, keyCode); 346 } 347 } 348 349 void Binder::emulateKeyPress(unsigned long modMask, KeyCode keyCode) { 350 351 Monitor *monitor = KERNEL->focusedMonitor(); 352 Client *client = monitor->focused()->topClient(); 353 354 if (client) { 355 XEvent event; 356 event.xkey.type = KeyPress; 357 event.xkey.time = CurrentTime; 358 event.xkey.window = client->clientWindow(); 359 event.xkey.display = KERNEL->display(); 360 event.xkey.state = modMask; 361 event.xkey.keycode = keyCode; 362 XCORE->sendEvent(client->clientWindow(), KeyPressMask, &event); 363 event.xkey.type = KeyRelease; 364 XCORE->sendEvent(client->clientWindow(), KeyReleaseMask, &event); 365 XCORE->sync(); 366 } 367 } 368 369 void Binder::nextKeystroke(unsigned long *modMask, KeyCode *keyCode) { 370 XEvent event; 371 KeySym sym; 372 *modMask = 0; 373 do { 374 XCORE->maskEvent(KeyPressMask, &event); 375 *modMask |= event.xkey.state & validModMask_; 376 *keyCode = event.xkey.keycode; 377 sym = XCORE->keyCodeToKeySym(event.xkey.keycode); 378 } while (IsModifierKey(sym)); 379 } 380 381 void Binder::handleKey(Window window, XKeyEvent *event) 382 { 383 LOGDEBUG("handle key press event"); 384 handleShortcut(window, event->state, event->keycode, 0); 385 } 386 387 void Binder::grabButtons(Window window, unsigned long modMask) 388 { 389 XCORE->grabButton(window, modMask, AnyModifier); 390 } 391 392 void Binder::ungrabButtons(Window window) { 393 XCORE->ungrabButton(window, AnyModifier, AnyButton); 394 } 395 396 #ifdef POSIX_REGEX 397 bool Binder::regex_first_match(const string& pattern, const string& haystack, int& begin, int& end){ 398 regmatch_t temp_regmatch; 399 400 begin = 0; 401 end = -1 ; 402 bool condition = false; 403 if (pattern == temp_pattern_ && pattern!="") { condition = true; } else 404 { 405 condition = (regcomp(&temp_regex_, pattern.c_str(), REG_EXTENDED)==0); 406 if (!condition) regex_prepare(); //reinitialize 407 } 408 if (condition){ 409 bool result = (regexec(&temp_regex_, haystack.c_str(), 1, &temp_regmatch, 0)==0); 410 if (result){ 411 begin = temp_regmatch.rm_so; 412 end = temp_regmatch.rm_eo; 413 } 414 temp_pattern_ = pattern; 415 return result; 416 } 417 return false; 418 } 419 420 bool Binder::regex_match(const string& pattern, const string& haystack){ 421 int begin; 422 int end; 423 return(regex_first_match(pattern, haystack, begin, end)); 424 } 425 #endif 426 427 428 string Binder::absolutePattern(string pattern, Sstring *names, 429 unsigned int offset) 430 { 431 432 string result = pattern; 433 if (!(names->empty())) { 434 435 #ifdef POSIX_REGEX 436 if (doRegex_) { 437 438 /* Check whether the search-pattern contains a modifier. 439 If it does, simply return the pattern itself, otherwise, 440 perform an infix-matching-algorithm. */ 441 442 string first = *names->begin(); 443 for (int direction = 0; direction <= 1; direction++){ 444 bool matches_all = true; 445 do { 446 LOGDEBUG("Entering do-while-infix-matching-loop"); 447 int begin; 448 int end; 449 450 if (regex_first_match (result, first, begin, end)){ 451 LOGDEBUG("pattern-rule matched first member"); 452 int count = end - begin + 1; 453 if (direction == 1) begin--; 454 if ((begin + count <= (int)first.length()) && (begin >= 0) && (count>0)){ 455 pattern=first.substr(begin, count); 456 LOGDEBUG("trying to add a char to pattern"); 457 LOGDEBUG(pattern); 458 } else break; 459 } 460 461 for (Sstring::iterator it = names->begin(); it != names->end(); it++) 462 if(!regex_match(pattern, (*it))) matches_all = false; 463 if (matches_all) result = pattern; 464 } while (matches_all); 465 } 466 return(result); 467 } 468 #endif 469 470 string firstName = *names->begin(); 471 string lastName = *names->rbegin(); 472 473 unsigned int firstLength = firstName.length(); 474 unsigned int lastLength = lastName.length(); 475 for (unsigned int i = offset; 476 (i < firstLength) && (i < lastLength); i++) 477 { 478 if (firstName[i] == lastName[i]) { 479 result += firstName[i]; 480 } 481 else { 482 break; 483 } 484 } 485 } 486 487 return result; // return absolute pattern 488 } 489 490 void Binder::matchPattern(string digest, string pattern, Sstring *strings, 491 unsigned int patternLength) 492 { 493 bool condition; 494 condition = (digest.substr(0, patternLength) == pattern); 495 496 #ifdef POSIX_REGEX 497 if (doRegex_) { 498 condition = regex_match(pattern, digest); 499 } 500 #endif 501 502 if (condition) { 503 strings->insert(digest); 504 } 505 } 506 507 void Binder::initRegex(string pattern){ 508 #ifdef POSIX_REGEX 509 doRegex_ = Util::get(KERNEL->commonSettings(), "autocompletion.mode") == "regex"; 510 #endif 511 } 512 513 string Binder::queryFramesForPattern(string pattern, Sstring *sFrames) 514 { 515 516 Workspace *workspace = KERNEL->focusedMonitor()->focused(); 517 CFrame *frames = workspace->frames(); 518 unsigned int patternLength = pattern.length(); 519 string lName; 520 initRegex(pattern); 521 for (LFrame::iterator it = frames->begin(); it != frames->end(); it++) { 522 Frame *frame = *it; 523 matchPattern(frame->name(), pattern, 524 sFrames, patternLength); 525 } 526 return absolutePattern(pattern, sFrames, patternLength); 527 } 528 529 string Binder::queryClientIdsForPattern(string pattern, Sstring *clients) 530 { 531 532 Monitor *focusedMonitor = KERNEL->focusedMonitor(); 533 MClient *clientMap = focusedMonitor->clients(); 534 unsigned int patternLength = pattern.length(); 535 initRegex(pattern); 536 for (MClient::iterator it = clientMap->begin(); 537 it != clientMap->end(); it++) 538 { 539 Client *client = (*it).second; 540 if (client->attached() 541 #ifdef SLOT_SUPPORT 542 || client->mode() == Client::SLOT 543 #endif // SLOT_SUPPORT 544 ) 545 { 546 matchPattern(client->id(), pattern, clients, patternLength); 547 } 548 } 549 return absolutePattern(pattern, clients, pattern.length()); 550 } 551 552 string Binder::queryClientsForPattern(string pattern, Sstring *clients) 553 { 554 555 Monitor *focusedMonitor = KERNEL->focusedMonitor(); 556 MClient *clientMap = focusedMonitor->clients(); 557 unsigned int patternLength = pattern.length(); 558 initRegex(pattern); 559 for (MClient::iterator it = clientMap->begin(); 560 it != clientMap->end(); it++) 561 { 562 Client *client = (*it).second; 563 if (client->attached() 564 #ifdef SLOT_SUPPORT 565 || client->mode() == Client::SLOT 566 #endif 567 ) 568 { 569 matchPattern(client->name(), pattern, clients, patternLength); 570 } 571 } 572 return absolutePattern(pattern, clients, pattern.length()); 573 } 574 575 string Binder::queryDetachedClientsForPattern(string pattern, Sstring *clients) 576 { 577 578 Monitor *focusedMonitor = KERNEL->focusedMonitor(); 579 CClient *detachedClients = focusedMonitor->detachedClients(); 580 unsigned int patternLength = pattern.length(); 581 initRegex(pattern); 582 for (LClient::iterator it = detachedClients->begin(); 583 it != detachedClients->end(); it++) 584 { 585 Client *client = *it; 586 matchPattern(client->name(), pattern, clients, patternLength); 587 } 588 return absolutePattern(pattern, clients, pattern.length()); 589 } 590 591 string Binder::queryMonitorsForPattern(string pattern, Sstring *monitors) { 592 593 CMonitor *ms = KERNEL->monitors(); 594 unsigned int patternLength = pattern.length(); 595 initRegex(pattern); 596 for (LMonitor::iterator it = ms->begin(); it != ms->end(); it++) { 597 matchPattern((*it)->displayString(), pattern, monitors, patternLength); 598 } 599 600 return absolutePattern(pattern, monitors, patternLength); 601 } 602 603 string Binder::queryWorkspacesForPattern(string pattern, 604 Sstring *workspaces) 605 { 606 607 Monitor *focusedMonitor = KERNEL->focusedMonitor(); 608 unsigned int patternLength = pattern.length(); 609 string wsName; 610 initRegex(pattern); 611 for (LWorkspace::iterator it = focusedMonitor->begin(); 612 it != focusedMonitor->end(); it++) 613 { 614 matchPattern((*it)->name(), pattern, workspaces, patternLength); 615 } 616 617 return absolutePattern(pattern, workspaces, patternLength); 618 } 619 620 string Binder::queryExternChainActionsForPattern( 621 string pattern, Sstring *actionKeys) 622 { 623 unsigned int patternLength = pattern.length(); 624 string actionKey; 625 Action *action; 626 initRegex(pattern); 627 for (MBindings::iterator it = actionBindings_->begin(); 628 it != actionBindings_->end(); it++) 629 { 630 actionKey = (*it).first; 631 action = (*it).second; 632 if (action->type() == Action::INTERN) { 633 continue; 634 } 635 matchPattern(actionKey, pattern, actionKeys, patternLength); 636 } 637 638 return absolutePattern(pattern, actionKeys, patternLength); 639 } 640 641 string Binder::queryActionKeysWithoutValidationForPattern( 642 string pattern, Sstring *actionKeys) 643 { 644 unsigned int patternLength = pattern.length(); 645 string actionKey; 646 initRegex(pattern); 647 for (MBindings::iterator it = actionBindings_->begin(); 648 it != actionBindings_->end(); it++) 649 { 650 actionKey = (*it).first; 651 matchPattern(actionKey, pattern, actionKeys, patternLength); 652 } 653 654 return absolutePattern(pattern, actionKeys, patternLength); 655 } 656 657 string Binder::queryActionKeysForPattern(string pattern, Sstring *actionKeys) { 658 659 unsigned int patternLength = pattern.length(); 660 string actionKey; 661 initRegex(pattern); 662 for (MBindings::iterator it = actionBindings_->begin(); 663 it != actionBindings_->end(); it++) 664 { 665 Action *action = (*it).second; 666 667 if (action->isValid()) { 668 actionKey = (*it).first; 669 matchPattern(actionKey, pattern, actionKeys, patternLength); 670 } 671 } 672 673 return absolutePattern(pattern, actionKeys, patternLength); 674 } 675 676 string Binder::queryCommandForPattern(string pattern, Sstring *expands) { 677 678 Expander::instance()->queryString(pattern); 679 Sstring exp = Expander::instance()->expands(); 680 initRegex(pattern); 681 682 683 unsigned int offset = pattern.find_last_of('/'); 684 if (offset == string::npos) offset=0; else offset++; 685 686 #ifdef POSIX_REGEX 687 doRegex_ = doRegex_ && (offset == 0); 688 #endif 689 690 for (Sstring::iterator it = exp.begin(); 691 it != exp.end(); it++) 692 { 693 matchPattern((string)(*it), pattern.substr(offset), expands, pattern.length()-offset); 694 } 695 696 return absolutePattern(pattern, expands, pattern.length() - 697 pattern.find_last_of('/') - 1); 698 } 699 700 #define NUM_MASKS 8 701 702 void Binder::initLockModifiers() { 703 XModifierKeymap *modmap; 704 KeyCode numLock, scrollLock; 705 706 // preinit 707 numLockMask_ = scrollLockMask_ = 0; 708 709 // init modifier map 710 modmap = XCORE->modifierMapping(); 711 712 // modifier masks we know 713 static int masks[NUM_MASKS] = { 714 ShiftMask, LockMask, ControlMask, Mod1Mask, 715 Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask 716 }; 717 718 // temporary keysyms of evil keys 719 numLock = XCORE->stringToKeyCode("Num_Lock"); 720 scrollLock = XCORE->stringToKeyCode("Scroll_Lock"); 721 722 if (modmap && modmap->max_keypermod > 0) { 723 unsigned int max = NUM_MASKS * modmap->max_keypermod; 724 for (unsigned int i = 0; i < max; i++) { 725 if (numLock && (modmap->modifiermap[i] == numLock)) { 726 numLockMask_ = masks[i / modmap->max_keypermod]; 727 } 728 else if (scrollLock && (modmap->modifiermap[i] == scrollLock)) { 729 scrollLockMask_ = masks[i / modmap->max_keypermod]; 730 } 731 } 732 } 733 734 XCORE->freeModifierMapping(modmap); 735 validModMask_ = 255 & ~(numLockMask_ | scrollLockMask_ | LockMask); 736 } 737 738 unsigned int Binder::validModMask() const { 739 return validModMask_; 740 }