2002-08-02 19:57:46 +00:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2001-11-19 00:33:36 +00:00
|
|
|
#include "CMSWindowsScreen.h"
|
2002-07-15 15:01:36 +00:00
|
|
|
#include "CMSWindowsClipboard.h"
|
2004-03-26 20:59:26 +00:00
|
|
|
#include "CMSWindowsDesks.h"
|
2004-02-28 12:19:49 +00:00
|
|
|
#include "CMSWindowsEventQueueBuffer.h"
|
2004-03-26 20:59:26 +00:00
|
|
|
#include "CMSWindowsKeyState.h"
|
2002-06-23 21:53:31 +00:00
|
|
|
#include "CMSWindowsScreenSaver.h"
|
2002-07-15 15:01:36 +00:00
|
|
|
#include "CClipboard.h"
|
2003-09-02 22:05:47 +00:00
|
|
|
#include "XScreen.h"
|
2001-11-19 00:33:36 +00:00
|
|
|
#include "CLock.h"
|
2004-02-28 12:19:49 +00:00
|
|
|
#include "CThread.h"
|
2003-09-02 22:05:47 +00:00
|
|
|
#include "CFunctionJob.h"
|
2001-11-19 00:33:36 +00:00
|
|
|
#include "CLog.h"
|
|
|
|
#include "CString.h"
|
2003-01-04 22:01:32 +00:00
|
|
|
#include "CStringUtil.h"
|
2004-02-28 12:19:49 +00:00
|
|
|
#include "IEventQueue.h"
|
|
|
|
#include "TMethodEventJob.h"
|
2003-09-02 22:05:47 +00:00
|
|
|
#include "TMethodJob.h"
|
|
|
|
#include "CArch.h"
|
2003-01-04 22:01:32 +00:00
|
|
|
#include "CArchMiscWindows.h"
|
2004-03-26 20:59:26 +00:00
|
|
|
#include <string.h>
|
2004-04-11 19:15:09 +00:00
|
|
|
#include <pbt.h>
|
2004-02-28 12:19:49 +00:00
|
|
|
|
2002-06-19 17:03:29 +00:00
|
|
|
//
|
2004-04-11 19:15:09 +00:00
|
|
|
// add backwards compatible multihead support (and suppress bogus warning).
|
|
|
|
// this isn't supported on MinGW yet AFAICT.
|
2002-06-19 17:03:29 +00:00
|
|
|
//
|
2004-04-11 19:15:09 +00:00
|
|
|
#if defined(_MSC_VER)
|
2002-06-19 17:03:29 +00:00
|
|
|
#pragma warning(push)
|
|
|
|
#pragma warning(disable: 4706) // assignment within conditional
|
|
|
|
#define COMPILE_MULTIMON_STUBS
|
|
|
|
#include <multimon.h>
|
|
|
|
#pragma warning(pop)
|
2004-04-11 19:15:09 +00:00
|
|
|
#endif
|
2002-06-19 17:03:29 +00:00
|
|
|
|
2003-09-02 22:05:47 +00:00
|
|
|
// X button stuff
|
|
|
|
#if !defined(WM_XBUTTONDOWN)
|
|
|
|
#define WM_XBUTTONDOWN 0x020B
|
|
|
|
#define WM_XBUTTONUP 0x020C
|
|
|
|
#define WM_XBUTTONDBLCLK 0x020D
|
|
|
|
#define WM_NCXBUTTONDOWN 0x00AB
|
|
|
|
#define WM_NCXBUTTONUP 0x00AC
|
|
|
|
#define WM_NCXBUTTONDBLCLK 0x00AD
|
|
|
|
#define MOUSEEVENTF_XDOWN 0x0100
|
|
|
|
#define MOUSEEVENTF_XUP 0x0200
|
|
|
|
#define XBUTTON1 0x0001
|
|
|
|
#define XBUTTON2 0x0002
|
|
|
|
#endif
|
2004-03-26 20:59:26 +00:00
|
|
|
#if !defined(VK_XBUTTON1)
|
|
|
|
#define VK_XBUTTON1 0x05
|
|
|
|
#define VK_XBUTTON2 0x06
|
|
|
|
#endif
|
2003-09-02 22:05:47 +00:00
|
|
|
|
2004-04-11 19:15:09 +00:00
|
|
|
// WM_POWERBROADCAST stuff
|
|
|
|
#if !defined(PBT_APMRESUMEAUTOMATIC)
|
|
|
|
#define PBT_APMRESUMEAUTOMATIC 0x0012
|
|
|
|
#endif
|
|
|
|
|
2001-11-19 00:33:36 +00:00
|
|
|
//
|
|
|
|
// CMSWindowsScreen
|
|
|
|
//
|
|
|
|
|
|
|
|
HINSTANCE CMSWindowsScreen::s_instance = NULL;
|
2004-02-28 12:19:49 +00:00
|
|
|
CMSWindowsScreen* CMSWindowsScreen::s_screen = NULL;
|
2001-11-19 00:33:36 +00:00
|
|
|
|
2004-03-13 17:13:55 +00:00
|
|
|
CMSWindowsScreen::CMSWindowsScreen(bool isPrimary,
|
|
|
|
IJob* suspend, IJob* resume) :
|
2004-02-28 12:19:49 +00:00
|
|
|
m_isPrimary(isPrimary),
|
2003-09-02 22:05:47 +00:00
|
|
|
m_is95Family(CArchMiscWindows::isWindows95Family()),
|
|
|
|
m_isOnScreen(m_isPrimary),
|
|
|
|
m_class(0),
|
2002-06-19 17:03:29 +00:00
|
|
|
m_x(0), m_y(0),
|
2002-06-10 22:06:45 +00:00
|
|
|
m_w(0), m_h(0),
|
2003-09-02 22:05:47 +00:00
|
|
|
m_xCenter(0), m_yCenter(0),
|
2002-07-15 15:01:36 +00:00
|
|
|
m_multimon(false),
|
2003-09-02 22:05:47 +00:00
|
|
|
m_xCursor(0), m_yCursor(0),
|
2004-02-28 12:19:49 +00:00
|
|
|
m_sequenceNumber(0),
|
2003-09-02 22:05:47 +00:00
|
|
|
m_mark(0),
|
|
|
|
m_markReceived(0),
|
2004-03-08 20:53:32 +00:00
|
|
|
m_keyLayout(NULL),
|
2004-03-28 14:07:58 +00:00
|
|
|
m_fixTimer(NULL),
|
2003-09-02 22:05:47 +00:00
|
|
|
m_screensaver(NULL),
|
|
|
|
m_screensaverNotify(false),
|
2004-04-11 19:15:09 +00:00
|
|
|
m_window(NULL),
|
2002-07-15 15:01:36 +00:00
|
|
|
m_nextClipboardWindow(NULL),
|
Fixed several win32 bugs. First, synergy wasn't forwarding mouse
events to other hook functions, which broke some tools like objectbar.
Second, windows key processing was fixed. Previously pressing and
release the key would only send a press event, locking the user onto
the client window; also, the win32 server treated as a Meta modifier
instead of a Super modifier, which broke any use of it as any kind of
modifier key. Third, added hacks to support several key combinations
on windows 95/98/me that are treated specially by windows, including
Alt+Tab, Alt+Shift+Tab, Alt+Esc, Alt+Shift+Esc, Ctrl+Esc, and any
combination using the windows key like Win+E and Win+F but not
Ctrl+Alt+Del. Fourth, scroll lock only locking to the client (which
only happened when using a synergy server on windows) has been fixed;
unfortunately the solution causes a lot of screen redraws for some
reason. Finally, there's been a fix to clipboard handling that may
or may not fix a problem where the clipboard would stop transferring
between systems after a little while. I can't be sure if it fixes
the problem because I can't reproduce the problem.
2003-04-13 14:59:53 +00:00
|
|
|
m_ownClipboard(false),
|
2004-03-26 20:59:26 +00:00
|
|
|
m_desks(NULL),
|
2002-07-15 15:01:36 +00:00
|
|
|
m_hookLibrary(NULL),
|
2004-03-13 17:13:55 +00:00
|
|
|
m_init(NULL),
|
|
|
|
m_cleanup(NULL),
|
|
|
|
m_setSides(NULL),
|
|
|
|
m_setZone(NULL),
|
|
|
|
m_setMode(NULL),
|
2004-02-28 12:19:49 +00:00
|
|
|
m_keyState(NULL),
|
2004-03-13 17:13:55 +00:00
|
|
|
m_suspend(suspend),
|
|
|
|
m_resume(resume)
|
2001-11-19 00:33:36 +00:00
|
|
|
{
|
2004-02-28 12:19:49 +00:00
|
|
|
assert(s_instance != NULL);
|
2003-09-02 22:05:47 +00:00
|
|
|
assert(s_screen == NULL);
|
2002-07-15 15:01:36 +00:00
|
|
|
|
2001-11-25 18:32:41 +00:00
|
|
|
s_screen = this;
|
2004-02-28 12:19:49 +00:00
|
|
|
try {
|
2004-03-13 17:13:55 +00:00
|
|
|
if (m_isPrimary) {
|
|
|
|
m_hookLibrary = openHookLibrary("synrgyhk");
|
|
|
|
}
|
2004-03-26 20:59:26 +00:00
|
|
|
m_screensaver = new CMSWindowsScreenSaver();
|
|
|
|
m_desks = new CMSWindowsDesks(m_isPrimary,
|
|
|
|
m_hookLibrary, m_screensaver,
|
|
|
|
new TMethodJob<CMSWindowsScreen>(this,
|
|
|
|
&CMSWindowsScreen::updateKeysCB));
|
|
|
|
m_keyState = new CMSWindowsKeyState(m_desks);
|
2004-02-28 12:19:49 +00:00
|
|
|
updateScreenShape();
|
2004-03-26 20:59:26 +00:00
|
|
|
m_class = createWindowClass();
|
2004-02-28 12:19:49 +00:00
|
|
|
m_window = createWindow(m_class, "Synergy");
|
|
|
|
LOG((CLOG_DEBUG "screen shape: %d,%d %dx%d %s", m_x, m_y, m_w, m_h, m_multimon ? "(multi-monitor)" : ""));
|
|
|
|
LOG((CLOG_DEBUG "window is 0x%08x", m_window));
|
|
|
|
}
|
|
|
|
catch (...) {
|
2004-03-26 20:59:26 +00:00
|
|
|
delete m_keyState;
|
|
|
|
delete m_desks;
|
2004-02-28 12:19:49 +00:00
|
|
|
delete m_screensaver;
|
|
|
|
destroyWindow(m_window);
|
|
|
|
destroyClass(m_class);
|
|
|
|
closeHookLibrary(m_hookLibrary);
|
2004-03-26 20:59:26 +00:00
|
|
|
delete m_suspend;
|
|
|
|
delete m_resume;
|
|
|
|
s_screen = NULL;
|
2004-02-28 12:19:49 +00:00
|
|
|
throw;
|
|
|
|
}
|
|
|
|
|
|
|
|
// install event handlers
|
|
|
|
EVENTQUEUE->adoptHandler(CEvent::kSystem, IEventQueue::getSystemTarget(),
|
|
|
|
new TMethodEventJob<CMSWindowsScreen>(this,
|
|
|
|
&CMSWindowsScreen::handleSystemEvent));
|
|
|
|
|
|
|
|
// install the platform event queue
|
|
|
|
EVENTQUEUE->adoptBuffer(new CMSWindowsEventQueueBuffer);
|
2001-11-19 00:33:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CMSWindowsScreen::~CMSWindowsScreen()
|
|
|
|
{
|
2002-07-15 15:01:36 +00:00
|
|
|
assert(s_screen != NULL);
|
|
|
|
|
2004-02-28 12:19:49 +00:00
|
|
|
disable();
|
|
|
|
EVENTQUEUE->adoptBuffer(NULL);
|
|
|
|
EVENTQUEUE->removeHandler(CEvent::kSystem, IEventQueue::getSystemTarget());
|
2004-03-26 20:59:26 +00:00
|
|
|
delete m_keyState;
|
|
|
|
delete m_desks;
|
2004-02-28 12:19:49 +00:00
|
|
|
delete m_screensaver;
|
|
|
|
destroyWindow(m_window);
|
|
|
|
destroyClass(m_class);
|
|
|
|
closeHookLibrary(m_hookLibrary);
|
2004-03-13 17:13:55 +00:00
|
|
|
delete m_suspend;
|
|
|
|
delete m_resume;
|
2001-11-25 18:32:41 +00:00
|
|
|
s_screen = NULL;
|
2001-11-19 00:33:36 +00:00
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
2002-06-17 13:31:21 +00:00
|
|
|
CMSWindowsScreen::init(HINSTANCE instance)
|
2001-11-19 00:33:36 +00:00
|
|
|
{
|
2004-02-28 12:19:49 +00:00
|
|
|
assert(s_instance == NULL);
|
|
|
|
assert(instance != NULL);
|
|
|
|
|
2001-11-19 00:33:36 +00:00
|
|
|
s_instance = instance;
|
|
|
|
}
|
|
|
|
|
2003-09-02 22:05:47 +00:00
|
|
|
HINSTANCE
|
|
|
|
CMSWindowsScreen::getInstance()
|
2001-11-19 00:33:36 +00:00
|
|
|
{
|
2003-09-02 22:05:47 +00:00
|
|
|
return s_instance;
|
|
|
|
}
|
2002-05-22 17:08:37 +00:00
|
|
|
|
2003-09-02 22:05:47 +00:00
|
|
|
void
|
|
|
|
CMSWindowsScreen::enable()
|
2003-03-12 22:34:07 +00:00
|
|
|
{
|
2003-09-02 22:05:47 +00:00
|
|
|
assert(m_isOnScreen == m_isPrimary);
|
|
|
|
|
2004-03-13 17:13:55 +00:00
|
|
|
// install our clipboard snooper
|
|
|
|
m_nextClipboardWindow = SetClipboardViewer(m_window);
|
|
|
|
|
2004-03-26 20:59:26 +00:00
|
|
|
// track the active desk and (re)install the hooks
|
|
|
|
m_desks->enable();
|
2003-09-02 22:05:47 +00:00
|
|
|
|
2004-03-26 20:59:26 +00:00
|
|
|
if (m_isPrimary) {
|
2003-09-02 22:05:47 +00:00
|
|
|
// set jump zones
|
|
|
|
m_setZone(m_x, m_y, m_w, m_h, getJumpZoneSize());
|
|
|
|
|
|
|
|
// watch jump zones
|
|
|
|
m_setMode(kHOOK_WATCH_JUMP_ZONE);
|
2003-03-12 22:34:07 +00:00
|
|
|
}
|
2004-03-13 17:13:55 +00:00
|
|
|
else {
|
|
|
|
// prevent the system from entering power saving modes. if
|
|
|
|
// it did we'd be forced to disconnect from the server and
|
|
|
|
// the server would not be able to wake us up.
|
|
|
|
CArchMiscWindows::addBusyState(CArchMiscWindows::kSYSTEM);
|
|
|
|
}
|
2002-07-12 20:41:23 +00:00
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
2003-09-02 22:05:47 +00:00
|
|
|
CMSWindowsScreen::disable()
|
2001-11-19 00:33:36 +00:00
|
|
|
{
|
2004-03-26 20:59:26 +00:00
|
|
|
// stop tracking the active desk
|
|
|
|
m_desks->disable();
|
2001-11-19 00:33:36 +00:00
|
|
|
|
2004-02-28 12:19:49 +00:00
|
|
|
if (m_isPrimary) {
|
2004-03-13 17:13:55 +00:00
|
|
|
// disable hooks
|
2004-02-28 12:19:49 +00:00
|
|
|
m_setMode(kHOOK_DISABLE);
|
2004-03-13 17:13:55 +00:00
|
|
|
|
|
|
|
// enable special key sequences on win95 family
|
|
|
|
enableSpecialKeys(true);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// allow the system to enter power saving mode
|
|
|
|
CArchMiscWindows::removeBusyState(CArchMiscWindows::kSYSTEM |
|
|
|
|
CArchMiscWindows::kDISPLAY);
|
2002-07-15 15:01:36 +00:00
|
|
|
}
|
2004-03-13 17:13:55 +00:00
|
|
|
|
2004-03-28 14:07:58 +00:00
|
|
|
// uninstall fix key timer
|
|
|
|
if (m_fixTimer != NULL) {
|
|
|
|
EVENTQUEUE->removeHandler(CEvent::kTimer, m_fixTimer);
|
|
|
|
EVENTQUEUE->deleteTimer(m_fixTimer);
|
|
|
|
m_fixTimer = NULL;
|
|
|
|
}
|
|
|
|
|
2004-03-13 17:13:55 +00:00
|
|
|
// stop snooping the clipboard
|
|
|
|
ChangeClipboardChain(m_window, m_nextClipboardWindow);
|
|
|
|
m_nextClipboardWindow = NULL;
|
|
|
|
|
|
|
|
m_isOnScreen = m_isPrimary;
|
2002-07-15 15:01:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2003-09-02 22:05:47 +00:00
|
|
|
CMSWindowsScreen::enter()
|
2001-11-19 00:33:36 +00:00
|
|
|
{
|
2004-03-26 20:59:26 +00:00
|
|
|
m_desks->enter();
|
2003-09-02 22:05:47 +00:00
|
|
|
if (m_isPrimary) {
|
|
|
|
// enable special key sequences on win95 family
|
|
|
|
enableSpecialKeys(true);
|
|
|
|
|
|
|
|
// watch jump zones
|
|
|
|
m_setMode(kHOOK_WATCH_JUMP_ZONE);
|
|
|
|
|
|
|
|
// all messages prior to now are invalid
|
|
|
|
nextMark();
|
|
|
|
}
|
2002-07-15 15:01:36 +00:00
|
|
|
|
2003-09-02 22:05:47 +00:00
|
|
|
// now on screen
|
|
|
|
m_isOnScreen = true;
|
|
|
|
}
|
2001-11-19 00:33:36 +00:00
|
|
|
|
2003-09-02 22:05:47 +00:00
|
|
|
bool
|
|
|
|
CMSWindowsScreen::leave()
|
|
|
|
{
|
2004-03-08 20:53:32 +00:00
|
|
|
// get keyboard layout of foreground window. we'll use this
|
|
|
|
// keyboard layout for translating keys sent to clients.
|
|
|
|
HWND window = GetForegroundWindow();
|
|
|
|
DWORD thread = GetWindowThreadProcessId(window, NULL);
|
|
|
|
m_keyLayout = GetKeyboardLayout(thread);
|
|
|
|
|
|
|
|
// tell the key mapper about the keyboard layout
|
2004-03-26 20:59:26 +00:00
|
|
|
m_keyState->setKeyLayout(m_keyLayout);
|
2004-03-08 20:53:32 +00:00
|
|
|
|
|
|
|
// tell desk that we're leaving and tell it the keyboard layout
|
2004-03-26 20:59:26 +00:00
|
|
|
m_desks->leave(m_keyLayout);
|
2003-09-06 23:17:41 +00:00
|
|
|
|
2004-02-28 12:19:49 +00:00
|
|
|
if (m_isPrimary) {
|
2003-09-02 22:05:47 +00:00
|
|
|
// warp to center
|
|
|
|
warpCursor(m_xCenter, m_yCenter);
|
|
|
|
|
|
|
|
// disable special key sequences on win95 family
|
|
|
|
enableSpecialKeys(false);
|
|
|
|
|
|
|
|
// all messages prior to now are invalid
|
|
|
|
nextMark();
|
|
|
|
|
2004-02-28 12:19:49 +00:00
|
|
|
// capture events
|
2003-09-02 22:05:47 +00:00
|
|
|
m_setMode(kHOOK_RELAY_EVENTS);
|
2002-07-11 18:58:49 +00:00
|
|
|
}
|
2001-11-19 00:33:36 +00:00
|
|
|
|
2003-09-02 22:05:47 +00:00
|
|
|
// now off screen
|
|
|
|
m_isOnScreen = false;
|
|
|
|
|
|
|
|
return true;
|
2001-11-19 00:33:36 +00:00
|
|
|
}
|
|
|
|
|
2002-07-15 15:01:36 +00:00
|
|
|
bool
|
|
|
|
CMSWindowsScreen::setClipboard(ClipboardID, const IClipboard* src)
|
2001-11-19 00:33:36 +00:00
|
|
|
{
|
2002-07-15 15:01:36 +00:00
|
|
|
CMSWindowsClipboard dst(m_window);
|
|
|
|
if (src != NULL) {
|
|
|
|
// save clipboard data
|
|
|
|
return CClipboard::copy(&dst, src);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// assert clipboard ownership
|
|
|
|
if (!dst.open(0)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
dst.empty();
|
|
|
|
dst.close();
|
|
|
|
return true;
|
|
|
|
}
|
2001-11-19 00:33:36 +00:00
|
|
|
}
|
|
|
|
|
2002-07-15 15:01:36 +00:00
|
|
|
void
|
|
|
|
CMSWindowsScreen::checkClipboards()
|
2001-11-19 00:33:36 +00:00
|
|
|
{
|
2002-07-15 15:01:36 +00:00
|
|
|
// if we think we own the clipboard but we don't then somebody
|
|
|
|
// grabbed the clipboard on this screen without us knowing.
|
|
|
|
// tell the server that this screen grabbed the clipboard.
|
|
|
|
//
|
|
|
|
// this works around bugs in the clipboard viewer chain.
|
|
|
|
// sometimes NT will simply never send WM_DRAWCLIPBOARD
|
|
|
|
// messages for no apparent reason and rebooting fixes the
|
|
|
|
// problem. since we don't want a broken clipboard until the
|
|
|
|
// next reboot we do this double check. clipboard ownership
|
|
|
|
// won't be reflected on other screens until we leave but at
|
|
|
|
// least the clipboard itself will work.
|
Fixed several win32 bugs. First, synergy wasn't forwarding mouse
events to other hook functions, which broke some tools like objectbar.
Second, windows key processing was fixed. Previously pressing and
release the key would only send a press event, locking the user onto
the client window; also, the win32 server treated as a Meta modifier
instead of a Super modifier, which broke any use of it as any kind of
modifier key. Third, added hacks to support several key combinations
on windows 95/98/me that are treated specially by windows, including
Alt+Tab, Alt+Shift+Tab, Alt+Esc, Alt+Shift+Esc, Ctrl+Esc, and any
combination using the windows key like Win+E and Win+F but not
Ctrl+Alt+Del. Fourth, scroll lock only locking to the client (which
only happened when using a synergy server on windows) has been fixed;
unfortunately the solution causes a lot of screen redraws for some
reason. Finally, there's been a fix to clipboard handling that may
or may not fix a problem where the clipboard would stop transferring
between systems after a little while. I can't be sure if it fixes
the problem because I can't reproduce the problem.
2003-04-13 14:59:53 +00:00
|
|
|
if (m_ownClipboard && !CMSWindowsClipboard::isOwnedBySynergy()) {
|
2003-09-02 22:05:47 +00:00
|
|
|
LOG((CLOG_DEBUG "clipboard changed: lost ownership and no notification received"));
|
Fixed several win32 bugs. First, synergy wasn't forwarding mouse
events to other hook functions, which broke some tools like objectbar.
Second, windows key processing was fixed. Previously pressing and
release the key would only send a press event, locking the user onto
the client window; also, the win32 server treated as a Meta modifier
instead of a Super modifier, which broke any use of it as any kind of
modifier key. Third, added hacks to support several key combinations
on windows 95/98/me that are treated specially by windows, including
Alt+Tab, Alt+Shift+Tab, Alt+Esc, Alt+Shift+Esc, Ctrl+Esc, and any
combination using the windows key like Win+E and Win+F but not
Ctrl+Alt+Del. Fourth, scroll lock only locking to the client (which
only happened when using a synergy server on windows) has been fixed;
unfortunately the solution causes a lot of screen redraws for some
reason. Finally, there's been a fix to clipboard handling that may
or may not fix a problem where the clipboard would stop transferring
between systems after a little while. I can't be sure if it fixes
the problem because I can't reproduce the problem.
2003-04-13 14:59:53 +00:00
|
|
|
m_ownClipboard = false;
|
2004-02-28 12:19:49 +00:00
|
|
|
sendClipboardEvent(getClipboardGrabbedEvent(), kClipboardClipboard);
|
|
|
|
sendClipboardEvent(getClipboardGrabbedEvent(), kClipboardSelection);
|
2002-07-15 15:01:36 +00:00
|
|
|
}
|
2001-11-19 00:33:36 +00:00
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
2002-07-15 15:01:36 +00:00
|
|
|
CMSWindowsScreen::openScreensaver(bool notify)
|
2002-05-24 17:54:28 +00:00
|
|
|
{
|
2002-07-15 15:01:36 +00:00
|
|
|
assert(m_screensaver != NULL);
|
|
|
|
|
|
|
|
m_screensaverNotify = notify;
|
|
|
|
if (m_screensaverNotify) {
|
2004-03-26 20:59:26 +00:00
|
|
|
m_desks->installScreensaverHooks(true);
|
2002-07-15 15:01:36 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
m_screensaver->disable();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CMSWindowsScreen::closeScreensaver()
|
|
|
|
{
|
|
|
|
if (m_screensaver != NULL) {
|
|
|
|
if (m_screensaverNotify) {
|
2004-03-26 20:59:26 +00:00
|
|
|
m_desks->installScreensaverHooks(false);
|
2002-07-15 15:01:36 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
m_screensaver->enable();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_screensaverNotify = false;
|
2002-05-24 17:54:28 +00:00
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
2002-07-15 15:01:36 +00:00
|
|
|
CMSWindowsScreen::screensaver(bool activate)
|
|
|
|
{
|
|
|
|
assert(m_screensaver != NULL);
|
2003-09-02 22:05:47 +00:00
|
|
|
|
2002-07-15 15:01:36 +00:00
|
|
|
if (activate) {
|
|
|
|
m_screensaver->activate();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
m_screensaver->deactivate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2003-09-02 22:05:47 +00:00
|
|
|
CMSWindowsScreen::resetOptions()
|
2002-07-15 15:01:36 +00:00
|
|
|
{
|
2003-09-02 22:05:47 +00:00
|
|
|
// no options
|
|
|
|
}
|
2002-07-15 15:01:36 +00:00
|
|
|
|
2003-09-02 22:05:47 +00:00
|
|
|
void
|
|
|
|
CMSWindowsScreen::setOptions(const COptionsList&)
|
|
|
|
{
|
|
|
|
// no options
|
|
|
|
}
|
|
|
|
|
2004-02-28 12:19:49 +00:00
|
|
|
void
|
|
|
|
CMSWindowsScreen::setSequenceNumber(UInt32 seqNum)
|
|
|
|
{
|
|
|
|
m_sequenceNumber = seqNum;
|
|
|
|
}
|
|
|
|
|
2003-09-02 22:05:47 +00:00
|
|
|
bool
|
|
|
|
CMSWindowsScreen::isPrimary() const
|
|
|
|
{
|
|
|
|
return m_isPrimary;
|
2002-07-15 15:01:36 +00:00
|
|
|
}
|
|
|
|
|
2004-02-28 12:19:49 +00:00
|
|
|
void*
|
|
|
|
CMSWindowsScreen::getEventTarget() const
|
|
|
|
{
|
|
|
|
return const_cast<CMSWindowsScreen*>(this);
|
|
|
|
}
|
|
|
|
|
2002-07-15 15:01:36 +00:00
|
|
|
bool
|
|
|
|
CMSWindowsScreen::getClipboard(ClipboardID, IClipboard* dst) const
|
|
|
|
{
|
|
|
|
CMSWindowsClipboard src(m_window);
|
|
|
|
CClipboard::copy(dst, &src);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2003-09-02 22:05:47 +00:00
|
|
|
CMSWindowsScreen::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
|
2001-11-19 00:33:36 +00:00
|
|
|
{
|
|
|
|
assert(m_class != 0);
|
|
|
|
|
2002-06-19 17:03:29 +00:00
|
|
|
x = m_x;
|
|
|
|
y = m_y;
|
|
|
|
w = m_w;
|
|
|
|
h = m_h;
|
2001-11-19 00:33:36 +00:00
|
|
|
}
|
|
|
|
|
2002-07-11 18:58:49 +00:00
|
|
|
void
|
|
|
|
CMSWindowsScreen::getCursorPos(SInt32& x, SInt32& y) const
|
|
|
|
{
|
2004-03-26 20:59:26 +00:00
|
|
|
m_desks->getCursorPos(x, y);
|
2002-07-11 18:58:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2003-09-02 22:05:47 +00:00
|
|
|
CMSWindowsScreen::reconfigure(UInt32 activeSides)
|
2002-07-11 18:58:49 +00:00
|
|
|
{
|
2003-09-02 22:05:47 +00:00
|
|
|
assert(m_isPrimary);
|
|
|
|
|
2004-02-28 12:19:49 +00:00
|
|
|
LOG((CLOG_DEBUG "active sides: %x", activeSides));
|
2003-09-02 22:05:47 +00:00
|
|
|
m_setSides(activeSides);
|
2002-07-11 18:58:49 +00:00
|
|
|
}
|
|
|
|
|
2002-07-15 15:01:36 +00:00
|
|
|
void
|
2003-09-02 22:05:47 +00:00
|
|
|
CMSWindowsScreen::warpCursor(SInt32 x, SInt32 y)
|
2002-07-11 18:58:49 +00:00
|
|
|
{
|
2003-09-02 22:05:47 +00:00
|
|
|
// warp mouse
|
|
|
|
warpCursorNoFlush(x, y);
|
|
|
|
|
|
|
|
// remove all input events before and including warp
|
|
|
|
MSG msg;
|
|
|
|
while (PeekMessage(&msg, NULL, SYNERGY_MSG_INPUT_FIRST,
|
|
|
|
SYNERGY_MSG_INPUT_LAST, PM_REMOVE)) {
|
|
|
|
// do nothing
|
|
|
|
}
|
2002-07-15 15:01:36 +00:00
|
|
|
|
2003-09-02 22:05:47 +00:00
|
|
|
// save position as last position
|
|
|
|
m_xCursor = x;
|
|
|
|
m_yCursor = y;
|
|
|
|
}
|
|
|
|
|
|
|
|
SInt32
|
|
|
|
CMSWindowsScreen::getJumpZoneSize() const
|
|
|
|
{
|
|
|
|
return 1;
|
2002-07-15 15:01:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2003-09-02 22:05:47 +00:00
|
|
|
CMSWindowsScreen::isAnyMouseButtonDown() const
|
2002-07-15 15:01:36 +00:00
|
|
|
{
|
2003-09-02 22:05:47 +00:00
|
|
|
static const char* buttonToName[] = {
|
2004-03-26 20:59:26 +00:00
|
|
|
"<invalid>",
|
2003-09-02 22:05:47 +00:00
|
|
|
"Left Button",
|
|
|
|
"Middle Button",
|
|
|
|
"Right Button",
|
|
|
|
"X Button 1",
|
|
|
|
"X Button 2"
|
|
|
|
};
|
|
|
|
|
2004-03-26 20:59:26 +00:00
|
|
|
for (UInt32 i = 1; i < sizeof(m_buttons) / sizeof(m_buttons[0]); ++i) {
|
|
|
|
if (m_buttons[i]) {
|
2003-09-02 22:05:47 +00:00
|
|
|
LOG((CLOG_DEBUG "locked by \"%s\"", buttonToName[i]));
|
2002-07-18 16:58:08 +00:00
|
|
|
return true;
|
2002-07-15 15:01:36 +00:00
|
|
|
}
|
2003-09-02 22:05:47 +00:00
|
|
|
}
|
2002-07-15 15:01:36 +00:00
|
|
|
|
2003-09-02 22:05:47 +00:00
|
|
|
return false;
|
|
|
|
}
|
Fixed several win32 bugs. First, synergy wasn't forwarding mouse
events to other hook functions, which broke some tools like objectbar.
Second, windows key processing was fixed. Previously pressing and
release the key would only send a press event, locking the user onto
the client window; also, the win32 server treated as a Meta modifier
instead of a Super modifier, which broke any use of it as any kind of
modifier key. Third, added hacks to support several key combinations
on windows 95/98/me that are treated specially by windows, including
Alt+Tab, Alt+Shift+Tab, Alt+Esc, Alt+Shift+Esc, Ctrl+Esc, and any
combination using the windows key like Win+E and Win+F but not
Ctrl+Alt+Del. Fourth, scroll lock only locking to the client (which
only happened when using a synergy server on windows) has been fixed;
unfortunately the solution causes a lot of screen redraws for some
reason. Finally, there's been a fix to clipboard handling that may
or may not fix a problem where the clipboard would stop transferring
between systems after a little while. I can't be sure if it fixes
the problem because I can't reproduce the problem.
2003-04-13 14:59:53 +00:00
|
|
|
|
2004-02-28 12:19:49 +00:00
|
|
|
void
|
|
|
|
CMSWindowsScreen::getCursorCenter(SInt32& x, SInt32& y) const
|
|
|
|
{
|
|
|
|
x = m_xCenter;
|
|
|
|
y = m_yCenter;
|
|
|
|
}
|
|
|
|
|
2003-09-02 22:05:47 +00:00
|
|
|
void
|
|
|
|
CMSWindowsScreen::fakeMouseButton(ButtonID id, bool press) const
|
|
|
|
{
|
2004-03-26 20:59:26 +00:00
|
|
|
m_desks->fakeMouseButton(id, press);
|
2003-09-02 22:05:47 +00:00
|
|
|
}
|
2002-07-15 15:01:36 +00:00
|
|
|
|
2003-09-02 22:05:47 +00:00
|
|
|
void
|
|
|
|
CMSWindowsScreen::fakeMouseMove(SInt32 x, SInt32 y) const
|
|
|
|
{
|
2004-03-26 20:59:26 +00:00
|
|
|
m_desks->fakeMouseMove(x, y);
|
2002-07-11 18:58:49 +00:00
|
|
|
}
|
|
|
|
|
2004-05-02 08:04:15 +00:00
|
|
|
void
|
|
|
|
CMSWindowsScreen::fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const
|
|
|
|
{
|
|
|
|
m_desks->fakeMouseRelativeMove(dx, dy);
|
|
|
|
}
|
|
|
|
|
2002-07-11 18:58:49 +00:00
|
|
|
void
|
2003-09-02 22:05:47 +00:00
|
|
|
CMSWindowsScreen::fakeMouseWheel(SInt32 delta) const
|
2002-07-11 18:58:49 +00:00
|
|
|
{
|
2004-03-26 20:59:26 +00:00
|
|
|
m_desks->fakeMouseWheel(delta);
|
2003-09-02 22:05:47 +00:00
|
|
|
}
|
|
|
|
|
2004-03-26 20:59:26 +00:00
|
|
|
void
|
|
|
|
CMSWindowsScreen::updateKeys()
|
2003-09-02 22:05:47 +00:00
|
|
|
{
|
2004-03-26 20:59:26 +00:00
|
|
|
m_desks->updateKeys();
|
2003-09-02 22:05:47 +00:00
|
|
|
}
|
|
|
|
|
2004-02-28 12:19:49 +00:00
|
|
|
HINSTANCE
|
|
|
|
CMSWindowsScreen::openHookLibrary(const char* name)
|
2003-09-02 22:05:47 +00:00
|
|
|
{
|
2004-02-28 12:19:49 +00:00
|
|
|
// load the hook library
|
|
|
|
HINSTANCE hookLibrary = LoadLibrary(name);
|
|
|
|
if (hookLibrary == NULL) {
|
|
|
|
LOG((CLOG_ERR "Failed to load hook library; %s.dll is missing", name));
|
|
|
|
throw XScreenOpenFailure();
|
|
|
|
}
|
2003-09-02 22:05:47 +00:00
|
|
|
|
2004-02-28 12:19:49 +00:00
|
|
|
// look up functions
|
|
|
|
m_setSides = (SetSidesFunc)GetProcAddress(hookLibrary, "setSides");
|
|
|
|
m_setZone = (SetZoneFunc)GetProcAddress(hookLibrary, "setZone");
|
|
|
|
m_setMode = (SetModeFunc)GetProcAddress(hookLibrary, "setMode");
|
|
|
|
m_init = (InitFunc)GetProcAddress(hookLibrary, "init");
|
|
|
|
m_cleanup = (CleanupFunc)GetProcAddress(hookLibrary, "cleanup");
|
|
|
|
if (m_setSides == NULL ||
|
|
|
|
m_setZone == NULL ||
|
|
|
|
m_setMode == NULL ||
|
|
|
|
m_init == NULL ||
|
2004-03-26 20:59:26 +00:00
|
|
|
m_cleanup == NULL) {
|
2004-02-28 12:19:49 +00:00
|
|
|
LOG((CLOG_ERR "Invalid hook library; use a newer %s.dll", name));
|
|
|
|
throw XScreenOpenFailure();
|
|
|
|
}
|
2003-09-02 22:05:47 +00:00
|
|
|
|
2004-02-28 12:19:49 +00:00
|
|
|
// initialize hook library
|
|
|
|
if (m_init(GetCurrentThreadId()) == 0) {
|
|
|
|
LOG((CLOG_ERR "Cannot initialize hook library; is synergy already running?"));
|
|
|
|
throw XScreenOpenFailure();
|
|
|
|
}
|
|
|
|
|
|
|
|
return hookLibrary;
|
2002-07-11 18:58:49 +00:00
|
|
|
}
|
|
|
|
|
2004-02-28 12:19:49 +00:00
|
|
|
void
|
|
|
|
CMSWindowsScreen::closeHookLibrary(HINSTANCE hookLibrary) const
|
2002-07-15 15:01:36 +00:00
|
|
|
{
|
2004-02-28 12:19:49 +00:00
|
|
|
if (hookLibrary != NULL) {
|
|
|
|
m_cleanup();
|
|
|
|
FreeLibrary(hookLibrary);
|
|
|
|
}
|
|
|
|
}
|
2002-07-15 15:01:36 +00:00
|
|
|
|
2004-02-28 12:19:49 +00:00
|
|
|
HCURSOR
|
|
|
|
CMSWindowsScreen::createBlankCursor() const
|
|
|
|
{
|
|
|
|
// create a transparent cursor
|
|
|
|
int cw = GetSystemMetrics(SM_CXCURSOR);
|
|
|
|
int ch = GetSystemMetrics(SM_CYCURSOR);
|
|
|
|
UInt8* cursorAND = new UInt8[ch * ((cw + 31) >> 2)];
|
|
|
|
UInt8* cursorXOR = new UInt8[ch * ((cw + 31) >> 2)];
|
|
|
|
memset(cursorAND, 0xff, ch * ((cw + 31) >> 2));
|
|
|
|
memset(cursorXOR, 0x00, ch * ((cw + 31) >> 2));
|
|
|
|
HCURSOR c = CreateCursor(s_instance, 0, 0, cw, ch, cursorAND, cursorXOR);
|
|
|
|
delete[] cursorXOR;
|
|
|
|
delete[] cursorAND;
|
|
|
|
return c;
|
|
|
|
}
|
2002-07-15 15:01:36 +00:00
|
|
|
|
2004-02-28 12:19:49 +00:00
|
|
|
void
|
|
|
|
CMSWindowsScreen::destroyCursor(HCURSOR cursor) const
|
|
|
|
{
|
|
|
|
if (cursor != NULL) {
|
|
|
|
DestroyCursor(cursor);
|
2002-07-15 15:01:36 +00:00
|
|
|
}
|
2004-02-28 12:19:49 +00:00
|
|
|
}
|
2002-07-15 15:01:36 +00:00
|
|
|
|
2004-02-28 12:19:49 +00:00
|
|
|
ATOM
|
|
|
|
CMSWindowsScreen::createWindowClass() const
|
|
|
|
{
|
|
|
|
WNDCLASSEX classInfo;
|
|
|
|
classInfo.cbSize = sizeof(classInfo);
|
|
|
|
classInfo.style = CS_DBLCLKS | CS_NOCLOSE;
|
|
|
|
classInfo.lpfnWndProc = &CMSWindowsScreen::wndProc;
|
|
|
|
classInfo.cbClsExtra = 0;
|
|
|
|
classInfo.cbWndExtra = 0;
|
|
|
|
classInfo.hInstance = s_instance;
|
|
|
|
classInfo.hIcon = NULL;
|
|
|
|
classInfo.hCursor = NULL;
|
|
|
|
classInfo.hbrBackground = NULL;
|
|
|
|
classInfo.lpszMenuName = NULL;
|
|
|
|
classInfo.lpszClassName = "Synergy";
|
|
|
|
classInfo.hIconSm = NULL;
|
|
|
|
return RegisterClassEx(&classInfo);
|
|
|
|
}
|
2002-07-15 15:01:36 +00:00
|
|
|
|
2004-02-28 12:19:49 +00:00
|
|
|
void
|
|
|
|
CMSWindowsScreen::destroyClass(ATOM windowClass) const
|
|
|
|
{
|
|
|
|
if (windowClass != 0) {
|
2004-04-11 19:15:09 +00:00
|
|
|
UnregisterClass(reinterpret_cast<LPCTSTR>(windowClass), s_instance);
|
2002-07-15 15:01:36 +00:00
|
|
|
}
|
2004-02-28 12:19:49 +00:00
|
|
|
}
|
2002-07-15 15:01:36 +00:00
|
|
|
|
2004-02-28 12:19:49 +00:00
|
|
|
HWND
|
|
|
|
CMSWindowsScreen::createWindow(ATOM windowClass, const char* name) const
|
|
|
|
{
|
|
|
|
HWND window = CreateWindowEx(WS_EX_TOPMOST |
|
2002-07-15 15:01:36 +00:00
|
|
|
WS_EX_TRANSPARENT |
|
|
|
|
WS_EX_TOOLWINDOW,
|
2004-04-11 19:15:09 +00:00
|
|
|
reinterpret_cast<LPCTSTR>(windowClass),
|
2004-02-28 12:19:49 +00:00
|
|
|
name,
|
2002-07-15 15:01:36 +00:00
|
|
|
WS_POPUP,
|
|
|
|
0, 0, 1, 1,
|
|
|
|
NULL, NULL,
|
2004-02-28 12:19:49 +00:00
|
|
|
s_instance,
|
2002-07-15 15:01:36 +00:00
|
|
|
NULL);
|
2004-02-28 12:19:49 +00:00
|
|
|
if (window == NULL) {
|
2002-10-15 21:29:44 +00:00
|
|
|
LOG((CLOG_ERR "failed to create window: %d", GetLastError()));
|
2004-02-28 12:19:49 +00:00
|
|
|
throw XScreenOpenFailure();
|
2002-07-15 15:01:36 +00:00
|
|
|
}
|
2004-02-28 12:19:49 +00:00
|
|
|
return window;
|
|
|
|
}
|
2002-07-15 15:01:36 +00:00
|
|
|
|
2004-02-28 12:19:49 +00:00
|
|
|
void
|
|
|
|
CMSWindowsScreen::destroyWindow(HWND hwnd) const
|
|
|
|
{
|
|
|
|
if (hwnd != NULL) {
|
|
|
|
DestroyWindow(hwnd);
|
2002-07-15 15:01:36 +00:00
|
|
|
}
|
2004-02-28 12:19:49 +00:00
|
|
|
}
|
2002-07-15 15:01:36 +00:00
|
|
|
|
2004-02-28 12:19:49 +00:00
|
|
|
void
|
|
|
|
CMSWindowsScreen::sendEvent(CEvent::Type type, void* data)
|
|
|
|
{
|
|
|
|
EVENTQUEUE->addEvent(CEvent(type, getEventTarget(), data));
|
|
|
|
}
|
2002-07-15 15:01:36 +00:00
|
|
|
|
2004-02-28 12:19:49 +00:00
|
|
|
void
|
|
|
|
CMSWindowsScreen::sendClipboardEvent(CEvent::Type type, ClipboardID id)
|
|
|
|
{
|
|
|
|
CClipboardInfo* info = (CClipboardInfo*)malloc(sizeof(CClipboardInfo));
|
|
|
|
info->m_id = id;
|
|
|
|
info->m_sequenceNumber = m_sequenceNumber;
|
|
|
|
sendEvent(type, info);
|
2002-07-15 15:01:36 +00:00
|
|
|
}
|
|
|
|
|
2003-09-02 22:05:47 +00:00
|
|
|
void
|
2004-02-28 12:19:49 +00:00
|
|
|
CMSWindowsScreen::handleSystemEvent(const CEvent& event, void*)
|
2003-09-02 22:05:47 +00:00
|
|
|
{
|
2004-02-28 12:19:49 +00:00
|
|
|
MSG* msg = reinterpret_cast<MSG*>(event.getData());
|
|
|
|
assert(msg != NULL);
|
2003-09-02 22:05:47 +00:00
|
|
|
|
2004-02-28 12:19:49 +00:00
|
|
|
if (CArchMiscWindows::processDialog(msg)) {
|
|
|
|
return;
|
2003-09-02 22:05:47 +00:00
|
|
|
}
|
2004-02-28 12:19:49 +00:00
|
|
|
if (onPreDispatch(msg->hwnd, msg->message, msg->wParam, msg->lParam)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
TranslateMessage(msg);
|
|
|
|
DispatchMessage(msg);
|
2003-09-02 22:05:47 +00:00
|
|
|
}
|
|
|
|
|
2004-03-26 20:59:26 +00:00
|
|
|
void
|
|
|
|
CMSWindowsScreen::updateButtons()
|
|
|
|
{
|
|
|
|
m_buttons[kButtonNone] = false;
|
|
|
|
m_buttons[kButtonLeft] = (GetKeyState(VK_LBUTTON) < 0);
|
|
|
|
m_buttons[kButtonMiddle] = (GetKeyState(VK_MBUTTON) < 0);
|
|
|
|
m_buttons[kButtonRight] = (GetKeyState(VK_RBUTTON) < 0);
|
|
|
|
m_buttons[kButtonExtra0 + 0] = (GetKeyState(VK_XBUTTON1) < 0);
|
|
|
|
m_buttons[kButtonExtra0 + 1] = (GetKeyState(VK_XBUTTON2) < 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
IKeyState*
|
|
|
|
CMSWindowsScreen::getKeyState() const
|
|
|
|
{
|
|
|
|
return m_keyState;
|
|
|
|
}
|
|
|
|
|
2003-09-02 22:05:47 +00:00
|
|
|
bool
|
|
|
|
CMSWindowsScreen::onPreDispatch(HWND hwnd,
|
|
|
|
UINT message, WPARAM wParam, LPARAM lParam)
|
2002-06-08 21:48:00 +00:00
|
|
|
{
|
2003-09-02 22:05:47 +00:00
|
|
|
// handle event
|
|
|
|
switch (message) {
|
|
|
|
case SYNERGY_MSG_SCREEN_SAVER:
|
|
|
|
return onScreensaver(wParam != 0);
|
2004-03-28 14:07:58 +00:00
|
|
|
|
|
|
|
case SYNERGY_MSG_DEBUG:
|
2004-04-05 21:08:49 +00:00
|
|
|
LOG((CLOG_DEBUG1 "hook: 0x%08x 0x%08x", wParam, lParam));
|
2004-03-28 14:07:58 +00:00
|
|
|
return true;
|
2003-09-02 22:05:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (m_isPrimary) {
|
|
|
|
return onPreDispatchPrimary(hwnd, message, wParam, lParam);
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
CMSWindowsScreen::onPreDispatchPrimary(HWND,
|
|
|
|
UINT message, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
|
|
|
// handle event
|
|
|
|
switch (message) {
|
|
|
|
case SYNERGY_MSG_MARK:
|
|
|
|
return onMark(static_cast<UInt32>(wParam));
|
|
|
|
|
|
|
|
case SYNERGY_MSG_KEY:
|
|
|
|
return onKey(wParam, lParam);
|
|
|
|
|
|
|
|
case SYNERGY_MSG_MOUSE_BUTTON:
|
|
|
|
return onMouseButton(wParam, lParam);
|
|
|
|
|
|
|
|
case SYNERGY_MSG_MOUSE_MOVE:
|
|
|
|
return onMouseMove(static_cast<SInt32>(wParam),
|
|
|
|
static_cast<SInt32>(lParam));
|
|
|
|
|
|
|
|
case SYNERGY_MSG_MOUSE_WHEEL:
|
|
|
|
return onMouseWheel(static_cast<SInt32>(wParam));
|
|
|
|
|
|
|
|
case SYNERGY_MSG_PRE_WARP:
|
|
|
|
{
|
|
|
|
// save position to compute delta of next motion
|
|
|
|
m_xCursor = static_cast<SInt32>(wParam);
|
|
|
|
m_yCursor = static_cast<SInt32>(lParam);
|
|
|
|
|
|
|
|
// we warped the mouse. discard events until we find the
|
|
|
|
// matching post warp event. see warpCursorNoFlush() for
|
|
|
|
// where the events are sent. we discard the matching
|
|
|
|
// post warp event and can be sure we've skipped the warp
|
|
|
|
// event.
|
|
|
|
MSG msg;
|
|
|
|
do {
|
|
|
|
GetMessage(&msg, NULL, SYNERGY_MSG_MOUSE_MOVE,
|
|
|
|
SYNERGY_MSG_POST_WARP);
|
|
|
|
} while (msg.message != SYNERGY_MSG_POST_WARP);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case SYNERGY_MSG_POST_WARP:
|
|
|
|
LOG((CLOG_WARN "unmatched post warp"));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2004-02-28 12:19:49 +00:00
|
|
|
CMSWindowsScreen::onEvent(HWND, UINT msg,
|
|
|
|
WPARAM wParam, LPARAM lParam, LRESULT* result)
|
2003-09-02 22:05:47 +00:00
|
|
|
{
|
2004-02-28 12:19:49 +00:00
|
|
|
switch (msg) {
|
2003-09-02 22:05:47 +00:00
|
|
|
case WM_QUERYENDSESSION:
|
|
|
|
if (m_is95Family) {
|
|
|
|
*result = TRUE;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_ENDSESSION:
|
|
|
|
if (m_is95Family) {
|
|
|
|
if (wParam == TRUE && lParam == 0) {
|
2004-02-28 12:19:49 +00:00
|
|
|
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
|
2003-09-02 22:05:47 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_DRAWCLIPBOARD:
|
|
|
|
LOG((CLOG_DEBUG "clipboard was taken"));
|
|
|
|
|
|
|
|
// first pass on the message
|
|
|
|
if (m_nextClipboardWindow != NULL) {
|
2004-02-28 12:19:49 +00:00
|
|
|
SendMessage(m_nextClipboardWindow, msg, wParam, lParam);
|
2003-09-02 22:05:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// now handle the message
|
|
|
|
return onClipboardChange();
|
|
|
|
|
|
|
|
case WM_CHANGECBCHAIN:
|
|
|
|
if (m_nextClipboardWindow == (HWND)wParam) {
|
|
|
|
m_nextClipboardWindow = (HWND)lParam;
|
|
|
|
LOG((CLOG_DEBUG "clipboard chain: new next: 0x%08x", m_nextClipboardWindow));
|
|
|
|
}
|
|
|
|
else if (m_nextClipboardWindow != NULL) {
|
2004-02-28 12:19:49 +00:00
|
|
|
LOG((CLOG_DEBUG "clipboard chain: forward: %d 0x%08x 0x%08x", msg, wParam, lParam));
|
|
|
|
SendMessage(m_nextClipboardWindow, msg, wParam, lParam);
|
2003-09-02 22:05:47 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case WM_DISPLAYCHANGE:
|
|
|
|
return onDisplayChange();
|
2004-03-13 17:13:55 +00:00
|
|
|
|
|
|
|
case WM_POWERBROADCAST:
|
|
|
|
switch (wParam) {
|
|
|
|
case PBT_APMRESUMEAUTOMATIC:
|
|
|
|
case PBT_APMRESUMECRITICAL:
|
|
|
|
case PBT_APMRESUMESUSPEND:
|
|
|
|
if (m_resume != NULL) {
|
|
|
|
m_resume->run();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PBT_APMSUSPEND:
|
|
|
|
if (m_suspend != NULL) {
|
|
|
|
m_suspend->run();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
*result = TRUE;
|
|
|
|
return true;
|
2003-09-02 22:05:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
CMSWindowsScreen::onMark(UInt32 mark)
|
|
|
|
{
|
|
|
|
m_markReceived = mark;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
CMSWindowsScreen::onKey(WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
2004-03-26 20:59:26 +00:00
|
|
|
LOG((CLOG_DEBUG1 "event: Key char=%d, vk=0x%02x, lParam=0x%08x", (wParam & 0xff00u) >> 8, wParam & 0xffu, lParam));
|
2004-03-08 20:53:32 +00:00
|
|
|
|
2004-03-28 14:07:58 +00:00
|
|
|
// fix up key state
|
|
|
|
fixKeys();
|
|
|
|
|
|
|
|
// get key info
|
2004-03-26 20:59:26 +00:00
|
|
|
KeyButton button = (KeyButton)((lParam & 0x01ff0000) >> 16);
|
2004-03-28 14:07:58 +00:00
|
|
|
bool down = ((lParam & 0xc0000000u) == 0x00000000u);
|
|
|
|
bool up = ((lParam & 0x80000000u) == 0x80000000u);
|
|
|
|
bool wasDown = isKeyDown(button);
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
// update key state. ignore key repeats.
|
|
|
|
if (down) {
|
2004-03-26 20:59:26 +00:00
|
|
|
m_keyState->setKeyDown(button, true);
|
2004-03-17 20:59:25 +00:00
|
|
|
}
|
2004-03-28 14:07:58 +00:00
|
|
|
else if (up) {
|
2004-03-26 20:59:26 +00:00
|
|
|
m_keyState->setKeyDown(button, false);
|
2004-03-17 20:59:25 +00:00
|
|
|
}
|
|
|
|
|
2004-03-28 14:07:58 +00:00
|
|
|
// schedule a timer if we need to fix keys later
|
|
|
|
scheduleFixKeys();
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|
2003-09-02 22:05:47 +00:00
|
|
|
// ignore message if posted prior to last mark change
|
|
|
|
if (!ignore()) {
|
|
|
|
// check for ctrl+alt+del emulation
|
2004-03-26 20:59:26 +00:00
|
|
|
UINT virtKey = (wParam & 0xffu);
|
2004-03-28 14:07:58 +00:00
|
|
|
if ((virtKey == VK_PAUSE || virtKey == VK_CANCEL) && ctrlAlt) {
|
2003-09-02 22:05:47 +00:00
|
|
|
LOG((CLOG_DEBUG "emulate ctrl+alt+del"));
|
2004-03-26 20:59:26 +00:00
|
|
|
// switch wParam and lParam to be as if VK_DELETE was
|
|
|
|
// pressed or released
|
|
|
|
wParam = VK_DELETE;
|
|
|
|
lParam &= 0xfe000000;
|
|
|
|
lParam |= m_keyState->virtualKeyToButton(wParam) << 16;
|
|
|
|
lParam |= 0x00000001;
|
2003-09-02 22:05:47 +00:00
|
|
|
}
|
|
|
|
|
2004-03-26 20:59:26 +00:00
|
|
|
// process key
|
2003-09-02 22:05:47 +00:00
|
|
|
KeyModifierMask mask;
|
2004-03-26 20:59:26 +00:00
|
|
|
KeyID key = m_keyState->mapKeyFromEvent(wParam, lParam, &mask);
|
|
|
|
button = static_cast<KeyButton>((lParam & 0x01ff0000u) >> 16);
|
|
|
|
if (key != kKeyNone) {
|
2004-03-28 14:07:58 +00:00
|
|
|
// fix up key. 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) {
|
|
|
|
switch (virtKey) {
|
|
|
|
case VK_LSHIFT:
|
|
|
|
case VK_RSHIFT:
|
|
|
|
case VK_SHIFT:
|
|
|
|
case VK_LCONTROL:
|
|
|
|
case VK_RCONTROL:
|
|
|
|
case VK_CONTROL:
|
|
|
|
case VK_LMENU:
|
|
|
|
case VK_RMENU:
|
|
|
|
case VK_MENU:
|
|
|
|
case VK_CAPITAL:
|
|
|
|
case VK_NUMLOCK:
|
|
|
|
case VK_SCROLL:
|
|
|
|
case VK_LWIN:
|
|
|
|
case VK_RWIN:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
m_keyState->sendKeyEvent(getEventTarget(),
|
|
|
|
true, false, key, mask, 1, button);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// do it
|
2004-03-26 20:59:26 +00:00
|
|
|
m_keyState->sendKeyEvent(getEventTarget(),
|
2004-03-28 14:07:58 +00:00
|
|
|
((lParam & 0x80000000u) == 0),
|
|
|
|
((lParam & 0x40000000u) == 1),
|
2004-03-26 20:59:26 +00:00
|
|
|
key, mask, (SInt32)(lParam & 0xffff), button);
|
2003-09-02 22:05:47 +00:00
|
|
|
}
|
|
|
|
else {
|
2004-03-26 20:59:26 +00:00
|
|
|
LOG((CLOG_DEBUG2 "event: cannot map key"));
|
2003-09-02 22:05:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
CMSWindowsScreen::onMouseButton(WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
|
|
|
// get which button
|
2004-05-01 08:56:24 +00:00
|
|
|
bool pressed = mapPressFromEvent(wParam, lParam);
|
|
|
|
ButtonID button = mapButtonFromEvent(wParam, lParam);
|
2003-09-02 22:05:47 +00:00
|
|
|
|
2004-03-26 20:59:26 +00:00
|
|
|
// keep our shadow key state up to date
|
|
|
|
if (button >= kButtonLeft && button <= kButtonExtra0 + 1) {
|
|
|
|
if (pressed) {
|
|
|
|
m_buttons[button] = true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
m_buttons[button] = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-09-02 22:05:47 +00:00
|
|
|
// ignore message if posted prior to last mark change
|
|
|
|
if (!ignore()) {
|
2004-05-01 08:56:24 +00:00
|
|
|
if (pressed) {
|
2003-09-02 22:05:47 +00:00
|
|
|
LOG((CLOG_DEBUG1 "event: button press button=%d", button));
|
|
|
|
if (button != kButtonNone) {
|
2004-02-28 12:19:49 +00:00
|
|
|
sendEvent(getButtonDownEvent(), CButtonInfo::alloc(button));
|
2003-09-02 22:05:47 +00:00
|
|
|
}
|
2004-05-01 08:56:24 +00:00
|
|
|
}
|
|
|
|
else {
|
2003-09-02 22:05:47 +00:00
|
|
|
LOG((CLOG_DEBUG1 "event: button release button=%d", button));
|
|
|
|
if (button != kButtonNone) {
|
2004-02-28 12:19:49 +00:00
|
|
|
sendEvent(getButtonUpEvent(), CButtonInfo::alloc(button));
|
2003-09-02 22:05:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
CMSWindowsScreen::onMouseMove(SInt32 mx, SInt32 my)
|
|
|
|
{
|
|
|
|
// compute motion delta (relative to the last known
|
|
|
|
// mouse position)
|
|
|
|
SInt32 x = mx - m_xCursor;
|
|
|
|
SInt32 y = my - m_yCursor;
|
|
|
|
|
|
|
|
// ignore if the mouse didn't move or if message posted prior
|
|
|
|
// to last mark change.
|
|
|
|
if (ignore() || (x == 0 && y == 0)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// save position to compute delta of next motion
|
|
|
|
m_xCursor = mx;
|
|
|
|
m_yCursor = my;
|
|
|
|
|
|
|
|
if (m_isOnScreen) {
|
|
|
|
// motion on primary screen
|
2004-02-28 12:19:49 +00:00
|
|
|
sendEvent(getMotionOnPrimaryEvent(),
|
|
|
|
CMotionInfo::alloc(m_xCursor, m_yCursor));
|
2002-07-15 15:01:36 +00:00
|
|
|
}
|
|
|
|
else {
|
2003-09-02 22:05:47 +00:00
|
|
|
// motion on secondary screen. warp mouse back to
|
|
|
|
// center.
|
|
|
|
warpCursorNoFlush(m_xCenter, m_yCenter);
|
|
|
|
|
|
|
|
// examine the motion. if it's about the distance
|
|
|
|
// from the center of the screen to an edge then
|
|
|
|
// it's probably a bogus motion that we want to
|
|
|
|
// ignore (see warpCursorNoFlush() for a further
|
|
|
|
// description).
|
|
|
|
static SInt32 bogusZoneSize = 10;
|
|
|
|
if (-x + bogusZoneSize > m_xCenter - m_x ||
|
|
|
|
x + bogusZoneSize > m_x + m_w - m_xCenter ||
|
|
|
|
-y + bogusZoneSize > m_yCenter - m_y ||
|
|
|
|
y + bogusZoneSize > m_y + m_h - m_yCenter) {
|
|
|
|
LOG((CLOG_DEBUG "dropped bogus motion %+d,%+d", x, y));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// send motion
|
2004-02-28 12:19:49 +00:00
|
|
|
sendEvent(getMotionOnSecondaryEvent(), CMotionInfo::alloc(x, y));
|
2003-09-02 22:05:47 +00:00
|
|
|
}
|
2002-07-15 15:01:36 +00:00
|
|
|
}
|
2003-09-02 22:05:47 +00:00
|
|
|
|
|
|
|
return true;
|
2002-06-08 21:48:00 +00:00
|
|
|
}
|
|
|
|
|
2003-09-02 22:05:47 +00:00
|
|
|
bool
|
|
|
|
CMSWindowsScreen::onMouseWheel(SInt32 delta)
|
2002-06-08 21:48:00 +00:00
|
|
|
{
|
2003-09-02 22:05:47 +00:00
|
|
|
// ignore message if posted prior to last mark change
|
|
|
|
if (!ignore()) {
|
|
|
|
LOG((CLOG_DEBUG1 "event: button wheel delta=%d", delta));
|
2004-02-28 12:19:49 +00:00
|
|
|
sendEvent(getWheelEvent(), CWheelInfo::alloc(delta));
|
2002-06-08 21:48:00 +00:00
|
|
|
}
|
2003-09-02 22:05:47 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
CMSWindowsScreen::onScreensaver(bool activated)
|
|
|
|
{
|
|
|
|
// ignore this message if there are any other screen saver
|
|
|
|
// messages already in the queue. this is important because
|
|
|
|
// our checkStarted() function has a deliberate delay, so it
|
|
|
|
// can't respond to events at full CPU speed and will fall
|
|
|
|
// behind if a lot of screen saver events are generated.
|
|
|
|
// that can easily happen because windows will continually
|
|
|
|
// send SC_SCREENSAVE until the screen saver starts, even if
|
|
|
|
// the screen saver is disabled!
|
|
|
|
MSG msg;
|
|
|
|
if (PeekMessage(&msg, NULL, SYNERGY_MSG_SCREEN_SAVER,
|
|
|
|
SYNERGY_MSG_SCREEN_SAVER, PM_NOREMOVE)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (activated) {
|
|
|
|
if (m_screensaver->checkStarted(SYNERGY_MSG_SCREEN_SAVER, FALSE, 0)) {
|
2004-02-28 12:19:49 +00:00
|
|
|
sendEvent(getScreensaverActivatedEvent());
|
2004-03-13 17:13:55 +00:00
|
|
|
|
|
|
|
// enable display power down
|
|
|
|
CArchMiscWindows::removeBusyState(CArchMiscWindows::kDISPLAY);
|
2003-09-02 22:05:47 +00:00
|
|
|
}
|
2002-07-15 15:01:36 +00:00
|
|
|
}
|
2002-06-08 21:48:00 +00:00
|
|
|
else {
|
2004-02-28 12:19:49 +00:00
|
|
|
sendEvent(getScreensaverDeactivatedEvent());
|
2004-03-13 17:13:55 +00:00
|
|
|
|
|
|
|
// disable display power down
|
|
|
|
CArchMiscWindows::addBusyState(CArchMiscWindows::kDISPLAY);
|
2003-09-02 22:05:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
CMSWindowsScreen::onDisplayChange()
|
|
|
|
{
|
|
|
|
// screen resolution may have changed. save old shape.
|
|
|
|
SInt32 xOld = m_x, yOld = m_y, wOld = m_w, hOld = m_h;
|
|
|
|
|
|
|
|
// update shape
|
|
|
|
updateScreenShape();
|
|
|
|
|
|
|
|
// do nothing if resolution hasn't changed
|
|
|
|
if (xOld != m_x || yOld != m_y || wOld != m_w || hOld != m_h) {
|
|
|
|
if (m_isPrimary) {
|
|
|
|
// warp mouse to center if off screen
|
|
|
|
if (!m_isOnScreen) {
|
|
|
|
warpCursor(m_xCenter, m_yCenter);
|
|
|
|
}
|
|
|
|
|
|
|
|
// tell hook about resize if on screen
|
|
|
|
else {
|
|
|
|
m_setZone(m_x, m_y, m_w, m_h, getJumpZoneSize());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// send new screen info
|
2004-02-28 12:19:49 +00:00
|
|
|
sendEvent(getShapeChangedEvent());
|
2003-09-02 22:05:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
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;
|
2004-02-28 12:19:49 +00:00
|
|
|
sendClipboardEvent(getClipboardGrabbedEvent(), kClipboardClipboard);
|
|
|
|
sendClipboardEvent(getClipboardGrabbedEvent(), kClipboardSelection);
|
2003-09-02 22:05:47 +00:00
|
|
|
}
|
2003-02-16 19:50:36 +00:00
|
|
|
}
|
|
|
|
else {
|
2003-09-02 22:05:47 +00:00
|
|
|
LOG((CLOG_DEBUG "clipboard changed: synergy owned"));
|
|
|
|
m_ownClipboard = true;
|
2003-02-16 19:50:36 +00:00
|
|
|
}
|
2003-09-02 22:05:47 +00:00
|
|
|
|
|
|
|
return true;
|
2002-06-23 21:53:31 +00:00
|
|
|
}
|
|
|
|
|
2003-09-02 22:05:47 +00:00
|
|
|
void
|
|
|
|
CMSWindowsScreen::warpCursorNoFlush(SInt32 x, SInt32 y)
|
|
|
|
{
|
|
|
|
// send an event that we can recognize before the mouse warp
|
2004-02-28 12:19:49 +00:00
|
|
|
PostThreadMessage(GetCurrentThreadId(), SYNERGY_MSG_PRE_WARP, x, y);
|
2003-09-02 22:05:47 +00:00
|
|
|
|
|
|
|
// warp mouse. hopefully this inserts a mouse motion event
|
|
|
|
// between the previous message and the following message.
|
|
|
|
SetCursorPos(x, y);
|
|
|
|
|
|
|
|
// yield the CPU. there's a race condition when warping:
|
|
|
|
// a hardware mouse event occurs
|
|
|
|
// the mouse hook is not called because that process doesn't have the CPU
|
|
|
|
// we send PRE_WARP, SetCursorPos(), send POST_WARP
|
|
|
|
// we process all of those events and update m_x, m_y
|
|
|
|
// we finish our time slice
|
|
|
|
// the hook is called
|
|
|
|
// the hook sends us a mouse event from the pre-warp position
|
|
|
|
// we get the CPU
|
|
|
|
// we compute a bogus warp
|
|
|
|
// we need the hook to process all mouse events that occur
|
|
|
|
// before we warp before we do the warp but i'm not sure how
|
|
|
|
// to guarantee that. yielding the CPU here may reduce the
|
|
|
|
// chance of undesired behavior. we'll also check for very
|
|
|
|
// large motions that look suspiciously like about half width
|
|
|
|
// or height of the screen.
|
|
|
|
ARCH->sleep(0.0);
|
|
|
|
|
|
|
|
// send an event that we can recognize after the mouse warp
|
2004-02-28 12:19:49 +00:00
|
|
|
PostThreadMessage(GetCurrentThreadId(), SYNERGY_MSG_POST_WARP, 0, 0);
|
2003-09-02 22:05:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CMSWindowsScreen::nextMark()
|
|
|
|
{
|
|
|
|
// next mark
|
|
|
|
++m_mark;
|
|
|
|
|
|
|
|
// mark point in message queue where the mark was changed
|
2004-02-28 12:19:49 +00:00
|
|
|
PostThreadMessage(GetCurrentThreadId(), SYNERGY_MSG_MARK, m_mark, 0);
|
2003-09-02 22:05:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
CMSWindowsScreen::ignore() const
|
|
|
|
{
|
|
|
|
return (m_mark != m_markReceived);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2004-02-28 12:19:49 +00:00
|
|
|
CMSWindowsScreen::updateScreenShape()
|
2003-09-02 22:05:47 +00:00
|
|
|
{
|
2004-02-28 12:19:49 +00:00
|
|
|
// get shape
|
|
|
|
m_x = GetSystemMetrics(SM_XVIRTUALSCREEN);
|
|
|
|
m_y = GetSystemMetrics(SM_YVIRTUALSCREEN);
|
|
|
|
m_w = GetSystemMetrics(SM_CXVIRTUALSCREEN);
|
|
|
|
m_h = GetSystemMetrics(SM_CYVIRTUALSCREEN);
|
|
|
|
|
|
|
|
// get center for cursor
|
|
|
|
m_xCenter = GetSystemMetrics(SM_CXSCREEN) >> 1;
|
|
|
|
m_yCenter = GetSystemMetrics(SM_CYSCREEN) >> 1;
|
|
|
|
|
|
|
|
// check for multiple monitors
|
|
|
|
m_multimon = (m_w != GetSystemMetrics(SM_CXSCREEN) ||
|
|
|
|
m_h != GetSystemMetrics(SM_CYSCREEN));
|
|
|
|
LOG((CLOG_DEBUG "screen shape: %d,%d %dx%d %s", m_x, m_y, m_w, m_h, m_multimon ? "(multi-monitor)" : ""));
|
2004-03-26 20:59:26 +00:00
|
|
|
|
|
|
|
// tell the desks
|
|
|
|
m_desks->setShape(m_x, m_y, m_w, m_h, m_xCenter, m_yCenter, m_multimon);
|
2003-09-02 22:05:47 +00:00
|
|
|
}
|
2002-07-12 20:41:23 +00:00
|
|
|
|
2003-09-02 22:05:47 +00:00
|
|
|
void
|
|
|
|
CMSWindowsScreen::enableSpecialKeys(bool enable) const
|
|
|
|
{
|
|
|
|
// enable/disable ctrl+alt+del, alt+tab, etc on win95 family.
|
|
|
|
// since the win95 family doesn't support low-level hooks, we
|
|
|
|
// use this undocumented feature to suppress normal handling
|
|
|
|
// of certain key combinations.
|
|
|
|
if (m_is95Family) {
|
|
|
|
DWORD dummy = 0;
|
|
|
|
SystemParametersInfo(SPI_SETSCREENSAVERRUNNING,
|
|
|
|
enable ? FALSE : TRUE, &dummy, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ButtonID
|
|
|
|
CMSWindowsScreen::mapButtonFromEvent(WPARAM msg, LPARAM button) const
|
|
|
|
{
|
|
|
|
switch (msg) {
|
|
|
|
case WM_LBUTTONDOWN:
|
|
|
|
case WM_LBUTTONDBLCLK:
|
|
|
|
case WM_LBUTTONUP:
|
|
|
|
case WM_NCLBUTTONDOWN:
|
|
|
|
case WM_NCLBUTTONDBLCLK:
|
|
|
|
case WM_NCLBUTTONUP:
|
|
|
|
return kButtonLeft;
|
|
|
|
|
|
|
|
case WM_MBUTTONDOWN:
|
|
|
|
case WM_MBUTTONDBLCLK:
|
|
|
|
case WM_MBUTTONUP:
|
|
|
|
case WM_NCMBUTTONDOWN:
|
|
|
|
case WM_NCMBUTTONDBLCLK:
|
|
|
|
case WM_NCMBUTTONUP:
|
|
|
|
return kButtonMiddle;
|
|
|
|
|
|
|
|
case WM_RBUTTONDOWN:
|
|
|
|
case WM_RBUTTONDBLCLK:
|
|
|
|
case WM_RBUTTONUP:
|
|
|
|
case WM_NCRBUTTONDOWN:
|
|
|
|
case WM_NCRBUTTONDBLCLK:
|
|
|
|
case WM_NCRBUTTONUP:
|
|
|
|
return kButtonRight;
|
|
|
|
|
|
|
|
case WM_XBUTTONDOWN:
|
|
|
|
case WM_XBUTTONDBLCLK:
|
|
|
|
case WM_XBUTTONUP:
|
|
|
|
case WM_NCXBUTTONDOWN:
|
|
|
|
case WM_NCXBUTTONDBLCLK:
|
|
|
|
case WM_NCXBUTTONUP:
|
|
|
|
switch (button) {
|
|
|
|
case XBUTTON1:
|
|
|
|
return kButtonExtra0 + 0;
|
|
|
|
|
|
|
|
case XBUTTON2:
|
|
|
|
return kButtonExtra0 + 1;
|
|
|
|
}
|
|
|
|
return kButtonNone;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return kButtonNone;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-05-01 08:56:24 +00:00
|
|
|
bool
|
|
|
|
CMSWindowsScreen::mapPressFromEvent(WPARAM msg, LPARAM) const
|
|
|
|
{
|
|
|
|
switch (msg) {
|
|
|
|
case WM_LBUTTONDOWN:
|
|
|
|
case WM_MBUTTONDOWN:
|
|
|
|
case WM_RBUTTONDOWN:
|
|
|
|
case WM_XBUTTONDOWN:
|
|
|
|
case WM_LBUTTONDBLCLK:
|
|
|
|
case WM_MBUTTONDBLCLK:
|
|
|
|
case WM_RBUTTONDBLCLK:
|
|
|
|
case WM_XBUTTONDBLCLK:
|
|
|
|
case WM_NCLBUTTONDOWN:
|
|
|
|
case WM_NCMBUTTONDOWN:
|
|
|
|
case WM_NCRBUTTONDOWN:
|
|
|
|
case WM_NCXBUTTONDOWN:
|
|
|
|
case WM_NCLBUTTONDBLCLK:
|
|
|
|
case WM_NCMBUTTONDBLCLK:
|
|
|
|
case WM_NCRBUTTONDBLCLK:
|
|
|
|
case WM_NCXBUTTONDBLCLK:
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case WM_LBUTTONUP:
|
|
|
|
case WM_MBUTTONUP:
|
|
|
|
case WM_RBUTTONUP:
|
|
|
|
case WM_XBUTTONUP:
|
|
|
|
case WM_NCLBUTTONUP:
|
|
|
|
case WM_NCMBUTTONUP:
|
|
|
|
case WM_NCRBUTTONUP:
|
|
|
|
case WM_NCXBUTTONUP:
|
|
|
|
return false;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-03-28 14:07:58 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2003-09-02 22:05:47 +00:00
|
|
|
void
|
2004-03-26 20:59:26 +00:00
|
|
|
CMSWindowsScreen::updateKeysCB(void*)
|
2003-09-02 22:05:47 +00:00
|
|
|
{
|
2004-03-26 20:59:26 +00:00
|
|
|
m_keyState->updateKeys();
|
|
|
|
updateButtons();
|
2003-09-02 22:05:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
LRESULT CALLBACK
|
|
|
|
CMSWindowsScreen::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
|
|
|
assert(s_screen != NULL);
|
|
|
|
|
|
|
|
LRESULT result = 0;
|
|
|
|
if (!s_screen->onEvent(hwnd, msg, wParam, lParam, &result)) {
|
|
|
|
result = DefWindowProc(hwnd, msg, wParam, lParam);
|
2002-07-12 20:41:23 +00:00
|
|
|
}
|
2003-09-02 22:05:47 +00:00
|
|
|
|
|
|
|
return result;
|
2001-11-19 00:33:36 +00:00
|
|
|
}
|