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.
This commit is contained in:
crs23 2007-09-10 00:59:51 +00:00
parent d001ca488a
commit b728885e25
12 changed files with 415 additions and 58 deletions

View File

@ -925,6 +925,8 @@ CInputFilter::CAction*
CHotkeyOptions::CActionDialog::s_action = NULL; CHotkeyOptions::CActionDialog::s_action = NULL;
CInputFilter::CAction* CInputFilter::CAction*
CHotkeyOptions::CActionDialog::s_lastGoodAction = NULL; CHotkeyOptions::CActionDialog::s_lastGoodAction = NULL;
std::set<CString>
CHotkeyOptions::CActionDialog::s_screens;
WNDPROC CHotkeyOptions::CActionDialog::s_editWndProc = NULL; WNDPROC CHotkeyOptions::CActionDialog::s_editWndProc = NULL;
bool bool
@ -995,11 +997,21 @@ CHotkeyOptions::CActionDialog::doInit(HWND hwnd)
// fill lock modes // fill lock modes
child = getItem(hwnd, IDC_HOTKEY_ACTION_LOCK_LIST); child = getItem(hwnd, IDC_HOTKEY_ACTION_LOCK_LIST);
SendMessage(child, CB_ADDSTRING, 0, SendMessage(child, CB_ADDSTRING, 0,
(LPARAM)getString(IDS_LOCK_MODE_OFF).c_str()); (LPARAM)getString(IDS_MODE_OFF).c_str());
SendMessage(child, CB_ADDSTRING, 0, SendMessage(child, CB_ADDSTRING, 0,
(LPARAM)getString(IDS_LOCK_MODE_ON).c_str()); (LPARAM)getString(IDS_MODE_ON).c_str());
SendMessage(child, CB_ADDSTRING, 0, SendMessage(child, CB_ADDSTRING, 0,
(LPARAM)getString(IDS_LOCK_MODE_TOGGLE).c_str()); (LPARAM)getString(IDS_MODE_TOGGLE).c_str());
SendMessage(child, CB_SETCURSEL, 0, 0);
// fill keyboard broadcast modes
child = getItem(hwnd, IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST_LIST);
SendMessage(child, CB_ADDSTRING, 0,
(LPARAM)getString(IDS_MODE_OFF).c_str());
SendMessage(child, CB_ADDSTRING, 0,
(LPARAM)getString(IDS_MODE_ON).c_str());
SendMessage(child, CB_ADDSTRING, 0,
(LPARAM)getString(IDS_MODE_TOGGLE).c_str());
SendMessage(child, CB_SETCURSEL, 0, 0); SendMessage(child, CB_SETCURSEL, 0, 0);
// select when // select when
@ -1011,6 +1023,9 @@ CHotkeyOptions::CActionDialog::doInit(HWND hwnd)
} }
setItemChecked(child, true); setItemChecked(child, true);
// no screens by default
s_screens.clear();
// select mode // select mode
child = NULL; child = NULL;
CInputFilter::CKeystrokeAction* keyAction = CInputFilter::CKeystrokeAction* keyAction =
@ -1023,6 +1038,8 @@ CHotkeyOptions::CActionDialog::doInit(HWND hwnd)
dynamic_cast<CInputFilter::CSwitchToScreenAction*>(s_action); dynamic_cast<CInputFilter::CSwitchToScreenAction*>(s_action);
CInputFilter::CSwitchInDirectionAction* switchInAction = CInputFilter::CSwitchInDirectionAction* switchInAction =
dynamic_cast<CInputFilter::CSwitchInDirectionAction*>(s_action); dynamic_cast<CInputFilter::CSwitchInDirectionAction*>(s_action);
CInputFilter::CKeyboardBroadcastAction* keyboardBroadcastAction=
dynamic_cast<CInputFilter::CKeyboardBroadcastAction*>(s_action);
if (keyAction != NULL) { if (keyAction != NULL) {
if (dynamic_cast<CKeystrokeDownUpAction*>(s_action) != NULL) { if (dynamic_cast<CKeystrokeDownUpAction*>(s_action) != NULL) {
child = getItem(hwnd, IDC_HOTKEY_ACTION_DOWNUP); child = getItem(hwnd, IDC_HOTKEY_ACTION_DOWNUP);
@ -1066,6 +1083,14 @@ CHotkeyOptions::CActionDialog::doInit(HWND hwnd)
switchInAction->getDirection() - kLeft, 0); switchInAction->getDirection() - kLeft, 0);
child = getItem(hwnd, IDC_HOTKEY_ACTION_SWITCH_IN); child = getItem(hwnd, IDC_HOTKEY_ACTION_SWITCH_IN);
} }
else if (keyboardBroadcastAction != NULL) {
// Save the screens we're broadcasting to
s_screens = keyboardBroadcastAction->getScreens();
child = getItem(hwnd, IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST_LIST);
SendMessage(child, CB_SETCURSEL, keyboardBroadcastAction->getMode(), 0);
child = getItem(hwnd, IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST);
}
if (child != NULL) { if (child != NULL) {
setItemChecked(child, true); setItemChecked(child, true);
} }
@ -1111,12 +1136,18 @@ CHotkeyOptions::CActionDialog::updateControls(HWND hwnd)
else if (isItemChecked(getItem(hwnd, IDC_HOTKEY_ACTION_LOCK))) { else if (isItemChecked(getItem(hwnd, IDC_HOTKEY_ACTION_LOCK))) {
mode = 4; mode = 4;
} }
else if (isItemChecked(getItem(hwnd,
IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST))) {
mode = 5;
}
// enable/disable all mode specific controls // enable/disable all mode specific controls
enableItem(hwnd, IDC_HOTKEY_ACTION_HOTKEY, mode == 1); enableItem(hwnd, IDC_HOTKEY_ACTION_HOTKEY, mode == 1);
enableItem(hwnd, IDC_HOTKEY_ACTION_SWITCH_TO_LIST, mode == 2); enableItem(hwnd, IDC_HOTKEY_ACTION_SWITCH_TO_LIST, mode == 2);
enableItem(hwnd, IDC_HOTKEY_ACTION_SWITCH_IN_LIST, mode == 3); enableItem(hwnd, IDC_HOTKEY_ACTION_SWITCH_IN_LIST, mode == 3);
enableItem(hwnd, IDC_HOTKEY_ACTION_LOCK_LIST, mode == 4); enableItem(hwnd, IDC_HOTKEY_ACTION_LOCK_LIST, mode == 4);
enableItem(hwnd, IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST_LIST, mode == 5);
enableItem(hwnd, IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST_SCREENS, mode == 5);
// can only set screens in key actions // can only set screens in key actions
CInputFilter::CKeystrokeAction* keyAction = CInputFilter::CKeystrokeAction* keyAction =
@ -1306,6 +1337,18 @@ CHotkeyOptions::CActionDialog::onSwitchInAction(HWND hwnd)
} }
} }
void
CHotkeyOptions::CActionDialog::onKeyboardBroadcastAction(HWND hwnd)
{
HWND child = getItem(hwnd, IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST_LIST);
LRESULT index = SendMessage(child, CB_GETCURSEL, 0, 0);
if (index != CB_ERR) {
delete s_action;
s_action = new CInputFilter::CKeyboardBroadcastAction(
(CInputFilter::CKeyboardBroadcastAction::Mode)index, s_screens);
}
}
KeyID KeyID
CHotkeyOptions::CActionDialog::getChar(WPARAM wParam, LPARAM lParam) CHotkeyOptions::CActionDialog::getChar(WPARAM wParam, LPARAM lParam)
{ {
@ -1509,6 +1552,11 @@ CHotkeyOptions::CActionDialog::dlgProc(HWND hwnd,
updateControls(hwnd); updateControls(hwnd);
return TRUE; return TRUE;
case IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST:
onKeyboardBroadcastAction(hwnd);
updateControls(hwnd);
return TRUE;
case IDC_HOTKEY_ACTION_LOCK_LIST: case IDC_HOTKEY_ACTION_LOCK_LIST:
switch (HIWORD(wParam)) { switch (HIWORD(wParam)) {
case LBN_SELCHANGE: case LBN_SELCHANGE:
@ -1533,11 +1581,37 @@ CHotkeyOptions::CActionDialog::dlgProc(HWND hwnd,
} }
break; break;
case IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST_LIST:
switch (HIWORD(wParam)) {
case LBN_SELCHANGE:
onKeyboardBroadcastAction(hwnd);
return TRUE;
}
break;
case IDC_HOTKEY_ACTION_SCREENS: case IDC_HOTKEY_ACTION_SCREENS:
CScreensDialog::doModal(hwnd, s_config, CScreensDialog::doModal(hwnd, s_config,
dynamic_cast<CInputFilter::CKeystrokeAction*>(s_action)); dynamic_cast<CInputFilter::CKeystrokeAction*>(s_action));
fillHotkey(hwnd); fillHotkey(hwnd);
return TRUE; return TRUE;
case IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST_SCREENS: {
// convert screens to form that CScreenDialog::doModal() wants
IPlatformScreen::CKeyInfo* tmpInfo =
IPlatformScreen::CKeyInfo::alloc(0, 0, 0, 1, s_screens);
CInputFilter::CKeystrokeAction tmpAction(tmpInfo, true);
// get the screens
CScreensDialog::doModal(hwnd, s_config, &tmpAction);
// convert screens back
IPlatformScreen::CKeyInfo::split(
tmpAction.getInfo()->m_screens, s_screens);
// update
onKeyboardBroadcastAction(hwnd);
return TRUE;
}
} }
break; break;

View File

@ -156,6 +156,7 @@ private:
static void onLockAction(HWND hwnd); static void onLockAction(HWND hwnd);
static void onSwitchToAction(HWND hwnd); static void onSwitchToAction(HWND hwnd);
static void onSwitchInAction(HWND hwnd); static void onSwitchInAction(HWND hwnd);
static void onKeyboardBroadcastAction(HWND hwnd);
static KeyID getChar(WPARAM wParam, LPARAM lParam); static KeyID getChar(WPARAM wParam, LPARAM lParam);
static KeyModifierMask static KeyModifierMask
@ -176,6 +177,7 @@ private:
s_action; s_action;
static CInputFilter::CAction* static CInputFilter::CAction*
s_lastGoodAction; s_lastGoodAction;
static std::set<CString> s_screens;
static WNDPROC s_editWndProc; static WNDPROC s_editWndProc;
}; };

