Files
barrier/lib/server/CInputFilter.cpp
crs23 b728885e25 Applied patch 1547642, key broadcasting. Modified the patch to conform
to style guidelines.  Also enhanced it to allow binding hot keys to not
only toggling broadcasting but also turning it on or off, resized the
hot key dialog to accommodate the keyboard broadcasting option, changed
the configuration string for the keyboard broadcasting option, and
added documentation.

This change does not include the VS8 fix included in the patch.
2007-09-10 00:59:51 +00:00

1067 lines
24 KiB
C++

/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2005 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "CInputFilter.h"
#include "CServer.h"
#include "CPrimaryClient.h"
#include "CKeyMap.h"
#include "CEventQueue.h"
#include "CLog.h"
#include "TMethodEventJob.h"
#include <stdlib.h>
#include <string.h>
// -----------------------------------------------------------------------------
// Input Filter Condition Classes
// -----------------------------------------------------------------------------
CInputFilter::CCondition::CCondition()
{
// do nothing
}
CInputFilter::CCondition::~CCondition()
{
// do nothing
}
void
CInputFilter::CCondition::enablePrimary(CPrimaryClient*)
{
// do nothing
}
void
CInputFilter::CCondition::disablePrimary(CPrimaryClient*)
{
// do nothing
}
CInputFilter::CKeystrokeCondition::CKeystrokeCondition(
IPlatformScreen::CKeyInfo* info) :
m_id(0),
m_key(info->m_key),
m_mask(info->m_mask)
{
free(info);
}
CInputFilter::CKeystrokeCondition::CKeystrokeCondition(
KeyID key, KeyModifierMask mask) :
m_id(0),
m_key(key),
m_mask(mask)
{
// do nothing
}
CInputFilter::CKeystrokeCondition::~CKeystrokeCondition()
{
// do nothing
}
KeyID
CInputFilter::CKeystrokeCondition::getKey() const
{
return m_key;
}
KeyModifierMask
CInputFilter::CKeystrokeCondition::getMask() const
{
return m_mask;
}
CInputFilter::CCondition*
CInputFilter::CKeystrokeCondition::clone() const
{
return new CKeystrokeCondition(m_key, m_mask);
}
CString
CInputFilter::CKeystrokeCondition::format() const
{
return CStringUtil::print("keystroke(%s)",
CKeyMap::formatKey(m_key, m_mask).c_str());
}
CInputFilter::EFilterStatus
CInputFilter::CKeystrokeCondition::match(const CEvent& event)
{
EFilterStatus status;
// check for hotkey events
CEvent::Type type = event.getType();
if (type == IPrimaryScreen::getHotKeyDownEvent()) {
status = kActivate;
}
else if (type == IPrimaryScreen::getHotKeyUpEvent()) {
status = kDeactivate;
}
else {
return kNoMatch;
}
// check if it's our hotkey
IPrimaryScreen::CHotKeyInfo* kinfo =
reinterpret_cast<IPlatformScreen::CHotKeyInfo*>(event.getData());
if (kinfo->m_id != m_id) {
return kNoMatch;
}
return status;
}
void
CInputFilter::CKeystrokeCondition::enablePrimary(CPrimaryClient* primary)
{
m_id = primary->registerHotKey(m_key, m_mask);
}
void
CInputFilter::CKeystrokeCondition::disablePrimary(CPrimaryClient* primary)
{
primary->unregisterHotKey(m_id);
m_id = 0;
}
CInputFilter::CMouseButtonCondition::CMouseButtonCondition(
IPlatformScreen::CButtonInfo* info) :
m_button(info->m_button),
m_mask(info->m_mask)
{
free(info);
}
CInputFilter::CMouseButtonCondition::CMouseButtonCondition(
ButtonID button, KeyModifierMask mask) :
m_button(button),
m_mask(mask)
{
// do nothing
}
CInputFilter::CMouseButtonCondition::~CMouseButtonCondition()
{
// do nothing
}
ButtonID
CInputFilter::CMouseButtonCondition::getButton() const
{
return m_button;
}
KeyModifierMask
CInputFilter::CMouseButtonCondition::getMask() const
{
return m_mask;
}
CInputFilter::CCondition*
CInputFilter::CMouseButtonCondition::clone() const
{
return new CMouseButtonCondition(m_button, m_mask);
}
CString
CInputFilter::CMouseButtonCondition::format() const
{
CString key = CKeyMap::formatKey(kKeyNone, m_mask);
if (!key.empty()) {
key += "+";
}
return CStringUtil::print("mousebutton(%s%d)", key.c_str(), m_button);
}
CInputFilter::EFilterStatus
CInputFilter::CMouseButtonCondition::match(const CEvent& event)
{
static const KeyModifierMask s_ignoreMask =
KeyModifierAltGr | KeyModifierCapsLock |
KeyModifierNumLock | KeyModifierScrollLock;
EFilterStatus status;
// check for hotkey events
CEvent::Type type = event.getType();
if (type == IPrimaryScreen::getButtonDownEvent()) {
status = kActivate;
}
else if (type == IPrimaryScreen::getButtonUpEvent()) {
status = kDeactivate;
}
else {
return kNoMatch;
}
// check if it's the right button and modifiers. ignore modifiers
// that cannot be combined with a mouse button.
IPlatformScreen::CButtonInfo* minfo =
reinterpret_cast<IPlatformScreen::CButtonInfo*>(event.getData());
if (minfo->m_button != m_button ||
(minfo->m_mask & ~s_ignoreMask) != m_mask) {
return kNoMatch;
}
return status;
}
CInputFilter::CScreenConnectedCondition::CScreenConnectedCondition(
const CString& screen) :
m_screen(screen)
{
// do nothing
}
CInputFilter::CScreenConnectedCondition::~CScreenConnectedCondition()
{
// do nothing
}
CInputFilter::CCondition*
CInputFilter::CScreenConnectedCondition::clone() const
{
return new CScreenConnectedCondition(m_screen);
}
CString
CInputFilter::CScreenConnectedCondition::format() const
{
return CStringUtil::print("connect(%s)", m_screen.c_str());
}
CInputFilter::EFilterStatus
CInputFilter::CScreenConnectedCondition::match(const CEvent& event)
{
if (event.getType() == CServer::getConnectedEvent()) {
CServer::CScreenConnectedInfo* info =
reinterpret_cast<CServer::CScreenConnectedInfo*>(event.getData());
if (m_screen == info->m_screen || m_screen.empty()) {
return kActivate;
}
}
return kNoMatch;
}
// -----------------------------------------------------------------------------
// Input Filter Action Classes
// -----------------------------------------------------------------------------
CInputFilter::CAction::CAction()
{
// do nothing
}
CInputFilter::CAction::~CAction()
{
// do nothing
}
CInputFilter::CLockCursorToScreenAction::CLockCursorToScreenAction(Mode mode) :
m_mode(mode)
{
// do nothing
}
CInputFilter::CLockCursorToScreenAction::Mode
CInputFilter::CLockCursorToScreenAction::getMode() const
{
return m_mode;
}
CInputFilter::CAction*
CInputFilter::CLockCursorToScreenAction::clone() const
{
return new CLockCursorToScreenAction(*this);
}
CString
CInputFilter::CLockCursorToScreenAction::format() const
{
static const char* s_mode[] = { "off", "on", "toggle" };
return CStringUtil::print("lockCursorToScreen(%s)", s_mode[m_mode]);
}
void
CInputFilter::CLockCursorToScreenAction::perform(const CEvent& event)
{
static const CServer::CLockCursorToScreenInfo::State s_state[] = {
CServer::CLockCursorToScreenInfo::kOff,
CServer::CLockCursorToScreenInfo::kOn,
CServer::CLockCursorToScreenInfo::kToggle
};
// send event
CServer::CLockCursorToScreenInfo* info =
CServer::CLockCursorToScreenInfo::alloc(s_state[m_mode]);
EVENTQUEUE->addEvent(CEvent(CServer::getLockCursorToScreenEvent(),
event.getTarget(), info,
CEvent::kDeliverImmediately));
}
CInputFilter::CSwitchToScreenAction::CSwitchToScreenAction(
const CString& screen) :
m_screen(screen)
{
// do nothing
}
CString
CInputFilter::CSwitchToScreenAction::getScreen() const
{
return m_screen;
}
CInputFilter::CAction*
CInputFilter::CSwitchToScreenAction::clone() const
{
return new CSwitchToScreenAction(*this);
}
CString
CInputFilter::CSwitchToScreenAction::format() const
{
return CStringUtil::print("switchToScreen(%s)", m_screen.c_str());
}
void
CInputFilter::CSwitchToScreenAction::perform(const CEvent& event)
{
// pick screen name. if m_screen is empty then use the screen from
// event if it has one.
CString screen = m_screen;
if (screen.empty() && event.getType() == CServer::getConnectedEvent()) {
CServer::CScreenConnectedInfo* info =
reinterpret_cast<CServer::CScreenConnectedInfo*>(event.getData());
screen = info->m_screen;
}
// send event
CServer::CSwitchToScreenInfo* info =
CServer::CSwitchToScreenInfo::alloc(screen);
EVENTQUEUE->addEvent(CEvent(CServer::getSwitchToScreenEvent(),
event.getTarget(), info,
CEvent::kDeliverImmediately));
}
CInputFilter::CSwitchInDirectionAction::CSwitchInDirectionAction(
EDirection direction) :
m_direction(direction)
{
// do nothing
}
EDirection
CInputFilter::CSwitchInDirectionAction::getDirection() const
{
return m_direction;
}
CInputFilter::CAction*
CInputFilter::CSwitchInDirectionAction::clone() const
{
return new CSwitchInDirectionAction(*this);
}
CString
CInputFilter::CSwitchInDirectionAction::format() const
{
static const char* s_names[] = {
"",
"left",
"right",
"up",
"down"
};
return CStringUtil::print("switchInDirection(%s)", s_names[m_direction]);
}
void
CInputFilter::CSwitchInDirectionAction::perform(const CEvent& event)
{
CServer::CSwitchInDirectionInfo* info =
CServer::CSwitchInDirectionInfo::alloc(m_direction);
EVENTQUEUE->addEvent(CEvent(CServer::getSwitchInDirectionEvent(),
event.getTarget(), info,
CEvent::kDeliverImmediately));
}
CInputFilter::CKeyboardBroadcastAction::CKeyboardBroadcastAction(Mode mode) :
m_mode(mode)
{
// do nothing
}
CInputFilter::CKeyboardBroadcastAction::CKeyboardBroadcastAction(
Mode mode,
const std::set<CString>& screens) :
m_mode(mode),
m_screens(IKeyState::CKeyInfo::join(screens))
{
// do nothing
}
CInputFilter::CKeyboardBroadcastAction::Mode
CInputFilter::CKeyboardBroadcastAction::getMode() const
{
return m_mode;
}
std::set<CString>
CInputFilter::CKeyboardBroadcastAction::getScreens() const
{
std::set<CString> screens;
IKeyState::CKeyInfo::split(m_screens.c_str(), screens);
return screens;
}
CInputFilter::CAction*
CInputFilter::CKeyboardBroadcastAction::clone() const
{
return new CKeyboardBroadcastAction(*this);
}
CString
CInputFilter::CKeyboardBroadcastAction::format() const
{
static const char* s_mode[] = { "off", "on", "toggle" };
static const char* s_name = "keyboardBroadcast";
if (m_screens.empty() || m_screens[0] == '*') {
return CStringUtil::print("%s(%s)", s_name, s_mode[m_mode]);
}
else {
return CStringUtil::print("%s(%s,%.*s)", s_name, s_mode[m_mode],
m_screens.size() - 2,
m_screens.c_str() + 1);
}
}
void
CInputFilter::CKeyboardBroadcastAction::perform(const CEvent& event)
{
static const CServer::CKeyboardBroadcastInfo::State s_state[] = {
CServer::CKeyboardBroadcastInfo::kOff,
CServer::CKeyboardBroadcastInfo::kOn,
CServer::CKeyboardBroadcastInfo::kToggle
};
// send event
CServer::CKeyboardBroadcastInfo* info =
CServer::CKeyboardBroadcastInfo::alloc(s_state[m_mode], m_screens);
EVENTQUEUE->addEvent(CEvent(CServer::getKeyboardBroadcastEvent(),
event.getTarget(), info,
CEvent::kDeliverImmediately));
}
CInputFilter::CKeystrokeAction::CKeystrokeAction(
IPlatformScreen::CKeyInfo* info, bool press) :
m_keyInfo(info),
m_press(press)
{
// do nothing
}
CInputFilter::CKeystrokeAction::~CKeystrokeAction()
{
free(m_keyInfo);
}
void
CInputFilter::CKeystrokeAction::adoptInfo(IPlatformScreen::CKeyInfo* info)
{
free(m_keyInfo);
m_keyInfo = info;
}
const IPlatformScreen::CKeyInfo*
CInputFilter::CKeystrokeAction::getInfo() const
{
return m_keyInfo;
}
bool
CInputFilter::CKeystrokeAction::isOnPress() const
{
return m_press;
}
CInputFilter::CAction*
CInputFilter::CKeystrokeAction::clone() const
{
IKeyState::CKeyInfo* info = IKeyState::CKeyInfo::alloc(*m_keyInfo);
return new CKeystrokeAction(info, m_press);
}
CString
CInputFilter::CKeystrokeAction::format() const
{
const char* type = formatName();
if (m_keyInfo->m_screens[0] == '\0') {
return CStringUtil::print("%s(%s)", type,
CKeyMap::formatKey(m_keyInfo->m_key,
m_keyInfo->m_mask).c_str());
}
else if (m_keyInfo->m_screens[0] == '*') {
return CStringUtil::print("%s(%s,*)", type,
CKeyMap::formatKey(m_keyInfo->m_key,
m_keyInfo->m_mask).c_str());
}
else {
return CStringUtil::print("%s(%s,%.*s)", type,
CKeyMap::formatKey(m_keyInfo->m_key,
m_keyInfo->m_mask).c_str(),
strlen(m_keyInfo->m_screens + 1) - 1,
m_keyInfo->m_screens + 1);
}
}
void
CInputFilter::CKeystrokeAction::perform(const CEvent& event)
{
CEvent::Type type = m_press ? IPlatformScreen::getKeyDownEvent() :
IPlatformScreen::getKeyUpEvent();
EVENTQUEUE->addEvent(CEvent(IPlatformScreen::getFakeInputBeginEvent(),
event.getTarget(), NULL,
CEvent::kDeliverImmediately));
EVENTQUEUE->addEvent(CEvent(type, event.getTarget(), m_keyInfo,
CEvent::kDeliverImmediately |
CEvent::kDontFreeData));
EVENTQUEUE->addEvent(CEvent(IPlatformScreen::getFakeInputEndEvent(),
event.getTarget(), NULL,
CEvent::kDeliverImmediately));
}
const char*
CInputFilter::CKeystrokeAction::formatName() const
{
return (m_press ? "keyDown" : "keyUp");
}
CInputFilter::CMouseButtonAction::CMouseButtonAction(
IPlatformScreen::CButtonInfo* info, bool press) :
m_buttonInfo(info),
m_press(press)
{
// do nothing
}
CInputFilter::CMouseButtonAction::~CMouseButtonAction()
{
free(m_buttonInfo);
}
const IPlatformScreen::CButtonInfo*
CInputFilter::CMouseButtonAction::getInfo() const
{
return m_buttonInfo;
}
bool
CInputFilter::CMouseButtonAction::isOnPress() const
{
return m_press;
}
CInputFilter::CAction*
CInputFilter::CMouseButtonAction::clone() const
{
IPlatformScreen::CButtonInfo* info =
IPrimaryScreen::CButtonInfo::alloc(*m_buttonInfo);
return new CMouseButtonAction(info, m_press);
}
CString
CInputFilter::CMouseButtonAction::format() const
{
const char* type = formatName();
CString key = CKeyMap::formatKey(kKeyNone, m_buttonInfo->m_mask);
return CStringUtil::print("%s(%s%s%d)", type,
key.c_str(), key.empty() ? "" : "+",
m_buttonInfo->m_button);
}
void
CInputFilter::CMouseButtonAction::perform(const CEvent& event)
{
// send modifiers
IPlatformScreen::CKeyInfo* modifierInfo = NULL;
if (m_buttonInfo->m_mask != 0) {
KeyID key = m_press ? kKeySetModifiers : kKeyClearModifiers;
modifierInfo =
IKeyState::CKeyInfo::alloc(key, m_buttonInfo->m_mask, 0, 1);
EVENTQUEUE->addEvent(CEvent(IPlatformScreen::getKeyDownEvent(),
event.getTarget(), modifierInfo,
CEvent::kDeliverImmediately));
}
// send button
CEvent::Type type = m_press ? IPlatformScreen::getButtonDownEvent() :
IPlatformScreen::getButtonUpEvent();
EVENTQUEUE->addEvent(CEvent(type, event.getTarget(), m_buttonInfo,
CEvent::kDeliverImmediately |
CEvent::kDontFreeData));
}
const char*
CInputFilter::CMouseButtonAction::formatName() const
{
return (m_press ? "mouseDown" : "mouseUp");
}
//
// CInputFilter::CRule
//
CInputFilter::CRule::CRule() :
m_condition(NULL)
{
// do nothing
}
CInputFilter::CRule::CRule(CCondition* adoptedCondition) :
m_condition(adoptedCondition)
{
// do nothing
}
CInputFilter::CRule::CRule(const CRule& rule) :
m_condition(NULL)
{
copy(rule);
}
CInputFilter::CRule::~CRule()
{
clear();
}
CInputFilter::CRule&
CInputFilter::CRule::operator=(const CRule& rule)
{
if (&rule != this) {
copy(rule);
}
return *this;
}
void
CInputFilter::CRule::clear()
{
delete m_condition;
for (CActionList::iterator i = m_activateActions.begin();
i != m_activateActions.end(); ++i) {
delete *i;
}
for (CActionList::iterator i = m_deactivateActions.begin();
i != m_deactivateActions.end(); ++i) {
delete *i;
}
m_condition = NULL;
m_activateActions.clear();
m_deactivateActions.clear();
}
void
CInputFilter::CRule::copy(const CRule& rule)
{
clear();
if (rule.m_condition != NULL) {
m_condition = rule.m_condition->clone();
}
for (CActionList::const_iterator i = rule.m_activateActions.begin();
i != rule.m_activateActions.end(); ++i) {
m_activateActions.push_back((*i)->clone());
}
for (CActionList::const_iterator i = rule.m_deactivateActions.begin();
i != rule.m_deactivateActions.end(); ++i) {
m_deactivateActions.push_back((*i)->clone());
}
}
void
CInputFilter::CRule::setCondition(CCondition* adopted)
{
delete m_condition;
m_condition = adopted;
}
void
CInputFilter::CRule::adoptAction(CAction* action, bool onActivation)
{
if (action != NULL) {
if (onActivation) {
m_activateActions.push_back(action);
}
else {
m_deactivateActions.push_back(action);
}
}
}
void
CInputFilter::CRule::removeAction(bool onActivation, UInt32 index)
{
if (onActivation) {
delete m_activateActions[index];
m_activateActions.erase(m_activateActions.begin() + index);
}
else {
delete m_deactivateActions[index];
m_deactivateActions.erase(m_deactivateActions.begin() + index);
}
}
void
CInputFilter::CRule::replaceAction(CAction* adopted,
bool onActivation, UInt32 index)
{
if (adopted == NULL) {
removeAction(onActivation, index);
}
else if (onActivation) {
delete m_activateActions[index];
m_activateActions[index] = adopted;
}
else {
delete m_deactivateActions[index];
m_deactivateActions[index] = adopted;
}
}
void
CInputFilter::CRule::enable(CPrimaryClient* primaryClient)
{
if (m_condition != NULL) {
m_condition->enablePrimary(primaryClient);
}
}
void
CInputFilter::CRule::disable(CPrimaryClient* primaryClient)
{
if (m_condition != NULL) {
m_condition->disablePrimary(primaryClient);
}
}
bool
CInputFilter::CRule::handleEvent(const CEvent& event)
{
// NULL condition never matches
if (m_condition == NULL) {
return false;
}
// match
const CActionList* actions;
switch (m_condition->match(event)) {
default:
// not handled
return false;
case kActivate:
actions = &m_activateActions;
LOG((CLOG_DEBUG1 "activate actions"));
break;
case kDeactivate:
actions = &m_deactivateActions;
LOG((CLOG_DEBUG1 "deactivate actions"));
break;
}
// perform actions
for (CActionList::const_iterator i = actions->begin();
i != actions->end(); ++i) {
LOG((CLOG_DEBUG1 "hotkey: %s", (*i)->format().c_str()));
(*i)->perform(event);
}
return true;
}
CString
CInputFilter::CRule::format() const
{
CString s;
if (m_condition != NULL) {
// condition
s += m_condition->format();
s += " = ";
// activate actions
CActionList::const_iterator i = m_activateActions.begin();
if (i != m_activateActions.end()) {
s += (*i)->format();
while (++i != m_activateActions.end()) {
s += ", ";
s += (*i)->format();
}
}
// deactivate actions
if (!m_deactivateActions.empty()) {
s += "; ";
i = m_deactivateActions.begin();
if (i != m_deactivateActions.end()) {
s += (*i)->format();
while (++i != m_deactivateActions.end()) {
s += ", ";
s += (*i)->format();
}
}
}
}
return s;
}
const CInputFilter::CCondition*
CInputFilter::CRule::getCondition() const
{
return m_condition;
}
UInt32
CInputFilter::CRule::getNumActions(bool onActivation) const
{
if (onActivation) {
return static_cast<UInt32>(m_activateActions.size());
}
else {
return static_cast<UInt32>(m_deactivateActions.size());
}
}
const CInputFilter::CAction&
CInputFilter::CRule::getAction(bool onActivation, UInt32 index) const
{
if (onActivation) {
return *m_activateActions[index];
}
else {
return *m_deactivateActions[index];
}
}
// -----------------------------------------------------------------------------
// Input Filter Class
// -----------------------------------------------------------------------------
CInputFilter::CInputFilter() :
m_primaryClient(NULL)
{
// do nothing
}
CInputFilter::CInputFilter(const CInputFilter& x) :
m_ruleList(x.m_ruleList),
m_primaryClient(NULL)
{
setPrimaryClient(x.m_primaryClient);
}
CInputFilter::~CInputFilter()
{
setPrimaryClient(NULL);
}
CInputFilter&
CInputFilter::operator=(const CInputFilter& x)
{
if (&x != this) {
CPrimaryClient* oldClient = m_primaryClient;
setPrimaryClient(NULL);
m_ruleList = x.m_ruleList;
setPrimaryClient(oldClient);
}
return *this;
}
void
CInputFilter::addFilterRule(const CRule& rule)
{
m_ruleList.push_back(rule);
if (m_primaryClient != NULL) {
m_ruleList.back().enable(m_primaryClient);
}
}
void
CInputFilter::removeFilterRule(UInt32 index)
{
if (m_primaryClient != NULL) {
m_ruleList[index].disable(m_primaryClient);
}
m_ruleList.erase(m_ruleList.begin() + index);
}
CInputFilter::CRule&
CInputFilter::getRule(UInt32 index)
{
return m_ruleList[index];
}
void
CInputFilter::setPrimaryClient(CPrimaryClient* client)
{
if (m_primaryClient == client) {
return;
}
if (m_primaryClient != NULL) {
for (CRuleList::iterator rule = m_ruleList.begin();
rule != m_ruleList.end(); ++rule) {
rule->disable(m_primaryClient);
}
EVENTQUEUE->removeHandler(IPlatformScreen::getKeyDownEvent(),
m_primaryClient->getEventTarget());
EVENTQUEUE->removeHandler(IPlatformScreen::getKeyUpEvent(),
m_primaryClient->getEventTarget());
EVENTQUEUE->removeHandler(IPlatformScreen::getKeyRepeatEvent(),
m_primaryClient->getEventTarget());
EVENTQUEUE->removeHandler(IPlatformScreen::getButtonDownEvent(),
m_primaryClient->getEventTarget());
EVENTQUEUE->removeHandler(IPlatformScreen::getButtonUpEvent(),
m_primaryClient->getEventTarget());
EVENTQUEUE->removeHandler(IPlatformScreen::getHotKeyDownEvent(),
m_primaryClient->getEventTarget());
EVENTQUEUE->removeHandler(IPlatformScreen::getHotKeyUpEvent(),
m_primaryClient->getEventTarget());
EVENTQUEUE->removeHandler(CServer::getConnectedEvent(),
m_primaryClient->getEventTarget());
}
m_primaryClient = client;
if (m_primaryClient != NULL) {
EVENTQUEUE->adoptHandler(IPlatformScreen::getKeyDownEvent(),
m_primaryClient->getEventTarget(),
new TMethodEventJob<CInputFilter>(this,
&CInputFilter::handleEvent));
EVENTQUEUE->adoptHandler(IPlatformScreen::getKeyUpEvent(),
m_primaryClient->getEventTarget(),
new TMethodEventJob<CInputFilter>(this,
&CInputFilter::handleEvent));
EVENTQUEUE->adoptHandler(IPlatformScreen::getKeyRepeatEvent(),
m_primaryClient->getEventTarget(),
new TMethodEventJob<CInputFilter>(this,
&CInputFilter::handleEvent));
EVENTQUEUE->adoptHandler(IPlatformScreen::getButtonDownEvent(),
m_primaryClient->getEventTarget(),
new TMethodEventJob<CInputFilter>(this,
&CInputFilter::handleEvent));
EVENTQUEUE->adoptHandler(IPlatformScreen::getButtonUpEvent(),
m_primaryClient->getEventTarget(),
new TMethodEventJob<CInputFilter>(this,
&CInputFilter::handleEvent));
EVENTQUEUE->adoptHandler(IPlatformScreen::getHotKeyDownEvent(),
m_primaryClient->getEventTarget(),
new TMethodEventJob<CInputFilter>(this,
&CInputFilter::handleEvent));
EVENTQUEUE->adoptHandler(IPlatformScreen::getHotKeyUpEvent(),
m_primaryClient->getEventTarget(),
new TMethodEventJob<CInputFilter>(this,
&CInputFilter::handleEvent));
EVENTQUEUE->adoptHandler(CServer::getConnectedEvent(),
m_primaryClient->getEventTarget(),
new TMethodEventJob<CInputFilter>(this,
&CInputFilter::handleEvent));
for (CRuleList::iterator rule = m_ruleList.begin();
rule != m_ruleList.end(); ++rule) {
rule->enable(m_primaryClient);
}
}
}
CString
CInputFilter::format(const CString& linePrefix) const
{
CString s;
for (CRuleList::const_iterator i = m_ruleList.begin();
i != m_ruleList.end(); ++i) {
s += linePrefix;
s += i->format();
s += "\n";
}
return s;
}
UInt32
CInputFilter::getNumRules() const
{
return static_cast<UInt32>(m_ruleList.size());
}
bool
CInputFilter::operator==(const CInputFilter& x) const
{
// if there are different numbers of rules then we can't be equal
if (m_ruleList.size() != x.m_ruleList.size()) {
return false;
}
// compare rule lists. the easiest way to do that is to format each
// rule into a string, sort the strings, then compare the results.
std::vector<CString> aList, bList;
for (CRuleList::const_iterator i = m_ruleList.begin();
i != m_ruleList.end(); ++i) {
aList.push_back(i->format());
}
for (CRuleList::const_iterator i = x.m_ruleList.begin();
i != x.m_ruleList.end(); ++i) {
bList.push_back(i->format());
}
std::partial_sort(aList.begin(), aList.end(), aList.end());
std::partial_sort(bList.begin(), bList.end(), bList.end());
return (aList == bList);
}
bool
CInputFilter::operator!=(const CInputFilter& x) const
{
return !operator==(x);
}
void
CInputFilter::handleEvent(const CEvent& event, void*)
{
// copy event and adjust target
CEvent myEvent(event.getType(), this, event.getData(),
event.getFlags() | CEvent::kDontFreeData |
CEvent::kDeliverImmediately);
// let each rule try to match the event until one does
for (CRuleList::iterator rule = m_ruleList.begin();
rule != m_ruleList.end(); ++rule) {
if (rule->handleEvent(myEvent)) {
// handled
return;
}
}
// not handled so pass through
EVENTQUEUE->addEvent(myEvent);
}