Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members

CInputFilter.cpp

00001 /*
00002  * synergy -- mouse and keyboard sharing utility
00003  * Copyright (C) 2005 Chris Schoeneman
00004  * 
00005  * This package is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU General Public License
00007  * found in the file COPYING that should have accompanied this file.
00008  * 
00009  * This package is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  */
00014 
00015 #include "CInputFilter.h"
00016 #include "CServer.h"
00017 #include "CPrimaryClient.h"
00018 #include "CKeyMap.h"
00019 #include "CEventQueue.h"
00020 #include "CLog.h"
00021 #include "TMethodEventJob.h"
00022 #include <cstdlib>
00023 #include <cstring>
00024 
00025 // -----------------------------------------------------------------------------
00026 // Input Filter Condition Classes
00027 // -----------------------------------------------------------------------------
00028 CInputFilter::CCondition::CCondition()
00029 {
00030     // do nothing
00031 }
00032 
00033 CInputFilter::CCondition::~CCondition()
00034 {
00035     // do nothing
00036 }
00037 
00038 void
00039 CInputFilter::CCondition::enablePrimary(CPrimaryClient*)
00040 {
00041     // do nothing
00042 }
00043 
00044 void
00045 CInputFilter::CCondition::disablePrimary(CPrimaryClient*)
00046 {
00047     // do nothing
00048 }
00049 
00050 CInputFilter::CKeystrokeCondition::CKeystrokeCondition(
00051         IPlatformScreen::CKeyInfo* info) :
00052     m_id(0),
00053     m_key(info->m_key),
00054     m_mask(info->m_mask)
00055 {
00056     free(info);
00057 }
00058 
00059 CInputFilter::CKeystrokeCondition::CKeystrokeCondition(
00060         KeyID key, KeyModifierMask mask) :
00061     m_id(0),
00062     m_key(key),
00063     m_mask(mask)
00064 {
00065     // do nothing
00066 }
00067 
00068 CInputFilter::CKeystrokeCondition::~CKeystrokeCondition()
00069 {
00070     // do nothing
00071 }
00072 
00073 KeyID
00074 CInputFilter::CKeystrokeCondition::getKey() const
00075 {
00076     return m_key;
00077 }
00078 
00079 KeyModifierMask
00080 CInputFilter::CKeystrokeCondition::getMask() const
00081 {
00082     return m_mask;
00083 }
00084 
00085 CInputFilter::CCondition*
00086 CInputFilter::CKeystrokeCondition::clone() const
00087 {
00088     return new CKeystrokeCondition(m_key, m_mask);
00089 }
00090 
00091 CString
00092 CInputFilter::CKeystrokeCondition::format() const
00093 {
00094     return CStringUtil::print("keystroke(%s)",
00095                             CKeyMap::formatKey(m_key, m_mask).c_str());
00096 }
00097 
00098 CInputFilter::EFilterStatus
00099 CInputFilter::CKeystrokeCondition::match(const CEvent& event)
00100 {
00101     EFilterStatus status;
00102 
00103     // check for hotkey events
00104     CEvent::Type type = event.getType();
00105     if (type == IPrimaryScreen::getHotKeyDownEvent()) {
00106         status = kActivate;
00107     }
00108     else if (type == IPrimaryScreen::getHotKeyUpEvent()) {
00109         status = kDeactivate;
00110     }
00111     else {
00112         return kNoMatch;
00113     }
00114 
00115     // check if it's our hotkey
00116     IPrimaryScreen::CHotKeyInfo* kinfo =
00117         reinterpret_cast<IPlatformScreen::CHotKeyInfo*>(event.getData());
00118     if (kinfo->m_id != m_id) {
00119         return kNoMatch;
00120     }
00121 
00122     return status;
00123 }
00124 
00125 void
00126 CInputFilter::CKeystrokeCondition::enablePrimary(CPrimaryClient* primary)
00127 {
00128     m_id = primary->registerHotKey(m_key, m_mask);
00129 }
00130 
00131 void
00132 CInputFilter::CKeystrokeCondition::disablePrimary(CPrimaryClient* primary)
00133 {
00134     primary->unregisterHotKey(m_id);
00135     m_id = 0;
00136 }
00137 
00138 CInputFilter::CMouseButtonCondition::CMouseButtonCondition(
00139         IPlatformScreen::CButtonInfo* info) :
00140     m_button(info->m_button),
00141     m_mask(info->m_mask)
00142 {
00143     free(info);
00144 }
00145 
00146 CInputFilter::CMouseButtonCondition::CMouseButtonCondition(
00147         ButtonID button, KeyModifierMask mask) :
00148     m_button(button),
00149     m_mask(mask)
00150 {
00151     // do nothing
00152 }
00153 
00154 CInputFilter::CMouseButtonCondition::~CMouseButtonCondition()
00155 {
00156     // do nothing
00157 }
00158 
00159 ButtonID
00160 CInputFilter::CMouseButtonCondition::getButton() const
00161 {
00162     return m_button;
00163 }
00164 
00165 KeyModifierMask
00166 CInputFilter::CMouseButtonCondition::getMask() const
00167 {
00168     return m_mask;
00169 }
00170 
00171 CInputFilter::CCondition*
00172 CInputFilter::CMouseButtonCondition::clone() const
00173 {
00174     return new CMouseButtonCondition(m_button, m_mask);
00175 }
00176 
00177 CString
00178 CInputFilter::CMouseButtonCondition::format() const
00179 {
00180     CString key = CKeyMap::formatKey(kKeyNone, m_mask);
00181     if (!key.empty()) {
00182         key += "+";
00183     }
00184     return CStringUtil::print("mousebutton(%s%d)", key.c_str(), m_button);
00185 }
00186 
00187 CInputFilter::EFilterStatus     
00188 CInputFilter::CMouseButtonCondition::match(const CEvent& event)
00189 {
00190     static const KeyModifierMask s_ignoreMask =
00191         KeyModifierAltGr | KeyModifierCapsLock |
00192         KeyModifierNumLock | KeyModifierScrollLock;
00193 
00194     EFilterStatus status;
00195 
00196     // check for hotkey events
00197     CEvent::Type type = event.getType();
00198     if (type == IPrimaryScreen::getButtonDownEvent()) {
00199         status = kActivate;
00200     }
00201     else if (type == IPrimaryScreen::getButtonUpEvent()) {
00202         status = kDeactivate;
00203     }
00204     else {
00205         return kNoMatch;
00206     }
00207 
00208     // check if it's the right button and modifiers.  ignore modifiers
00209     // that cannot be combined with a mouse button.
00210     IPlatformScreen::CButtonInfo* minfo =
00211         reinterpret_cast<IPlatformScreen::CButtonInfo*>(event.getData());
00212     if (minfo->m_button != m_button ||
00213         (minfo->m_mask & ~s_ignoreMask) != m_mask) {
00214         return kNoMatch;
00215     }
00216 
00217     return status;
00218 }
00219 
00220 CInputFilter::CScreenConnectedCondition::CScreenConnectedCondition(
00221                 const CString& screen) :
00222     m_screen(screen)
00223 {
00224     // do nothing
00225 }
00226 
00227 CInputFilter::CScreenConnectedCondition::~CScreenConnectedCondition()
00228 {
00229     // do nothing
00230 }
00231 
00232 CInputFilter::CCondition*
00233 CInputFilter::CScreenConnectedCondition::clone() const
00234 {
00235     return new CScreenConnectedCondition(m_screen);
00236 }
00237 
00238 CString
00239 CInputFilter::CScreenConnectedCondition::format() const
00240 {
00241     return CStringUtil::print("connect(%s)", m_screen.c_str());
00242 }
00243 
00244 CInputFilter::EFilterStatus
00245 CInputFilter::CScreenConnectedCondition::match(const CEvent& event)
00246 {
00247     if (event.getType() == CServer::getConnectedEvent()) {
00248         CServer::CScreenConnectedInfo* info = 
00249             reinterpret_cast<CServer::CScreenConnectedInfo*>(event.getData());
00250         if (m_screen == info->m_screen || m_screen.empty()) {
00251             return kActivate;
00252         }
00253     }
00254 
00255     return kNoMatch;
00256 }
00257 
00258 // -----------------------------------------------------------------------------
00259 // Input Filter Action Classes
00260 // -----------------------------------------------------------------------------
00261 CInputFilter::CAction::CAction()
00262 {
00263     // do nothing
00264 }
00265 
00266 CInputFilter::CAction::~CAction()
00267 {
00268     // do nothing
00269 }
00270 
00271 CInputFilter::CLockCursorToScreenAction::CLockCursorToScreenAction(Mode mode) :
00272     m_mode(mode)
00273 {
00274     // do nothing
00275 }
00276 
00277 CInputFilter::CLockCursorToScreenAction::Mode
00278 CInputFilter::CLockCursorToScreenAction::getMode() const
00279 {
00280     return m_mode;
00281 }
00282 
00283 CInputFilter::CAction*
00284 CInputFilter::CLockCursorToScreenAction::clone() const
00285 {
00286     return new CLockCursorToScreenAction(*this);
00287 }
00288 
00289 CString
00290 CInputFilter::CLockCursorToScreenAction::format() const
00291 {
00292     static const char* s_mode[] = { "off", "on", "toggle" };
00293 
00294     return CStringUtil::print("lockCursorToScreen(%s)", s_mode[m_mode]);
00295 }
00296 
00297 void
00298 CInputFilter::CLockCursorToScreenAction::perform(const CEvent& event)
00299 {
00300     static const CServer::CLockCursorToScreenInfo::State s_state[] = {
00301         CServer::CLockCursorToScreenInfo::kOff,
00302         CServer::CLockCursorToScreenInfo::kOn,
00303         CServer::CLockCursorToScreenInfo::kToggle
00304     };
00305 
00306     // send event
00307     CServer::CLockCursorToScreenInfo* info = 
00308         CServer::CLockCursorToScreenInfo::alloc(s_state[m_mode]);
00309     EVENTQUEUE->addEvent(CEvent(CServer::getLockCursorToScreenEvent(),
00310                                 event.getTarget(), info,
00311                                 CEvent::kDeliverImmediately));
00312 }
00313 
00314 CInputFilter::CSwitchToScreenAction::CSwitchToScreenAction(
00315                 const CString& screen) :
00316     m_screen(screen)
00317 {
00318     // do nothing
00319 }
00320 
00321 CString
00322 CInputFilter::CSwitchToScreenAction::getScreen() const
00323 {
00324     return m_screen;
00325 }
00326 
00327 CInputFilter::CAction*
00328 CInputFilter::CSwitchToScreenAction::clone() const
00329 {
00330     return new CSwitchToScreenAction(*this);
00331 }
00332 
00333 CString
00334 CInputFilter::CSwitchToScreenAction::format() const
00335 {
00336     return CStringUtil::print("switchToScreen(%s)", m_screen.c_str());
00337 }
00338 
00339 void
00340 CInputFilter::CSwitchToScreenAction::perform(const CEvent& event)
00341 {
00342     // pick screen name.  if m_screen is empty then use the screen from
00343     // event if it has one.
00344     CString screen = m_screen;
00345     if (screen.empty() && event.getType() == CServer::getConnectedEvent()) {
00346         CServer::CScreenConnectedInfo* info = 
00347             reinterpret_cast<CServer::CScreenConnectedInfo*>(event.getData());
00348         screen = info->m_screen;
00349     }
00350 
00351     // send event
00352     CServer::CSwitchToScreenInfo* info =
00353         CServer::CSwitchToScreenInfo::alloc(screen);
00354     EVENTQUEUE->addEvent(CEvent(CServer::getSwitchToScreenEvent(),
00355                                 event.getTarget(), info,
00356                                 CEvent::kDeliverImmediately));
00357 }
00358 
00359 CInputFilter::CSwitchInDirectionAction::CSwitchInDirectionAction(
00360                 EDirection direction) :
00361     m_direction(direction)
00362 {
00363     // do nothing
00364 }
00365 
00366 EDirection
00367 CInputFilter::CSwitchInDirectionAction::getDirection() const
00368 {
00369     return m_direction;
00370 }
00371 
00372 CInputFilter::CAction*
00373 CInputFilter::CSwitchInDirectionAction::clone() const
00374 {
00375     return new CSwitchInDirectionAction(*this);
00376 }
00377 
00378 CString
00379 CInputFilter::CSwitchInDirectionAction::format() const
00380 {
00381     static const char* s_names[] = {
00382         "",
00383         "left",
00384         "right",
00385         "up",
00386         "down"
00387     };
00388 
00389     return CStringUtil::print("switchInDirection(%s)", s_names[m_direction]);
00390 }
00391 
00392 void
00393 CInputFilter::CSwitchInDirectionAction::perform(const CEvent& event)
00394 {
00395     CServer::CSwitchInDirectionInfo* info =
00396         CServer::CSwitchInDirectionInfo::alloc(m_direction);
00397     EVENTQUEUE->addEvent(CEvent(CServer::getSwitchInDirectionEvent(),
00398                                 event.getTarget(), info,
00399                                 CEvent::kDeliverImmediately));
00400 }
00401 
00402 CInputFilter::CKeyboardBroadcastAction::CKeyboardBroadcastAction(Mode mode) :
00403     m_mode(mode)
00404 {
00405     // do nothing
00406 }
00407 
00408 CInputFilter::CKeyboardBroadcastAction::CKeyboardBroadcastAction(
00409         Mode mode,
00410         const std::set<CString>& screens) :
00411     m_mode(mode),
00412     m_screens(IKeyState::CKeyInfo::join(screens))
00413 {
00414     // do nothing
00415 }
00416 
00417 CInputFilter::CKeyboardBroadcastAction::Mode
00418 CInputFilter::CKeyboardBroadcastAction::getMode() const
00419 {
00420     return m_mode;
00421 }
00422 
00423 std::set<CString>
00424 CInputFilter::CKeyboardBroadcastAction::getScreens() const
00425 {
00426     std::set<CString> screens;
00427     IKeyState::CKeyInfo::split(m_screens.c_str(), screens);
00428     return screens;
00429 }
00430 
00431 CInputFilter::CAction*
00432 CInputFilter::CKeyboardBroadcastAction::clone() const
00433 {
00434     return new CKeyboardBroadcastAction(*this);
00435 }
00436 
00437 CString
00438 CInputFilter::CKeyboardBroadcastAction::format() const
00439 {
00440     static const char* s_mode[] = { "off", "on", "toggle" };
00441     static const char* s_name = "keyboardBroadcast";
00442 
00443     if (m_screens.empty() || m_screens[0] == '*') {
00444         return CStringUtil::print("%s(%s)", s_name, s_mode[m_mode]);
00445     }
00446     else {
00447         return CStringUtil::print("%s(%s,%.*s)", s_name, s_mode[m_mode],
00448                             m_screens.size() - 2,
00449                             m_screens.c_str() + 1);
00450     }
00451 }
00452 
00453 void
00454 CInputFilter::CKeyboardBroadcastAction::perform(const CEvent& event)
00455 {
00456     static const CServer::CKeyboardBroadcastInfo::State s_state[] = {
00457         CServer::CKeyboardBroadcastInfo::kOff,
00458         CServer::CKeyboardBroadcastInfo::kOn,
00459         CServer::CKeyboardBroadcastInfo::kToggle
00460     };
00461 
00462     // send event
00463     CServer::CKeyboardBroadcastInfo* info = 
00464         CServer::CKeyboardBroadcastInfo::alloc(s_state[m_mode], m_screens);
00465     EVENTQUEUE->addEvent(CEvent(CServer::getKeyboardBroadcastEvent(),
00466                                 event.getTarget(), info,
00467                                 CEvent::kDeliverImmediately));
00468 }
00469 
00470 CInputFilter::CKeystrokeAction::CKeystrokeAction(
00471         IPlatformScreen::CKeyInfo* info, bool press) :
00472     m_keyInfo(info),
00473     m_press(press)
00474 {
00475     // do nothing
00476 }
00477 
00478 CInputFilter::CKeystrokeAction::~CKeystrokeAction()
00479 {
00480     free(m_keyInfo);
00481 }
00482 
00483 void
00484 CInputFilter::CKeystrokeAction::adoptInfo(IPlatformScreen::CKeyInfo* info)
00485 {
00486     free(m_keyInfo);
00487     m_keyInfo = info;
00488 }
00489 
00490 const IPlatformScreen::CKeyInfo*
00491 CInputFilter::CKeystrokeAction::getInfo() const
00492 {
00493     return m_keyInfo;
00494 }
00495 
00496 bool
00497 CInputFilter::CKeystrokeAction::isOnPress() const
00498 {
00499     return m_press;
00500 }
00501 
00502 CInputFilter::CAction*
00503 CInputFilter::CKeystrokeAction::clone() const
00504 {
00505     IKeyState::CKeyInfo* info = IKeyState::CKeyInfo::alloc(*m_keyInfo);
00506     return new CKeystrokeAction(info, m_press);
00507 }
00508 
00509 CString
00510 CInputFilter::CKeystrokeAction::format() const
00511 {
00512     const char* type = formatName();
00513 
00514     if (m_keyInfo->m_screens[0] == '\0') {
00515         return CStringUtil::print("%s(%s)", type,
00516                             CKeyMap::formatKey(m_keyInfo->m_key,
00517                                 m_keyInfo->m_mask).c_str());
00518     }
00519     else if (m_keyInfo->m_screens[0] == '*') {
00520         return CStringUtil::print("%s(%s,*)", type,
00521                             CKeyMap::formatKey(m_keyInfo->m_key,
00522                                 m_keyInfo->m_mask).c_str());
00523     }
00524     else {
00525         return CStringUtil::print("%s(%s,%.*s)", type,
00526                             CKeyMap::formatKey(m_keyInfo->m_key,
00527                                 m_keyInfo->m_mask).c_str(),
00528                             strlen(m_keyInfo->m_screens + 1) - 1,
00529                             m_keyInfo->m_screens + 1);
00530     }
00531 }
00532 
00533 void
00534 CInputFilter::CKeystrokeAction::perform(const CEvent& event)
00535 {
00536     CEvent::Type type = m_press ? IPlatformScreen::getKeyDownEvent() :
00537                                 IPlatformScreen::getKeyUpEvent();
00538     EVENTQUEUE->addEvent(CEvent(IPlatformScreen::getFakeInputBeginEvent(),
00539                                 event.getTarget(), NULL,
00540                                 CEvent::kDeliverImmediately));
00541     EVENTQUEUE->addEvent(CEvent(type, event.getTarget(), m_keyInfo,
00542                                 CEvent::kDeliverImmediately |
00543                                 CEvent::kDontFreeData));
00544     EVENTQUEUE->addEvent(CEvent(IPlatformScreen::getFakeInputEndEvent(),
00545                                 event.getTarget(), NULL,
00546                                 CEvent::kDeliverImmediately));
00547 }
00548 
00549 const char*
00550 CInputFilter::CKeystrokeAction::formatName() const
00551 {
00552     return (m_press ? "keyDown" : "keyUp");
00553 }
00554 
00555 CInputFilter::CMouseButtonAction::CMouseButtonAction(
00556         IPlatformScreen::CButtonInfo* info, bool press) : 
00557     m_buttonInfo(info),
00558     m_press(press)
00559 {
00560     // do nothing
00561 }
00562 
00563 CInputFilter::CMouseButtonAction::~CMouseButtonAction()
00564 {
00565     free(m_buttonInfo);
00566 }
00567 
00568 const IPlatformScreen::CButtonInfo*
00569 CInputFilter::CMouseButtonAction::getInfo() const
00570 {
00571     return m_buttonInfo;
00572 }
00573 
00574 bool
00575 CInputFilter::CMouseButtonAction::isOnPress() const
00576 {
00577     return m_press;
00578 }
00579 
00580 CInputFilter::CAction*
00581 CInputFilter::CMouseButtonAction::clone() const
00582 {
00583     IPlatformScreen::CButtonInfo* info =
00584         IPrimaryScreen::CButtonInfo::alloc(*m_buttonInfo);
00585     return new CMouseButtonAction(info, m_press);
00586 }
00587 
00588 CString
00589 CInputFilter::CMouseButtonAction::format() const
00590 {
00591     const char* type = formatName();
00592 
00593     CString key = CKeyMap::formatKey(kKeyNone, m_buttonInfo->m_mask);
00594     return CStringUtil::print("%s(%s%s%d)", type,
00595                             key.c_str(), key.empty() ? "" : "+",
00596                             m_buttonInfo->m_button);
00597 }
00598 
00599 void
00600 CInputFilter::CMouseButtonAction::perform(const CEvent& event)
00601 
00602 {
00603     // send modifiers
00604     IPlatformScreen::CKeyInfo* modifierInfo = NULL;
00605     if (m_buttonInfo->m_mask != 0) {
00606         KeyID key = m_press ? kKeySetModifiers : kKeyClearModifiers;
00607         modifierInfo =
00608             IKeyState::CKeyInfo::alloc(key, m_buttonInfo->m_mask, 0, 1);
00609         EVENTQUEUE->addEvent(CEvent(IPlatformScreen::getKeyDownEvent(),
00610                                 event.getTarget(), modifierInfo,
00611                                 CEvent::kDeliverImmediately));
00612     }
00613 
00614     // send button
00615     CEvent::Type type = m_press ? IPlatformScreen::getButtonDownEvent() :
00616                                 IPlatformScreen::getButtonUpEvent();
00617     EVENTQUEUE->addEvent(CEvent(type, event.getTarget(), m_buttonInfo,
00618                                 CEvent::kDeliverImmediately |
00619                                 CEvent::kDontFreeData));
00620 }
00621 
00622 const char*
00623 CInputFilter::CMouseButtonAction::formatName() const
00624 {
00625     return (m_press ? "mouseDown" : "mouseUp");
00626 }
00627 
00628 //
00629 // CInputFilter::CRule
00630 //
00631 
00632 CInputFilter::CRule::CRule() :
00633     m_condition(NULL)
00634 {
00635     // do nothing
00636 }
00637 
00638 CInputFilter::CRule::CRule(CCondition* adoptedCondition) :
00639     m_condition(adoptedCondition)
00640 {
00641     // do nothing
00642 }
00643 
00644 CInputFilter::CRule::CRule(const CRule& rule) :
00645     m_condition(NULL)
00646 {
00647     copy(rule);
00648 }
00649 
00650 CInputFilter::CRule::~CRule()
00651 {
00652     clear();
00653 }
00654 
00655 CInputFilter::CRule&
00656 CInputFilter::CRule::operator=(const CRule& rule)
00657 {
00658     if (&rule != this) {
00659         copy(rule);
00660     }
00661     return *this;
00662 }
00663 
00664 void
00665 CInputFilter::CRule::clear()
00666 {
00667     delete m_condition;
00668     for (CActionList::iterator i = m_activateActions.begin();
00669                                 i != m_activateActions.end(); ++i) {
00670         delete *i;
00671     }
00672     for (CActionList::iterator i = m_deactivateActions.begin();
00673                                 i != m_deactivateActions.end(); ++i) {
00674         delete *i;
00675     }
00676 
00677     m_condition = NULL;
00678     m_activateActions.clear();
00679     m_deactivateActions.clear();
00680 }
00681 
00682 void
00683 CInputFilter::CRule::copy(const CRule& rule)
00684 {
00685     clear();
00686     if (rule.m_condition != NULL) {
00687         m_condition = rule.m_condition->clone();
00688     }
00689     for (CActionList::const_iterator i = rule.m_activateActions.begin();
00690                                 i != rule.m_activateActions.end(); ++i) {
00691         m_activateActions.push_back((*i)->clone());
00692     }
00693     for (CActionList::const_iterator i = rule.m_deactivateActions.begin();
00694                                 i != rule.m_deactivateActions.end(); ++i) {
00695         m_deactivateActions.push_back((*i)->clone());
00696     }
00697 }
00698 
00699 void
00700 CInputFilter::CRule::setCondition(CCondition* adopted)
00701 {
00702     delete m_condition;
00703     m_condition = adopted;
00704 }
00705 
00706 void
00707 CInputFilter::CRule::adoptAction(CAction* action, bool onActivation)
00708 {
00709     if (action != NULL) {
00710         if (onActivation) {
00711             m_activateActions.push_back(action);
00712         }
00713         else {
00714             m_deactivateActions.push_back(action);
00715         }
00716     }
00717 }
00718 
00719 void
00720 CInputFilter::CRule::removeAction(bool onActivation, UInt32 index)
00721 {
00722     if (onActivation) {
00723         delete m_activateActions[index];
00724         m_activateActions.erase(m_activateActions.begin() + index);
00725     }
00726     else {
00727         delete m_deactivateActions[index];
00728         m_deactivateActions.erase(m_deactivateActions.begin() + index);
00729     }
00730 }
00731 
00732 void
00733 CInputFilter::CRule::replaceAction(CAction* adopted,
00734                 bool onActivation, UInt32 index)
00735 {
00736     if (adopted == NULL) {
00737         removeAction(onActivation, index);
00738     }
00739     else if (onActivation) {
00740         delete m_activateActions[index];
00741         m_activateActions[index] = adopted;
00742     }
00743     else {
00744         delete m_deactivateActions[index];
00745         m_deactivateActions[index] = adopted;
00746     }
00747 }
00748 
00749 void
00750 CInputFilter::CRule::enable(CPrimaryClient* primaryClient)
00751 {
00752     if (m_condition != NULL) {
00753         m_condition->enablePrimary(primaryClient);
00754     }
00755 }
00756 
00757 void
00758 CInputFilter::CRule::disable(CPrimaryClient* primaryClient)
00759 {
00760     if (m_condition != NULL) {
00761         m_condition->disablePrimary(primaryClient);
00762     }
00763 }
00764 
00765 bool
00766 CInputFilter::CRule::handleEvent(const CEvent& event)
00767 {
00768     // NULL condition never matches
00769     if (m_condition == NULL) {
00770         return false;
00771     }
00772 
00773     // match
00774     const CActionList* actions;
00775     switch (m_condition->match(event)) {
00776     default:
00777         // not handled
00778         return false;
00779 
00780     case kActivate:
00781         actions = &m_activateActions;
00782         LOG((CLOG_DEBUG1 "activate actions"));
00783         break;
00784 
00785     case kDeactivate:
00786         actions = &m_deactivateActions;
00787         LOG((CLOG_DEBUG1 "deactivate actions"));
00788         break;
00789     }
00790 
00791     // perform actions
00792     for (CActionList::const_iterator i = actions->begin();
00793                                 i != actions->end(); ++i) {
00794         LOG((CLOG_DEBUG1 "hotkey: %s", (*i)->format().c_str()));
00795         (*i)->perform(event);
00796     }
00797 
00798     return true;
00799 }
00800 
00801 CString
00802 CInputFilter::CRule::format() const
00803 {
00804     CString s;
00805     if (m_condition != NULL) {
00806         // condition
00807         s += m_condition->format();
00808         s += " = ";
00809 
00810         // activate actions
00811         CActionList::const_iterator i = m_activateActions.begin();
00812         if (i != m_activateActions.end()) {
00813             s += (*i)->format();
00814             while (++i != m_activateActions.end()) {
00815                 s += ", ";
00816                 s += (*i)->format();
00817             }
00818         }
00819 
00820         // deactivate actions
00821         if (!m_deactivateActions.empty()) {
00822             s += "; ";
00823             i = m_deactivateActions.begin();
00824             if (i != m_deactivateActions.end()) {
00825                 s += (*i)->format();
00826                 while (++i != m_deactivateActions.end()) {
00827                     s += ", ";
00828                     s += (*i)->format();
00829                 }
00830             }
00831         }
00832     }
00833     return s;
00834 }
00835 
00836 const CInputFilter::CCondition*
00837 CInputFilter::CRule::getCondition() const
00838 {
00839     return m_condition;
00840 }
00841 
00842 UInt32
00843 CInputFilter::CRule::getNumActions(bool onActivation) const
00844 {
00845     if (onActivation) {
00846         return static_cast<UInt32>(m_activateActions.size());
00847     }
00848     else {
00849         return static_cast<UInt32>(m_deactivateActions.size());
00850     }
00851 }
00852 
00853 const CInputFilter::CAction&
00854 CInputFilter::CRule::getAction(bool onActivation, UInt32 index) const
00855 {
00856     if (onActivation) {
00857         return *m_activateActions[index];
00858     }
00859     else {
00860         return *m_deactivateActions[index];
00861     }
00862 }
00863 
00864 
00865 // -----------------------------------------------------------------------------
00866 // Input Filter Class
00867 // -----------------------------------------------------------------------------
00868 CInputFilter::CInputFilter() :
00869     m_primaryClient(NULL)
00870 {
00871     // do nothing
00872 }
00873 
00874 CInputFilter::CInputFilter(const CInputFilter& x) :
00875     m_ruleList(x.m_ruleList),
00876     m_primaryClient(NULL)
00877 {
00878     setPrimaryClient(x.m_primaryClient);
00879 }
00880 
00881 CInputFilter::~CInputFilter()
00882 {
00883     setPrimaryClient(NULL);
00884 }
00885 
00886 CInputFilter&
00887 CInputFilter::operator=(const CInputFilter& x)
00888 {
00889     if (&x != this) {
00890         CPrimaryClient* oldClient = m_primaryClient;
00891         setPrimaryClient(NULL);
00892 
00893         m_ruleList = x.m_ruleList;
00894 
00895         setPrimaryClient(oldClient);
00896     }
00897     return *this;
00898 }
00899 
00900 void
00901 CInputFilter::addFilterRule(const CRule& rule)
00902 {
00903     m_ruleList.push_back(rule);
00904     if (m_primaryClient != NULL) {
00905         m_ruleList.back().enable(m_primaryClient);
00906     }
00907 }
00908 
00909 void
00910 CInputFilter::removeFilterRule(UInt32 index)
00911 {
00912     if (m_primaryClient != NULL) {
00913         m_ruleList[index].disable(m_primaryClient);
00914     }
00915     m_ruleList.erase(m_ruleList.begin() + index);
00916 }
00917 
00918 CInputFilter::CRule&
00919 CInputFilter::getRule(UInt32 index)
00920 {
00921     return m_ruleList[index];
00922 }
00923 
00924 void
00925 CInputFilter::setPrimaryClient(CPrimaryClient* client)
00926 {
00927     if (m_primaryClient == client) {
00928         return;
00929     }
00930 
00931     if (m_primaryClient != NULL) {
00932         for (CRuleList::iterator rule  = m_ruleList.begin();
00933                                  rule != m_ruleList.end(); ++rule) {
00934             rule->disable(m_primaryClient);
00935         }
00936 
00937         EVENTQUEUE->removeHandler(IPlatformScreen::getKeyDownEvent(),
00938                             m_primaryClient->getEventTarget());
00939         EVENTQUEUE->removeHandler(IPlatformScreen::getKeyUpEvent(),
00940                             m_primaryClient->getEventTarget());
00941         EVENTQUEUE->removeHandler(IPlatformScreen::getKeyRepeatEvent(),
00942                             m_primaryClient->getEventTarget());
00943         EVENTQUEUE->removeHandler(IPlatformScreen::getButtonDownEvent(),
00944                             m_primaryClient->getEventTarget());
00945         EVENTQUEUE->removeHandler(IPlatformScreen::getButtonUpEvent(),
00946                             m_primaryClient->getEventTarget());
00947         EVENTQUEUE->removeHandler(IPlatformScreen::getHotKeyDownEvent(),
00948                             m_primaryClient->getEventTarget());
00949         EVENTQUEUE->removeHandler(IPlatformScreen::getHotKeyUpEvent(),
00950                             m_primaryClient->getEventTarget());
00951         EVENTQUEUE->removeHandler(CServer::getConnectedEvent(),
00952                             m_primaryClient->getEventTarget());
00953     }
00954 
00955     m_primaryClient = client;
00956 
00957     if (m_primaryClient != NULL) {
00958         EVENTQUEUE->adoptHandler(IPlatformScreen::getKeyDownEvent(),
00959                             m_primaryClient->getEventTarget(),
00960                             new TMethodEventJob<CInputFilter>(this,
00961                                 &CInputFilter::handleEvent));
00962         EVENTQUEUE->adoptHandler(IPlatformScreen::getKeyUpEvent(),
00963                             m_primaryClient->getEventTarget(),
00964                             new TMethodEventJob<CInputFilter>(this,
00965                                 &CInputFilter::handleEvent));
00966         EVENTQUEUE->adoptHandler(IPlatformScreen::getKeyRepeatEvent(),
00967                             m_primaryClient->getEventTarget(),
00968                             new TMethodEventJob<CInputFilter>(this,
00969                                 &CInputFilter::handleEvent));
00970         EVENTQUEUE->adoptHandler(IPlatformScreen::getButtonDownEvent(),
00971                             m_primaryClient->getEventTarget(),
00972                             new TMethodEventJob<CInputFilter>(this,
00973                                 &CInputFilter::handleEvent));
00974         EVENTQUEUE->adoptHandler(IPlatformScreen::getButtonUpEvent(),
00975                             m_primaryClient->getEventTarget(),
00976                             new TMethodEventJob<CInputFilter>(this,
00977                                 &CInputFilter::handleEvent));
00978         EVENTQUEUE->adoptHandler(IPlatformScreen::getHotKeyDownEvent(),
00979                             m_primaryClient->getEventTarget(),
00980                             new TMethodEventJob<CInputFilter>(this,
00981                                 &CInputFilter::handleEvent));
00982         EVENTQUEUE->adoptHandler(IPlatformScreen::getHotKeyUpEvent(),
00983                             m_primaryClient->getEventTarget(),
00984                             new TMethodEventJob<CInputFilter>(this,
00985                                 &CInputFilter::handleEvent));
00986         EVENTQUEUE->adoptHandler(CServer::getConnectedEvent(),
00987                             m_primaryClient->getEventTarget(),
00988                             new TMethodEventJob<CInputFilter>(this,
00989                                 &CInputFilter::handleEvent));
00990 
00991         for (CRuleList::iterator rule  = m_ruleList.begin();
00992                                  rule != m_ruleList.end(); ++rule) {
00993             rule->enable(m_primaryClient);
00994         }
00995     }
00996 }
00997 
00998 CString
00999 CInputFilter::format(const CString& linePrefix) const
01000 {
01001     CString s;
01002     for (CRuleList::const_iterator i = m_ruleList.begin();
01003                                 i != m_ruleList.end(); ++i) {
01004         s += linePrefix;
01005         s += i->format();
01006         s += "\n";
01007     }
01008     return s;
01009 }
01010 
01011 UInt32
01012 CInputFilter::getNumRules() const
01013 {
01014     return static_cast<UInt32>(m_ruleList.size());
01015 }
01016 
01017 bool
01018 CInputFilter::operator==(const CInputFilter& x) const
01019 {
01020     // if there are different numbers of rules then we can't be equal
01021     if (m_ruleList.size() != x.m_ruleList.size()) {
01022         return false;
01023     }
01024 
01025     // compare rule lists.  the easiest way to do that is to format each
01026     // rule into a string, sort the strings, then compare the results.
01027     std::vector<CString> aList, bList;
01028     for (CRuleList::const_iterator i = m_ruleList.begin();
01029                                 i != m_ruleList.end(); ++i) {
01030         aList.push_back(i->format());
01031     }
01032     for (CRuleList::const_iterator i = x.m_ruleList.begin();
01033                                 i != x.m_ruleList.end(); ++i) {
01034         bList.push_back(i->format());
01035     }
01036     std::partial_sort(aList.begin(), aList.end(), aList.end());
01037     std::partial_sort(bList.begin(), bList.end(), bList.end());
01038     return (aList == bList);
01039 }
01040 
01041 bool
01042 CInputFilter::operator!=(const CInputFilter& x) const
01043 {
01044     return !operator==(x);
01045 }
01046 
01047 void
01048 CInputFilter::handleEvent(const CEvent& event, void*)
01049 {
01050     // copy event and adjust target
01051     CEvent myEvent(event.getType(), this, event.getData(),
01052                                 event.getFlags() | CEvent::kDontFreeData |
01053                                 CEvent::kDeliverImmediately);
01054 
01055     // let each rule try to match the event until one does
01056     for (CRuleList::iterator rule  = m_ruleList.begin();
01057                              rule != m_ruleList.end(); ++rule) {
01058         if (rule->handleEvent(myEvent)) {
01059             // handled
01060             return;
01061         }
01062     }
01063 
01064     // not handled so pass through
01065     EVENTQUEUE->addEvent(myEvent);
01066 }

Generated on Fri Nov 6 00:21:14 2009 for synergy-plus by  doxygen 1.3.9.1