View File

@ -338,7 +338,7 @@ BEGIN
PUSHBUTTON "Cancel",IDCANCEL,126,37,50,14 PUSHBUTTON "Cancel",IDCANCEL,126,37,50,14
END END
IDD_HOTKEY_ACTION DIALOG DISCARDABLE 0, 0, 183, 202 IDD_HOTKEY_ACTION DIALOG DISCARDABLE 0, 0, 183, 218
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Action" CAPTION "Action"
FONT 8, "MS Sans Serif" FONT 8, "MS Sans Serif"
@ -356,6 +356,9 @@ BEGIN
"Button",BS_AUTORADIOBUTTON,7,101,77,10 "Button",BS_AUTORADIOBUTTON,7,101,77,10
CONTROL "Lock Cursor to Screen:",IDC_HOTKEY_ACTION_LOCK,"Button", CONTROL "Lock Cursor to Screen:",IDC_HOTKEY_ACTION_LOCK,"Button",
BS_AUTORADIOBUTTON,7,117,89,10 BS_AUTORADIOBUTTON,7,117,89,10
CONTROL "Keyboard broadcasting:",
IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST,"Button",
BS_AUTORADIOBUTTON,7,133,89,10
LTEXT "&Hot key or mouse button:",IDC_STATIC,7,55,80,8 LTEXT "&Hot key or mouse button:",IDC_STATIC,7,55,80,8
EDITTEXT IDC_HOTKEY_ACTION_HOTKEY,7,67,152,12,ES_WANTRETURN EDITTEXT IDC_HOTKEY_ACTION_HOTKEY,7,67,152,12,ES_WANTRETURN
PUSHBUTTON "...",IDC_HOTKEY_ACTION_SCREENS,162,67,14,12 PUSHBUTTON "...",IDC_HOTKEY_ACTION_SCREENS,162,67,14,12
@ -365,13 +368,17 @@ BEGIN
CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
COMBOBOX IDC_HOTKEY_ACTION_LOCK_LIST,106,115,70,58, COMBOBOX IDC_HOTKEY_ACTION_LOCK_LIST,106,115,70,58,
CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Action takes place &when:",IDC_STATIC,7,137,81,8 COMBOBOX IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST_LIST,106,131,53,58,
CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "...",IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST_SCREENS,
162,131,14,12
LTEXT "Action takes place &when:",IDC_STATIC,7,153,81,8
CONTROL "Hot key is pressed",IDC_HOTKEY_ACTION_ON_ACTIVATE, CONTROL "Hot key is pressed",IDC_HOTKEY_ACTION_ON_ACTIVATE,
"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,7,149,74,10 "Button",BS_AUTORADIOBUTTON | WS_TABSTOP,7,165,74,10
CONTROL "Hot key is released",IDC_HOTKEY_ACTION_ON_DEACTIVATE, CONTROL "Hot key is released",IDC_HOTKEY_ACTION_ON_DEACTIVATE,
"Button",BS_AUTORADIOBUTTON,7,161,76,10 "Button",BS_AUTORADIOBUTTON,7,177,76,10
DEFPUSHBUTTON "OK",IDOK,70,181,50,14 DEFPUSHBUTTON "OK",IDOK,70,197,50,14
PUSHBUTTON "Cancel",IDCANCEL,126,181,50,14 PUSHBUTTON "Cancel",IDCANCEL,126,197,50,14
END END
IDD_HOTKEY_SCREENS DIALOG DISCARDABLE 0, 0, 237, 79 IDD_HOTKEY_SCREENS DIALOG DISCARDABLE 0, 0, 237, 79
@ -586,9 +593,9 @@ BEGIN
IDS_AUTOSTART_SAVE_FAILED "Failed to save autostart configuration: %{1}" IDS_AUTOSTART_SAVE_FAILED "Failed to save autostart configuration: %{1}"
IDS_LOAD_FAILED "Failed to load configuration." IDS_LOAD_FAILED "Failed to load configuration."
IDS_CONFIG_CHANGED "Configuration changed on disk. Reload?" IDS_CONFIG_CHANGED "Configuration changed on disk. Reload?"
IDS_LOCK_MODE_OFF "off" IDS_MODE_OFF "off"
IDS_LOCK_MODE_ON "on" IDS_MODE_ON "on"
IDS_LOCK_MODE_TOGGLE "toggle" IDS_MODE_TOGGLE "toggle"
IDS_ALL_SCREENS "All Screens" IDS_ALL_SCREENS "All Screens"
IDS_ACTIVE_SCREEN "Active Screen" IDS_ACTIVE_SCREEN "Active Screen"
END END

