Restored lost files and changes in version 1.3.1 to depot.

This commit is contained in:
crs
2007-06-17 11:19:18 +00:00
parent 73acb7860d
commit 52ae656411
199 changed files with 27622 additions and 13726 deletions

View File

@@ -14,6 +14,7 @@
#include "CMSWindowsDesks.h"
#include "CMSWindowsScreen.h"
#include "CSynergyHook.h"
#include "IScreenSaver.h"
#include "XScreen.h"
#include "CLock.h"
@@ -45,8 +46,8 @@
#define WM_NCXBUTTONDOWN 0x00AB
#define WM_NCXBUTTONUP 0x00AC
#define WM_NCXBUTTONDBLCLK 0x00AD
#define MOUSEEVENTF_XDOWN 0x0100
#define MOUSEEVENTF_XUP 0x0200
#define MOUSEEVENTF_XDOWN 0x0080
#define MOUSEEVENTF_XUP 0x0100
#define XBUTTON1 0x0001
#define XBUTTON2 0x0002
#endif
@@ -67,7 +68,7 @@
#define SYNERGY_MSG_FAKE_BUTTON SYNERGY_HOOK_LAST_MSG + 5
// x; y
#define SYNERGY_MSG_FAKE_MOVE SYNERGY_HOOK_LAST_MSG + 6
// delta; <unused>
// xDelta; yDelta
#define SYNERGY_MSG_FAKE_WHEEL SYNERGY_HOOK_LAST_MSG + 7
// POINT*; <unused>
#define SYNERGY_MSG_CURSOR_POS SYNERGY_HOOK_LAST_MSG + 8
@@ -77,6 +78,8 @@
#define SYNERGY_MSG_SCREENSAVER SYNERGY_HOOK_LAST_MSG + 10
// dx; dy
#define SYNERGY_MSG_FAKE_REL_MOVE SYNERGY_HOOK_LAST_MSG + 11
// enable; <unused>
#define SYNERGY_MSG_FAKE_INPUT SYNERGY_HOOK_LAST_MSG + 12
//
// CMSWindowsDesks
@@ -106,6 +109,7 @@ CMSWindowsDesks::CMSWindowsDesks(
m_cursor = createBlankCursor();
m_deskClass = createDeskWindowClass(m_isPrimary);
m_keyLayout = GetKeyboardLayout(GetCurrentThreadId());
resetOptions();
}
CMSWindowsDesks::~CMSWindowsDesks()
@@ -164,6 +168,23 @@ CMSWindowsDesks::leave(HKL keyLayout)
sendMessage(SYNERGY_MSG_LEAVE, (WPARAM)keyLayout, 0);
}
void
CMSWindowsDesks::resetOptions()
{
m_leaveForegroundOption = false;
}
void
CMSWindowsDesks::setOptions(const COptionsList& options)
{
for (UInt32 i = 0, n = options.size(); i < n; i += 2) {
if (options[i] == kOptionWin32KeepForeground) {
m_leaveForegroundOption = (options[i + 1] != 0);
LOG((CLOG_DEBUG1 "%s the foreground window", m_leaveForegroundOption ? "Don\'t grab" : "Grab"));
}
}
}
void
CMSWindowsDesks::updateKeys()
{
@@ -193,6 +214,18 @@ CMSWindowsDesks::installScreensaverHooks(bool install)
}
}
void
CMSWindowsDesks::fakeInputBegin()
{
sendMessage(SYNERGY_MSG_FAKE_INPUT, 1, 0);
}
void
CMSWindowsDesks::fakeInputEnd()
{
sendMessage(SYNERGY_MSG_FAKE_INPUT, 0, 0);
}
void
CMSWindowsDesks::getCursorPos(SInt32& x, SInt32& y) const
{
@@ -310,9 +343,9 @@ CMSWindowsDesks::fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const
}
void
CMSWindowsDesks::fakeMouseWheel(SInt32 delta) const
CMSWindowsDesks::fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const
{
sendMessage(SYNERGY_MSG_FAKE_WHEEL, delta, 0);
sendMessage(SYNERGY_MSG_FAKE_WHEEL, xDelta, yDelta);
}
void
@@ -565,9 +598,21 @@ CMSWindowsDesks::deskEnter(CDesk* desk)
SWP_NOMOVE | SWP_NOSIZE |
SWP_NOACTIVATE | SWP_HIDEWINDOW);
// this is here only because of the "ConsoleWindowClass" stuff in
// deskLeave.
// restore the foreground window
// XXX -- this raises the window to the top of the Z-order. we
// want it to stay wherever it was to properly support X-mouse
// (mouse over activation) but i've no idea how to do that.
// the obvious workaround of using SetWindowPos() to move it back
// after being raised doesn't work.
DWORD thisThread =
GetWindowThreadProcessId(desk->m_window, NULL);
DWORD thatThread =
GetWindowThreadProcessId(desk->m_foregroundWindow, NULL);
AttachThreadInput(thatThread, thisThread, TRUE);
SetForegroundWindow(desk->m_foregroundWindow);
AttachThreadInput(thatThread, thisThread, FALSE);
EnableWindow(desk->m_window, desk->m_lowLevel ? FALSE : TRUE);
desk->m_foregroundWindow = NULL;
}
void
@@ -575,9 +620,6 @@ CMSWindowsDesks::deskLeave(CDesk* desk, HKL keyLayout)
{
ShowCursor(FALSE);
if (m_isPrimary) {
// update key state
m_updateKeys->run();
// map a window to hide the cursor and to use whatever keyboard
// layout we choose rather than the keyboard layout of the last
// active window.
@@ -610,38 +652,26 @@ CMSWindowsDesks::deskLeave(CDesk* desk, HKL keyLayout)
SetActiveWindow(desk->m_window);
}
// if the active window is a console then activate our window.
// we do this because for some reason our hook reports unshifted
// characters when the shift is down and a console window is
// active. interestingly we do see the shift key go down and up.
// if using low-level hooks then disable the foreground window
// so it can't mess up any of our keyboard events. the console
// program, for example, will cause characters to be reported as
// unshifted, regardless of the shift key state. interestingly
// we do see the shift key go down and up.
//
// note that we must enable the window to activate it and we
// need to disable the window on deskEnter.
// FIXME -- figure out the real problem here and solve it.
else {
HWND foreground = GetForegroundWindow();
if (foreground != NULL) {
char className[40];
if (GetClassName(foreground, className,
sizeof(className) / sizeof(className[0])) &&
strcmp(className, "ConsoleWindowClass") == 0) {
EnableWindow(desk->m_window, TRUE);
SetActiveWindow(desk->m_window);
// force our window to the foreground. we can't
// simply call SetForegroundWindow() because that
// will only alert the user that the window wants
// to be the foreground as of windows 98/2000. we
// have to attach to the thread of the current
// foreground window then call it on our window
// and finally detach the threads.
DWORD thisThread =
GetWindowThreadProcessId(desk->m_window, NULL);
DWORD thatThread =
GetWindowThreadProcessId(foreground, NULL);
AttachThreadInput(thatThread, thisThread, TRUE);
SetForegroundWindow(desk->m_window);
AttachThreadInput(thatThread, thisThread, FALSE);
}
desk->m_foregroundWindow = getForegroundWindow();
if (desk->m_foregroundWindow != NULL) {
EnableWindow(desk->m_window, TRUE);
SetActiveWindow(desk->m_window);
DWORD thisThread =
GetWindowThreadProcessId(desk->m_window, NULL);
DWORD thatThread =
GetWindowThreadProcessId(desk->m_foregroundWindow, NULL);
AttachThreadInput(thatThread, thisThread, TRUE);
SetForegroundWindow(desk->m_window);
AttachThreadInput(thatThread, thisThread, FALSE);
}
}
@@ -671,9 +701,10 @@ CMSWindowsDesks::deskThread(void* vdesk)
MSG msg;
// use given desktop for this thread
CDesk* desk = reinterpret_cast<CDesk*>(vdesk);
desk->m_threadID = GetCurrentThreadId();
desk->m_window = NULL;
CDesk* desk = reinterpret_cast<CDesk*>(vdesk);
desk->m_threadID = GetCurrentThreadId();
desk->m_window = NULL;
desk->m_foregroundWindow = NULL;
if (desk->m_desk != NULL && SetThreadDesktop(desk->m_desk) != 0) {
// create a message queue
PeekMessage(&msg, NULL, 0,0, PM_NOREMOVE);
@@ -763,7 +794,10 @@ CMSWindowsDesks::deskThread(void* vdesk)
break;
case SYNERGY_MSG_FAKE_WHEEL:
mouse_event(MOUSEEVENTF_WHEEL, 0, 0, msg.wParam, 0);
// XXX -- add support for x-axis scrolling
if (msg.lParam != 0) {
mouse_event(MOUSEEVENTF_WHEEL, 0, 0, msg.lParam, 0);
}
break;
case SYNERGY_MSG_CURSOR_POS: {
@@ -787,6 +821,12 @@ CMSWindowsDesks::deskThread(void* vdesk)
m_uninstallScreensaver();
}
break;
case SYNERGY_MSG_FAKE_INPUT:
keybd_event(SYNERGY_HOOK_FAKE_INPUT_VIRTUAL_KEY,
SYNERGY_HOOK_FAKE_INPUT_SCANCODE,
msg.wParam ? 0 : KEYEVENTF_KEYUP, 0);
break;
}
// notify that message was processed
@@ -870,11 +910,12 @@ CMSWindowsDesks::checkDesk()
// inaccessible desktop to an accessible one we have to
// update the keyboard state.
LOG((CLOG_DEBUG "switched to desk \"%s\"", name.c_str()));
bool syncKeys = false;
bool isAccessible = isDeskAccessible(desk);
if (isDeskAccessible(m_activeDesk) != isAccessible) {
if (isAccessible) {
LOG((CLOG_DEBUG "desktop is now accessible"));
sendMessage(SYNERGY_MSG_SYNC_KEYS, 0, 0);
syncKeys = true;
}
else {
LOG((CLOG_DEBUG "desktop is now inaccessible"));
@@ -890,6 +931,11 @@ CMSWindowsDesks::checkDesk()
if (!wasOnScreen) {
sendMessage(SYNERGY_MSG_LEAVE, (WPARAM)m_keyLayout, 0);
}
// update keys if necessary
if (syncKeys) {
updateKeys();
}
}
else if (name != m_activeDeskName) {
// screen saver might have started
@@ -972,3 +1018,16 @@ CMSWindowsDesks::getDesktopName(HDESK desk)
return result;
}
}
HWND
CMSWindowsDesks::getForegroundWindow() const
{
// Ideally we'd return NULL as much as possible, only returning
// the actual foreground window when we know it's going to mess
// up our keyboard input. For now we'll just let the user
// decide.
if (m_leaveForegroundOption) {
return NULL;
}
return GetForegroundWindow();
}

View File

@@ -18,6 +18,7 @@
#include "CSynergyHook.h"
#include "KeyTypes.h"
#include "MouseTypes.h"
#include "OptionTypes.h"
#include "CCondVar.h"
#include "CMutex.h"
#include "CString.h"
@@ -92,6 +93,19 @@ public:
*/
void leave(HKL keyLayout);
//! Notify of options changes
/*!
Resets all options to their default values.
*/
void resetOptions();
//! Notify of options changes
/*!
Set options to given values. Ignores unknown options and doesn't
modify options that aren't given in \c options.
*/
void setOptions(const COptionsList& options);
//! Update the key state
/*!
Causes the key state to get updated to reflect the physical keyboard
@@ -115,6 +129,18 @@ public:
*/
void installScreensaverHooks(bool install);
//! Start ignoring user input
/*!
Starts ignoring user input so we don't pick up our own synthesized events.
*/
void fakeInputBegin();
//! Stop ignoring user input
/*!
Undoes whatever \c fakeInputBegin() did.
*/
void fakeInputEnd();
//@}
//! @name accessors
//@{
@@ -152,9 +178,9 @@ public:
//! Fake mouse wheel
/*!
Synthesize a mouse wheel event of amount \c delta.
Synthesize a mouse wheel event of amount \c delta in direction \c axis.
*/
void fakeMouseWheel(SInt32 delta) const;
void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const;
//@}
@@ -167,6 +193,7 @@ private:
DWORD m_targetID;
HDESK m_desk;
HWND m_window;
HWND m_foregroundWindow;
bool m_lowLevel;
};
typedef std::map<CString, CDesk*> CDesks;
@@ -198,6 +225,9 @@ private:
void waitForDesk() const;
void sendMessage(UINT, WPARAM, LPARAM) const;
// work around for messed up keyboard events from low-level hooks
HWND getForegroundWindow() const;
// desk API wrappers
HDESK openInputDesktop();
void closeDesktop(HDESK);
@@ -258,6 +288,9 @@ private:
// keyboard stuff
IJob* m_updateKeys;
HKL m_keyLayout;
// options
bool m_leaveForegroundOption;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -17,9 +17,12 @@
#include "CKeyState.h"
#include "CString.h"
#include "stdvector.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
class CEvent;
class CEventQueueTimer;
class CMSWindowsDesks;
//! Microsoft Windows key mapper
@@ -28,24 +31,62 @@ This class maps KeyIDs to keystrokes.
*/
class CMSWindowsKeyState : public CKeyState {
public:
CMSWindowsKeyState(CMSWindowsDesks* desks);
CMSWindowsKeyState(CMSWindowsDesks* desks, void* eventTarget);
virtual ~CMSWindowsKeyState();
//! @name accessors
//! @name manipulators
//@{
//! Handle screen disabling
/*!
Called when screen is disabled. This is needed to deal with platform
brokenness.
*/
void disable();
//! Set the active keyboard layout
/*!
Uses \p keyLayout when querying the keyboard.
*/
void setKeyLayout(HKL keyLayout);
//! Check the named virtual key for release
//! Test and set autorepeat state
/*!
If \p virtualKey isn't really pressed but we think it is then
update our state and post a key release event to \p eventTarget.
Returns true if the given button is autorepeating and updates internal
state.
*/
void fixKey(void* eventTarget, UINT virtualKey);
bool testAutoRepeat(bool press, bool isRepeat, KeyButton);
//! Remember modifier state
/*!
Records the current non-toggle modifier state.
*/
void saveModifiers();
//! Set effective modifier state
/*!
Temporarily sets the non-toggle modifier state to those saved by the
last call to \c saveModifiers if \p enable is \c true. Restores the
modifier state to the current modifier state if \p enable is \c false.
This is for synthesizing keystrokes on the primary screen when the
cursor is on a secondary screen. When on a secondary screen we capture
all non-toggle modifier state, track the state internally and do not
pass it on. So if Alt+F1 synthesizes Alt+X we need to synthesize
not just X but also Alt, despite the fact that our internal modifier
state indicates Alt is down, because local apps never saw the Alt down
event.
*/
void useSavedModifiers(bool enable);
//@}
//! @name accessors
//@{
//! Map a virtual key to a button
/*!
Returns the button for the \p virtualKey.
*/
KeyButton virtualKeyToButton(UINT virtualKey) const;
//! Map key event to a key
/*!
@@ -55,84 +96,121 @@ public:
KeyID mapKeyFromEvent(WPARAM charAndVirtKey,
LPARAM info, KeyModifierMask* maskOut) const;
//! Map a virtual key to a button
//! Check if keyboard groups have changed
/*!
Returns the button for the \p virtualKey.
Returns true iff the number or order of the keyboard groups have
changed since the last call to updateKeys().
*/
KeyButton virtualKeyToButton(UINT virtualKey) const;
bool didGroupsChange() const;
//! Map key to virtual key
/*!
Returns the virtual key for key \p key or 0 if there's no such virtual
key.
*/
UINT mapKeyToVirtualKey(KeyID key) const;
//! Map virtual key and button to KeyID
/*!
Returns the KeyID for virtual key \p virtualKey and button \p button
(button should include the extended key bit), or kKeyNone if there is
no such key.
*/
static KeyID getKeyID(UINT virtualKey, KeyButton button);
//@}
// IKeyState overrides
virtual void fakeKeyDown(KeyID id, KeyModifierMask mask,
KeyButton button);
virtual void fakeKeyRepeat(KeyID id, KeyModifierMask mask,
SInt32 count, KeyButton button);
virtual bool fakeCtrlAltDel();
virtual KeyModifierMask
pollActiveModifiers() const;
virtual SInt32 pollActiveGroup() const;
virtual void pollPressedKeys(KeyButtonSet& pressedKeys) const;
// CKeyState overrides
virtual void onKey(KeyButton button, bool down,
KeyModifierMask newState);
virtual void sendKeyEvent(void* target,
bool press, bool isAutoRepeat,
KeyID key, KeyModifierMask mask,
SInt32 count, KeyButton button);
virtual bool fakeCtrlAltDel();
virtual const char* getKeyName(KeyButton) const;
protected:
// IKeyState overrides
virtual void doUpdateKeys();
virtual void doFakeKeyEvent(KeyButton button,
bool press, bool isAutoRepeat);
virtual KeyButton mapKey(Keystrokes& keys, KeyID id,
KeyModifierMask desiredMask,
bool isAutoRepeat) const;
// CKeyState overrides
virtual void getKeyMap(CKeyMap& keyMap);
virtual void fakeKey(const Keystroke& keystroke);
virtual KeyModifierMask&
getActiveModifiersRValue();
private:
typedef std::vector<HKL> GroupList;
// send ctrl+alt+del hotkey event on NT family
static void ctrlAltDelThread(void*);
// convert a language ID to a code page
UINT getCodePageFromLangID(LANGID langid) const;
bool getGroups(GroupList&) const;
void setWindowGroup(SInt32 group);
// map a virtual key to a button. this tries to deal with the
// broken win32 API as best it can.
KeyButton mapVirtKeyToButton(UINT virtualKey,
KeyButton& extended) const;
void fixKeys();
void handleFixKeys(const CEvent&, void*);
// same as above and discard extended
KeyButton mapVirtKeyToButton(UINT virtualKey) const;
KeyID getIDForKey(CKeyMap::KeyItem& item,
KeyButton button, UINT virtualKey,
PBYTE keyState, HKL hkl) const;
// map character \c c given keyboard layout \c hkl to the keystrokes
// to generate it.
KeyButton mapCharacter(Keystrokes& keys,
char c, HKL hkl, bool isAutoRepeat) const;
// map \c virtualKey to the keystrokes to generate it, along with
// keystrokes to update and restore the modifier state.
KeyButton mapToKeystrokes(Keystrokes& keys, KeyButton button,
KeyModifierMask desiredMask,
KeyModifierMask requiredMask,
bool isAutoRepeat) const;
// get keystrokes to get modifiers in a desired state
bool adjustModifiers(Keystrokes& keys,
Keystrokes& undo,
KeyModifierMask desiredMask,
KeyModifierMask requiredMask) const;
// pass character to ToAsciiEx(), returning what it returns
int toAscii(TCHAR c, HKL hkl, bool menu, WORD* chars) const;
// return true iff \c c is a dead character
bool isDeadChar(TCHAR c, HKL hkl, bool menu) const;
void addKeyEntry(CKeyMap& keyMap, CKeyMap::KeyItem& item);
private:
// not implemented
CMSWindowsKeyState(const CMSWindowsKeyState&);
CMSWindowsKeyState& operator=(const CMSWindowsKeyState&);
private:
typedef std::map<HKL, SInt32> GroupMap;
typedef std::map<KeyID, UINT> KeyToVKMap;
bool m_is95Family;
void* m_eventTarget;
CMSWindowsDesks* m_desks;
HKL m_keyLayout;
CString m_keyName;
UINT m_scanCodeToVirtKey[512];
UINT m_scanCodeToVirtKeyNumLock[512];
KeyButton m_virtKeyToScanCode[256];
UINT m_buttonToVK[512];
UINT m_buttonToNumpadVK[512];
KeyButton m_virtualKeyToButton[256];
KeyToVKMap m_keyToVKMap;
static const char* s_vkToName[];
static const KeyID s_virtualKey[][2];
static const UINT s_mapE000[];
static const UINT s_mapEE00[];
static const UINT s_mapEF00[];
// the timer used to check for fixing key state
CEventQueueTimer* m_fixTimer;
// the groups (keyboard layouts)
GroupList m_groups;
GroupMap m_groupMap;
// the last button that we generated a key down event for. this
// is zero if the last key event was a key up. we use this to
// synthesize key repeats since the low level keyboard hook can't
// tell us if an event is a key repeat.
KeyButton m_lastDown;
// modifier tracking
bool m_useSavedModifiers;
KeyModifierMask m_savedModifiers;
KeyModifierMask m_originalSavedModifiers;
// pointer to ToUnicodeEx. on win95 family this will be NULL.
typedef int (WINAPI *ToUnicodeEx_t)(UINT wVirtKey,
UINT wScanCode,
PBYTE lpKeyState,
LPWSTR pwszBuff,
int cchBuff,
UINT wFlags,
HKL dwhkl);
ToUnicodeEx_t m_ToUnicodeEx;
static const KeyID s_virtualKey[];
};
#endif

View File

@@ -19,6 +19,7 @@
#include "CMSWindowsKeyState.h"
#include "CMSWindowsScreenSaver.h"
#include "CClipboard.h"
#include "CKeyMap.h"
#include "XScreen.h"
#include "CLock.h"
#include "CThread.h"
@@ -54,8 +55,8 @@
#define WM_NCXBUTTONDOWN 0x00AB
#define WM_NCXBUTTONUP 0x00AC
#define WM_NCXBUTTONDBLCLK 0x00AD
#define MOUSEEVENTF_XDOWN 0x0100
#define MOUSEEVENTF_XUP 0x0200
#define MOUSEEVENTF_XDOWN 0x0080
#define MOUSEEVENTF_XUP 0x0100
#define XBUTTON1 0x0001
#define XBUTTON2 0x0002
#endif
@@ -76,8 +77,7 @@
HINSTANCE CMSWindowsScreen::s_instance = NULL;
CMSWindowsScreen* CMSWindowsScreen::s_screen = NULL;
CMSWindowsScreen::CMSWindowsScreen(bool isPrimary,
IJob* suspend, IJob* resume) :
CMSWindowsScreen::CMSWindowsScreen(bool isPrimary) :
m_isPrimary(isPrimary),
m_is95Family(CArchMiscWindows::isWindows95Family()),
m_isOnScreen(m_isPrimary),
@@ -90,8 +90,8 @@ CMSWindowsScreen::CMSWindowsScreen(bool isPrimary,
m_sequenceNumber(0),
m_mark(0),
m_markReceived(0),
m_keyLayout(NULL),
m_fixTimer(NULL),
m_keyLayout(NULL),
m_screensaver(NULL),
m_screensaverNotify(false),
m_screensaverActive(false),
@@ -106,8 +106,6 @@ CMSWindowsScreen::CMSWindowsScreen(bool isPrimary,
m_setZone(NULL),
m_setMode(NULL),
m_keyState(NULL),
m_suspend(suspend),
m_resume(resume),
m_hasMouse(GetSystemMetrics(SM_MOUSEPRESENT) != 0),
m_showingMouse(false)
{
@@ -124,7 +122,7 @@ CMSWindowsScreen::CMSWindowsScreen(bool isPrimary,
m_hookLibrary, m_screensaver,
new TMethodJob<CMSWindowsScreen>(this,
&CMSWindowsScreen::updateKeysCB));
m_keyState = new CMSWindowsKeyState(m_desks);
m_keyState = new CMSWindowsKeyState(m_desks, getEventTarget());
updateScreenShape();
m_class = createWindowClass();
m_window = createWindow(m_class, "Synergy");
@@ -139,8 +137,6 @@ CMSWindowsScreen::CMSWindowsScreen(bool isPrimary,
destroyWindow(m_window);
destroyClass(m_class);
closeHookLibrary(m_hookLibrary);
delete m_suspend;
delete m_resume;
s_screen = NULL;
throw;
}
@@ -167,8 +163,6 @@ CMSWindowsScreen::~CMSWindowsScreen()
destroyWindow(m_window);
destroyClass(m_class);
closeHookLibrary(m_hookLibrary);
delete m_suspend;
delete m_resume;
s_screen = NULL;
}
@@ -192,6 +186,12 @@ CMSWindowsScreen::enable()
{
assert(m_isOnScreen == m_isPrimary);
// we need to poll some things to fix them
m_fixTimer = EVENTQUEUE->newTimer(1.0, NULL);
EVENTQUEUE->adoptHandler(CEvent::kTimer, m_fixTimer,
new TMethodEventJob<CMSWindowsScreen>(this,
&CMSWindowsScreen::handleFixes));
// install our clipboard snooper
m_nextClipboardWindow = SetClipboardViewer(m_window);
@@ -232,17 +232,20 @@ CMSWindowsScreen::disable()
CArchMiscWindows::kDISPLAY);
}
// uninstall fix key timer
// tell key state
m_keyState->disable();
// stop snooping the clipboard
ChangeClipboardChain(m_window, m_nextClipboardWindow);
m_nextClipboardWindow = NULL;
// uninstall fix timer
if (m_fixTimer != NULL) {
EVENTQUEUE->removeHandler(CEvent::kTimer, m_fixTimer);
EVENTQUEUE->deleteTimer(m_fixTimer);
m_fixTimer = NULL;
}
// stop snooping the clipboard
ChangeClipboardChain(m_window, m_nextClipboardWindow);
m_nextClipboardWindow = NULL;
m_isOnScreen = m_isPrimary;
forceShowCursor();
}
@@ -292,6 +295,10 @@ CMSWindowsScreen::leave()
// all messages prior to now are invalid
nextMark();
// remember the modifier state. this is the modifier state
// reflected in the internal keyboard state.
m_keyState->saveModifiers();
// capture events
m_setMode(kHOOK_RELAY_EVENTS);
}
@@ -388,13 +395,13 @@ CMSWindowsScreen::screensaver(bool activate)
void
CMSWindowsScreen::resetOptions()
{
// no options
m_desks->resetOptions();
}
void
CMSWindowsScreen::setOptions(const COptionsList&)
CMSWindowsScreen::setOptions(const COptionsList& options)
{
// no options
m_desks->setOptions(options);
}
void
@@ -467,6 +474,130 @@ CMSWindowsScreen::warpCursor(SInt32 x, SInt32 y)
m_yCursor = y;
}
UInt32
CMSWindowsScreen::registerHotKey(KeyID key, KeyModifierMask mask)
{
// only allow certain modifiers
if ((mask & ~(KeyModifierShift | KeyModifierControl |
KeyModifierAlt | KeyModifierSuper)) != 0) {
LOG((CLOG_WARN "could not map hotkey id=%04x mask=%04x", key, mask));
return 0;
}
// fail if no keys
if (key == kKeyNone && mask == 0) {
return 0;
}
// convert to win32
UINT modifiers = 0;
if ((mask & KeyModifierShift) != 0) {
modifiers |= MOD_SHIFT;
}
if ((mask & KeyModifierControl) != 0) {
modifiers |= MOD_CONTROL;
}
if ((mask & KeyModifierAlt) != 0) {
modifiers |= MOD_ALT;
}
if ((mask & KeyModifierSuper) != 0) {
modifiers |= MOD_WIN;
}
UINT vk = m_keyState->mapKeyToVirtualKey(key);
if (key != kKeyNone && vk == 0) {
// can't map key
LOG((CLOG_WARN "could not map hotkey id=%04x mask=%04x", key, mask));
return 0;
}
// choose hotkey id
UInt32 id;
if (!m_oldHotKeyIDs.empty()) {
id = m_oldHotKeyIDs.back();
m_oldHotKeyIDs.pop_back();
}
else {
id = m_hotKeys.size() + 1;
}
// if this hot key has modifiers only then we'll handle it specially
bool err;
if (key == kKeyNone) {
// check if already registered
err = (m_hotKeyToIDMap.count(CHotKeyItem(vk, modifiers)) > 0);
}
else {
// register with OS
err = (RegisterHotKey(NULL, id, modifiers, vk) == 0);
}
if (!err) {
m_hotKeys.insert(std::make_pair(id, CHotKeyItem(vk, modifiers)));
m_hotKeyToIDMap[CHotKeyItem(vk, modifiers)] = id;
}
else {
m_oldHotKeyIDs.push_back(id);
m_hotKeys.erase(id);
LOG((CLOG_WARN "failed to register hotkey %s (id=%04x mask=%04x)", CKeyMap::formatKey(key, mask).c_str(), key, mask));
return 0;
}
LOG((CLOG_DEBUG "registered hotkey %s (id=%04x mask=%04x) as id=%d", CKeyMap::formatKey(key, mask).c_str(), key, mask, id));
return id;
}
void
CMSWindowsScreen::unregisterHotKey(UInt32 id)
{
// look up hotkey
HotKeyMap::iterator i = m_hotKeys.find(id);
if (i == m_hotKeys.end()) {
return;
}
// unregister with OS
bool err;
if (i->second.getVirtualKey() != 0) {
err = !UnregisterHotKey(NULL, id);
}
else {
err = false;
}
if (err) {
LOG((CLOG_WARN "failed to unregister hotkey id=%d", id));
}
else {
LOG((CLOG_DEBUG "unregistered hotkey id=%d", id));
}
// discard hot key from map and record old id for reuse
m_hotKeyToIDMap.erase(i->second);
m_hotKeys.erase(i);
m_oldHotKeyIDs.push_back(id);
}
void
CMSWindowsScreen::fakeInputBegin()
{
assert(m_isPrimary);
if (!m_isOnScreen) {
m_keyState->useSavedModifiers(true);
}
m_desks->fakeInputBegin();
}
void
CMSWindowsScreen::fakeInputEnd()
{
assert(m_isPrimary);
m_desks->fakeInputEnd();
if (!m_isOnScreen) {
m_keyState->useSavedModifiers(false);
}
}
SInt32
CMSWindowsScreen::getJumpZoneSize() const
{
@@ -521,9 +652,9 @@ CMSWindowsScreen::fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const
}
void
CMSWindowsScreen::fakeMouseWheel(SInt32 delta) const
CMSWindowsScreen::fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const
{
m_desks->fakeMouseWheel(delta);
m_desks->fakeMouseWheel(xDelta, yDelta);
}
void
@@ -556,9 +687,9 @@ CMSWindowsScreen::fakeKeyUp(KeyButton button)
}
void
CMSWindowsScreen::fakeToggle(KeyModifierMask modifier)
CMSWindowsScreen::fakeAllKeysUp()
{
CPlatformScreen::fakeToggle(modifier);
CPlatformScreen::fakeAllKeysUp();
updateForceShowCursor();
}
@@ -776,7 +907,8 @@ CMSWindowsScreen::onPreDispatchPrimary(HWND,
static_cast<SInt32>(lParam));
case SYNERGY_MSG_MOUSE_WHEEL:
return onMouseWheel(static_cast<SInt32>(wParam));
// XXX -- support x-axis scrolling
return onMouseWheel(0, static_cast<SInt32>(wParam));
case SYNERGY_MSG_PRE_WARP:
{
@@ -800,6 +932,13 @@ CMSWindowsScreen::onPreDispatchPrimary(HWND,
case SYNERGY_MSG_POST_WARP:
LOG((CLOG_WARN "unmatched post warp"));
return true;
case WM_HOTKEY:
// we discard these messages. we'll catch the hot key in the
// regular key event handling, where we can detect both key
// press and release. we only register the hot key so no other
// app will act on the key combination.
break;
}
return false;
@@ -827,8 +966,6 @@ CMSWindowsScreen::onEvent(HWND, UINT msg,
break;
case WM_DRAWCLIPBOARD:
LOG((CLOG_DEBUG "clipboard was taken"));
// first pass on the message
if (m_nextClipboardWindow != NULL) {
SendMessage(m_nextClipboardWindow, msg, wParam, lParam);
@@ -843,7 +980,6 @@ CMSWindowsScreen::onEvent(HWND, UINT msg,
LOG((CLOG_DEBUG "clipboard chain: new next: 0x%08x", m_nextClipboardWindow));
}
else if (m_nextClipboardWindow != NULL) {
LOG((CLOG_DEBUG "clipboard chain: forward: %d 0x%08x 0x%08x", msg, wParam, lParam));
SendMessage(m_nextClipboardWindow, msg, wParam, lParam);
}
return true;
@@ -856,15 +992,15 @@ CMSWindowsScreen::onEvent(HWND, UINT msg,
case PBT_APMRESUMEAUTOMATIC:
case PBT_APMRESUMECRITICAL:
case PBT_APMRESUMESUSPEND:
if (m_resume != NULL) {
m_resume->run();
}
EVENTQUEUE->addEvent(CEvent(IScreen::getResumeEvent(),
getEventTarget(), NULL,
CEvent::kDeliverImmediately));
break;
case PBT_APMSUSPEND:
if (m_suspend != NULL) {
m_suspend->run();
}
EVENTQUEUE->addEvent(CEvent(IScreen::getSuspendEvent(),
getEventTarget(), NULL,
CEvent::kDeliverImmediately));
break;
}
*result = TRUE;
@@ -894,62 +1030,70 @@ CMSWindowsScreen::onMark(UInt32 mark)
bool
CMSWindowsScreen::onKey(WPARAM wParam, LPARAM lParam)
{
LOG((CLOG_DEBUG1 "event: Key char=%d, vk=0x%02x, lParam=0x%08x", (wParam & 0xff00u) >> 8, wParam & 0xffu, lParam));
static const KeyModifierMask s_ctrlAlt =
KeyModifierControl | KeyModifierAlt;
// fix up key state
fixKeys();
LOG((CLOG_DEBUG1 "event: Key char=%d, vk=0x%02x, nagr=%d, lParam=0x%08x", (wParam & 0xff00u) >> 8, wParam & 0xffu, (wParam & 0x10000u) ? 1 : 0, lParam));
// get key info
KeyButton button = (KeyButton)((lParam & 0x01ff0000) >> 16);
bool down = ((lParam & 0xc0000000u) == 0x00000000u);
bool up = ((lParam & 0x80000000u) == 0x80000000u);
bool wasDown = isKeyDown(button);
// get event info
KeyButton button = (KeyButton)((lParam & 0x01ff0000) >> 16);
bool down = ((lParam & 0x80000000u) == 0x00000000u);
bool wasDown = isKeyDown(button);
KeyModifierMask oldState = pollActiveModifiers();
// the windows keys are a royal pain on the windows 95 family.
// the system eats the key up events if and only if the windows
// key wasn't combined with another key, i.e. it was tapped.
// fixKeys() and scheduleFixKeys() are all about synthesizing
// the missing key up. but even windows itself gets a little
// confused and sets bit 30 in lParam if you tap the windows
// key twice. that bit means the key was previously down and
// that makes some sense since the up event was missing.
// anyway, on the windows 95 family we forget about windows
// key repeats and treat anything that's not a key down as a
// key up.
if (m_is95Family &&
((wParam & 0xffu) == VK_LWIN || (wParam & 0xffu) == VK_RWIN)) {
down = !up;
// check for autorepeat
if (m_keyState->testAutoRepeat(down, (lParam & 0x40000000u) == 1, button)) {
lParam |= 0x40000000u;
}
// update key state. ignore key repeats.
if (down) {
m_keyState->setKeyDown(button, true);
}
else if (up) {
m_keyState->setKeyDown(button, false);
// if the button is zero then guess what the button should be.
// these are badly synthesized key events and logitech software
// that maps mouse buttons to keys is known to do this.
// alternatively, we could just throw these events out.
if (button == 0) {
button = m_keyState->virtualKeyToButton(wParam & 0xffu);
if (button == 0) {
return true;
}
wasDown = isKeyDown(button);
}
// schedule a timer if we need to fix keys later
scheduleFixKeys();
// record keyboard state
m_keyState->onKey(button, down, oldState);
// special case: we detect ctrl+alt+del being pressed on some
// systems but we don't detect the release of those keys. so
// if ctrl, alt, and del are down then mark them up.
KeyModifierMask mask = getActiveModifiers();
bool ctrlAlt = ((mask & (KeyModifierControl | KeyModifierAlt)) ==
(KeyModifierControl | KeyModifierAlt));
if (down && ctrlAlt &&
isKeyDown(m_keyState->virtualKeyToButton(VK_DELETE))) {
m_keyState->setKeyDown(
m_keyState->virtualKeyToButton(VK_LCONTROL), false);
m_keyState->setKeyDown(
m_keyState->virtualKeyToButton(VK_RCONTROL), false);
m_keyState->setKeyDown(
m_keyState->virtualKeyToButton(VK_LMENU), false);
m_keyState->setKeyDown(
m_keyState->virtualKeyToButton(VK_RMENU), false);
m_keyState->setKeyDown(
m_keyState->virtualKeyToButton(VK_DELETE), false);
// windows doesn't tell us the modifier key state on mouse or key
// events so we have to figure it out. most apps would use
// GetKeyState() or even GetAsyncKeyState() for that but we can't
// because our hook doesn't pass on key events for several modifiers.
// it can't otherwise the system would interpret them normally on
// the primary screen even when on a secondary screen. so tapping
// alt would activate menus and tapping the windows key would open
// the start menu. if you don't pass those events on in the hook
// then GetKeyState() understandably doesn't reflect the effect of
// the event. curiously, neither does GetAsyncKeyState(), which is
// surprising.
//
// so anyway, we have to track the modifier state ourselves for
// at least those modifiers we don't pass on. pollActiveModifiers()
// does that but we have to update the keyboard state before calling
// pollActiveModifiers() to get the right answer. but the only way
// to set the modifier state or to set the up/down state of a key
// is via onKey(). so we have to call onKey() twice.
KeyModifierMask state = pollActiveModifiers();
m_keyState->onKey(button, down, state);
// check for hot keys
if (oldState != state) {
// modifier key was pressed/released
if (onHotKey(0, lParam)) {
return true;
}
}
else {
// non-modifier was pressed/released
if (onHotKey(wParam, lParam)) {
return true;
}
}
// ignore message if posted prior to last mark change
@@ -957,20 +1101,23 @@ CMSWindowsScreen::onKey(WPARAM wParam, LPARAM lParam)
// check for ctrl+alt+del. we do not want to pass that to the
// client. the user can use ctrl+alt+pause to emulate it.
UINT virtKey = (wParam & 0xffu);
if (virtKey == VK_DELETE && ctrlAlt) {
if (virtKey == VK_DELETE && (state & s_ctrlAlt) == s_ctrlAlt) {
LOG((CLOG_DEBUG "discard ctrl+alt+del"));
return true;
}
// check for ctrl+alt+del emulation
if ((virtKey == VK_PAUSE || virtKey == VK_CANCEL) && ctrlAlt) {
if ((virtKey == VK_PAUSE || virtKey == VK_CANCEL) &&
(state & s_ctrlAlt) == s_ctrlAlt) {
LOG((CLOG_DEBUG "emulate ctrl+alt+del"));
// switch wParam and lParam to be as if VK_DELETE was
// pressed or released
wParam = VK_DELETE;
// pressed or released. when mapping the key we require that
// we not use AltGr (the 0x10000 flag in wParam) and we not
// use the keypad delete key (the 0x01000000 flag in lParam).
wParam = VK_DELETE | 0x00010000u;
lParam &= 0xfe000000;
lParam |= m_keyState->virtualKeyToButton(wParam) << 16;
lParam |= 0x00000001;
lParam |= m_keyState->virtualKeyToButton(wParam & 0xffu) << 16;
lParam |= 0x01000001;
}
// process key
@@ -978,28 +1125,28 @@ CMSWindowsScreen::onKey(WPARAM wParam, LPARAM lParam)
KeyID key = m_keyState->mapKeyFromEvent(wParam, lParam, &mask);
button = static_cast<KeyButton>((lParam & 0x01ff0000u) >> 16);
if (key != kKeyNone) {
// fix up key. if the key isn't down according to
// fix key up. if the key isn't down according to
// our table then we never got the key press event
// for it. if it's not a modifier key then we'll
// synthesize the press first. only do this on
// the windows 95 family, which eats certain special
// keys like alt+tab, ctrl+esc, etc.
if (m_is95Family && !wasDown && up) {
if (m_is95Family && !wasDown && !down) {
switch (virtKey) {
case VK_SHIFT:
case VK_LSHIFT:
case VK_RSHIFT:
case VK_SHIFT:
case VK_CONTROL:
case VK_LCONTROL:
case VK_RCONTROL:
case VK_CONTROL:
case VK_MENU:
case VK_LMENU:
case VK_RMENU:
case VK_MENU:
case VK_LWIN:
case VK_RWIN:
case VK_CAPITAL:
case VK_NUMLOCK:
case VK_SCROLL:
case VK_LWIN:
case VK_RWIN:
break;
default:
@@ -1012,17 +1159,64 @@ CMSWindowsScreen::onKey(WPARAM wParam, LPARAM lParam)
// do it
m_keyState->sendKeyEvent(getEventTarget(),
((lParam & 0x80000000u) == 0),
((lParam & 0x40000000u) == 1),
((lParam & 0x40000000u) != 0),
key, mask, (SInt32)(lParam & 0xffff), button);
}
else {
LOG((CLOG_DEBUG2 "event: cannot map key"));
LOG((CLOG_DEBUG1 "cannot map key"));
}
}
return true;
}
bool
CMSWindowsScreen::onHotKey(WPARAM wParam, LPARAM lParam)
{
// get the key info
KeyModifierMask state = getActiveModifiers();
UINT virtKey = (wParam & 0xffu);
UINT modifiers = 0;
if ((state & KeyModifierShift) != 0) {
modifiers |= MOD_SHIFT;
}
if ((state & KeyModifierControl) != 0) {
modifiers |= MOD_CONTROL;
}
if ((state & KeyModifierAlt) != 0) {
modifiers |= MOD_ALT;
}
if ((state & KeyModifierSuper) != 0) {
modifiers |= MOD_WIN;
}
// find the hot key id
HotKeyToIDMap::const_iterator i =
m_hotKeyToIDMap.find(CHotKeyItem(virtKey, modifiers));
if (i == m_hotKeyToIDMap.end()) {
return false;
}
// find what kind of event
CEvent::Type type;
if ((lParam & 0x80000000u) == 0u) {
if ((lParam & 0x40000000u) != 0u) {
// ignore key repeats but it counts as a hot key
return true;
}
type = getHotKeyDownEvent();
}
else {
type = getHotKeyUpEvent();
}
// generate event
EVENTQUEUE->addEvent(CEvent(type, getEventTarget(),
CHotKeyInfo::alloc(i->second)));
return true;
}
bool
CMSWindowsScreen::onMouseButton(WPARAM wParam, LPARAM lParam)
{
@@ -1042,16 +1236,19 @@ CMSWindowsScreen::onMouseButton(WPARAM wParam, LPARAM lParam)
// ignore message if posted prior to last mark change
if (!ignore()) {
KeyModifierMask mask = m_keyState->getActiveModifiers();
if (pressed) {
LOG((CLOG_DEBUG1 "event: button press button=%d", button));
if (button != kButtonNone) {
sendEvent(getButtonDownEvent(), CButtonInfo::alloc(button));
sendEvent(getButtonDownEvent(),
CButtonInfo::alloc(button, mask));
}
}
else {
LOG((CLOG_DEBUG1 "event: button release button=%d", button));
if (button != kButtonNone) {
sendEvent(getButtonUpEvent(), CButtonInfo::alloc(button));
sendEvent(getButtonUpEvent(),
CButtonInfo::alloc(button, mask));
}
}
}
@@ -1109,12 +1306,12 @@ CMSWindowsScreen::onMouseMove(SInt32 mx, SInt32 my)
}
bool
CMSWindowsScreen::onMouseWheel(SInt32 delta)
CMSWindowsScreen::onMouseWheel(SInt32 xDelta, SInt32 yDelta)
{
// ignore message if posted prior to last mark change
if (!ignore()) {
LOG((CLOG_DEBUG1 "event: button wheel delta=%d", delta));
sendEvent(getWheelEvent(), CWheelInfo::alloc(delta));
LOG((CLOG_DEBUG1 "event: button wheel delta=%+d,%+d", xDelta, yDelta));
sendEvent(getWheelEvent(), CWheelInfo::alloc(xDelta, yDelta));
}
return true;
}
@@ -1197,7 +1394,6 @@ CMSWindowsScreen::onClipboardChange()
// now notify client that somebody changed the clipboard (unless
// we're the owner).
if (!CMSWindowsClipboard::isOwnedBySynergy()) {
LOG((CLOG_DEBUG "clipboard changed: foreign owned"));
if (m_ownClipboard) {
LOG((CLOG_DEBUG "clipboard changed: lost ownership"));
m_ownClipboard = false;
@@ -1205,7 +1401,7 @@ CMSWindowsScreen::onClipboardChange()
sendClipboardEvent(getClipboardGrabbedEvent(), kClipboardSelection);
}
}
else {
else if (!m_ownClipboard) {
LOG((CLOG_DEBUG "clipboard changed: synergy owned"));
m_ownClipboard = true;
}
@@ -1282,6 +1478,34 @@ CMSWindowsScreen::updateScreenShape()
m_desks->setShape(m_x, m_y, m_w, m_h, m_xCenter, m_yCenter, m_multimon);
}
void
CMSWindowsScreen::handleFixes(const CEvent&, void*)
{
// fix clipboard chain
fixClipboardViewer();
// update keys if keyboard layouts have changed
if (m_keyState->didGroupsChange()) {
updateKeys();
}
}
void
CMSWindowsScreen::fixClipboardViewer()
{
// XXX -- disable this code for now. somehow it can cause an infinite
// recursion in the WM_DRAWCLIPBOARD handler. either we're sending
// the message to our own window or some window farther down the chain
// forwards the message to our window or a window farther up the chain.
// i'm not sure how that could happen. the m_nextClipboardWindow = NULL
// was not in the code that infinite loops and may fix the bug but i
// doubt it.
return;
ChangeClipboardChain(m_window, m_nextClipboardWindow);
m_nextClipboardWindow = NULL;
m_nextClipboardWindow = SetClipboardViewer(m_window);
}
void
CMSWindowsScreen::enableSpecialKeys(bool enable) const
{
@@ -1387,63 +1611,37 @@ CMSWindowsScreen::mapPressFromEvent(WPARAM msg, LPARAM) const
}
}
void
CMSWindowsScreen::fixKeys()
{
// fake key releases for the windows keys if we think they're
// down but they're really up. we have to do this because if the
// user presses and releases a windows key without pressing any
// other key while it's down then the system will eat the key
// release. if we don't detect that and synthesize the release
// then the client won't take the usual windows key release action
// (which on windows is to show the start menu).
//
// only check on the windows 95 family since the NT family reports
// the key releases as usual.
if (m_is95Family) {
m_keyState->fixKey(getEventTarget(), VK_LWIN);
m_keyState->fixKey(getEventTarget(), VK_RWIN);
// check if we need the fix timer anymore
scheduleFixKeys();
}
}
void
CMSWindowsScreen::scheduleFixKeys()
{
if (m_is95Family) {
// see if any keys that need fixing are down
bool fix =
(m_keyState->isKeyDown(m_keyState->virtualKeyToButton(VK_LWIN)) ||
m_keyState->isKeyDown(m_keyState->virtualKeyToButton(VK_RWIN)));
// start or stop fix timer
if (fix && m_fixTimer == NULL) {
m_fixTimer = EVENTQUEUE->newTimer(0.1, NULL);
EVENTQUEUE->adoptHandler(CEvent::kTimer, m_fixTimer,
new TMethodEventJob<CMSWindowsScreen>(
this, &CMSWindowsScreen::handleFixKeys));
}
else if (!fix && m_fixTimer != NULL) {
EVENTQUEUE->removeHandler(CEvent::kTimer, m_fixTimer);
EVENTQUEUE->deleteTimer(m_fixTimer);
m_fixTimer = NULL;
}
}
}
void
CMSWindowsScreen::handleFixKeys(const CEvent&, void*)
{
fixKeys();
}
void
CMSWindowsScreen::updateKeysCB(void*)
{
m_keyState->updateKeys();
updateButtons();
// record which keys we think are down
bool down[IKeyState::kNumButtons];
bool sendFixes = (isPrimary() && !m_isOnScreen);
if (sendFixes) {
for (KeyButton i = 0; i < IKeyState::kNumButtons; ++i) {
down[i] = m_keyState->isKeyDown(i);
}
}
// update layouts if necessary
if (m_keyState->didGroupsChange()) {
CPlatformScreen::updateKeyMap();
}
// now update the keyboard state
CPlatformScreen::updateKeyState();
// now see which keys we thought were down but now think are up.
// send key releases for these keys to the active client.
if (sendFixes) {
KeyModifierMask mask = pollActiveModifiers();
for (KeyButton i = 0; i < IKeyState::kNumButtons; ++i) {
if (down[i] && !m_keyState->isKeyDown(i)) {
m_keyState->sendKeyEvent(getEventTarget(),
false, false, kKeyNone, mask, 1, i);
}
}
}
}
void
@@ -1512,3 +1710,28 @@ CMSWindowsScreen::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
return result;
}
//
// CMSWindowsScreen::CHotKeyItem
//
CMSWindowsScreen::CHotKeyItem::CHotKeyItem(UINT keycode, UINT mask) :
m_keycode(keycode),
m_mask(mask)
{
// do nothing
}
UINT
CMSWindowsScreen::CHotKeyItem::getVirtualKey() const
{
return m_keycode;
}
bool
CMSWindowsScreen::CHotKeyItem::operator<(const CHotKeyItem& x) const
{
return (m_keycode < x.m_keycode ||
(m_keycode == x.m_keycode && m_mask < x.m_mask));
}

View File

@@ -28,12 +28,11 @@ class CMSWindowsDesks;
class CMSWindowsKeyState;
class CMSWindowsScreenSaver;
class CThread;
class IJob;
//! Implementation of IPlatformScreen for Microsoft Windows
class CMSWindowsScreen : public CPlatformScreen {
public:
CMSWindowsScreen(bool isPrimary, IJob* suspend, IJob* resume);
CMSWindowsScreen(bool isPrimary);
virtual ~CMSWindowsScreen();
//! @name manipulators
@@ -68,6 +67,11 @@ public:
// IPrimaryScreen overrides
virtual void reconfigure(UInt32 activeSides);
virtual void warpCursor(SInt32 x, SInt32 y);
virtual UInt32 registerHotKey(KeyID key,
KeyModifierMask mask);
virtual void unregisterHotKey(UInt32 id);
virtual void fakeInputBegin();
virtual void fakeInputEnd();
virtual SInt32 getJumpZoneSize() const;
virtual bool isAnyMouseButtonDown() const;
virtual void getCursorCenter(SInt32& x, SInt32& y) const;
@@ -76,7 +80,7 @@ public:
virtual void fakeMouseButton(ButtonID id, bool press) const;
virtual void fakeMouseMove(SInt32 x, SInt32 y) const;
virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const;
virtual void fakeMouseWheel(SInt32 delta) const;
virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const;
// IKeyState overrides
virtual void updateKeys();
@@ -85,7 +89,7 @@ public:
virtual void fakeKeyRepeat(KeyID id, KeyModifierMask mask,
SInt32 count, KeyButton button);
virtual void fakeKeyUp(KeyButton button);
virtual void fakeToggle(KeyModifierMask modifier);
virtual void fakeAllKeysUp();
// IPlatformScreen overrides
virtual void enable();
@@ -139,9 +143,10 @@ private:
// message handlers
bool onMark(UInt32 mark);
bool onKey(WPARAM, LPARAM);
bool onHotKey(WPARAM, LPARAM);
bool onMouseButton(WPARAM, LPARAM);
bool onMouseMove(SInt32 x, SInt32 y);
bool onMouseWheel(SInt32 delta);
bool onMouseWheel(SInt32 xDelta, SInt32 yDelta);
bool onScreensaver(bool activated);
bool onDisplayChange();
bool onClipboardChange();
@@ -158,6 +163,12 @@ private:
// update screen size cache
void updateScreenShape();
// fix timer callback
void handleFixes(const CEvent&, void*);
// fix the clipboard viewer chain
void fixClipboardViewer();
// enable/disable special key combinations so we can catch/pass them
void enableSpecialKeys(bool) const;
@@ -167,16 +178,6 @@ private:
// map a button event to a press (true) or release (false)
bool mapPressFromEvent(WPARAM msg, LPARAM button) const;
// fix the key state, synthesizing fake key releases for keys
// that aren't down anymore.
void fixKeys();
// (un)schedule a later call to fixKeys
void scheduleFixKeys();
// event handler to fix the key state
void handleFixKeys(const CEvent&, void*);
// job to update the key state
void updateKeysCB(void*);
@@ -194,6 +195,22 @@ private:
static LRESULT CALLBACK wndProc(HWND, UINT, WPARAM, LPARAM);
private:
struct CHotKeyItem {
public:
CHotKeyItem(UINT vk, UINT modifiers);
UINT getVirtualKey() const;
bool operator<(const CHotKeyItem&) const;
private:
UINT m_keycode;
UINT m_mask;
};
typedef std::map<UInt32, CHotKeyItem> HotKeyMap;
typedef std::vector<UInt32> HotKeyIDList;
typedef std::map<CHotKeyItem, UInt32> HotKeyToIDMap;
static HINSTANCE s_instance;
// true if screen is being used as a primary screen, false otherwise
@@ -229,12 +246,12 @@ private:
// the main loop's thread id
DWORD m_threadID;
// timer for periodically checking stuff that requires polling
CEventQueueTimer* m_fixTimer;
// the keyboard layout to use when off primary screen
HKL m_keyLayout;
// the timer used to check for fixing key state
CEventQueueTimer* m_fixTimer;
// screen saver stuff
CMSWindowsScreenSaver* m_screensaver;
bool m_screensaverNotify;
@@ -260,13 +277,14 @@ private:
// keyboard stuff
CMSWindowsKeyState* m_keyState;
// hot key stuff
HotKeyMap m_hotKeys;
HotKeyIDList m_oldHotKeyIDs;
HotKeyToIDMap m_hotKeyToIDMap;
// map of button state
bool m_buttons[1 + kButtonExtra0 + 1];
// suspend/resume callbacks
IJob* m_suspend;
IJob* m_resume;
// the system shows the mouse cursor when an internal display count
// is >= 0. this count is maintained per application but there's
// apparently a system wide count added to the application's count.

View File

@@ -107,7 +107,7 @@ CMSWindowsScreenSaver::checkStarted(UINT msg, WPARAM wParam, LPARAM lParam)
HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, processID);
if (process == NULL) {
// didn't start
LOG((CLOG_DEBUG "can't open screen saver process"));
LOG((CLOG_DEBUG2 "can't open screen saver process"));
return false;
}
@@ -123,7 +123,7 @@ CMSWindowsScreenSaver::checkStarted(UINT msg, WPARAM wParam, LPARAM lParam)
// we first check that the screen saver is indeed active
// before watching for it to stop.
if (!isActive()) {
LOG((CLOG_DEBUG "can't open screen saver desktop"));
LOG((CLOG_DEBUG2 "can't open screen saver desktop"));
return false;
}
@@ -441,7 +441,7 @@ void
CMSWindowsScreenSaver::setSecure(bool secure, bool saveSecureAsInt)
{
HKEY hkey =
CArchMiscWindows::openKey(HKEY_CURRENT_USER, g_pathScreenSaverIsSecure);
CArchMiscWindows::addKey(HKEY_CURRENT_USER, g_pathScreenSaverIsSecure);
if (hkey == NULL) {
return;
}

View File

@@ -42,15 +42,18 @@ COSXClipboard::empty()
assert(m_scrap != NULL);
OSStatus err = ClearScrap(&m_scrap);
// XXX -- check err?
if (err != noErr) {
LOG((CLOG_DEBUG "failed to grab clipboard"));
return false;
}
// we own the clipboard
err = PutScrapFlavor(
m_scrap,
getOwnershipFlavor(),
kScrapFlavorMaskNone,
0,
0);
0);
if (err != noErr) {
LOG((CLOG_DEBUG "failed to grab clipboard"));
return false;

File diff suppressed because it is too large Load Diff

View File

@@ -32,6 +32,28 @@ public:
COSXKeyState();
virtual ~COSXKeyState();
//! @name modifiers
//@{
//! Handle modifier key change
/*!
Determines which modifier keys have changed and updates the modifier
state and sends key events as appropriate.
*/
void handleModifierKeys(void* target,
KeyModifierMask oldMask, KeyModifierMask newMask);
//@}
//! @name accessors
//@{
//! Convert OS X modifier mask to synergy mask
/*!
Returns the synergy modifier mask corresponding to the OS X modifier
mask in \p mask.
*/
KeyModifierMask mapModifiersFromOSX(UInt32 mask) const;
//! Map key event to keys
/*!
Converts a key event into a sequence of KeyIDs and the shadow modifier
@@ -43,80 +65,64 @@ public:
KeyButton mapKeyFromEvent(CKeyIDs& ids,
KeyModifierMask* maskOut, EventRef event) const;
//! Handle modifier key change
//! Map key and mask to native values
/*!
Determines which modifier keys have changed and updates the modifier
state and sends key events as appropriate.
Calculates mac virtual key and mask for a key \p key and modifiers
\p mask. Returns \c true if the key can be mapped, \c false otherwise.
*/
void handleModifierKeys(void* target,
KeyModifierMask oldMask, KeyModifierMask newMask);
bool mapSynergyHotKeyToMac(KeyID key, KeyModifierMask mask,
UInt32& macVirtualKey,
UInt32& macModifierMask) const;
//@}
// IKeyState overrides
virtual void setHalfDuplexMask(KeyModifierMask);
virtual bool fakeCtrlAltDel();
virtual const char* getKeyName(KeyButton) const;
virtual void sendKeyEvent(void* target,
bool press, bool isAutoRepeat,
KeyID key, KeyModifierMask mask,
SInt32 count, KeyButton button);
virtual KeyModifierMask
pollActiveModifiers() const;
virtual SInt32 pollActiveGroup() const;
virtual void pollPressedKeys(KeyButtonSet& pressedKeys) const;
protected:
// IKeyState overrides
virtual void doUpdateKeys();
virtual void doFakeKeyEvent(KeyButton button,
bool press, bool isAutoRepeat);
virtual KeyButton mapKey(Keystrokes& keys, KeyID id,
KeyModifierMask desiredMask,
bool isAutoRepeat) const;
// CKeyState overrides
virtual void getKeyMap(CKeyMap& keyMap);
virtual void fakeKey(const Keystroke& keystroke);
private:
struct CKeyEventInfo {
public:
KeyButton m_button;
KeyModifierMask m_requiredMask;
KeyModifierMask m_requiredState;
};
typedef std::vector<CKeyEventInfo> CKeySequence;
typedef std::map<KeyID, CKeySequence> CKeyIDMap;
typedef std::map<UInt32, KeyID> CVirtualKeyMap;
typedef std::map<UInt16, std::pair<SInt32, KeyModifierMask> > CDeadKeyMap;
class CKeyResource;
typedef std::vector<KeyboardLayoutRef> GroupList;
KeyButton addKeystrokes(Keystrokes& keys,
KeyButton keyButton,
KeyModifierMask desiredMask,
KeyModifierMask requiredMask,
bool isAutoRepeat) const;
bool adjustModifiers(Keystrokes& keys,
Keystrokes& undo,
KeyModifierMask desiredMask,
KeyModifierMask requiredMask) const;
void addKeyButton(KeyButtons& keys, KeyID id) const;
void handleModifierKey(void* target, KeyID id, bool down);
// Add hard coded special keys to a CKeyMap.
void getKeyMapForSpecialKeys(
CKeyMap& keyMap, SInt32 group) const;
// Check if the keyboard layout has changed and call doUpdateKeys
// Convert keyboard resource to a key map
bool getKeyMap(CKeyMap& keyMap,
SInt32 group, const CKeyResource& r) const;
// Get the available keyboard groups
bool getGroups(GroupList&) const;
// Change active keyboard group to group
void setGroup(SInt32 group);
// Check if the keyboard layout has changed and update keyboard state
// if so.
void checkKeyboardLayout();
// Switch to a new keyboard layout.
void setKeyboardLayout(SInt16 keyboardLayoutID);
// Send an event for the given modifier key
void handleModifierKey(void* target,
UInt32 virtualKey, KeyID id,
bool down, KeyModifierMask newMask);
// Insert KeyID to key sequences for non-printing characters, like
// delete, home, up arrow, etc. and the virtual key to KeyID mapping.
void fillSpecialKeys(CKeyIDMap& keyMap,
CVirtualKeyMap& virtualKeyMap) const;
// Convert the KCHR resource to a KeyID to key sequence map. the
// map maps each KeyID to the sequence of keys (with modifiers)
// that would have to be synthesized to generate the KeyID character.
// Returns false iff no KCHR resource was found.
bool fillKCHRKeysMap(CKeyIDMap& keyMap) const;
// Convert the uchr resource to a KeyID to key sequence map. the
// map maps each KeyID to the sequence of keys (with modifiers)
// that would have to be synthesized to generate the KeyID character.
// Returns false iff no uchr resource was found or it couldn't be
// mapped.
bool filluchrKeysMap(CKeyIDMap& keyMap) const;
// Checks if any in \p ids is a glyph key and if \p isCommand is false.
// If so it adds the AltGr modifier to \p mask. This allows OS X
// servers to use the option key both as AltGr and as a modifier. If
// option is acting as AltGr (i.e. it generates a glyph and there are
// no command modifiers active) then we don't send the super modifier
// to clients because they'd try to match it as a command modifier.
void adjustAltGrModifier(const CKeyIDs& ids,
KeyModifierMask* mask, bool isCommand) const;
// Maps an OS X virtual key id to a KeyButton. This simply remaps
// the ids so we don't use KeyButton 0.
@@ -126,28 +132,89 @@ private:
// mapVirtualKeyToKeyButton.
static UInt32 mapKeyButtonToVirtualKey(KeyButton keyButton);
// Convert a character in the current script to the equivalent KeyID.
static KeyID charToKeyID(UInt8);
// Convert a unicode character to the equivalent KeyID.
static KeyID unicharToKeyID(UniChar);
// Choose the modifier mask with the fewest modifiers for character
// mapping table i. The tableSelectors table has numEntries. If
// no mapping is found for i, try mapping defaultIndex.
static KeyModifierMask
maskForTable(UInt8 i, UInt8* tableSelectors,
UInt32 numEntries, UInt8 defaultIndex);
// Save characters built from dead key sequences.
static void mapDeadKeySequence(CKeyIDMap& keyMap,
CKeySequence& sequence,
UInt16 state, const UInt8* base,
const UCKeyStateRecordsIndex* sri,
const UCKeyStateTerminators* st,
CDeadKeyMap& dkMap);
private:
class CKeyResource : public IInterface {
public:
virtual bool isValid() const = 0;
virtual UInt32 getNumModifierCombinations() const = 0;
virtual UInt32 getNumTables() const = 0;
virtual UInt32 getNumButtons() const = 0;
virtual UInt32 getTableForModifier(UInt32 mask) const = 0;
virtual KeyID getKey(UInt32 table, UInt32 button) const = 0;
// Convert a character in the current script to the equivalent KeyID
static KeyID getKeyID(UInt8);
// Convert a unicode character to the equivalent KeyID.
static KeyID unicharToKeyID(UniChar);
};
class CKCHRKeyResource : public CKeyResource {
public:
CKCHRKeyResource(const void*);
// CKeyResource overrides
virtual bool isValid() const;
virtual UInt32 getNumModifierCombinations() const;
virtual UInt32 getNumTables() const;
virtual UInt32 getNumButtons() const;
virtual UInt32 getTableForModifier(UInt32 mask) const;
virtual KeyID getKey(UInt32 table, UInt32 button) const;
private:
struct KCHRResource {
public:
SInt16 m_version;
UInt8 m_tableSelectionIndex[256];
SInt16 m_numTables;
UInt8 m_characterTables[1][128];
};
struct CKCHRDeadKeyRecord {
public:
UInt8 m_tableIndex;
UInt8 m_virtualKey;
SInt16 m_numCompletions;
UInt8 m_completion[1][2];
};
struct CKCHRDeadKeys {
public:
SInt16 m_numRecords;
CKCHRDeadKeyRecord m_records[1];
};
const KCHRResource* m_resource;
};
class CUCHRKeyResource : public CKeyResource {
public:
CUCHRKeyResource(const void*, UInt32 keyboardType);
// CKeyResource overrides
virtual bool isValid() const;
virtual UInt32 getNumModifierCombinations() const;
virtual UInt32 getNumTables() const;
virtual UInt32 getNumButtons() const;
virtual UInt32 getTableForModifier(UInt32 mask) const;
virtual KeyID getKey(UInt32 table, UInt32 button) const;
private:
typedef std::vector<KeyID> KeySequence;
bool getDeadKey(KeySequence& keys, UInt16 index) const;
bool getKeyRecord(KeySequence& keys,
UInt16 index, UInt16& state) const;
bool addSequence(KeySequence& keys, UCKeyCharSeq c) const;
private:
const UCKeyboardLayout* m_resource;
const UCKeyModifiersToTableNum* m_m;
const UCKeyToCharTableIndex* m_cti;
const UCKeySequenceDataIndex* m_sdi;
const UCKeyStateRecordsIndex* m_sri;
const UCKeyStateTerminators* m_st;
UInt16 m_spaceOutput;
};
// OS X uses a physical key if 0 for the 'A' key. synergy reserves
// KeyButton 0 so we offset all OS X physical key ids by this much
// when used as a KeyButton and by minus this much to map a KeyButton
@@ -156,25 +223,13 @@ private:
KeyButtonOffset = 1
};
// KCHR resource header
struct CKCHRResource {
public:
SInt16 m_version;
UInt8 m_tableSelectionIndex[256];
SInt16 m_numTables;
UInt8 m_characterTables[1][128];
};
typedef std::map<KeyboardLayoutRef, SInt32> GroupMap;
typedef std::map<UInt32, KeyID> CVirtualKeyMap;
SInt16 m_keyboardLayoutID;
UInt32 m_keyboardType;
mutable UInt32 m_deadKeyState;
Handle m_KCHRHandle;
Handle m_uchrHandle;
CKCHRResource* m_KCHRResource;
UCKeyboardLayout* m_uchrResource;
CKeyIDMap m_keyMap;
CVirtualKeyMap m_virtualKeyMap;
bool m_uchrFound;
mutable UInt32 m_deadKeyState;
GroupList m_groups;
GroupMap m_groupMap;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -16,9 +16,21 @@
#define COSXSCREEN_H
#include "CPlatformScreen.h"
#include "stdmap.h"
#include "stdvector.h"
#include <Carbon/Carbon.h>
#include <mach/mach_port.h>
#include <mach/mach_interface.h>
#include <mach/mach_init.h>
#include <IOKit/pwr_mgt/IOPMLib.h>
#include <IOKit/IOMessage.h>
template <class T>
class CCondVar;
class CEventQueueTimer;
class CMutex;
class CThread;
class COSXKeyState;
class COSXScreenSaver;
@@ -38,6 +50,10 @@ public:
// IPrimaryScreen overrides
virtual void reconfigure(UInt32 activeSides);
virtual void warpCursor(SInt32 x, SInt32 y);
virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask);
virtual void unregisterHotKey(UInt32 id);
virtual void fakeInputBegin();
virtual void fakeInputEnd();
virtual SInt32 getJumpZoneSize() const;
virtual bool isAnyMouseButtonDown() const;
virtual void getCursorCenter(SInt32& x, SInt32& y) const;
@@ -46,7 +62,7 @@ public:
virtual void fakeMouseButton(ButtonID id, bool press) const;
virtual void fakeMouseMove(SInt32 x, SInt32 y) const;
virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const;
virtual void fakeMouseWheel(SInt32 delta) const;
virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const;
// IPlatformScreen overrides
virtual void enable();
@@ -71,7 +87,7 @@ protected:
private:
void updateScreenShape();
void postMouseEvent(const CGPoint &) const;
void postMouseEvent(CGPoint&) const;
// convenience function to send events
void sendEvent(CEvent::Type type, void* = NULL) const;
@@ -82,25 +98,83 @@ private:
// mouse button handler. pressed is true if this is a mousedown
// event, false if it is a mouseup event. macButton is the index
// of the button pressed using the mac button mapping.
bool onMouseButton(bool pressed, UInt16 macButton) const;
bool onMouseWheel(SInt32 delta) const;
bool onMouseButton(bool pressed, UInt16 macButton);
bool onMouseWheel(SInt32 xDelta, SInt32 yDelta) const;
bool onDisplayChange();
bool onKey(EventRef event) const;
bool onKey(EventRef event);
bool onHotKey(EventRef event) const;
// map mac mouse button to synergy buttons
ButtonID mapMacButtonToSynergy(UInt16) const;
// map mac modifier mask to synergy modifier mask
KeyModifierMask mapMacModifiersToSynergy(EventRef event) const;
/// Resolution switch callback
// map mac scroll wheel value to a synergy scroll wheel value
SInt32 mapScrollWheelToSynergy(SInt32) const;
// map synergy scroll wheel value to a mac scroll wheel value
SInt32 mapScrollWheelFromSynergy(SInt32) const;
// get the current scroll wheel speed
double getScrollSpeed() const;
// get the current scroll wheel speed
double getScrollSpeedFactor() const;
// enable/disable drag handling for buttons 3 and up
void enableDragTimer(bool enable);
// drag timer handler
void handleDrag(const CEvent&, void*);
// clipboard check timer handler
void handleClipboardCheck(const CEvent&, void*);
// Resolution switch callback
static pascal void displayManagerCallback(void* inUserData,
SInt16 inMessage, void* inNotifyData);
// fast user switch callback
static pascal OSStatus
userSwitchCallback(EventHandlerCallRef nextHandler,
EventRef theEvent, void* inUserData);
// sleep / wakeup support
void watchSystemPowerThread(void*);
static void testCanceled(CFRunLoopTimerRef timer, void*info);
static void powerChangeCallback(void* refcon, io_service_t service,
natural_t messageType, void* messageArgument);
void handlePowerChangeRequest(natural_t messageType,
void* messageArgument);
static CEvent::Type getConfirmSleepEvent();
void handleConfirmSleep(const CEvent& event, void*);
// global hotkey operating mode
static bool isGlobalHotKeyOperatingModeAvailable();
static void setGlobalHotKeysEnabled(bool enabled);
static bool getGlobalHotKeysEnabled();
private:
struct CHotKeyItem {
public:
CHotKeyItem(UInt32, UInt32);
CHotKeyItem(EventHotKeyRef, UInt32, UInt32);
EventHotKeyRef getRef() const;
bool operator<(const CHotKeyItem&) const;
private:
EventHotKeyRef m_ref;
UInt32 m_keycode;
UInt32 m_mask;
};
typedef std::map<UInt32, CHotKeyItem> HotKeyMap;
typedef std::vector<UInt32> HotKeyIDList;
typedef std::map<KeyModifierMask, UInt32> ModifierHotKeyMap;
typedef std::map<CHotKeyItem, UInt32> HotKeyToIDMap;
// true if screen is being used as a primary screen, false otherwise
bool m_isPrimary;
@@ -120,6 +194,9 @@ private:
mutable bool m_cursorPosValid;
mutable boolean_t m_buttons[5];
bool m_cursorHidden;
SInt32 m_dragNumButtonsDown;
Point m_dragLastPoint;
CEventQueueTimer* m_dragTimer;
// keyboard stuff
COSXKeyState* m_keyState;
@@ -133,17 +210,43 @@ private:
// clipboard stuff
bool m_ownClipboard;
CEventQueueTimer* m_clipboardTimer;
// window object that gets user input events when the server
// has focus.
WindowRef m_hiddenWindow;
// window object that gets user input events when the server
// does not have focus.
WindowRef m_userInputWindow;
// display manager stuff (to get screen resolution switches).
DMExtendedNotificationUPP m_displayManagerNotificationUPP;
ProcessSerialNumber m_PSN;
// fast user switching
EventHandlerRef m_switchEventHandlerRef;
// sleep / wakeup
CMutex* m_pmMutex;
CThread* m_pmWatchThread;
CCondVar<bool>* m_pmThreadReady;
CFRunLoopRef m_pmRunloop;
io_connect_t m_pmRootPort;
// hot key stuff
HotKeyMap m_hotKeys;
HotKeyIDList m_oldHotKeyIDs;
ModifierHotKeyMap m_modifierHotKeys;
UInt32 m_activeModifierHotKey;
KeyModifierMask m_activeModifierHotKeyMask;
HotKeyToIDMap m_hotKeyToIDMap;
// global hotkey operating mode
static bool s_testedForGHOM;
static bool s_hasGHOM;
// events
static CEvent::Type s_confirmSleepEvent;
};
#endif

View File

@@ -12,45 +12,164 @@
* GNU General Public License for more details.
*/
#include "COSXScreenSaver.h"
#include <Carbon/Carbon.h>
// FIXME -- implement this
#import "COSXScreenSaver.h"
#import "COSXScreenSaverUtil.h"
#import "CLog.h"
#import "IEventQueue.h"
#import "IPrimaryScreen.h"
#import <string.h>
//
// COSXScreenSaver
//
COSXScreenSaver::COSXScreenSaver()
COSXScreenSaver::COSXScreenSaver(void* eventTarget) :
m_eventTarget(eventTarget),
m_enabled(true)
{
m_autoReleasePool = screenSaverUtilCreatePool();
m_screenSaverController = screenSaverUtilCreateController();
// install launch/termination event handlers
EventTypeSpec launchEventTypes[2];
launchEventTypes[0].eventClass = kEventClassApplication;
launchEventTypes[0].eventKind = kEventAppLaunched;
launchEventTypes[1].eventClass = kEventClassApplication;
launchEventTypes[1].eventKind = kEventAppTerminated;
EventHandlerUPP launchTerminationEventHandler =
NewEventHandlerUPP(launchTerminationCallback);
InstallApplicationEventHandler(launchTerminationEventHandler, 2,
launchEventTypes, this,
&m_launchTerminationEventHandlerRef);
DisposeEventHandlerUPP(launchTerminationEventHandler);
m_screenSaverPSN.highLongOfPSN = 0;
m_screenSaverPSN.lowLongOfPSN = 0;
// test if screensaver is running and find process number
if (isActive()) {
ProcessInfoRec procInfo;
Str31 procName; // pascal string. first byte holds length.
memset(&procInfo, 0, sizeof(procInfo));
procInfo.processName = procName;
procInfo.processInfoLength = sizeof(ProcessInfoRec);
ProcessSerialNumber psn;
OSErr err = GetNextProcess(&psn);
while (err == 0) {
memset(procName, 0, sizeof(procName));
err = GetProcessInformation(&psn, &procInfo);
if (err != 0) {
break;
}
if (strcmp("ScreenSaverEngine", (const char*)&procName[1]) == 0) {
m_screenSaverPSN = psn;
break;
}
err = GetNextProcess(&psn);
}
}
}
COSXScreenSaver::~COSXScreenSaver()
{
RemoveEventHandler(m_launchTerminationEventHandlerRef);
// screenSaverUtilReleaseController(m_screenSaverController);
screenSaverUtilReleasePool(m_autoReleasePool);
}
void
COSXScreenSaver::enable()
{
m_enabled = true;
screenSaverUtilEnable(m_screenSaverController);
}
void
COSXScreenSaver::disable()
{
m_enabled = false;
screenSaverUtilDisable(m_screenSaverController);
}
void
COSXScreenSaver::activate()
{
screenSaverUtilActivate(m_screenSaverController);
}
void
COSXScreenSaver::deactivate()
{
screenSaverUtilDeactivate(m_screenSaverController, m_enabled);
}
bool
COSXScreenSaver::isActive() const
{
return false;
return (screenSaverUtilIsActive(m_screenSaverController) != 0);
}
void
COSXScreenSaver::processLaunched(ProcessSerialNumber psn)
{
CFStringRef processName;
OSStatus err = CopyProcessName(&psn, &processName);
if (err == 0 && CFEqual(CFSTR("ScreenSaverEngine"), processName)) {
m_screenSaverPSN = psn;
LOG((CLOG_DEBUG1 "ScreenSaverEngine launched. Enabled=%d", m_enabled));
if (m_enabled) {
EVENTQUEUE->addEvent(
CEvent(IPrimaryScreen::getScreensaverActivatedEvent(),
m_eventTarget));
}
}
}
void
COSXScreenSaver::processTerminated(ProcessSerialNumber psn)
{
if (m_screenSaverPSN.highLongOfPSN == psn.highLongOfPSN &&
m_screenSaverPSN.lowLongOfPSN == psn.lowLongOfPSN) {
LOG((CLOG_DEBUG1 "ScreenSaverEngine terminated. Enabled=%d", m_enabled));
if (m_enabled) {
EVENTQUEUE->addEvent(
CEvent(IPrimaryScreen::getScreensaverDeactivatedEvent(),
m_eventTarget));
}
m_screenSaverPSN.highLongOfPSN = 0;
m_screenSaverPSN.lowLongOfPSN = 0;
}
}
pascal OSStatus
COSXScreenSaver::launchTerminationCallback(
EventHandlerCallRef nextHandler,
EventRef theEvent, void* userData)
{
OSStatus result;
ProcessSerialNumber psn;
EventParamType actualType;
UInt32 actualSize;
result = GetEventParameter(theEvent, kEventParamProcessID,
typeProcessSerialNumber, &actualType,
sizeof(psn), &actualSize, &psn);
if ((result == noErr) &&
(actualSize > 0) &&
(actualType == typeProcessSerialNumber)) {
COSXScreenSaver* screenSaver = (COSXScreenSaver*)userData;
UInt32 eventKind = GetEventKind(theEvent);
if (eventKind == kEventAppLaunched) {
screenSaver->processLaunched(psn);
}
else if (eventKind == kEventAppTerminated) {
screenSaver->processTerminated(psn);
}
}
return (CallNextEventHandler(nextHandler, theEvent));
}

View File

@@ -16,11 +16,12 @@
#define COSXSCREENSAVER_H
#include "IScreenSaver.h"
#include <Carbon/Carbon.h>
//! OSX screen saver implementation
class COSXScreenSaver : public IScreenSaver {
public:
COSXScreenSaver();
COSXScreenSaver(void* eventTarget);
virtual ~COSXScreenSaver();
// IScreenSaver overrides
@@ -29,6 +30,25 @@ public:
virtual void activate();
virtual void deactivate();
virtual bool isActive() const;
private:
void processLaunched(ProcessSerialNumber psn);
void processTerminated(ProcessSerialNumber psn);
static pascal OSStatus
launchTerminationCallback(
EventHandlerCallRef nextHandler,
EventRef theEvent, void* userData);
private:
// the target for the events we generate
void* m_eventTarget;
bool m_enabled;
void* m_screenSaverController;
void* m_autoReleasePool;
EventHandlerRef m_launchTerminationEventHandlerRef;
ProcessSerialNumber m_screenSaverPSN;
};
#endif

View File

@@ -0,0 +1,39 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 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.
*/
#ifndef COSXSCREENSAVERUTIL_H
#define COSXSCREENSAVERUTIL_H
#include "common.h"
#if defined(__cplusplus)
extern "C" {
#endif
void* screenSaverUtilCreatePool();
void screenSaverUtilReleasePool(void*);
void* screenSaverUtilCreateController();
void screenSaverUtilReleaseController(void*);
void screenSaverUtilEnable(void*);
void screenSaverUtilDisable(void*);
void screenSaverUtilActivate(void*);
void screenSaverUtilDeactivate(void*, int isEnabled);
int screenSaverUtilIsActive(void*);
#if defined(__cplusplus)
}
#endif
#endif

View File

@@ -0,0 +1,81 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 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.
*/
#import "COSXScreenSaverUtil.h"
#import "OSXScreenSaverControl.h"
#import <Foundation/NSAutoreleasePool.h>
//
// screenSaverUtil functions
//
// Note: these helper functions exist only so we can avoid using ObjC++.
// autoconf/automake don't know about ObjC++ and I don't know how to
// teach them about it.
//
void*
screenSaverUtilCreatePool()
{
return [[NSAutoreleasePool alloc] init];
}
void
screenSaverUtilReleasePool(void* pool)
{
[(NSAutoreleasePool*)pool release];
}
void*
screenSaverUtilCreateController()
{
return [[ScreenSaverController controller] retain];
}
void
screenSaverUtilReleaseController(void* controller)
{
[(ScreenSaverController*)controller release];
}
void
screenSaverUtilEnable(void* controller)
{
[(ScreenSaverController*)controller setScreenSaverCanRun:YES];
}
void
screenSaverUtilDisable(void* controller)
{
[(ScreenSaverController*)controller setScreenSaverCanRun:NO];
}
void
screenSaverUtilActivate(void* controller)
{
[(ScreenSaverController*)controller setScreenSaverCanRun:YES];
[(ScreenSaverController*)controller screenSaverStartNow];
}
void
screenSaverUtilDeactivate(void* controller, int isEnabled)
{
[(ScreenSaverController*)controller screenSaverStopNow];
[(ScreenSaverController*)controller setScreenSaverCanRun:isEnabled];
}
int
screenSaverUtilIsActive(void* controller)
{
return [(ScreenSaverController*)controller screenSaverIsRunning];
}

View File

@@ -59,8 +59,8 @@ typedef struct tagMOUSEHOOKSTRUCTWin2000 {
#define WM_NCXBUTTONDOWN 0x00AB
#define WM_NCXBUTTONUP 0x00AC
#define WM_NCXBUTTONDBLCLK 0x00AD
#define MOUSEEVENTF_XDOWN 0x0100
#define MOUSEEVENTF_XUP 0x0200
#define MOUSEEVENTF_XDOWN 0x0080
#define MOUSEEVENTF_XUP 0x0100
#define XBUTTON1 0x0001
#define XBUTTON2 0x0002
#endif
@@ -96,10 +96,10 @@ static SInt32 g_wScreen = 0;
static SInt32 g_hScreen = 0;
static WPARAM g_deadVirtKey = 0;
static LPARAM g_deadLParam = 0;
static WPARAM g_oldDeadVirtKey = 0;
static BYTE g_deadKeyState[256] = { 0 };
static DWORD g_hookThread = 0;
static DWORD g_attachedThread = 0;
static bool g_fakeInput = false;
#if defined(_MSC_VER)
#pragma data_seg()
@@ -161,192 +161,213 @@ attachThreadToForeground()
#if !NO_GRAB_KEYBOARD
static
WPARAM
makeKeyMsg(UINT virtKey, char c)
makeKeyMsg(UINT virtKey, char c, bool noAltGr)
{
return MAKEWPARAM(MAKEWORD(virtKey & 0xff, (BYTE)c), 0);
return MAKEWPARAM(MAKEWORD(virtKey & 0xff, (BYTE)c), noAltGr ? 1 : 0);
}
static
void
keyboardGetState(BYTE keys[256])
{
if (g_hookThread != 0) {
GetKeyboardState(keys);
}
else {
SHORT key;
for (int i = 0; i < 256; ++i) {
key = GetAsyncKeyState(i);
keys[i] = (BYTE)((key < 0) ? 0x80u : 0);
}
key = GetKeyState(VK_CAPITAL);
keys[VK_CAPITAL] = (BYTE)(((key < 0) ? 0x80 : 0) | (key & 1));
// we have to use GetAsyncKeyState() rather than GetKeyState() because
// we don't pass through most keys so the event synchronous state
// doesn't get updated. we do that because certain modifier keys have
// side effects, like alt and the windows key.
SHORT key;
for (int i = 0; i < 256; ++i) {
key = GetAsyncKeyState(i);
keys[i] = (BYTE)((key < 0) ? 0x80u : 0);
}
key = GetKeyState(VK_CAPITAL);
keys[VK_CAPITAL] = (BYTE)(((key < 0) ? 0x80 : 0) | (key & 1));
}
static
bool
doKeyboardHookHandler(WPARAM wParam, LPARAM lParam)
{
// check for dead keys. we don't forward those to our window.
// instead we'll leave the key in the keyboard layout (a buffer
// internal to the system) for translation when the next key is
// pressed. note that some systems set bit 31 to indicate a
// dead key and others bit 15. nice.
UINT c = MapVirtualKey(wParam, 2);
PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG,
wParam | 0x00000000, c);
PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG,
wParam | (c << 8) | 0x01000000, lParam);
if ((c & 0x80008000u) != 0) {
if ((lParam & 0x80000000u) == 0) {
if (g_deadVirtKey == 0) {
// dead key press, no dead key in the buffer
g_deadVirtKey = wParam;
g_deadLParam = lParam;
keyboardGetState(g_deadKeyState);
PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG,
wParam | 0x02000000, lParam);
return false;
}
// second dead key press in a row so let it pass
PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG,
wParam | 0x03000000, lParam);
}
else if (wParam == g_oldDeadVirtKey) {
// dead key release for second dead key in a row. discard
// because we've already handled it. also take it out of
// the keyboard buffer.
g_oldDeadVirtKey = 0;
WORD c;
UINT scanCode = ((lParam & 0x00ff0000u) >> 16);
ToAscii(wParam, scanCode, g_deadKeyState, &c, 0);
PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG,
wParam | 0x09000000, lParam);
return true;
}
else {
// dead key release
PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG,
wParam | 0x04000000, lParam);
// check for special events indicating if we should start or stop
// passing events through and not report them to the server. this
// is used to allow the server to synthesize events locally but
// not pick them up as user events.
if (wParam == SYNERGY_HOOK_FAKE_INPUT_VIRTUAL_KEY &&
((lParam >> 16) & 0xffu) == SYNERGY_HOOK_FAKE_INPUT_SCANCODE) {
// update flag
g_fakeInput = ((lParam & 0x80000000u) == 0);
PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG,
0xff000000u | wParam, lParam);
// discard event
return true;
}
// if we're expecting fake input then just pass the event through
// and do not forward to the server
if (g_fakeInput) {
PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG,
0xfe000000u | wParam, lParam);
return false;
}
// VK_RSHIFT may be sent with an extended scan code but right shift
// is not an extended key so we reset that bit.
if (wParam == VK_RSHIFT) {
lParam &= ~0x01000000u;
}
// tell server about event
PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG, wParam, lParam);
// ignore dead key release
if (g_deadVirtKey == wParam &&
(lParam & 0x80000000u) != 0) {
PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG,
wParam | 0x04000000, lParam);
return false;
}
// we need the keyboard state for ToAscii()
BYTE keys[256];
keyboardGetState(keys);
// ToAscii() maps ctrl+letter to the corresponding control code
// and ctrl+backspace to delete. we don't want those translations
// so clear the control modifier state. however, if we want to
// simulate AltGr (which is ctrl+alt) then we must not clear it.
UINT control = keys[VK_CONTROL] | keys[VK_LCONTROL] | keys[VK_RCONTROL];
UINT menu = keys[VK_MENU] | keys[VK_LMENU] | keys[VK_RMENU];
if ((control & 0x80) == 0 || (menu & 0x80) == 0) {
keys[VK_LCONTROL] = 0;
keys[VK_RCONTROL] = 0;
keys[VK_CONTROL] = 0;
}
else {
keys[VK_LCONTROL] = 0x80;
keys[VK_RCONTROL] = 0x80;
keys[VK_CONTROL] = 0x80;
keys[VK_LMENU] = 0x80;
keys[VK_RMENU] = 0x80;
keys[VK_MENU] = 0x80;
}
// ToAscii() needs to know if a menu is active for some reason.
// we don't know and there doesn't appear to be any way to find
// out. so we'll just assume a menu is active if the menu key
// is down.
// FIXME -- figure out some way to check if a menu is active
UINT flags = 0;
if ((menu & 0x80) != 0)
flags |= 1;
// if we're on the server screen then just pass numpad keys with alt
// key down as-is. we won't pick up the resulting character but the
// local app will. if on a client screen then grab keys as usual;
// if the client is a windows system it'll synthesize the expected
// character. if not then it'll probably just do nothing.
if (g_mode != kHOOK_RELAY_EVENTS) {
// we don't use virtual keys because we don't know what the
// state of the numlock key is. we'll hard code the scan codes
// instead. hopefully this works across all keyboards.
UINT sc = (lParam & 0x01ff0000u) >> 16;
if (menu &&
(sc >= 0x47u && sc <= 0x52u && sc != 0x4au && sc != 0x4eu)) {
return false;
}
}
// convert key to a character. this combines a saved dead key,
// if any, with this key. however, the dead key must remain in
// the keyboard layout for the application receiving this event
// so it can also convert the key to a character. we only do
// this on a key press.
WPARAM charAndVirtKey = (wParam & 0xffu);
if (c != 0) {
// we need the keyboard state for ToAscii()
BYTE keys[256];
keyboardGetState(keys);
// ToAscii() maps ctrl+letter to the corresponding control code
// and ctrl+backspace to delete. we don't want those translations
// so clear the control modifier state. however, if we want to
// simulate AltGr (which is ctrl+alt) then we must not clear it.
UINT control = keys[VK_CONTROL] | keys[VK_LCONTROL] | keys[VK_RCONTROL];
UINT menu = keys[VK_MENU] | keys[VK_LMENU] | keys[VK_RMENU];
if ((control & 0x80) == 0 || (menu & 0x80) == 0) {
keys[VK_LCONTROL] = 0;
keys[VK_RCONTROL] = 0;
keys[VK_CONTROL] = 0;
}
else {
keys[VK_LCONTROL] = 0x80;
keys[VK_RCONTROL] = 0x80;
keys[VK_CONTROL] = 0x80;
keys[VK_LMENU] = 0x80;
keys[VK_RMENU] = 0x80;
keys[VK_MENU] = 0x80;
}
// ToAscii() needs to know if a menu is active for some reason.
// we don't know and there doesn't appear to be any way to find
// out. so we'll just assume a menu is active if the menu key
// is down.
// FIXME -- figure out some way to check if a menu is active
UINT flags = 0;
if ((menu & 0x80) != 0)
flags |= 1;
// map the key event to a character. this has the side
// effect of removing the dead key from the system's keyboard
// layout buffer.
WORD c = 0;
UINT scanCode = ((lParam & 0x00ff0000u) >> 16);
int n = ToAscii(wParam, scanCode, keys, &c, flags);
// if mapping failed and ctrl and alt are pressed then try again
// with both not pressed. this handles the case where ctrl and
// alt are being used as individual modifiers rather than AltGr.
// we have to put the dead key back first, if there was one.
if (n == 0 && (control & 0x80) != 0 && (menu & 0x80) != 0) {
PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG,
wParam | 0x05000000, lParam);
if (g_deadVirtKey != 0) {
ToAscii(g_deadVirtKey, (g_deadLParam & 0x00ff0000u) >> 16,
g_deadKeyState, &c, flags);
}
keys[VK_LCONTROL] = 0;
keys[VK_RCONTROL] = 0;
keys[VK_CONTROL] = 0;
keys[VK_LMENU] = 0;
keys[VK_RMENU] = 0;
keys[VK_MENU] = 0;
n = ToAscii(wParam, scanCode, keys, &c, flags);
}
// map the key event to a character. we have to put the dead
// key back first and this has the side effect of removing it.
if (g_deadVirtKey != 0) {
WORD c = 0;
ToAscii(g_deadVirtKey, (g_deadLParam & 0x10ff0000u) >> 16,
g_deadKeyState, &c, flags);
}
WORD c = 0;
UINT scanCode = ((lParam & 0x10ff0000u) >> 16);
int n = ToAscii(wParam, scanCode, keys, &c, flags);
// if mapping failed and ctrl and alt are pressed then try again
// with both not pressed. this handles the case where ctrl and
// alt are being used as individual modifiers rather than AltGr.
// we note that's the case in the message sent back to synergy
// because there's no simple way to deduce it after the fact.
// we have to put the dead key back first, if there was one.
bool noAltGr = false;
if (n == 0 && (control & 0x80) != 0 && (menu & 0x80) != 0) {
noAltGr = true;
PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG,
wParam | (c << 8) | ((n & 0xff) << 16) | 0x06000000,
wParam | 0x05000000, lParam);
if (g_deadVirtKey != 0) {
ToAscii(g_deadVirtKey, (g_deadLParam & 0x10ff0000u) >> 16,
g_deadKeyState, &c, flags);
}
BYTE keys2[256];
for (size_t i = 0; i < sizeof(keys) / sizeof(keys[0]); ++i) {
keys2[i] = keys[i];
}
keys2[VK_LCONTROL] = 0;
keys2[VK_RCONTROL] = 0;
keys2[VK_CONTROL] = 0;
keys2[VK_LMENU] = 0;
keys2[VK_RMENU] = 0;
keys2[VK_MENU] = 0;
n = ToAscii(wParam, scanCode, keys2, &c, flags);
}
PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG,
wParam | ((c & 0xff) << 8) |
((n & 0xff) << 16) | 0x06000000,
lParam);
switch (n) {
default:
// key is a dead key; we're not expecting this since we
// bailed out above for any dead key.
g_deadVirtKey = wParam;
g_deadLParam = lParam;
break;
WPARAM charAndVirtKey = 0;
bool clearDeadKey = false;
switch (n) {
default:
// key is a dead key
g_deadVirtKey = wParam;
g_deadLParam = lParam;
for (size_t i = 0; i < sizeof(keys) / sizeof(keys[0]); ++i) {
g_deadKeyState[i] = keys[i];
}
break;
case 0:
// key doesn't map to a character. this can happen if
// non-character keys are pressed after a dead key.
break;
case 0:
// key doesn't map to a character. this can happen if
// non-character keys are pressed after a dead key.
charAndVirtKey = makeKeyMsg(wParam, (char)0, noAltGr);
break;
case 1:
// key maps to a character composed with dead key
charAndVirtKey = makeKeyMsg(wParam, (char)LOBYTE(c));
break;
case 1:
// key maps to a character composed with dead key
charAndVirtKey = makeKeyMsg(wParam, (char)LOBYTE(c), noAltGr);
clearDeadKey = true;
break;
case 2: {
// previous dead key not composed. send a fake key press
// and release for the dead key to our window.
WPARAM deadCharAndVirtKey =
makeKeyMsg(g_deadVirtKey, (char)LOBYTE(c));
PostThreadMessage(g_threadID, SYNERGY_MSG_KEY,
case 2: {
// previous dead key not composed. send a fake key press
// and release for the dead key to our window.
WPARAM deadCharAndVirtKey =
makeKeyMsg(g_deadVirtKey, (char)LOBYTE(c), noAltGr);
PostThreadMessage(g_threadID, SYNERGY_MSG_KEY,
deadCharAndVirtKey, g_deadLParam & 0x7fffffffu);
PostThreadMessage(g_threadID, SYNERGY_MSG_KEY,
PostThreadMessage(g_threadID, SYNERGY_MSG_KEY,
deadCharAndVirtKey, g_deadLParam | 0x80000000u);
// use uncomposed character
charAndVirtKey = makeKeyMsg(wParam, (char)HIBYTE(c));
break;
}
}
// use uncomposed character
charAndVirtKey = makeKeyMsg(wParam, (char)HIBYTE(c), noAltGr);
clearDeadKey = true;
break;
}
}
// put back the dead key, if any, for the application to use
if (g_deadVirtKey != 0) {
ToAscii(g_deadVirtKey, (g_deadLParam & 0x00ff0000u) >> 16,
// put back the dead key, if any, for the application to use
if (g_deadVirtKey != 0) {
ToAscii(g_deadVirtKey, (g_deadLParam & 0x10ff0000u) >> 16,
g_deadKeyState, &c, flags);
for (int i = 0; i < 256; ++i) {
g_deadKeyState[i] = 0;
}
}
}
// clear out old dead key state
// clear out old dead key state
if (clearDeadKey) {
g_deadVirtKey = 0;
g_deadLParam = 0;
}
@@ -355,19 +376,12 @@ doKeyboardHookHandler(WPARAM wParam, LPARAM lParam)
// forwarding events to clients because this'll keep our thread's
// key state table up to date. that's important for querying
// the scroll lock toggle state.
PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG,
charAndVirtKey | 0x07000000, lParam);
PostThreadMessage(g_threadID, SYNERGY_MSG_KEY, charAndVirtKey, lParam);
// send fake key release if the user just pressed two dead keys
// in a row, otherwise we'll lose the release because we always
// return from the top of this function for all dead key releases.
if ((c & 0x80008000u) != 0) {
g_oldDeadVirtKey = wParam;
// XXX -- with hot keys for actions we may only need to do this when
// forwarding.
if (charAndVirtKey != 0) {
PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG,
wParam | 0x08000000, lParam);
PostThreadMessage(g_threadID, SYNERGY_MSG_KEY,
charAndVirtKey, lParam | 0x80000000u);
charAndVirtKey | 0x07000000, lParam);
PostThreadMessage(g_threadID, SYNERGY_MSG_KEY, charAndVirtKey, lParam);
}
if (g_mode == kHOOK_RELAY_EVENTS) {
@@ -381,32 +395,14 @@ doKeyboardHookHandler(WPARAM wParam, LPARAM lParam)
// lights may not stay synchronized.
break;
case VK_SHIFT:
case VK_LSHIFT:
case VK_RSHIFT:
// pass the shift modifiers. if we don't do this
// we may not get the right dead key when caps lock
// is on. for example, on the french layout (with
// english keycaps) on caps lock then press shift + [
// and q. instead of an A with ^ above it you get an
// A with dots above it.
break;
case VK_CONTROL:
case VK_LCONTROL:
case VK_RCONTROL:
case VK_MENU:
case VK_LMENU:
case VK_RMENU:
case VK_HANGUL:
// pass the control and alt modifiers if using a low
// level hook, discard them if not.
// pass these modifiers if using a low level hook, discard
// them if not.
if (g_hookThread == 0) {
return true;
}
break;
default:
// discard
return true;
@@ -531,7 +527,7 @@ static
bool
mouseHookHandler(WPARAM wParam, SInt32 x, SInt32 y, SInt32 data)
{
attachThreadToForeground();
// attachThreadToForeground();
return doMouseHookHandler(wParam, x, y, data);
}
@@ -804,7 +800,7 @@ init(DWORD threadID)
// save thread id. we'll post messages to this thread's
// message queue.
g_threadID = threadID;
g_threadID = threadID;
// set defaults
g_mode = kHOOK_DISABLE;
@@ -847,6 +843,9 @@ install()
g_deadVirtKey = 0;
g_deadLParam = 0;
// reset fake input flag
g_fakeInput = false;
// check for mouse wheel support
g_wheelSupport = getWheelSupport();

View File

@@ -38,6 +38,9 @@
#define SYNERGY_MSG_INPUT_LAST SYNERGY_MSG_PRE_WARP
#define SYNERGY_HOOK_LAST_MSG SYNERGY_MSG_DEBUG
#define SYNERGY_HOOK_FAKE_INPUT_VIRTUAL_KEY VK_CANCEL
#define SYNERGY_HOOK_FAKE_INPUT_SCANCODE 0
extern "C" {
enum EHookResult {

View File

@@ -503,11 +503,10 @@ CXWindowsClipboard::icccmFillCache()
(target != m_atomAtom && target != m_atomTargets)) {
LOG((CLOG_DEBUG1 "selection doesn't support TARGETS"));
data = "";
target = XA_STRING;
data.append(reinterpret_cast<char*>(&target), sizeof(target));
CXWindowsUtil::appendAtomData(data, XA_STRING);
}
CXWindowsUtil::convertAtomProperty(data);
const Atom* targets = reinterpret_cast<const Atom*>(data.data());
const UInt32 numTargets = data.size() / sizeof(Atom);
LOG((CLOG_DEBUG " available targets: %s", CXWindowsUtil::atomsToString(m_display, targets, numTargets).c_str()));
@@ -525,12 +524,18 @@ CXWindowsClipboard::icccmFillCache()
// see if atom is in target list
Atom target = None;
// XXX -- just ask for the converter's target to see if it's
// available rather than checking TARGETS. i've seen clipboard
// owners that don't report all the targets they support.
target = converter->getAtom();
/*
for (UInt32 i = 0; i < numTargets; ++i) {
if (converter->getAtom() == targets[i]) {
target = targets[i];
break;
}
}
*/
if (target == None) {
continue;
}
@@ -661,7 +666,7 @@ CXWindowsClipboard::motifOwnsClipboard() const
reinterpret_cast<const CMotifClipHeader*>(data.data());
if (data.size() >= sizeof(CMotifClipHeader) &&
header->m_id == kMotifClipHeader) {
if (header->m_selectionOwner == owner) {
if (static_cast<Window>(header->m_selectionOwner) == owner) {
return true;
}
}
@@ -835,12 +840,12 @@ CXWindowsClipboard::insertMultipleReply(Window requestor,
}
// fail if the requested targets isn't of the correct form
if (format != 32 ||
target != m_atomAtomPair) {
if (format != 32 || target != m_atomAtomPair) {
return false;
}
// data is a list of atom pairs: target, property
CXWindowsUtil::convertAtomProperty(data);
const Atom* targets = reinterpret_cast<const Atom*>(data.data());
const UInt32 numTargets = data.size() / sizeof(Atom);
@@ -851,10 +856,7 @@ CXWindowsClipboard::insertMultipleReply(Window requestor,
const Atom property = targets[i + 1];
if (!addSimpleRequest(requestor, target, time, property)) {
// note that we can't perform the requested conversion
static const Atom none = None;
data.replace(i * sizeof(Atom), sizeof(Atom),
reinterpret_cast<const char*>(&none),
sizeof(Atom));
CXWindowsUtil::replaceAtomData(data, i, None);
changed = true;
}
}
@@ -900,16 +902,18 @@ CXWindowsClipboard::insertReply(CReply* reply)
if (newWindow) {
// note errors while we adjust event masks
bool error = false;
CXWindowsUtil::CErrorLock lock(m_display, &error);
{
CXWindowsUtil::CErrorLock lock(m_display, &error);
// get and save the current event mask
XWindowAttributes attr;
XGetWindowAttributes(m_display, reply->m_requestor, &attr);
m_eventMasks[reply->m_requestor] = attr.your_event_mask;
// get and save the current event mask
XWindowAttributes attr;
XGetWindowAttributes(m_display, reply->m_requestor, &attr);
m_eventMasks[reply->m_requestor] = attr.your_event_mask;
// add the events we want
XSelectInput(m_display, reply->m_requestor, attr.your_event_mask |
StructureNotifyMask | PropertyChangeMask);
// add the events we want
XSelectInput(m_display, reply->m_requestor, attr.your_event_mask |
StructureNotifyMask | PropertyChangeMask);
}
// if we failed then the window has already been destroyed
if (error) {
@@ -1193,13 +1197,9 @@ CXWindowsClipboard::getTargetsData(CString& data, int* format) const
assert(format != NULL);
// add standard targets
Atom atom;
atom = m_atomTargets;
data.append(reinterpret_cast<char*>(&atom), sizeof(Atom));
atom = m_atomMultiple;
data.append(reinterpret_cast<char*>(&atom), sizeof(Atom));
atom = m_atomTimestamp;
data.append(reinterpret_cast<char*>(&atom), sizeof(Atom));
CXWindowsUtil::appendAtomData(data, m_atomTargets);
CXWindowsUtil::appendAtomData(data, m_atomMultiple);
CXWindowsUtil::appendAtomData(data, m_atomTimestamp);
// add targets we can convert to
for (ConverterList::const_iterator index = m_converters.begin();
@@ -1208,8 +1208,7 @@ CXWindowsClipboard::getTargetsData(CString& data, int* format) const
// skip formats we don't have
if (m_added[converter->getFormat()]) {
atom = converter->getAtom();
data.append(reinterpret_cast<char*>(&atom), sizeof(Atom));
CXWindowsUtil::appendAtomData(data, converter->getAtom());
}
}
@@ -1222,9 +1221,8 @@ CXWindowsClipboard::getTimestampData(CString& data, int* format) const
{
assert(format != NULL);
assert(sizeof(m_timeOwned) == 4);
checkCache();
data.append(reinterpret_cast<const char*>(&m_timeOwned), 4);
CXWindowsUtil::appendTimeData(data, m_timeOwned);
*format = 32;
return m_atomInteger;
}
@@ -1264,6 +1262,9 @@ CXWindowsClipboard::CICCCMGetClipboard::readClipboard(Display* display,
LOG((CLOG_DEBUG1 "request selection=%s, target=%s, window=%x", CXWindowsUtil::atomToString(display, selection).c_str(), CXWindowsUtil::atomToString(display, target).c_str(), m_requestor));
m_atomNone = XInternAtom(display, "NONE", False);
m_atomIncr = XInternAtom(display, "INCR", False);
// save output pointers
m_actualTarget = actualTarget;
m_data = data;
@@ -1361,7 +1362,8 @@ CXWindowsClipboard::CICCCMGetClipboard::processEvent(
case SelectionNotify:
if (xevent->xselection.requestor == m_requestor) {
// done if we can't convert
if (xevent->xselection.property == None) {
if (xevent->xselection.property == None ||
xevent->xselection.property == m_atomNone) {
m_done = true;
return true;
}
@@ -1409,7 +1411,7 @@ CXWindowsClipboard::CICCCMGetClipboard::processEvent(
// note if incremental. if we're already incremental then the
// selection owner is busted. if the INCR property has no size
// then the selection owner is busted.
if (target == XInternAtom(display, "INCR", False)) {
if (target == m_atomIncr) {
if (m_incr) {
m_failed = true;
m_error = true;

View File

@@ -155,6 +155,10 @@ private:
bool m_failed;
bool m_done;
// atoms needed for the protocol
Atom m_atomNone; // NONE, not None
Atom m_atomIncr;
// true iff we've received the selection notify
bool m_reading;
@@ -182,7 +186,7 @@ private:
SInt32 m_pad2[4];
SInt32 m_numItems;
SInt32 m_pad3[3];
Window m_selectionOwner;
SInt32 m_selectionOwner; // a Window
SInt32 m_pad4[2];
};
@@ -204,9 +208,9 @@ private:
SInt32 m_pad1[6];
SInt32 m_length;
SInt32 m_data;
Atom m_type;
SInt32 m_type; // an Atom
SInt32 m_pad2[1];
int m_deleted;
SInt32 m_deleted;
SInt32 m_pad3[4];
};

File diff suppressed because it is too large Load Diff

View File

@@ -17,6 +17,7 @@
#include "CKeyState.h"
#include "stdmap.h"
#include "stdvector.h"
#if X_DISPLAY_MISSING
# error X11 is required to build synergy
#else
@@ -26,6 +27,9 @@
# else
# error The XTest extension is required to build synergy
# endif
# if HAVE_XKB_EXTENSION
# include <X11/extensions/XKBstr.h>
# endif
#endif
//! X Windows key state
@@ -34,9 +38,35 @@ A key state for X Windows.
*/
class CXWindowsKeyState : public CKeyState {
public:
CXWindowsKeyState(Display*);
typedef std::vector<int> CKeycodeList;
enum {
kGroupPoll = -1,
kGroupPollAndSet = -2
};
CXWindowsKeyState(Display*, bool useXKB);
~CXWindowsKeyState();
//! @name modifiers
//@{
//! Set active group
/*!
Sets the active group to \p group. This is the group returned by
\c pollActiveGroup(). If \p group is \c kGroupPoll then
\c pollActiveGroup() will really poll, but that's a slow operation
on X11. If \p group is \c kGroupPollAndSet then this will poll the
active group now and use it for future calls to \c pollActiveGroup().
*/
void setActiveGroup(SInt32 group);
//! Set the auto-repeat state
/*!
Sets the auto-repeat state.
*/
void setAutoRepeat(const XKeyboardState&);
//@}
//! @name accessors
//@{
@@ -47,106 +77,79 @@ public:
*/
KeyModifierMask mapModifiersFromX(unsigned int state) const;
//! Convert synergy modifier mask to X mask
/*!
Converts the synergy modifier mask to the corresponding X modifier
mask. Returns \c true if successful and \c false if any modifier
could not be converted.
*/
bool mapModifiersToX(KeyModifierMask, unsigned int&) const;
//! Convert synergy key to all corresponding X keycodes
/*!
Converts the synergy key \p key to all of the keycodes that map to
that key.
*/
void mapKeyToKeycodes(KeyID key,
CKeycodeList& keycodes) const;
//@}
// IKeyState overrides
virtual bool fakeCtrlAltDel();
virtual const char* getKeyName(KeyButton) const;
virtual KeyModifierMask
pollActiveModifiers() const;
virtual SInt32 pollActiveGroup() const;
virtual void pollPressedKeys(KeyButtonSet& pressedKeys) const;
protected:
// IKeyState overrides
virtual void doUpdateKeys();
virtual void doFakeKeyEvent(KeyButton button,
bool press, bool isAutoRepeat);
virtual KeyButton mapKey(Keystrokes& keys, KeyID id,
KeyModifierMask desiredMask,
bool isAutoRepeat) const;
// CKeyState overrides
virtual void getKeyMap(CKeyMap& keyMap);
virtual void fakeKey(const Keystroke& keystroke);
private:
class KeyMapping {
void updateKeysymMap(CKeyMap&);
void updateKeysymMapXKB(CKeyMap&);
bool hasModifiersXKB() const;
int getEffectiveGroup(KeyCode, int group) const;
UInt32 getGroupFromState(unsigned int state) const;
static void remapKeyModifiers(KeyID, SInt32,
CKeyMap::KeyItem&, void*);
private:
struct XKBModifierInfo {
public:
KeyMapping();
public:
// KeyCode to generate keysym and whether keycode[i] is
// sensitive to shift and mode switch.
KeyCode m_keycode[4];
bool m_shiftSensitive[4];
bool m_modeSwitchSensitive[4];
// the modifier mask of keysym or 0 if not a modifier
KeyModifierMask m_modifierMask;
// whether keysym is sensitive to caps and num lock
bool m_numLockSensitive;
bool m_capsLockSensitive;
unsigned char m_level;
UInt32 m_mask;
bool m_lock;
};
typedef std::map<KeySym, KeyMapping> KeySymMap;
typedef KeySymMap::const_iterator KeySymIndex;
// save the current keyboard mapping and note the modifiers
void updateKeysymMap();
typedef std::vector<KeyModifierMask> KeyModifierMaskList;
typedef std::map<KeyModifierMask, unsigned int> KeyModifierToXMask;
typedef std::multimap<KeyID, KeyCode> KeyToKeyCodeMap;
typedef std::map<KeyCode, unsigned int> NonXKBModifierMap;
typedef std::map<UInt32, XKBModifierInfo> XKBModifierMap;
// note interesting modifier KeySyms
void updateModifiers();
// map a modifier index and its KeySym to a modifier mask. also
// save the modifier mask in one of m_*Mask.
KeyModifierMask mapToModifierMask(unsigned int, KeySym);
// convert a KeyID to a KeySym
KeySym keyIDToKeySym(KeyID id, KeyModifierMask mask) const;
// map a KeySym into the keystrokes to produce it
KeyButton mapToKeystrokes(Keystrokes& keys,
KeySymIndex keyIndex,
bool isAutoRepeat,
bool pressAndRelease) const;
// map a decomposition into keystrokes to produce it. returns the
// last key added to keys iff successful and 0 otherwise.
KeyButton mapDecompositionToKeystrokes(Keystrokes& keys,
KeySym keysym, bool usingDeadKeys) const;
// choose the best set of modifiers to generate the KeySym
unsigned int findBestKeyIndex(KeySymIndex keyIndex,
KeyModifierMask currentMask) const;
// returns true if the sense of shift is inverted for KeySym
bool isShiftInverted(KeySymIndex keyIndex,
KeyModifierMask currentMask) const;
// returns the keystrokes to adjust the modifiers into the desired
// state the keystrokes to get back to the current state.
bool adjustModifiers(Keystrokes& keys,
Keystrokes& undo,
KeyModifierMask desiredMask) const;
// returns true if keysym is sensitive to the NumLock state
bool isNumLockSensitive(KeySym keysym) const;
// returns true if keysym is sensitive to the CapsLock state
bool isCapsLockSensitive(KeySym keysym) const;
private:
Display* m_display;
#if HAVE_XKB_EXTENSION
XkbDescPtr m_xkb;
#endif
SInt32 m_group;
XKBModifierMap m_lastGoodXKBModifiers;
NonXKBModifierMap m_lastGoodNonXKBModifiers;
// keysym to keycode mapping
KeySymMap m_keysymMap;
// X modifier (bit number) to synergy modifier (mask) mapping
KeyModifierMaskList m_modifierFromX;
// the keyboard control state the last time this screen was entered
XKeyboardState m_keyControl;
// synergy modifier (mask) to X modifier (mask)
KeyModifierToXMask m_modifierToX;
// modifier keysyms
KeySym m_modeSwitchKeysym;
// map KeyID to all keycodes that can synthesize that KeyID
KeyToKeyCodeMap m_keyCodeFromKey;
// modifier masks
unsigned int m_altMask;
unsigned int m_metaMask;
unsigned int m_superMask;
unsigned int m_modeSwitchMask;
unsigned int m_numLockMask;
unsigned int m_scrollLockMask;
// autorepeat state
XKeyboardState m_keyboardState;
};
#endif

View File

@@ -19,6 +19,7 @@
#include "CXWindowsScreenSaver.h"
#include "CXWindowsUtil.h"
#include "CClipboard.h"
#include "CKeyMap.h"
#include "XScreen.h"
#include "CLog.h"
#include "CStopwatch.h"
@@ -45,47 +46,12 @@
# include <X11/extensions/Xinerama.h>
}
# endif
# if HAVE_XKB_EXTENSION
# include <X11/XKBlib.h>
# endif
#endif
#include "CArch.h"
// map "Internet" keys to KeyIDs
static const KeySym g_map1008FF[] =
{
/* 0x00 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x08 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x10 */ 0, kKeyAudioDown, kKeyAudioMute, kKeyAudioUp,
/* 0x14 */ kKeyAudioPlay, kKeyAudioStop, kKeyAudioPrev, kKeyAudioNext,
/* 0x18 */ kKeyWWWHome, kKeyAppMail, 0, kKeyWWWSearch, 0, 0, 0, 0,
/* 0x20 */ 0, 0, 0, 0, 0, 0, kKeyWWWBack, kKeyWWWForward,
/* 0x28 */ kKeyWWWStop, kKeyWWWRefresh, 0, 0, kKeyEject, 0, 0, 0,
/* 0x30 */ kKeyWWWFavorites, 0, kKeyAppMedia, 0, 0, 0, 0, 0,
/* 0x38 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x40 */ kKeyAppUser1, kKeyAppUser2, 0, 0, 0, 0, 0, 0,
/* 0x48 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x50 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x58 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x60 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x68 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x70 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x78 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x80 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x88 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x90 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x98 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xa0 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xa8 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xb0 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xb8 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xc0 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xc8 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xd0 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xd8 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xe0 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xe8 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xf0 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xf8 */ 0, 0, 0, 0, 0, 0, 0, 0
};
//
// CXWindowsScreen
@@ -123,7 +89,8 @@ CXWindowsScreen::CXWindowsScreen(const char* displayName, bool isPrimary) :
m_sequenceNumber(0),
m_screensaver(NULL),
m_screensaverNotify(false),
m_xtestIsXineramaUnaware(true)
m_xtestIsXineramaUnaware(true),
m_xkb(false)
{
assert(s_screen == NULL);
@@ -139,7 +106,7 @@ CXWindowsScreen::CXWindowsScreen(const char* displayName, bool isPrimary) :
m_window = openWindow();
m_screensaver = new CXWindowsScreenSaver(m_display,
m_window, getEventTarget());
m_keyState = new CXWindowsKeyState(m_display);
m_keyState = new CXWindowsKeyState(m_display, m_xkb);
LOG((CLOG_DEBUG "screen shape: %d,%d %dx%d %s", m_x, m_y, m_w, m_h, m_xinerama ? "(xinerama)" : ""));
LOG((CLOG_DEBUG "window is 0x%08x", m_window));
}
@@ -215,6 +182,7 @@ CXWindowsScreen::enable()
XKeyboardState keyControl;
XGetKeyboardControl(m_display, &keyControl);
m_autoRepeat = (keyControl.global_auto_repeat == AutoRepeatModeOn);
m_keyState->setAutoRepeat(keyControl);
// move hider window under the cursor center
XMoveWindow(m_display, m_window, m_xCenter, m_yCenter);
@@ -226,8 +194,6 @@ CXWindowsScreen::enable()
// warp the mouse to the cursor center
fakeMouseMove(m_xCenter, m_yCenter);
}
updateKeys();
}
void
@@ -256,10 +222,6 @@ CXWindowsScreen::enter()
XUnsetICFocus(m_ic);
}
// unmap the hider/grab window. this also ungrabs the mouse and
// keyboard if they're grabbed.
XUnmapWindow(m_display, m_window);
// set the input focus to what it had been when we took it
if (m_lastFocus != None) {
// the window may not exist anymore so ignore errors
@@ -267,6 +229,10 @@ CXWindowsScreen::enter()
XSetInputFocus(m_display, m_lastFocus, m_lastFocusRevert, CurrentTime);
}
// unmap the hider/grab window. this also ungrabs the mouse and
// keyboard if they're grabbed.
XUnmapWindow(m_display, m_window);
/* maybe call this if entering for the screensaver
// set keyboard focus to root window. the screensaver should then
// pick up key events for when the user enters a password to unlock.
@@ -278,6 +244,7 @@ CXWindowsScreen::enter()
XKeyboardState keyControl;
XGetKeyboardControl(m_display, &keyControl);
m_autoRepeat = (keyControl.global_auto_repeat == AutoRepeatModeOn);
m_keyState->setAutoRepeat(keyControl);
// turn off auto-repeat. we do this so fake key press events don't
// cause the local server to generate their own auto-repeats of
@@ -511,6 +478,245 @@ CXWindowsScreen::warpCursor(SInt32 x, SInt32 y)
m_yCursor = y;
}
UInt32
CXWindowsScreen::registerHotKey(KeyID key, KeyModifierMask mask)
{
// only allow certain modifiers
if ((mask & ~(KeyModifierShift | KeyModifierControl |
KeyModifierAlt | KeyModifierSuper)) != 0) {
LOG((CLOG_WARN "could not map hotkey id=%04x mask=%04x", key, mask));
return 0;
}
// fail if no keys
if (key == kKeyNone && mask == 0) {
return 0;
}
// convert to X
unsigned int modifiers;
if (!m_keyState->mapModifiersToX(mask, modifiers)) {
// can't map all modifiers
LOG((CLOG_WARN "could not map hotkey id=%04x mask=%04x", key, mask));
return 0;
}
CXWindowsKeyState::CKeycodeList keycodes;
m_keyState->mapKeyToKeycodes(key, keycodes);
if (key != kKeyNone && keycodes.empty()) {
// can't map key
LOG((CLOG_WARN "could not map hotkey id=%04x mask=%04x", key, mask));
return 0;
}
// choose hotkey id
UInt32 id;
if (!m_oldHotKeyIDs.empty()) {
id = m_oldHotKeyIDs.back();
m_oldHotKeyIDs.pop_back();
}
else {
id = m_hotKeys.size() + 1;
}
HotKeyList& hotKeys = m_hotKeys[id];
// all modifier hotkey must be treated specially. for each modifier
// we need to grab the modifier key in combination with all the other
// requested modifiers.
bool err = false;
{
CXWindowsUtil::CErrorLock lock(m_display, &err);
if (key == kKeyNone) {
static const KeyModifierMask s_hotKeyModifiers[] = {
KeyModifierShift,
KeyModifierControl,
KeyModifierAlt,
KeyModifierMeta,
KeyModifierSuper
};
XModifierKeymap* modKeymap = XGetModifierMapping(m_display);
for (size_t j = 0; j < sizeof(s_hotKeyModifiers) /
sizeof(s_hotKeyModifiers[0]) && !err; ++j) {
// skip modifier if not in mask
if ((mask & s_hotKeyModifiers[j]) == 0) {
continue;
}
// skip with error if we can't map remaining modifiers
unsigned int modifiers2;
KeyModifierMask mask2 = (mask & ~s_hotKeyModifiers[j]);
if (!m_keyState->mapModifiersToX(mask2, modifiers2)) {
err = true;
continue;
}
// compute modifier index for modifier. there should be
// exactly one X modifier missing
int index;
switch (modifiers ^ modifiers2) {
case ShiftMask:
index = ShiftMapIndex;
break;
case LockMask:
index = LockMapIndex;
break;
case ControlMask:
index = ControlMapIndex;
break;
case Mod1Mask:
index = Mod1MapIndex;
break;
case Mod2Mask:
index = Mod2MapIndex;
break;
case Mod3Mask:
index = Mod3MapIndex;
break;
case Mod4Mask:
index = Mod4MapIndex;
break;
case Mod5Mask:
index = Mod5MapIndex;
break;
default:
err = true;
continue;
}
// grab each key for the modifier
const KeyCode* modifiermap =
modKeymap->modifiermap + index * modKeymap->max_keypermod;
for (int k = 0; k < modKeymap->max_keypermod && !err; ++k) {
KeyCode code = modifiermap[k];
if (modifiermap[k] != 0) {
XGrabKey(m_display, code, modifiers2, m_root,
False, GrabModeAsync, GrabModeAsync);
if (!err) {
hotKeys.push_back(std::make_pair(code, modifiers2));
m_hotKeyToIDMap[CHotKeyItem(code, modifiers2)] = id;
}
}
}
}
XFreeModifiermap(modKeymap);
}
// a non-modifier key must be insensitive to CapsLock, NumLock and
// ScrollLock, so we have to grab the key with every combination of
// those.
else {
// collect available toggle modifiers
unsigned int modifier;
unsigned int toggleModifiers[3];
size_t numToggleModifiers = 0;
if (m_keyState->mapModifiersToX(KeyModifierCapsLock, modifier)) {
toggleModifiers[numToggleModifiers++] = modifier;
}
if (m_keyState->mapModifiersToX(KeyModifierNumLock, modifier)) {
toggleModifiers[numToggleModifiers++] = modifier;
}
if (m_keyState->mapModifiersToX(KeyModifierScrollLock, modifier)) {
toggleModifiers[numToggleModifiers++] = modifier;
}
for (CXWindowsKeyState::CKeycodeList::iterator j = keycodes.begin();
j != keycodes.end() && !err; ++j) {
for (size_t i = 0; i < (1u << numToggleModifiers); ++i) {
// add toggle modifiers for index i
unsigned int tmpModifiers = modifiers;
if ((i & 1) != 0) {
tmpModifiers |= toggleModifiers[0];
}
if ((i & 2) != 0) {
tmpModifiers |= toggleModifiers[1];
}
if ((i & 4) != 0) {
tmpModifiers |= toggleModifiers[2];
}
// add grab
XGrabKey(m_display, *j, tmpModifiers, m_root,
False, GrabModeAsync, GrabModeAsync);
if (!err) {
hotKeys.push_back(std::make_pair(*j, tmpModifiers));
m_hotKeyToIDMap[CHotKeyItem(*j, tmpModifiers)] = id;
}
}
}
}
}
if (err) {
// if any failed then unregister any we did get
for (HotKeyList::iterator j = hotKeys.begin();
j != hotKeys.end(); ++j) {
XUngrabKey(m_display, j->first, j->second, m_root);
m_hotKeyToIDMap.erase(CHotKeyItem(j->first, j->second));
}
m_oldHotKeyIDs.push_back(id);
m_hotKeys.erase(id);
LOG((CLOG_WARN "failed to register hotkey %s (id=%04x mask=%04x)", CKeyMap::formatKey(key, mask).c_str(), key, mask));
return 0;
}
LOG((CLOG_DEBUG "registered hotkey %s (id=%04x mask=%04x) as id=%d", CKeyMap::formatKey(key, mask).c_str(), key, mask, id));
return id;
}
void
CXWindowsScreen::unregisterHotKey(UInt32 id)
{
// look up hotkey
HotKeyMap::iterator i = m_hotKeys.find(id);
if (i == m_hotKeys.end()) {
return;
}
// unregister with OS
bool err = false;
{
CXWindowsUtil::CErrorLock lock(m_display, &err);
HotKeyList& hotKeys = i->second;
for (HotKeyList::iterator j = hotKeys.begin();
j != hotKeys.end(); ++j) {
XUngrabKey(m_display, j->first, j->second, m_root);
m_hotKeyToIDMap.erase(CHotKeyItem(j->first, j->second));
}
}
if (err) {
LOG((CLOG_WARN "failed to unregister hotkey id=%d", id));
}
else {
LOG((CLOG_DEBUG "unregistered hotkey id=%d", id));
}
// discard hot key from map and record old id for reuse
m_hotKeys.erase(i);
m_oldHotKeyIDs.push_back(id);
}
void
CXWindowsScreen::fakeInputBegin()
{
// FIXME -- not implemented
}
void
CXWindowsScreen::fakeInputEnd()
{
// FIXME -- not implemented
}
SInt32
CXWindowsScreen::getJumpZoneSize() const
{
@@ -578,17 +784,22 @@ CXWindowsScreen::fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const
}
void
CXWindowsScreen::fakeMouseWheel(SInt32 delta) const
CXWindowsScreen::fakeMouseWheel(SInt32, SInt32 yDelta) const
{
// XXX -- support x-axis scrolling
if (yDelta == 0) {
return;
}
// choose button depending on rotation direction
const unsigned int xButton = mapButtonToX(static_cast<ButtonID>(
(delta >= 0) ? -1 : -2));
(yDelta >= 0) ? -1 : -2));
if (xButton == 0) {
// If we get here, then the XServer does not support the scroll
// wheel buttons, so send PageUp/PageDown keystrokes instead.
// Patch by Tom Chadwick.
KeyCode keycode = 0;
if (delta >= 0) {
if (yDelta >= 0) {
keycode = XKeysymToKeycode(m_display, XK_Page_Up);
}
else {
@@ -602,12 +813,12 @@ CXWindowsScreen::fakeMouseWheel(SInt32 delta) const
}
// now use absolute value of delta
if (delta < 0) {
delta = -delta;
if (yDelta < 0) {
yDelta = -yDelta;
}
// send as many clicks as necessary
for (; delta >= 120; delta -= 120) {
for (; yDelta >= 120; yDelta -= 120) {
XTestFakeButtonEvent(m_display, xButton, True, CurrentTime);
XTestFakeButtonEvent(m_display, xButton, False, CurrentTime);
}
@@ -615,7 +826,7 @@ CXWindowsScreen::fakeMouseWheel(SInt32 delta) const
}
Display*
CXWindowsScreen::openDisplay(const char* displayName) const
CXWindowsScreen::openDisplay(const char* displayName)
{
// get the DISPLAY
if (displayName == NULL) {
@@ -643,6 +854,25 @@ CXWindowsScreen::openDisplay(const char* displayName) const
}
}
#if HAVE_XKB_EXTENSION
{
m_xkb = false;
int major = XkbMajorVersion, minor = XkbMinorVersion;
if (XkbLibraryVersion(&major, &minor)) {
int opcode, firstError;
if (XkbQueryExtension(display, &opcode, &m_xkbEventBase,
&firstError, &major, &minor)) {
m_xkb = true;
XkbSelectEvents(display, XkbUseCoreKbd,
XkbMapNotifyMask, XkbMapNotifyMask);
XkbSelectEventDetails(display, XkbUseCoreKbd,
XkbStateNotifyMask,
XkbGroupStateMask, XkbGroupStateMask);
}
}
}
#endif
return display;
}
@@ -864,10 +1094,22 @@ CXWindowsScreen::handleSystemEvent(const CEvent& event, void*)
}
if (xevent->type == KeyPress || xevent->type == KeyRelease) {
if (!isRepeat) {
m_keyState->setKeyDown(xevent->xkey.keycode,
xevent->type == KeyPress);
if (xevent->xkey.window == m_root) {
// this is a hot key
onHotKey(xevent->xkey, isRepeat);
return;
}
else if (!m_isOnScreen) {
// this might be a hot key
if (onHotKey(xevent->xkey, isRepeat)) {
return;
}
}
bool down = (isRepeat || xevent->type == KeyPress);
KeyModifierMask state =
m_keyState->mapModifiersFromX(xevent->xkey.state);
m_keyState->onKey(xevent->xkey.keycode, down, state);
}
}
@@ -924,19 +1166,7 @@ CXWindowsScreen::handleSystemEvent(const CEvent& event, void*)
break;
case MappingNotify:
if (XPending(m_display) > 0) {
XEvent tmpEvent;
XPeekEvent(m_display, &tmpEvent);
if (tmpEvent.type == MappingNotify) {
// discard this MappingNotify since another follows.
// we tend to get a bunch of these in a row.
return;
}
}
// keyboard mapping changed
XRefreshKeyboardMapping(&xevent->xmapping);
m_keyState->updateKeys();
refreshKeyboard(xevent);
break;
case LeaveNotify:
@@ -1036,6 +1266,21 @@ CXWindowsScreen::handleSystemEvent(const CEvent& event, void*)
return;
default:
#if HAVE_XKB_EXTENSION
if (m_xkb && xevent->type == m_xkbEventBase) {
XkbEvent* xkbEvent = reinterpret_cast<XkbEvent*>(xevent);
switch (xkbEvent->any.xkb_type) {
case XkbMapNotify:
refreshKeyboard(xevent);
return;
case XkbStateNotify:
LOG((CLOG_INFO "group change: %d", xkbEvent->state.group));
m_keyState->setActiveGroup((SInt32)xkbEvent->state.group);
return;
}
}
#endif
break;
}
}
@@ -1116,13 +1361,44 @@ CXWindowsScreen::onKeyRelease(XKeyEvent& xkey, bool isRepeat)
}
}
bool
CXWindowsScreen::onHotKey(XKeyEvent& xkey, bool isRepeat)
{
// find the hot key id
HotKeyToIDMap::const_iterator i =
m_hotKeyToIDMap.find(CHotKeyItem(xkey.keycode, xkey.state));
if (i == m_hotKeyToIDMap.end()) {
return false;
}
// find what kind of event
CEvent::Type type;
if (xkey.type == KeyPress) {
type = getHotKeyDownEvent();
}
else if (xkey.type == KeyRelease) {
type = getHotKeyUpEvent();
}
else {
return false;
}
// generate event (ignore key repeats)
if (!isRepeat) {
EVENTQUEUE->addEvent(CEvent(type, getEventTarget(),
CHotKeyInfo::alloc(i->second)));
}
return true;
}
void
CXWindowsScreen::onMousePress(const XButtonEvent& xbutton)
{
LOG((CLOG_DEBUG1 "event: ButtonPress button=%d", xbutton.button));
const ButtonID button = mapButtonFromX(&xbutton);
ButtonID button = mapButtonFromX(&xbutton);
KeyModifierMask mask = m_keyState->mapModifiersFromX(xbutton.state);
if (button != kButtonNone) {
sendEvent(getButtonDownEvent(), CButtonInfo::alloc(button));
sendEvent(getButtonDownEvent(), CButtonInfo::alloc(button, mask));
}
}
@@ -1130,18 +1406,20 @@ void
CXWindowsScreen::onMouseRelease(const XButtonEvent& xbutton)
{
LOG((CLOG_DEBUG1 "event: ButtonRelease button=%d", xbutton.button));
const ButtonID button = mapButtonFromX(&xbutton);
ButtonID button = mapButtonFromX(&xbutton);
KeyModifierMask mask = m_keyState->mapModifiersFromX(xbutton.state);
if (button != kButtonNone) {
sendEvent(getButtonUpEvent(), CButtonInfo::alloc(button));
sendEvent(getButtonUpEvent(), CButtonInfo::alloc(button, mask));
}
else if (xbutton.button == 4) {
// wheel forward (away from user)
sendEvent(getWheelEvent(), CWheelInfo::alloc(120));
sendEvent(getWheelEvent(), CWheelInfo::alloc(0, 120));
}
else if (xbutton.button == 5) {
// wheel backward (toward user)
sendEvent(getWheelEvent(), CWheelInfo::alloc(-120));
sendEvent(getWheelEvent(), CWheelInfo::alloc(0, -120));
}
// XXX -- support x-axis scrolling
}
void
@@ -1409,41 +1687,7 @@ CXWindowsScreen::mapKeyFromX(XKeyEvent* event) const
}
// convert key
switch (keysym & 0xffffff00) {
case 0x0000:
// Latin-1
return static_cast<KeyID>(keysym);
case 0xfe00:
// ISO 9995 Function and Modifier Keys
if (keysym == XK_ISO_Left_Tab) {
return kKeyLeftTab;
}
if (keysym == XK_ISO_Level3_Shift) {
// treat ISO_Level3_Shift as ModeSwitch
return kKeyModeSwitch;
}
return kKeyNone;
case 0xff00:
// MISCELLANY
return static_cast<KeyID>(keysym - 0xff00 + 0xef00);
case 0x1008ff00:
// "Internet" keys
return g_map1008FF[keysym & 0xff];
default: {
// lookup character in table
UInt32 key = CXWindowsUtil::mapKeySymToUCS4(keysym);
if (key != 0x0000ffff) {
return static_cast<KeyID>(key);
}
// unknown character
return kKeyNone;
}
}
return CXWindowsUtil::mapKeySymToKeyID(keysym);
}
ButtonID
@@ -1608,3 +1852,50 @@ CXWindowsScreen::grabMouseAndKeyboard()
LOG((CLOG_DEBUG1 "grabbed pointer and keyboard"));
return true;
}
void
CXWindowsScreen::refreshKeyboard(XEvent* event)
{
if (XPending(m_display) > 0) {
XEvent tmpEvent;
XPeekEvent(m_display, &tmpEvent);
if (tmpEvent.type == MappingNotify) {
// discard this event since another follows.
// we tend to get a bunch of these in a row.
return;
}
}
// keyboard mapping changed
#if HAVE_XKB_EXTENSION
if (m_xkb && event->type == m_xkbEventBase) {
XkbRefreshKeyboardMapping((XkbMapNotifyEvent*)event);
}
else
#else
{
XRefreshKeyboardMapping(&event->xmapping);
}
#endif
m_keyState->updateKeyMap();
m_keyState->updateKeyState();
}
//
// CXWindowsScreen::CHotKeyItem
//
CXWindowsScreen::CHotKeyItem::CHotKeyItem(int keycode, unsigned int mask) :
m_keycode(keycode),
m_mask(mask)
{
// do nothing
}
bool
CXWindowsScreen::CHotKeyItem::operator<(const CHotKeyItem& x) const
{
return (m_keycode < x.m_keycode ||
(m_keycode == x.m_keycode && m_mask < x.m_mask));
}

View File

@@ -49,6 +49,10 @@ public:
// IPrimaryScreen overrides
virtual void reconfigure(UInt32 activeSides);
virtual void warpCursor(SInt32 x, SInt32 y);
virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask);
virtual void unregisterHotKey(UInt32 id);
virtual void fakeInputBegin();
virtual void fakeInputEnd();
virtual SInt32 getJumpZoneSize() const;
virtual bool isAnyMouseButtonDown() const;
virtual void getCursorCenter(SInt32& x, SInt32& y) const;
@@ -57,7 +61,7 @@ public:
virtual void fakeMouseButton(ButtonID id, bool press) const;
virtual void fakeMouseMove(SInt32 x, SInt32 y) const;
virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const;
virtual void fakeMouseWheel(SInt32 delta) const;
virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const;
// IPlatformScreen overrides
virtual void enable();
@@ -112,7 +116,7 @@ private:
KeyCode m_keycode;
};
Display* openDisplay(const char* displayName) const;
Display* openDisplay(const char* displayName);
void saveShape();
Window openWindow() const;
void openIM();
@@ -120,6 +124,7 @@ private:
bool grabMouseAndKeyboard();
void onKeyPress(XKeyEvent&);
void onKeyRelease(XKeyEvent&, bool isRepeat);
bool onHotKey(XKeyEvent&, bool isRepeat);
void onMousePress(const XButtonEvent&);
void onMouseRelease(const XButtonEvent&);
void onMouseMove(const XMotionEvent&);
@@ -133,10 +138,27 @@ private:
void warpCursorNoFlush(SInt32 x, SInt32 y);
void refreshKeyboard(XEvent*);
static Bool findKeyEvent(Display*, XEvent* xevent, XPointer arg);
private:
struct CHotKeyItem {
public:
CHotKeyItem(int, unsigned int);
bool operator<(const CHotKeyItem&) const;
private:
int m_keycode;
unsigned int m_mask;
};
typedef std::set<bool> CFilteredKeycodes;
typedef std::vector<std::pair<int, unsigned int> > HotKeyList;
typedef std::map<UInt32, HotKeyList> HotKeyMap;
typedef std::vector<UInt32> HotKeyIDList;
typedef std::map<CHotKeyItem, UInt32> HotKeyToIDMap;
// true if screen is being used as a primary screen, false otherwise
bool m_isPrimary;
@@ -158,6 +180,11 @@ private:
// keyboard stuff
CXWindowsKeyState* m_keyState;
// hot key stuff
HotKeyMap m_hotKeys;
HotKeyIDList m_oldHotKeyIDs;
HotKeyToIDMap m_hotKeyToIDMap;
// input focus stuff
Window m_lastFocus;
int m_lastFocusRevert;
@@ -190,6 +217,10 @@ private:
bool m_xtestIsXineramaUnaware;
bool m_xinerama;
// XKB extension stuff
bool m_xkb;
int m_xkbEventBase;
// pointer to (singleton) screen. this is only needed by
// ioErrorHandler().
static CXWindowsScreen* s_screen;

View File

@@ -62,7 +62,8 @@ CXWindowsScreenSaver::CXWindowsScreenSaver(
m_dpms(false),
m_disabled(false),
m_suppressDisable(false),
m_disableTimer(NULL)
m_disableTimer(NULL),
m_disablePos(0)
{
// get atoms
m_atomScreenSaver = XInternAtom(m_display,
@@ -87,18 +88,18 @@ CXWindowsScreenSaver::CXWindowsScreenSaver(
#endif
// watch top-level windows for changes
bool error = false;
{
bool error = false;
CXWindowsUtil::CErrorLock lock(m_display, &error);
Window root = DefaultRootWindow(m_display);
XWindowAttributes attr;
XGetWindowAttributes(m_display, root, &attr);
m_rootEventMask = attr.your_event_mask;
XSelectInput(m_display, root, m_rootEventMask | SubstructureNotifyMask);
if (error) {
LOG((CLOG_DEBUG "didn't set root event mask"));
m_rootEventMask = 0;
}
}
if (error) {
LOG((CLOG_DEBUG "didn't set root event mask"));
m_rootEventMask = 0;
}
// get the built-in settings
@@ -346,9 +347,11 @@ CXWindowsScreenSaver::setXScreenSaver(Window window)
// see if xscreensaver is active
bool error = false;
CXWindowsUtil::CErrorLock lock(m_display, &error);
XWindowAttributes attr;
XGetWindowAttributes(m_display, m_xscreensaver, &attr);
{
CXWindowsUtil::CErrorLock lock(m_display, &error);
XGetWindowAttributes(m_display, m_xscreensaver, &attr);
}
setXScreenSaverActive(!error && attr.map_state != IsUnmapped);
// save current DPMS state; xscreensaver may have changed it.
@@ -418,8 +421,10 @@ CXWindowsScreenSaver::sendXScreenSaverCommand(Atom cmd, long arg1, long arg2)
LOG((CLOG_DEBUG "send xscreensaver command: %d %d %d", (long)cmd, arg1, arg2));
bool error = false;
CXWindowsUtil::CErrorLock lock(m_display, &error);
XSendEvent(m_display, m_xscreensaver, False, 0, &event);
{
CXWindowsUtil::CErrorLock lock(m_display, &error);
XSendEvent(m_display, m_xscreensaver, False, 0, &event);
}
if (error) {
findXScreenSaver();
}
@@ -465,18 +470,23 @@ CXWindowsScreenSaver::clearWatchForXScreenSaver()
void
CXWindowsScreenSaver::addWatchXScreenSaver(Window window)
{
bool error = false;
CXWindowsUtil::CErrorLock lock(m_display, &error);
// get window attributes
bool error = false;
XWindowAttributes attr;
XGetWindowAttributes(m_display, window, &attr);
{
CXWindowsUtil::CErrorLock lock(m_display, &error);
XGetWindowAttributes(m_display, window, &attr);
}
// if successful and window uses override_redirect (like xscreensaver
// does) then watch it for property changes.
if (!error && attr.override_redirect == True) {
XSelectInput(m_display, window,
error = false;
{
CXWindowsUtil::CErrorLock lock(m_display, &error);
XSelectInput(m_display, window,
attr.your_event_mask | PropertyChangeMask);
}
if (!error) {
// if successful then add the window to our list
m_watchWindows.insert(std::make_pair(window, attr.your_event_mask));
@@ -509,9 +519,9 @@ CXWindowsScreenSaver::handleDisableTimer(const CEvent&, void*)
event.xmotion.root = DefaultRootWindow(m_display);
event.xmotion.subwindow = None;
event.xmotion.time = CurrentTime;
event.xmotion.x = 0;
event.xmotion.x = m_disablePos;
event.xmotion.y = 0;
event.xmotion.x_root = 0;
event.xmotion.x_root = m_disablePos;
event.xmotion.y_root = 0;
event.xmotion.state = 0;
event.xmotion.is_hint = NotifyNormal;
@@ -519,6 +529,8 @@ CXWindowsScreenSaver::handleDisableTimer(const CEvent&, void*)
CXWindowsUtil::CErrorLock lock(m_display);
XSendEvent(m_display, m_xscreensaver, False, 0, &event);
m_disablePos = 20 - m_disablePos;
}
}

View File

@@ -154,6 +154,11 @@ private:
// the disable timer (NULL if not installed)
CEventQueueTimer* m_disableTimer;
// fake mouse motion position for suppressing the screen saver.
// xscreensaver since 2.21 requires the mouse to move more than 10
// pixels to be considered significant.
SInt32 m_disablePos;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -59,37 +59,19 @@ public:
*/
static Time getCurrentTime(Display*, Window);
//! Convert KeySym to UCS-4
//! Convert KeySym to KeyID
/*!
Converts a KeySym to the equivalent UCS-4 character. Returns
0x0000ffff if the KeySym cannot be mapped.
Converts a KeySym to the equivalent KeyID. Returns kKeyNone if the
KeySym cannot be mapped.
*/
static UInt32 mapKeySymToUCS4(KeySym);
static UInt32 mapKeySymToKeyID(KeySym);
//! Convert UCS-4 to KeySym
//! Convert KeySym to corresponding KeyModifierMask
/*!
Converts a UCS-4 character to the equivalent KeySym. Returns
NoSymbol (0) if the character cannot be mapped.
Converts a KeySym to the corresponding KeyModifierMask, or 0 if the
KeySym is not a modifier.
*/
static KeySym mapUCS4ToKeySym(UInt32);
//! Decompose a KeySym using dead keys
/*!
Decomposes \c keysym into its component keysyms. All but the last
decomposed KeySym are dead keys. Returns true iff the decomposition
was successful.
*/
static bool decomposeKeySymWithDeadKeys(KeySym keysym,
KeySyms& decomposed);
//! Decompose a KeySym using the compose key
/*!
Decomposes \c keysym into its component keysyms. The first key is
Multi_key and the rest are normal (i.e. not dead) keys. Returns
true iff the decomposition was successful.
*/
static bool decomposeKeySymWithCompose(KeySym keysym,
KeySyms& decomposed);
static UInt32 getModifierBitForKeySym(KeySym keysym);
//! Convert Atom to its string
/*!
@@ -105,6 +87,35 @@ public:
static CString atomsToString(Display* display,
const Atom* atom, UInt32 num);
//! Prepare a property of atoms for use
/*!
64-bit systems may need to modify a property's data if it's a
list of Atoms before using it.
*/
static void convertAtomProperty(CString& data);
//! Append an Atom to property data
/*!
Converts \p atom to a 32-bit on-the-wire format and appends it to
\p data.
*/
static void appendAtomData(CString& data, Atom atom);
//! Replace an Atom in property data
/*!
Converts \p atom to a 32-bit on-the-wire format and replaces the atom
at index \p index in \p data.
*/
static void replaceAtomData(CString& data,
UInt32 index, Atom atom);
//! Append an Time to property data
/*!
Converts \p time to a 32-bit on-the-wire format and appends it to
\p data.
*/
static void appendTimeData(CString& data, Time time);
//! X11 error handler
/*!
This class sets an X error handler in the c'tor and restores the
@@ -167,13 +178,8 @@ private:
private:
typedef std::map<KeySym, UInt32> CKeySymMap;
typedef std::map<UInt32, KeySym> CUCS4Map;
typedef std::map<KeySym, KeySyms> CKeySymsMap;
static CKeySymMap s_keySymToUCS4;
static CUCS4Map s_UCS4ToKeySym;
static CKeySymsMap s_deadKeyDecomposedKeySyms;
static CKeySymsMap s_composeDecomposedKeySyms;
};
#endif

View File

@@ -78,6 +78,7 @@ CARBON_SOURCE_FILES = \
COSXKeyState.cpp \
COSXScreen.cpp \
COSXScreenSaver.cpp \
COSXScreenSaverUtil.m \
COSXClipboard.h \
COSXClipboardAnyTextConverter.h \
COSXClipboardTextConverter.h \
@@ -86,6 +87,8 @@ CARBON_SOURCE_FILES = \
COSXKeyState.h \
COSXScreen.h \
COSXScreenSaver.h \
COSXScreenSaverUtil.h \
OSXScreenSaverControl.h \
$(NULL)
EXTRA_DIST = \

View File

@@ -0,0 +1,36 @@
// ScreenSaver.framework private API
// Class dumping by Alex Harper http://www.ragingmenace.com/
#import <Foundation/NSObject.h>
@protocol ScreenSaverControl
- (double)screenSaverTimeRemaining;
- (void)restartForUser:fp12;
- (void)screenSaverStopNow;
- (void)screenSaverStartNow;
- (void)setScreenSaverCanRun:(char)fp12;
- (BOOL)screenSaverCanRun;
- (BOOL)screenSaverIsRunning;
@end
@interface ScreenSaverController:NSObject <ScreenSaverControl>
+ controller;
+ monitor;
+ daemonConnectionName;
+ daemonPath;
+ enginePath;
- init;
- (void)dealloc;
- (void)_connectionClosed:fp12;
- (BOOL)screenSaverIsRunning;
- (BOOL)screenSaverCanRun;
- (void)setScreenSaverCanRun:(char)fp12;
- (void)screenSaverStartNow;
- (void)screenSaverStopNow;
- (void)restartForUser:fp12;
- (double)screenSaverTimeRemaining;
@end

View File

@@ -41,7 +41,7 @@ RSC=rc.exe
# PROP Intermediate_Dir "..\..\gen\build"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
# ADD CPP /nologo /MT /W4 /GX /O2 /I "..\common" /I "..\arch" /I "..\base" /I "..\mt" /I "..\io" /I "..\synergy" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Fd"..\..\gen\build\platform.pdb" /FD /c
# ADD CPP /nologo /MT /W4 /GR /GX /O2 /I "..\common" /I "..\arch" /I "..\base" /I "..\mt" /I "..\io" /I "..\synergy" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Fd"..\..\gen\build\platform.pdb" /FD /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
@@ -65,7 +65,7 @@ LIB32=link.exe -lib
# PROP Intermediate_Dir "..\..\gen\debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\common" /I "..\arch" /I "..\base" /I "..\mt" /I "..\io" /I "..\synergy" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /Fd"..\..\gen\debug\platform.pdb" /FD /GZ /c
# ADD CPP /nologo /MTd /W4 /Gm /GR /GX /ZI /Od /I "..\common" /I "..\arch" /I "..\base" /I "..\mt" /I "..\io" /I "..\synergy" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /Fd"..\..\gen\debug\platform.pdb" /FD /GZ /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"

View File

@@ -43,7 +43,7 @@ RSC=rc.exe
# PROP Ignore_Export_Lib 1
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SYNRGYHK_EXPORTS" /YX /FD /c
# ADD CPP /nologo /MT /W4 /GX /O1 /I "..\common" /I "..\arch" /I "..\base" /I "..\net" /I "..\synergy" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SYNRGYHK_EXPORTS" /FD /c /Fd..\..\gen\build\synrgyhk.pdb
# ADD CPP /nologo /MT /W4 /GR /GX /O1 /I "..\common" /I "..\arch" /I "..\base" /I "..\net" /I "..\synergy" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SYNRGYHK_EXPORTS" /Fd"..\..\gen\build\synrgyhk.pdb" /FD /c
# SUBTRACT CPP /YX
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
@@ -71,7 +71,7 @@ LINK32=link.exe
# PROP Ignore_Export_Lib 1
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SYNRGYHK_EXPORTS" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\common" /I "..\arch" /I "..\base" /I "..\net" /I "..\synergy" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SYNRGYHK_EXPORTS" /FD /GZ /c /Fd..\..\gen\debug\synrgyhk.pdb
# ADD CPP /nologo /MTd /W4 /Gm /GR /GX /ZI /Od /I "..\common" /I "..\arch" /I "..\base" /I "..\net" /I "..\synergy" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SYNRGYHK_EXPORTS" /Fd"..\..\gen\debug\synrgyhk.pdb" /FD /GZ /c
# SUBTRACT CPP /YX
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32