00001
00002
00003
00004
00005
00006
00007 extern "C" {
00008 #include <assert.h>
00009 }
00010
00011 #include <sstream>
00012 #include <string>
00013 #include "ncwm.h"
00014
00015 #include "binder.h"
00016
00017 #include "action.h"
00018 #include "box.h"
00019 #include "client.h"
00020 #include "container.h"
00021 #include "cursors.h"
00022 #include "expander.h"
00023 #include "frame.h"
00024 #include "inputbar.h"
00025 #include "kernel.h"
00026 #include "logger.h"
00027 #include "monitor.h"
00028 #include "shortcut.h"
00029 #include "thing.h"
00030 #include "util.h"
00031 #include "workspace.h"
00032 #include "xcore.h"
00033
00034
00035 Binder::Binder() {
00036 actionBindings_ = KERNEL->actionBindings();
00037 initLockModifiers();
00038 #ifdef POSIX_REGEX
00039 temp_pattern_="uninitalized";
00040 regex_prepare();
00041 #endif
00042 }
00043
00044 Binder::~Binder() {
00045 }
00046
00047 void Binder::grabShortcut(Shortcut *shortcut, Window window) {
00048
00049
00050 if (shortcut->button()) {
00051 XCORE->grabButton(window, shortcut->modMask(),
00052 shortcut->button());
00053
00054 if (shortcut->modMask() == AnyModifier) {
00055 return;
00056 }
00057 if (numLockMask_) {
00058 XCORE->grabButton(window, shortcut->modMask() | numLockMask_,
00059 shortcut->button());
00060 XCORE->grabButton(window, shortcut->modMask() | numLockMask_
00061 | LockMask, shortcut->button());
00062 }
00063 if (scrollLockMask_) {
00064 XCORE->grabButton(window, shortcut->modMask() | scrollLockMask_,
00065 shortcut->button());
00066 XCORE->grabButton(window, shortcut->modMask() | scrollLockMask_
00067 | LockMask, shortcut->button());
00068 }
00069 if (numLockMask_ && scrollLockMask_) {
00070 XCORE->grabButton(window, shortcut->modMask() | numLockMask_
00071 | scrollLockMask_, shortcut->button());
00072 XCORE->grabButton(window, shortcut->modMask() | numLockMask_
00073 | scrollLockMask_ | LockMask, shortcut->button());
00074 }
00075 }
00076 else if (shortcut->keyCode()) {
00077 XCORE->grabKey(window, shortcut->modMask(),
00078 shortcut->keyCode());
00079
00080 if (shortcut->modMask() == AnyModifier) {
00081 return;
00082 }
00083 if (numLockMask_) {
00084 XCORE->grabKey(window, shortcut->modMask() | numLockMask_,
00085 shortcut->keyCode());
00086 XCORE->grabKey(window, shortcut->modMask() | numLockMask_
00087 | LockMask, shortcut->keyCode());
00088 }
00089 if (scrollLockMask_) {
00090 XCORE->grabKey(window, shortcut->modMask() | scrollLockMask_,
00091 shortcut->keyCode());
00092 XCORE->grabKey(window, shortcut->modMask() | scrollLockMask_
00093 | LockMask, shortcut->keyCode());
00094 }
00095 if (numLockMask_ && scrollLockMask_) {
00096 XCORE->grabKey(window, shortcut->modMask() | numLockMask_
00097 | scrollLockMask_, shortcut->keyCode());
00098 XCORE->grabKey(window, shortcut->modMask() | numLockMask_
00099 | scrollLockMask_ | LockMask, shortcut->keyCode());
00100 }
00101 }
00102 }
00103
00104 void Binder::ungrabShortcut(Shortcut *shortcut, Window window) {
00105
00106 if (shortcut->button()) {
00107 XCORE->ungrabButton(window, shortcut->modMask(), shortcut->button());
00108
00109 if (shortcut->modMask() == AnyModifier) {
00110 return;
00111 }
00112 if (numLockMask_) {
00113 XCORE->ungrabButton(window, shortcut->modMask() | numLockMask_,
00114 shortcut->button());
00115 XCORE->ungrabButton(window, shortcut->modMask() | numLockMask_
00116 | LockMask, shortcut->button());
00117 }
00118 if (scrollLockMask_) {
00119 XCORE->ungrabButton(window, shortcut->modMask() | scrollLockMask_,
00120 shortcut->button());
00121 XCORE->ungrabButton(window, shortcut->modMask() | scrollLockMask_
00122 | LockMask, shortcut->button());
00123 }
00124 if (numLockMask_ && scrollLockMask_) {
00125 XCORE->ungrabButton(window, shortcut->modMask() | numLockMask_
00126 | scrollLockMask_, shortcut->button());
00127 XCORE->ungrabButton(window, shortcut->modMask() | numLockMask_
00128 | scrollLockMask_ | LockMask, shortcut->button());
00129 }
00130 }
00131 else {
00132 XCORE->ungrabKey(window, shortcut->modMask(),
00133 shortcut->keyCode());
00134
00135 if (shortcut->modMask() == AnyModifier) {
00136 return;
00137 }
00138 if (numLockMask_) {
00139 XCORE->ungrabKey(window, shortcut->modMask() | numLockMask_,
00140 shortcut->keyCode());
00141 XCORE->ungrabKey(window, shortcut->modMask() | numLockMask_
00142 | LockMask, shortcut->keyCode());
00143 }
00144 if (scrollLockMask_) {
00145 XCORE->ungrabKey(window, shortcut->modMask() | scrollLockMask_,
00146 shortcut->keyCode());
00147 XCORE->ungrabKey(window, shortcut->modMask() | scrollLockMask_
00148 | LockMask, shortcut->keyCode());
00149 }
00150 if (numLockMask_ && scrollLockMask_) {
00151 XCORE->ungrabKey(window, shortcut->modMask() | numLockMask_
00152 | scrollLockMask_, shortcut->keyCode());
00153 XCORE->ungrabKey(window, shortcut->modMask() | numLockMask_
00154 | scrollLockMask_ | LockMask, shortcut->keyCode());
00155 }
00156 }
00157 }
00158
00159 void Binder::initKeys(Window window) {
00160
00161 for (MBindings::iterator it = actionBindings_->begin();
00162 it != actionBindings_->end(); it++)
00163 {
00164 Action *action = (*it).second;
00165 LOGDEBUG("initKeys: " + action->id());
00166 if (action->listenOn()) {
00167 grabShortcut(action->listenOn(), window);
00168 }
00169 }
00170 }
00171
00172 string Binder::prettyPrintKeyBindings() {
00173
00174 ostringstream oss;
00175 for (MBindings::iterator it = actionBindings_->begin();
00176 it != actionBindings_->end(); it++)
00177 {
00178 Action *action = (*it).second;
00179 Shortcut *shortcut = action->shortcut();
00180 Shortcut *tmp = action->shortcut();
00181 if (shortcut) {
00182 oss.width(35);
00183 oss.fill(' ');
00184 oss << action->id() << " = ";
00185 }
00186 while (tmp) {
00187 oss.width(0);
00188 if (tmp->button()) {
00189 oss << Util::stringForModMask(tmp->modMask())
00190 << Util::stringForButton(tmp->button());
00191 }
00192 else {
00193 oss << Util::stringForModMask(tmp->modMask())
00194 << XCORE->keyCodeToString(tmp->keyCode());
00195 }
00196 tmp = tmp->next();
00197 if (tmp) {
00198 oss << " :: ";
00199 }
00200 }
00201 if (shortcut) {
00202 oss << "\n";
00203 }
00204 }
00205
00206 string result = oss.str();
00207 if (result == "") {
00208 result = "no key bindings defined\n";
00209 }
00210 return result;
00211 }
00212
00213 void Binder::handleButton(Window window, XButtonEvent *event)
00214 {
00215 LOGDEBUG("handle button press event");
00216 handleShortcut(window, event->state, 0, event->button);
00217 }
00218
00219 void Binder::handleShortcut(Window window, unsigned long modMask,
00220 KeyCode keyCode, unsigned int button)
00221 {
00222 LOGDEBUG("handle shortcut event");
00223 LAction grabbedActions;
00224
00225
00226 for (MBindings::iterator it = actionBindings_->begin();
00227 it != actionBindings_->end(); it++)
00228 {
00229 Action *action = (*it).second;
00230 Shortcut *shortcut = action->listenOn();
00231
00232 if (shortcut &&
00233 (modMask == shortcut->modMask()) &&
00234 (keyCode == shortcut->keyCode()) &&
00235 (button == shortcut->button()))
00236 {
00237 if (shortcut->next()) {
00238 action->setListenOn(shortcut->next());
00239 grabbedActions.push_back(action);
00240 }
00241 else {
00242 grabbedActions.clear();
00243 LOGDEBUG("handle shortcut performs action '"
00244 + action->id() + "'");
00245 if (action->promptsCount() > 0) {
00246 KERNEL->focusedMonitor()->inputBar()->runArgument(action);
00247
00248 }
00249 else {
00250 action->perform();
00251 }
00252 break;
00253 }
00254 }
00255 }
00256 if (grabbedActions.size()) {
00257 Shortcut shortcut(modMask, keyCode, 0, button);
00258
00259 handleShortcutChains(window, &shortcut, &grabbedActions);
00260 }
00261
00262 for (MBindings::iterator it = actionBindings_->begin();
00263 it != actionBindings_->end(); it++)
00264 {
00265 Action *action = (*it).second;
00266 if (action->shortcut()) {
00267
00268 action->setListenOn(action->shortcut());
00269 }
00270 }
00271 }
00272
00273 void Binder::handleShortcutChains(Window window, Shortcut *prefix,
00274 LAction *grabbedActions)
00275 {
00276 string sequence =
00277 " " + Util::stringForModMask(prefix->modMask())
00278 + XCORE->keyCodeToString(prefix->keyCode()) + " ::";
00279 Box *box = KERNEL->focusedMonitor()->box();
00280 box->setText(sequence);
00281 box->show();
00282 box->illuminate();
00283
00284 XCORE->grabKeyboard(window);
00285
00286 bool isDoubleShortcut = false;
00287 unsigned long modMask;
00288 KeyCode keyCode;
00289 Action *action = 0;
00290 while (grabbedActions->size()) {
00291
00292 nextKeystroke(&modMask, &keyCode);
00293
00294 if ((prefix->modMask() == modMask) &&
00295 (prefix->keyCode() == keyCode))
00296 {
00297 isDoubleShortcut = true;
00298 break;
00299 }
00300 prefix->setModMask(modMask);
00301 prefix->setKeyCode(keyCode);
00302 sequence += " " + Util::stringForModMask(modMask)
00303 + XCORE->keyCodeToString(keyCode) + " ::";
00304 box->setText(sequence);
00305 box->illuminate();
00306 for (LAction::iterator it = grabbedActions->begin();
00307 it != grabbedActions->end(); )
00308 {
00309 action = *it;
00310 Shortcut *shortcut = action->listenOn();
00311 if (shortcut &&
00312 (modMask == shortcut->modMask()) &&
00313 (keyCode == shortcut->keyCode()))
00314 {
00315
00316 it++;
00317 if (shortcut->next()) {
00318 action->setListenOn(shortcut->next());
00319 }
00320 else {
00321 grabbedActions->clear();
00322 break;
00323 }
00324 }
00325 else {
00326
00327 it = grabbedActions->erase(it);
00328 }
00329 action = 0;
00330 }
00331 }
00332 XCORE->ungrabKeyboard();
00333 box->hide();
00334 if (action) {
00335
00336 LOGDEBUG("handle shortcut performs action '"
00337 + action->id() + "'");
00338 if (action->promptsCount() > 0) {
00339 KERNEL->focusedMonitor()->inputBar()->runArgument(action);
00340
00341 }
00342 else {
00343 action->perform();
00344 }
00345 }
00346 else if (isDoubleShortcut) {
00347 emulateKeyPress(modMask, keyCode);
00348 }
00349 }
00350
00351 void Binder::emulateKeyPress(unsigned long modMask, KeyCode keyCode) {
00352
00353 Monitor *monitor = KERNEL->focusedMonitor();
00354 Client *client = monitor->focused()->topClient();
00355
00356 if (client) {
00357 XEvent event;
00358 event.xkey.type = KeyPress;
00359 event.xkey.time = CurrentTime;
00360 event.xkey.window = client->clientWindow();
00361 event.xkey.display = KERNEL->display();
00362 event.xkey.state = modMask;
00363 event.xkey.keycode = keyCode;
00364 XCORE->sendEvent(client->clientWindow(), KeyPressMask, &event);
00365 event.xkey.type = KeyRelease;
00366 XCORE->sendEvent(client->clientWindow(), KeyReleaseMask, &event);
00367 XCORE->sync();
00368 }
00369 }
00370
00371 void Binder::nextKeystroke(unsigned long *modMask, KeyCode *keyCode) {
00372 XEvent event;
00373 KeySym sym;
00374 *modMask = 0;
00375 do {
00376 XCORE->maskEvent(KeyPressMask, &event);
00377 *modMask |= event.xkey.state & validModMask_;
00378 *keyCode = event.xkey.keycode;
00379 sym = XCORE->keyCodeToKeySym(event.xkey.keycode);
00380 } while (IsModifierKey(sym));
00381 }
00382
00383 void Binder::handleKey(Window window, XKeyEvent *event)
00384 {
00385 LOGDEBUG("handle key press event");
00386 handleShortcut(window, event->state, event->keycode, 0);
00387 }
00388
00389 void Binder::grabButtons(Window window, unsigned long modMask)
00390 {
00391 XCORE->grabButton(window, modMask, AnyModifier);
00392 }
00393
00394 void Binder::ungrabButtons(Window window) {
00395 XCORE->ungrabButton(window, AnyModifier, AnyButton);
00396 }
00397
00398 #ifdef POSIX_REGEX
00399 bool Binder::regex_first_match(const string& pattern, const string& haystack, int& begin, int& end){
00400 regmatch_t temp_regmatch;
00401
00402 begin = 0;
00403 end = -1 ;
00404 bool condition = false;
00405 if (pattern == temp_pattern_ && pattern!="") { condition = true; } else
00406 {
00407 condition = (regcomp(&temp_regex_, pattern.c_str(), REG_EXTENDED)==0);
00408 if (!condition) regex_prepare();
00409 }
00410 if (condition){
00411 bool result = (regexec(&temp_regex_, haystack.c_str(), 1, &temp_regmatch, 0)==0);
00412 if (result){
00413 begin = temp_regmatch.rm_so;
00414 end = temp_regmatch.rm_eo;
00415 }
00416 temp_pattern_ = pattern;
00417 return result;
00418 }
00419 return false;
00420 }
00421
00422 bool Binder::regex_match(const string& pattern, const string& haystack){
00423 int begin;
00424 int end;
00425 return(regex_first_match(pattern, haystack, begin, end));
00426 }
00427 #endif
00428
00429
00430 string Binder::absolutePattern(string pattern, Sstring *names,
00431 unsigned int offset)
00432 {
00433
00434 string result = pattern;
00435 if (!(names->empty())) {
00436
00437 #ifdef POSIX_REGEX
00438 if (doRegex_) {
00439
00440
00441
00442
00443
00444 string first = *names->begin();
00445 for (int direction = 0; direction <= 1; direction++){
00446 bool matches_all = true;
00447 do {
00448 LOGDEBUG("Entering do-while-infix-matching-loop");
00449 int begin;
00450 int end;
00451
00452 if (regex_first_match (result, first, begin, end)){
00453 LOGDEBUG("pattern-rule matched first member");
00454 int count = end - begin + 1;
00455 if (direction == 1) begin--;
00456 if ((begin + count <= (int)first.length()) && (begin >= 0) && (count>0)){
00457 pattern=first.substr(begin, count);
00458 LOGDEBUG("trying to add a char to pattern");
00459 LOGDEBUG(pattern);
00460 } else break;
00461 }
00462
00463 for (Sstring::iterator it = names->begin(); it != names->end(); it++)
00464 if(!regex_match(pattern, (*it))) matches_all = false;
00465 if (matches_all) result = pattern;
00466 } while (matches_all);
00467 }
00468 return(result);
00469 }
00470 #endif
00471
00472 string firstName = *names->begin();
00473 string lastName = *names->rbegin();
00474
00475 unsigned int firstLength = firstName.length();
00476 unsigned int lastLength = lastName.length();
00477 for (unsigned int i = offset;
00478 (i < firstLength) && (i < lastLength); i++)
00479 {
00480 if (firstName[i] == lastName[i]) {
00481 result += firstName[i];
00482 }
00483 else {
00484 break;
00485 }
00486 }
00487 }
00488
00489 return result;
00490 }
00491
00492 void Binder::matchPattern(string digest, string pattern, Sstring *strings,
00493 unsigned int patternLength)
00494 {
00495 bool condition;
00496 condition = (digest.substr(0, patternLength) == pattern);
00497
00498 #ifdef POSIX_REGEX
00499 if (doRegex_) {
00500 condition = regex_match(pattern, digest);
00501 }
00502 #endif
00503
00504 if (condition) {
00505 strings->insert(digest);
00506 }
00507 }
00508
00509 void Binder::initRegex(string pattern){
00510 #ifdef POSIX_REGEX
00511 doRegex_ = Util::get(KERNEL->commonSettings(), "autocompletion.mode") == "regex";
00512 #endif
00513 }
00514
00515 string Binder::queryFramesForPattern(string pattern, Sstring *sFrames)
00516 {
00517
00518 Workspace *workspace = KERNEL->focusedMonitor()->focused();
00519 CFrame *frames = workspace->frames();
00520 unsigned int patternLength = pattern.length();
00521 string lName;
00522 initRegex(pattern);
00523 for (LFrame::iterator it = frames->begin(); it != frames->end(); it++) {
00524 Frame *frame = *it;
00525 matchPattern(frame->name(), pattern,
00526 sFrames, patternLength);
00527 }
00528 return absolutePattern(pattern, sFrames, patternLength);
00529 }
00530
00531 string Binder::queryClientIdsForPattern(string pattern, Sstring *clients)
00532 {
00533
00534 Monitor *focusedMonitor = KERNEL->focusedMonitor();
00535 MClient *clientMap = focusedMonitor->clients();
00536 unsigned int patternLength = pattern.length();
00537 initRegex(pattern);
00538 for (MClient::iterator it = clientMap->begin();
00539 it != clientMap->end(); it++)
00540 {
00541 Client *client = (*it).second;
00542 if (client->attached()
00543 #ifdef SLOT_SUPPORT
00544 || client->mode() == Client::SLOT
00545 #endif // SLOT_SUPPORT
00546 )
00547 {
00548 matchPattern(client->id(), pattern, clients, patternLength);
00549 }
00550 }
00551 return absolutePattern(pattern, clients, pattern.length());
00552 }
00553
00554 string Binder::queryClientsForPattern(string pattern, Sstring *clients)
00555 {
00556
00557 Monitor *focusedMonitor = KERNEL->focusedMonitor();
00558 MClient *clientMap = focusedMonitor->clients();
00559 unsigned int patternLength = pattern.length();
00560 initRegex(pattern);
00561 for (MClient::iterator it = clientMap->begin();
00562 it != clientMap->end(); it++)
00563 {
00564 Client *client = (*it).second;
00565 if (client->attached()
00566 #ifdef SLOT_SUPPORT
00567 || client->mode() == Client::SLOT
00568 #endif
00569 )
00570 {
00571 matchPattern(client->name(), pattern, clients, patternLength);
00572 }
00573 }
00574 return absolutePattern(pattern, clients, pattern.length());
00575 }
00576
00577 string Binder::queryDetachedClientsForPattern(string pattern, Sstring *clients)
00578 {
00579
00580 Monitor *focusedMonitor = KERNEL->focusedMonitor();
00581 CClient *detachedClients = focusedMonitor->detachedClients();
00582 unsigned int patternLength = pattern.length();
00583 initRegex(pattern);
00584 for (LClient::iterator it = detachedClients->begin();
00585 it != detachedClients->end(); it++)
00586 {
00587 Client *client = *it;
00588 matchPattern(client->name(), pattern, clients, patternLength);
00589 }
00590 return absolutePattern(pattern, clients, pattern.length());
00591 }
00592
00593 string Binder::queryMonitorsForPattern(string pattern, Sstring *monitors) {
00594
00595 CMonitor *ms = KERNEL->monitors();
00596 unsigned int patternLength = pattern.length();
00597 initRegex(pattern);
00598 for (LMonitor::iterator it = ms->begin(); it != ms->end(); it++) {
00599 matchPattern((*it)->displayString(), pattern, monitors, patternLength);
00600 }
00601
00602 return absolutePattern(pattern, monitors, patternLength);
00603 }
00604
00605 string Binder::queryWorkspacesForPattern(string pattern,
00606 Sstring *workspaces)
00607 {
00608
00609 Monitor *focusedMonitor = KERNEL->focusedMonitor();
00610 unsigned int patternLength = pattern.length();
00611 string wsName;
00612 initRegex(pattern);
00613 for (LWorkspace::iterator it = focusedMonitor->begin();
00614 it != focusedMonitor->end(); it++)
00615 {
00616 matchPattern((*it)->name(), pattern, workspaces, patternLength);
00617 }
00618
00619 return absolutePattern(pattern, workspaces, patternLength);
00620 }
00621
00622 string Binder::queryExternChainActionsForPattern(
00623 string pattern, Sstring *actionKeys)
00624 {
00625 unsigned int patternLength = pattern.length();
00626 string actionKey;
00627 Action *action;
00628 initRegex(pattern);
00629 for (MBindings::iterator it = actionBindings_->begin();
00630 it != actionBindings_->end(); it++)
00631 {
00632 actionKey = (*it).first;
00633 action = (*it).second;
00634 if (action->type() == Action::INTERN) {
00635 continue;
00636 }
00637 matchPattern(actionKey, pattern, actionKeys, patternLength);
00638 }
00639
00640 return absolutePattern(pattern, actionKeys, patternLength);
00641 }
00642
00643 string Binder::queryActionKeysWithoutValidationForPattern(
00644 string pattern, Sstring *actionKeys)
00645 {
00646 unsigned int patternLength = pattern.length();
00647 string actionKey;
00648 initRegex(pattern);
00649 for (MBindings::iterator it = actionBindings_->begin();
00650 it != actionBindings_->end(); it++)
00651 {
00652 actionKey = (*it).first;
00653 matchPattern(actionKey, pattern, actionKeys, patternLength);
00654 }
00655
00656 return absolutePattern(pattern, actionKeys, patternLength);
00657 }
00658
00659 string Binder::queryActionKeysForPattern(string pattern, Sstring *actionKeys) {
00660
00661 unsigned int patternLength = pattern.length();
00662 string actionKey;
00663 initRegex(pattern);
00664 for (MBindings::iterator it = actionBindings_->begin();
00665 it != actionBindings_->end(); it++)
00666 {
00667 Action *action = (*it).second;
00668
00669 if (action->isValid()) {
00670 actionKey = (*it).first;
00671 matchPattern(actionKey, pattern, actionKeys, patternLength);
00672 }
00673 }
00674
00675 return absolutePattern(pattern, actionKeys, patternLength);
00676 }
00677
00678 string Binder::queryCommandForPattern(string pattern, Sstring *expands) {
00679
00680 Expander::instance()->queryString(pattern);
00681 Sstring exp = Expander::instance()->expands();
00682 initRegex(pattern);
00683
00684
00685 unsigned int offset = pattern.find_last_of('/');
00686 if (offset == string::npos) offset=0; else offset++;
00687
00688 #ifdef POSIX_REGEX
00689 doRegex_ = doRegex_ && (offset == 0);
00690 #endif
00691
00692 for (Sstring::iterator it = exp.begin();
00693 it != exp.end(); it++)
00694 {
00695 matchPattern((string)(*it), pattern.substr(offset), expands, pattern.length()-offset);
00696 }
00697
00698 return absolutePattern(pattern, expands, pattern.length() -
00699 pattern.find_last_of('/') - 1);
00700 }
00701
00702 #define NUM_MASKS 8
00703
00704 void Binder::initLockModifiers() {
00705 XModifierKeymap *modmap;
00706 KeyCode numLock, scrollLock;
00707
00708
00709 numLockMask_ = scrollLockMask_ = 0;
00710
00711
00712 modmap = XCORE->modifierMapping();
00713
00714
00715 static int masks[NUM_MASKS] = {
00716 ShiftMask, LockMask, ControlMask, Mod1Mask,
00717 Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
00718 };
00719
00720
00721 numLock = XCORE->stringToKeyCode("Num_Lock");
00722 scrollLock = XCORE->stringToKeyCode("Scroll_Lock");
00723
00724 if (modmap && modmap->max_keypermod > 0) {
00725 unsigned int max = NUM_MASKS * modmap->max_keypermod;
00726 for (unsigned int i = 0; i < max; i++) {
00727 if (numLock && (modmap->modifiermap[i] == numLock)) {
00728 numLockMask_ = masks[i / modmap->max_keypermod];
00729 }
00730 else if (scrollLock && (modmap->modifiermap[i] == scrollLock)) {
00731 scrollLockMask_ = masks[i / modmap->max_keypermod];
00732 }
00733 }
00734 }
00735
00736 XCORE->freeModifierMapping(modmap);
00737 validModMask_ = 255 & ~(numLockMask_ | scrollLockMask_ | LockMask);
00738 }
00739
00740 unsigned int Binder::validModMask() const {
00741 return validModMask_;
00742 }