View File

@ -59,9 +59,9 @@
#define IDS_AUTOSTART_SAVE_FAILED 54 #define IDS_AUTOSTART_SAVE_FAILED 54
#define IDS_LOAD_FAILED 55 #define IDS_LOAD_FAILED 55
#define IDS_CONFIG_CHANGED 56 #define IDS_CONFIG_CHANGED 56
#define IDS_LOCK_MODE_OFF 57 #define IDS_MODE_OFF 57
#define IDS_LOCK_MODE_ON 58 #define IDS_MODE_ON 58
#define IDS_LOCK_MODE_TOGGLE 59 #define IDS_MODE_TOGGLE 59
#define IDS_ALL_SCREENS 60 #define IDS_ALL_SCREENS 60
#define IDS_ACTIVE_SCREEN 61 #define IDS_ACTIVE_SCREEN 61
#define IDD_MAIN 101 #define IDD_MAIN 101
@ -169,6 +169,9 @@
#define IDC_HOTKEY_SCREENS_DST 1096 #define IDC_HOTKEY_SCREENS_DST 1096
#define IDC_HOTKEY_SCREENS_ADD 1097 #define IDC_HOTKEY_SCREENS_ADD 1097
#define IDC_HOTKEY_SCREENS_REMOVE 1098 #define IDC_HOTKEY_SCREENS_REMOVE 1098
#define IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST 1099
#define IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST_LIST 1100
#define IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST_SCREENS 1101
// Next default values for new objects // Next default values for new objects
// //
@ -177,7 +180,7 @@
#define _APS_NO_MFC 1 #define _APS_NO_MFC 1
#define _APS_NEXT_RESOURCE_VALUE 116 #define _APS_NEXT_RESOURCE_VALUE 116
#define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1098 #define _APS_NEXT_CONTROL_VALUE 1102
#define _APS_NEXT_SYMED_VALUE 101 #define _APS_NEXT_SYMED_VALUE 101
#endif #endif
#endif #endif

View File

@ -406,6 +406,8 @@ Allowed individual actions are:
<span class="arg">screens</span> lists the screen or screens to <span class="arg">screens</span> lists the screen or screens to
direct the event to, regardless of the active screen. If not direct the event to, regardless of the active screen. If not
given then the event is directed to the active screen only. given then the event is directed to the active screen only.
(Due to a bug, keys cannot be directed to the server while on a
client screen.)
</p><p> </p><p>
<span class="code">keyDown</span> synthesizes a key press and <span class="code">keyDown</span> synthesizes a key press and
<span class="code">keyUp</span> synthesizes a key release. <span class="code">keyUp</span> synthesizes a key release.
@ -458,6 +460,30 @@ Allowed individual actions are:
<span class="code">right</span>, <span class="code">up</span> or <span class="code">right</span>, <span class="code">up</span> or
<span class="code">down</span>. <span class="code">down</span>.
</p><p> </p><p>
<li><a name="keyboardBroadcast"></a><span class="code">keyboardBroadcast(<span class="arg">mode</span>[,<span class="arg">screens</span>])</span>
</p><p>
Turns broadcasting of keystrokes to multiple screens on and off. When
turned on all key presses and releases are sent to all of the screens
listed in <span class="arg">screens</span>. If not given, empty or
<span class="code">*</span> then keystrokes are broadcast to all screens.
(However, due to a bug, keys cannot be sent to the server while on a
client screen.)
</p><p>
<span class="arg">mode</span> can be <span class="code">off</span>
to turn broadcasting off, <span class="code">on</span> to turn it
on, or <span class="code">toggle</span> to toggle the current
state. The default is <span class="code">toggle</span>.
</p><p>
<span class="arg">screens</span> is either <span class="code">*</span>
to indicate all screens or a colon (:) separated list of screen
names. (Note that the screen name must have already been encountered
in the configuration file so you'll probably want to put actions at
the bottom of the file.)
</p><p>
Multiple <span class="code">keyboardBroadcast</span> actions may be
configured with different <span class="arg">screens</span>. The most
recently performed action defines the screens to broadcast to.
</p><p>
</ul> </ul>
</p><p> </p><p>
Examples: Examples:

View File

@ -1203,6 +1203,36 @@ CConfig::parseAction(CConfigReadContext& s,
action = new CInputFilter::CLockCursorToScreenAction(mode); action = new CInputFilter::CLockCursorToScreenAction(mode);
} }
else if (name == "keyboardBroadcast") {
if (args.size() > 2) {
throw XConfigRead(s, "syntax for action: keyboardBroadcast([{off|on|toggle}[,screens]])");
}
CInputFilter::CKeyboardBroadcastAction::Mode mode =
CInputFilter::CKeyboardBroadcastAction::kToggle;
if (args.size() >= 1) {
if (args[0] == "off") {
mode = CInputFilter::CKeyboardBroadcastAction::kOff;
}
else if (args[0] == "on") {
mode = CInputFilter::CKeyboardBroadcastAction::kOn;
}
else if (args[0] == "toggle") {
mode = CInputFilter::CKeyboardBroadcastAction::kToggle;
}
else {
throw XConfigRead(s, "syntax for action: keyboardBroadcast([{off|on|toggle}[,screens]])");
}
}
std::set<CString> screens;
if (args.size() >= 2) {
parseScreens(s, args[1], screens);
}
action = new CInputFilter::CKeyboardBroadcastAction(mode, screens);
}
else { else {
throw XConfigRead(s, "unknown action argument \"%{1}\"", name); throw XConfigRead(s, "unknown action argument \"%{1}\"", name);
} }

View File

@ -268,13 +268,12 @@ CInputFilter::CAction::~CAction()
// do nothing // do nothing
} }
CInputFilter::CLockCursorToScreenAction::CLockCursorToScreenAction(Mode mode): CInputFilter::CLockCursorToScreenAction::CLockCursorToScreenAction(Mode mode) :
m_mode(mode) m_mode(mode)
{ {
// do nothing // do nothing
} }
CInputFilter::CLockCursorToScreenAction::Mode CInputFilter::CLockCursorToScreenAction::Mode
CInputFilter::CLockCursorToScreenAction::getMode() const CInputFilter::CLockCursorToScreenAction::getMode() const
{ {
@ -400,6 +399,74 @@ CInputFilter::CSwitchInDirectionAction::perform(const CEvent& event)
CEvent::kDeliverImmediately)); 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( CInputFilter::CKeystrokeAction::CKeystrokeAction(
IPlatformScreen::CKeyInfo* info, bool press) : IPlatformScreen::CKeyInfo* info, bool press) :
m_keyInfo(info), m_keyInfo(info),

View File

@ -21,6 +21,7 @@
#include "IPlatformScreen.h" #include "IPlatformScreen.h"
#include "CString.h" #include "CString.h"
#include "stdmap.h" #include "stdmap.h"
#include "stdset.h"
class CPrimaryClient; class CPrimaryClient;
class CEvent; class CEvent;
@ -173,6 +174,27 @@ public:
EDirection m_direction; EDirection m_direction;
}; };
// CKeyboardBroadcastAction
class CKeyboardBroadcastAction : public CAction {
public:
enum Mode { kOff, kOn, kToggle };
CKeyboardBroadcastAction(Mode = kToggle);
CKeyboardBroadcastAction(Mode, const std::set<CString>& screens);
Mode getMode() const;
std::set<CString> getScreens() const;
// CAction overrides
virtual CAction* clone() const;
virtual CString format() const;
virtual void perform(const CEvent&);
private:
Mode m_mode;
CString m_screens;
};
// CKeystrokeAction // CKeystrokeAction
class CKeystrokeAction : public CAction { class CKeystrokeAction : public CAction {
public: public:

View File

@ -39,6 +39,7 @@ CEvent::Type CServer::s_connectedEvent = CEvent::kUnknown;
CEvent::Type CServer::s_disconnectedEvent = CEvent::kUnknown; CEvent::Type CServer::s_disconnectedEvent = CEvent::kUnknown;
CEvent::Type CServer::s_switchToScreen = CEvent::kUnknown; CEvent::Type CServer::s_switchToScreen = CEvent::kUnknown;
CEvent::Type CServer::s_switchInDirection = CEvent::kUnknown; CEvent::Type CServer::s_switchInDirection = CEvent::kUnknown;
CEvent::Type CServer::s_keyboardBroadcast = CEvent::kUnknown;
CEvent::Type CServer::s_lockCursorToScreen = CEvent::kUnknown; CEvent::Type CServer::s_lockCursorToScreen = CEvent::kUnknown;
CServer::CServer(const CConfig& config, CPrimaryClient* primaryClient) : CServer::CServer(const CConfig& config, CPrimaryClient* primaryClient) :
@ -61,6 +62,7 @@ CServer::CServer(const CConfig& config, CPrimaryClient* primaryClient) :
m_switchTwoTapArmed(false), m_switchTwoTapArmed(false),
m_switchTwoTapZone(3), m_switchTwoTapZone(3),
m_relativeMoves(false), m_relativeMoves(false),
m_keyboardBroadcasting(false),
m_lockedToScreen(false) m_lockedToScreen(false)
{ {
// must have a primary client and it must have a canonical name // must have a primary client and it must have a canonical name
@ -133,6 +135,10 @@ CServer::CServer(const CConfig& config, CPrimaryClient* primaryClient) :
m_inputFilter, m_inputFilter,
new TMethodEventJob<CServer>(this, new TMethodEventJob<CServer>(this,
&CServer::handleSwitchInDirectionEvent)); &CServer::handleSwitchInDirectionEvent));
EVENTQUEUE->adoptHandler(getKeyboardBroadcastEvent(),
m_inputFilter,
new TMethodEventJob<CServer>(this,
&CServer::handleKeyboardBroadcastEvent));
EVENTQUEUE->adoptHandler(getLockCursorToScreenEvent(), EVENTQUEUE->adoptHandler(getLockCursorToScreenEvent(),
m_inputFilter, m_inputFilter,
new TMethodEventJob<CServer>(this, new TMethodEventJob<CServer>(this,
@ -355,6 +361,13 @@ CServer::getSwitchInDirectionEvent()
"CServer::switchInDirection"); "CServer::switchInDirection");
} }
CEvent::Type
CServer::getKeyboardBroadcastEvent()
{
return CEvent::registerTypeOnce(s_keyboardBroadcast,
"CServer:keyboardBroadcast");
}
CEvent::Type CEvent::Type
CServer::getLockCursorToScreenEvent() CServer::getLockCursorToScreenEvent()
{ {
@ -1364,6 +1377,37 @@ CServer::handleSwitchInDirectionEvent(const CEvent& event, void*)
} }
} }
void
CServer::handleKeyboardBroadcastEvent(const CEvent& event, void*)
{
CKeyboardBroadcastInfo* info = (CKeyboardBroadcastInfo*)event.getData();
// choose new state
bool newState;
switch (info->m_state) {
case CKeyboardBroadcastInfo::kOff:
newState = false;
break;
default:
case CKeyboardBroadcastInfo::kOn:
newState = true;
break;
case CKeyboardBroadcastInfo::kToggle:
newState = !m_keyboardBroadcasting;
break;
}
// enter new state
if (newState != m_keyboardBroadcasting ||
info->m_screens != m_keyboardBroadcastingScreens) {
m_keyboardBroadcasting = newState;
m_keyboardBroadcastingScreens = info->m_screens;
LOG((CLOG_DEBUG "keyboard broadcasting %s: %s", m_keyboardBroadcasting ? "on" : "off", m_keyboardBroadcastingScreens.c_str()));
}
}
void void
CServer::handleLockCursorToScreenEvent(const CEvent& event, void*) CServer::handleLockCursorToScreenEvent(const CEvent& event, void*)
{ {
@ -1513,10 +1557,17 @@ CServer::onKeyDown(KeyID id, KeyModifierMask mask, KeyButton button,
assert(m_active != NULL); assert(m_active != NULL);
// relay // relay
if (IKeyState::CKeyInfo::isDefault(screens)) { if (!m_keyboardBroadcasting ||
(screens && IKeyState::CKeyInfo::isDefault(screens))) {
m_active->keyDown(id, mask, button); m_active->keyDown(id, mask, button);
} }
else { else {
if (!screens && m_keyboardBroadcasting) {
screens = m_keyboardBroadcastingScreens.c_str();
if (IKeyState::CKeyInfo::isDefault(screens)) {
screens = "*";
}
}
for (CClientList::const_iterator index = m_clients.begin(); for (CClientList::const_iterator index = m_clients.begin();
index != m_clients.end(); ++index) { index != m_clients.end(); ++index) {
if (IKeyState::CKeyInfo::contains(screens, index->first)) { if (IKeyState::CKeyInfo::contains(screens, index->first)) {
@ -1534,10 +1585,17 @@ CServer::onKeyUp(KeyID id, KeyModifierMask mask, KeyButton button,
assert(m_active != NULL); assert(m_active != NULL);
// relay // relay
if (IKeyState::CKeyInfo::isDefault(screens)) { if (!m_keyboardBroadcasting ||
(screens && IKeyState::CKeyInfo::isDefault(screens))) {
m_active->keyUp(id, mask, button); m_active->keyUp(id, mask, button);
} }
else { else {
if (!screens && m_keyboardBroadcasting) {
screens = m_keyboardBroadcastingScreens.c_str();
if (IKeyState::CKeyInfo::isDefault(screens)) {
screens = "*";
}
}
for (CClientList::const_iterator index = m_clients.begin(); for (CClientList::const_iterator index = m_clients.begin();
index != m_clients.end(); ++index) { index != m_clients.end(); ++index) {
if (IKeyState::CKeyInfo::contains(screens, index->first)) { if (IKeyState::CKeyInfo::contains(screens, index->first)) {
@ -2090,3 +2148,29 @@ CServer::CScreenConnectedInfo::alloc(const CString& screen)
strcpy(info->m_screen, screen.c_str()); strcpy(info->m_screen, screen.c_str());
return info; return info;
} }
//
// CServer::CKeyboardBroadcastInfo
//
CServer::CKeyboardBroadcastInfo*
CServer::CKeyboardBroadcastInfo::alloc(State state)
{
CKeyboardBroadcastInfo* info =
(CKeyboardBroadcastInfo*)malloc(sizeof(CKeyboardBroadcastInfo));
info->m_state = state;
info->m_screens[0] = '\0';
return info;
}
CServer::CKeyboardBroadcastInfo*
CServer::CKeyboardBroadcastInfo::alloc(State state, const CString& screens)
{
CKeyboardBroadcastInfo* info =
(CKeyboardBroadcastInfo*)malloc(sizeof(CKeyboardBroadcastInfo) +
screens.size());
info->m_state = state;
strcpy(info->m_screens, screens.c_str());
return info;
}

View File

@ -77,6 +77,20 @@ public:
char m_screen[1]; char m_screen[1];
}; };
//! Keyboard broadcast data
class CKeyboardBroadcastInfo {
public:
enum State { kOff, kOn, kToggle };
static CKeyboardBroadcastInfo* alloc(State state = kToggle);
static CKeyboardBroadcastInfo* alloc(State state,
const CString& screens);
public:
State m_state;
char m_screens[1];
};
/*! /*!
Start the server with the configuration \p config and the primary Start the server with the configuration \p config and the primary
client (local screen) \p primaryClient. The client retains client (local screen) \p primaryClient. The client retains
@ -166,6 +180,14 @@ public:
*/ */
static CEvent::Type getSwitchInDirectionEvent(); static CEvent::Type getSwitchInDirectionEvent();
//! Get keyboard broadcast event type
/*!
Returns the keyboard broadcast event type. The server responds
to this by turning on keyboard broadcasting or turning it off. The
event data is a \c CKeyboardBroadcastInfo*.
*/
static CEvent::Type getKeyboardBroadcastEvent();
//! Get lock cursor event type //! Get lock cursor event type
/*! /*!
Returns the lock cursor event type. The server responds to this Returns the lock cursor event type. The server responds to this
@ -304,6 +326,7 @@ private:
void handleClientCloseTimeout(const CEvent&, void*); void handleClientCloseTimeout(const CEvent&, void*);
void handleSwitchToScreenEvent(const CEvent&, void*); void handleSwitchToScreenEvent(const CEvent&, void*);
void handleSwitchInDirectionEvent(const CEvent&, void*); void handleSwitchInDirectionEvent(const CEvent&, void*);
void handleKeyboardBroadcastEvent(const CEvent&,void*);
void handleLockCursorToScreenEvent(const CEvent&, void*); void handleLockCursorToScreenEvent(const CEvent&, void*);
void handleFakeInputBeginEvent(const CEvent&, void*); void handleFakeInputBeginEvent(const CEvent&, void*);
void handleFakeInputEndEvent(const CEvent&, void*); void handleFakeInputEndEvent(const CEvent&, void*);
@ -421,6 +444,11 @@ private:
// relative mouse move option // relative mouse move option
bool m_relativeMoves; bool m_relativeMoves;
// flag whether or not we have broadcasting enabled and the screens to
// which we should send broadcasted keys.
bool m_keyboardBroadcasting;
CString m_keyboardBroadcastingScreens;
// screen locking (former scroll lock) // screen locking (former scroll lock)
bool m_lockedToScreen; bool m_lockedToScreen;
@ -429,6 +457,7 @@ private:
static CEvent::Type s_disconnectedEvent; static CEvent::Type s_disconnectedEvent;
static CEvent::Type s_switchToScreen; static CEvent::Type s_switchToScreen;
static CEvent::Type s_switchInDirection; static CEvent::Type s_switchInDirection;
static CEvent::Type s_keyboardBroadcast;
static CEvent::Type s_lockCursorToScreen; static CEvent::Type s_lockCursorToScreen;
}; };

View File

@ -53,12 +53,13 @@ IKeyState::CKeyInfo*
IKeyState::CKeyInfo::alloc(KeyID id, IKeyState::CKeyInfo::alloc(KeyID id,
KeyModifierMask mask, KeyButton button, SInt32 count) KeyModifierMask mask, KeyButton button, SInt32 count)
{ {
CKeyInfo* info = (CKeyInfo*)malloc(sizeof(CKeyInfo)); CKeyInfo* info = (CKeyInfo*)malloc(sizeof(CKeyInfo));
info->m_key = id; info->m_key = id;
info->m_mask = mask; info->m_mask = mask;
info->m_button = button; info->m_button = button;
info->m_count = count; info->m_count = count;
info->m_screens[0] = '\0'; info->m_screens = NULL;
info->m_screensBuffer[0] = '\0';
return info; return info;
} }
@ -67,44 +68,30 @@ IKeyState::CKeyInfo::alloc(KeyID id,
KeyModifierMask mask, KeyButton button, SInt32 count, KeyModifierMask mask, KeyButton button, SInt32 count,
const std::set<CString>& destinations) const std::set<CString>& destinations)
{ {
// collect destinations into a string. names are surrounded by ':' CString screens = join(destinations);
// which makes searching easy later. the string is empty if there
// are no destinations and "*" means all destinations.
CString screens;
for (std::set<CString>::const_iterator i = destinations.begin();
i != destinations.end(); ++i) {
if (*i == "*") {
screens = "*";
break;
}
else {
if (screens.empty()) {
screens = ":";
}
screens += *i;
screens += ":";
}
}
// build structure // build structure
CKeyInfo* info = (CKeyInfo*)malloc(sizeof(CKeyInfo) + screens.size()); CKeyInfo* info = (CKeyInfo*)malloc(sizeof(CKeyInfo) + screens.size());
info->m_key = id; info->m_key = id;
info->m_mask = mask; info->m_mask = mask;
info->m_button = button; info->m_button = button;
info->m_count = count; info->m_count = count;
strcpy(info->m_screens, screens.c_str()); info->m_screens = info->m_screensBuffer;
strcpy(info->m_screensBuffer, screens.c_str());
return info; return info;
} }
IKeyState::CKeyInfo* IKeyState::CKeyInfo*
IKeyState::CKeyInfo::alloc(const CKeyInfo& x) IKeyState::CKeyInfo::alloc(const CKeyInfo& x)
{ {
CKeyInfo* info = (CKeyInfo*)malloc(sizeof(CKeyInfo) + strlen(x.m_screens)); CKeyInfo* info = (CKeyInfo*)malloc(sizeof(CKeyInfo) +
info->m_key = x.m_key; strlen(x.m_screensBuffer));
info->m_mask = x.m_mask; info->m_key = x.m_key;
info->m_button = x.m_button; info->m_mask = x.m_mask;
info->m_count = x.m_count; info->m_button = x.m_button;
strcpy(info->m_screens, x.m_screens); info->m_count = x.m_count;
info->m_screens = x.m_screens ? info->m_screensBuffer : NULL;
strcpy(info->m_screensBuffer, x.m_screensBuffer);
return info; return info;
} }
@ -141,7 +128,31 @@ IKeyState::CKeyInfo::equal(const CKeyInfo* a, const CKeyInfo* b)
a->m_mask == b->m_mask && a->m_mask == b->m_mask &&
a->m_button == b->m_button && a->m_button == b->m_button &&
a->m_count == b->m_count && a->m_count == b->m_count &&
strcmp(a->m_screens, b->m_screens) == 0); strcmp(a->m_screensBuffer, b->m_screensBuffer) == 0);
}
CString
IKeyState::CKeyInfo::join(const std::set<CString>& destinations)
{
// collect destinations into a string. names are surrounded by ':'
// which makes searching easy. the string is empty if there are no
// destinations and "*" means all destinations.
CString screens;
for (std::set<CString>::const_iterator i = destinations.begin();
i != destinations.end(); ++i) {
if (*i == "*") {
screens = "*";
break;
}
else {
if (screens.empty()) {
screens = ":";
}
screens += *i;
screens += ":";
}
}
return screens;
} }
void void

View File

@ -43,6 +43,7 @@ public:
static bool isDefault(const char* screens); static bool isDefault(const char* screens);
static bool contains(const char* screens, const CString& name); static bool contains(const char* screens, const CString& name);
static bool equal(const CKeyInfo*, const CKeyInfo*); static bool equal(const CKeyInfo*, const CKeyInfo*);
static CString join(const std::set<CString>& destinations);
static void split(const char* screens, std::set<CString>&); static void split(const char* screens, std::set<CString>&);
public: public:
@ -50,7 +51,8 @@ public:
KeyModifierMask m_mask; KeyModifierMask m_mask;
KeyButton m_button; KeyButton m_button;
SInt32 m_count; SInt32 m_count;
char m_screens[1]; char* m_screens;
char m_screensBuffer[1];
}; };
typedef std::set<KeyButton> KeyButtonSet; typedef std::set<KeyButton> KeyButtonSet;