00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "CMSWindowsDesks.h"
00020 #include "CMSWindowsScreen.h"
00021 #include "CSynergyHook.h"
00022 #include "IScreenSaver.h"
00023 #include "XScreen.h"
00024 #include "CLock.h"
00025 #include "CThread.h"
00026 #include "CLog.h"
00027 #include "IEventQueue.h"
00028 #include "IJob.h"
00029 #include "TMethodEventJob.h"
00030 #include "TMethodJob.h"
00031 #include "CArchMiscWindows.h"
00032 #include <malloc.h>
00033 #include "IEventQueue.h"
00034
00035
00036 #if !defined(SPI_GETMOUSESPEED)
00037 #define SPI_GETMOUSESPEED 112
00038 #endif
00039 #if !defined(SPI_SETMOUSESPEED)
00040 #define SPI_SETMOUSESPEED 113
00041 #endif
00042 #if !defined(SPI_GETSCREENSAVERRUNNING)
00043 #define SPI_GETSCREENSAVERRUNNING 114
00044 #endif
00045
00046
00047 #if !defined(WM_XBUTTONDOWN)
00048 #define WM_XBUTTONDOWN 0x020B
00049 #define WM_XBUTTONUP 0x020C
00050 #define WM_XBUTTONDBLCLK 0x020D
00051 #define WM_NCXBUTTONDOWN 0x00AB
00052 #define WM_NCXBUTTONUP 0x00AC
00053 #define WM_NCXBUTTONDBLCLK 0x00AD
00054 #define MOUSEEVENTF_XDOWN 0x0080
00055 #define MOUSEEVENTF_XUP 0x0100
00056 #define XBUTTON1 0x0001
00057 #define XBUTTON2 0x0002
00058 #endif
00059 #if !defined(VK_XBUTTON1)
00060 #define VK_XBUTTON1 0x05
00061 #define VK_XBUTTON2 0x06
00062 #endif
00063
00064
00065 #define SYNERGY_MSG_SWITCH SYNERGY_HOOK_LAST_MSG + 1
00066
00067 #define SYNERGY_MSG_ENTER SYNERGY_HOOK_LAST_MSG + 2
00068
00069 #define SYNERGY_MSG_LEAVE SYNERGY_HOOK_LAST_MSG + 3
00070
00071 #define SYNERGY_MSG_FAKE_KEY SYNERGY_HOOK_LAST_MSG + 4
00072
00073 #define SYNERGY_MSG_FAKE_BUTTON SYNERGY_HOOK_LAST_MSG + 5
00074
00075 #define SYNERGY_MSG_FAKE_MOVE SYNERGY_HOOK_LAST_MSG + 6
00076
00077 #define SYNERGY_MSG_FAKE_WHEEL SYNERGY_HOOK_LAST_MSG + 7
00078
00079 #define SYNERGY_MSG_CURSOR_POS SYNERGY_HOOK_LAST_MSG + 8
00080
00081 #define SYNERGY_MSG_SYNC_KEYS SYNERGY_HOOK_LAST_MSG + 9
00082
00083 #define SYNERGY_MSG_SCREENSAVER SYNERGY_HOOK_LAST_MSG + 10
00084
00085 #define SYNERGY_MSG_FAKE_REL_MOVE SYNERGY_HOOK_LAST_MSG + 11
00086
00087 #define SYNERGY_MSG_FAKE_INPUT SYNERGY_HOOK_LAST_MSG + 12
00088
00089
00090
00091
00092
00093 CMSWindowsDesks::CMSWindowsDesks(
00094 bool isPrimary, bool noHooks, HINSTANCE hookLibrary,
00095 const IScreenSaver* screensaver, IEventQueue& eventQueue,
00096 IJob* updateKeys, bool stopOnDeskSwitch) :
00097 m_isPrimary(isPrimary),
00098 m_noHooks(noHooks),
00099 m_is95Family(CArchMiscWindows::isWindows95Family()),
00100 m_isModernFamily(CArchMiscWindows::isWindowsModern()),
00101 m_isOnScreen(m_isPrimary),
00102 m_x(0), m_y(0),
00103 m_w(0), m_h(0),
00104 m_xCenter(0), m_yCenter(0),
00105 m_multimon(false),
00106 m_timer(NULL),
00107 m_screensaver(screensaver),
00108 m_screensaverNotify(false),
00109 m_activeDesk(NULL),
00110 m_activeDeskName(),
00111 m_mutex(),
00112 m_deskReady(&m_mutex, false),
00113 m_updateKeys(updateKeys),
00114 m_eventQueue(eventQueue),
00115 m_stopOnDeskSwitch(stopOnDeskSwitch)
00116 {
00117 if (hookLibrary != NULL)
00118 queryHookLibrary(hookLibrary);
00119
00120 m_cursor = createBlankCursor();
00121 m_deskClass = createDeskWindowClass(m_isPrimary);
00122 m_keyLayout = GetKeyboardLayout(GetCurrentThreadId());
00123 resetOptions();
00124 }
00125
00126 CMSWindowsDesks::~CMSWindowsDesks()
00127 {
00128 disable();
00129 destroyClass(m_deskClass);
00130 destroyCursor(m_cursor);
00131 delete m_updateKeys;
00132 }
00133
00134 void
00135 CMSWindowsDesks::enable()
00136 {
00137 m_threadID = GetCurrentThreadId();
00138
00139
00140 checkDesk();
00141
00142
00143
00144
00145
00146 m_timer = m_eventQueue.newTimer(0.2, NULL);
00147 m_eventQueue.adoptHandler(CEvent::kTimer, m_timer,
00148 new TMethodEventJob<CMSWindowsDesks>(
00149 this, &CMSWindowsDesks::handleCheckDesk));
00150
00151 updateKeys();
00152 }
00153
00154 void
00155 CMSWindowsDesks::disable()
00156 {
00157
00158 if (m_timer != NULL) {
00159 m_eventQueue.removeHandler(CEvent::kTimer, m_timer);
00160 m_eventQueue.deleteTimer(m_timer);
00161 m_timer = NULL;
00162 }
00163
00164
00165 removeDesks();
00166
00167 m_isOnScreen = m_isPrimary;
00168 }
00169
00170 void
00171 CMSWindowsDesks::enter()
00172 {
00173 sendMessage(SYNERGY_MSG_ENTER, 0, 0);
00174 }
00175
00176 void
00177 CMSWindowsDesks::leave(HKL keyLayout)
00178 {
00179 sendMessage(SYNERGY_MSG_LEAVE, (WPARAM)keyLayout, 0);
00180 }
00181
00182 void
00183 CMSWindowsDesks::resetOptions()
00184 {
00185 m_leaveForegroundOption = false;
00186 }
00187
00188 void
00189 CMSWindowsDesks::setOptions(const COptionsList& options)
00190 {
00191 for (UInt32 i = 0, n = (UInt32)options.size(); i < n; i += 2) {
00192 if (options[i] == kOptionWin32KeepForeground) {
00193 m_leaveForegroundOption = (options[i + 1] != 0);
00194 LOG((CLOG_DEBUG1 "%s the foreground window", m_leaveForegroundOption ? "don\'t grab" : "grab"));
00195 }
00196 }
00197 }
00198
00199 void
00200 CMSWindowsDesks::updateKeys()
00201 {
00202 sendMessage(SYNERGY_MSG_SYNC_KEYS, 0, 0);
00203 }
00204
00205 void
00206 CMSWindowsDesks::setShape(SInt32 x, SInt32 y,
00207 SInt32 width, SInt32 height,
00208 SInt32 xCenter, SInt32 yCenter, bool isMultimon)
00209 {
00210 m_x = x;
00211 m_y = y;
00212 m_w = width;
00213 m_h = height;
00214 m_xCenter = xCenter;
00215 m_yCenter = yCenter;
00216 m_multimon = isMultimon;
00217 }
00218
00219 void
00220 CMSWindowsDesks::installScreensaverHooks(bool install)
00221 {
00222 if (m_isPrimary && m_screensaverNotify != install) {
00223 m_screensaverNotify = install;
00224 sendMessage(SYNERGY_MSG_SCREENSAVER, install, 0);
00225 }
00226 }
00227
00228 void
00229 CMSWindowsDesks::fakeInputBegin()
00230 {
00231 sendMessage(SYNERGY_MSG_FAKE_INPUT, 1, 0);
00232 }
00233
00234 void
00235 CMSWindowsDesks::fakeInputEnd()
00236 {
00237 sendMessage(SYNERGY_MSG_FAKE_INPUT, 0, 0);
00238 }
00239
00240 void
00241 CMSWindowsDesks::getCursorPos(SInt32& x, SInt32& y) const
00242 {
00243 POINT pos;
00244 sendMessage(SYNERGY_MSG_CURSOR_POS, reinterpret_cast<WPARAM>(&pos), 0);
00245 x = pos.x;
00246 y = pos.y;
00247 }
00248
00249 void
00250 CMSWindowsDesks::fakeKeyEvent(
00251 KeyButton button, UINT virtualKey,
00252 bool press, bool ) const
00253 {
00254
00255 if (m_is95Family) {
00256 switch (virtualKey) {
00257 case VK_LSHIFT:
00258 case VK_RSHIFT:
00259 virtualKey = VK_SHIFT;
00260 break;
00261
00262 case VK_LCONTROL:
00263 case VK_RCONTROL:
00264 virtualKey = VK_CONTROL;
00265 break;
00266
00267 case VK_LMENU:
00268 case VK_RMENU:
00269 virtualKey = VK_MENU;
00270 break;
00271 }
00272 }
00273
00274
00275 DWORD flags = 0;
00276 if (((button & 0x100u) != 0)) {
00277 flags |= KEYEVENTF_EXTENDEDKEY;
00278 }
00279 if (!press) {
00280 flags |= KEYEVENTF_KEYUP;
00281 }
00282 sendMessage(SYNERGY_MSG_FAKE_KEY, flags,
00283 MAKEWORD(static_cast<BYTE>(button & 0xffu),
00284 static_cast<BYTE>(virtualKey & 0xffu)));
00285 }
00286
00287 void
00288 CMSWindowsDesks::fakeMouseButton(ButtonID button, bool press)
00289 {
00290
00291
00292
00293
00294 if (GetSystemMetrics(SM_SWAPBUTTON)) {
00295 switch (button) {
00296 case kButtonLeft:
00297 button = kButtonRight;
00298 break;
00299
00300 case kButtonRight:
00301 button = kButtonLeft;
00302 break;
00303 }
00304 }
00305
00306
00307 DWORD data = 0;
00308 DWORD flags;
00309 switch (button) {
00310 case kButtonLeft:
00311 flags = press ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_LEFTUP;
00312 break;
00313
00314 case kButtonMiddle:
00315 flags = press ? MOUSEEVENTF_MIDDLEDOWN : MOUSEEVENTF_MIDDLEUP;
00316 break;
00317
00318 case kButtonRight:
00319 flags = press ? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_RIGHTUP;
00320 break;
00321
00322 case kButtonExtra0 + 0:
00323 data = XBUTTON1;
00324 flags = press ? MOUSEEVENTF_XDOWN : MOUSEEVENTF_XUP;
00325 break;
00326
00327 case kButtonExtra0 + 1:
00328 data = XBUTTON2;
00329 flags = press ? MOUSEEVENTF_XDOWN : MOUSEEVENTF_XUP;
00330 break;
00331
00332 default:
00333 return;
00334 }
00335
00336
00337 sendMessage(SYNERGY_MSG_FAKE_BUTTON, flags, data);
00338 }
00339
00340 void
00341 CMSWindowsDesks::fakeMouseMove(SInt32 x, SInt32 y) const
00342 {
00343 sendMessage(SYNERGY_MSG_FAKE_MOVE,
00344 static_cast<WPARAM>(x),
00345 static_cast<LPARAM>(y));
00346 }
00347
00348 void
00349 CMSWindowsDesks::fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const
00350 {
00351 sendMessage(SYNERGY_MSG_FAKE_REL_MOVE,
00352 static_cast<WPARAM>(dx),
00353 static_cast<LPARAM>(dy));
00354 }
00355
00356 void
00357 CMSWindowsDesks::fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const
00358 {
00359 sendMessage(SYNERGY_MSG_FAKE_WHEEL, xDelta, yDelta);
00360 }
00361
00362 void
00363 CMSWindowsDesks::sendMessage(UINT msg, WPARAM wParam, LPARAM lParam) const
00364 {
00365 if (m_activeDesk != NULL && m_activeDesk->m_window != NULL) {
00366 PostThreadMessage(m_activeDesk->m_threadID, msg, wParam, lParam);
00367 waitForDesk();
00368 }
00369 }
00370
00371 void
00372 CMSWindowsDesks::queryHookLibrary(HINSTANCE hookLibrary)
00373 {
00374
00375 if (m_isPrimary && !m_noHooks) {
00376 m_install = (InstallFunc)GetProcAddress(hookLibrary, "install");
00377 m_uninstall = (UninstallFunc)GetProcAddress(hookLibrary, "uninstall");
00378 m_installScreensaver =
00379 (InstallScreenSaverFunc)GetProcAddress(
00380 hookLibrary, "installScreenSaver");
00381 m_uninstallScreensaver =
00382 (UninstallScreenSaverFunc)GetProcAddress(
00383 hookLibrary, "uninstallScreenSaver");
00384 if (m_install == NULL ||
00385 m_uninstall == NULL ||
00386 m_installScreensaver == NULL ||
00387 m_uninstallScreensaver == NULL) {
00388 LOG((CLOG_ERR "Invalid hook library"));
00389 throw XScreenOpenFailure();
00390 }
00391 }
00392 else {
00393 m_install = NULL;
00394 m_uninstall = NULL;
00395 m_installScreensaver = NULL;
00396 m_uninstallScreensaver = NULL;
00397 }
00398 }
00399
00400 HCURSOR
00401 CMSWindowsDesks::createBlankCursor() const
00402 {
00403
00404 int cw = GetSystemMetrics(SM_CXCURSOR);
00405 int ch = GetSystemMetrics(SM_CYCURSOR);
00406 UInt8* cursorAND = new UInt8[ch * ((cw + 31) >> 2)];
00407 UInt8* cursorXOR = new UInt8[ch * ((cw + 31) >> 2)];
00408 memset(cursorAND, 0xff, ch * ((cw + 31) >> 2));
00409 memset(cursorXOR, 0x00, ch * ((cw + 31) >> 2));
00410 HCURSOR c = CreateCursor(CMSWindowsScreen::getWindowInstance(),
00411 0, 0, cw, ch, cursorAND, cursorXOR);
00412 delete[] cursorXOR;
00413 delete[] cursorAND;
00414 return c;
00415 }
00416
00417 void
00418 CMSWindowsDesks::destroyCursor(HCURSOR cursor) const
00419 {
00420 if (cursor != NULL) {
00421 DestroyCursor(cursor);
00422 }
00423 }
00424
00425 ATOM
00426 CMSWindowsDesks::createDeskWindowClass(bool isPrimary) const
00427 {
00428 WNDCLASSEX classInfo;
00429 classInfo.cbSize = sizeof(classInfo);
00430 classInfo.style = CS_DBLCLKS | CS_NOCLOSE;
00431 classInfo.lpfnWndProc = isPrimary ?
00432 &CMSWindowsDesks::primaryDeskProc :
00433 &CMSWindowsDesks::secondaryDeskProc;
00434 classInfo.cbClsExtra = 0;
00435 classInfo.cbWndExtra = 0;
00436 classInfo.hInstance = CMSWindowsScreen::getWindowInstance();
00437 classInfo.hIcon = NULL;
00438 classInfo.hCursor = m_cursor;
00439 classInfo.hbrBackground = NULL;
00440 classInfo.lpszMenuName = NULL;
00441 classInfo.lpszClassName = "SynergyDesk";
00442 classInfo.hIconSm = NULL;
00443 return RegisterClassEx(&classInfo);
00444 }
00445
00446 void
00447 CMSWindowsDesks::destroyClass(ATOM windowClass) const
00448 {
00449 if (windowClass != 0) {
00450 UnregisterClass(reinterpret_cast<LPCTSTR>(windowClass),
00451 CMSWindowsScreen::getWindowInstance());
00452 }
00453 }
00454
00455 HWND
00456 CMSWindowsDesks::createWindow(ATOM windowClass, const char* name) const
00457 {
00458 HWND window = CreateWindowEx(WS_EX_TOPMOST |
00459 WS_EX_TRANSPARENT |
00460 WS_EX_TOOLWINDOW,
00461 reinterpret_cast<LPCTSTR>(windowClass),
00462 name,
00463 WS_POPUP,
00464 0, 0, 1, 1,
00465 NULL, NULL,
00466 CMSWindowsScreen::getWindowInstance(),
00467 NULL);
00468 if (window == NULL) {
00469 LOG((CLOG_ERR "failed to create window: %d", GetLastError()));
00470 throw XScreenOpenFailure();
00471 }
00472 return window;
00473 }
00474
00475 void
00476 CMSWindowsDesks::destroyWindow(HWND hwnd) const
00477 {
00478 if (hwnd != NULL) {
00479 DestroyWindow(hwnd);
00480 }
00481 }
00482
00483 LRESULT CALLBACK
00484 CMSWindowsDesks::primaryDeskProc(
00485 HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
00486 {
00487 return DefWindowProc(hwnd, msg, wParam, lParam);
00488 }
00489
00490 LRESULT CALLBACK
00491 CMSWindowsDesks::secondaryDeskProc(
00492 HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
00493 {
00494
00495
00496 bool hide = false;
00497 switch (msg) {
00498 case WM_MOUSEMOVE:
00499 if (LOWORD(lParam) != 0 || HIWORD(lParam) != 0) {
00500 hide = true;
00501 }
00502 break;
00503 }
00504
00505 if (hide && IsWindowVisible(hwnd)) {
00506 ReleaseCapture();
00507 SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0,
00508 SWP_NOMOVE | SWP_NOSIZE |
00509 SWP_NOACTIVATE | SWP_HIDEWINDOW);
00510 }
00511
00512 return DefWindowProc(hwnd, msg, wParam, lParam);
00513 }
00514
00515 void
00516 CMSWindowsDesks::deskMouseMove(SInt32 x, SInt32 y) const
00517 {
00518
00519
00520
00521
00522 bool simple = (!m_multimon || !m_is95Family);
00523 if (!simple) {
00524
00525 simple = (x >= 0 && x < GetSystemMetrics(SM_CXSCREEN) &&
00526 y >= 0 && y < GetSystemMetrics(SM_CYSCREEN));
00527 }
00528
00529
00530 if (simple) {
00531
00532
00533
00534 SInt32 w = GetSystemMetrics(SM_CXSCREEN);
00535 SInt32 h = GetSystemMetrics(SM_CYSCREEN);
00536 mouse_event(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE,
00537 (DWORD)((65535.0f * x) / (w - 1) + 0.5f),
00538 (DWORD)((65535.0f * y) / (h - 1) + 0.5f),
00539 0, 0);
00540 }
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558 else {
00559 POINT pos;
00560 GetCursorPos(&pos);
00561 deskMouseRelativeMove(x - pos.x, y - pos.y);
00562 }
00563 }
00564
00565 void
00566 CMSWindowsDesks::deskMouseRelativeMove(SInt32 dx, SInt32 dy) const
00567 {
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578 int oldSpeed[4];
00579 bool accelChanged =
00580 SystemParametersInfo(SPI_GETMOUSE,0, oldSpeed, 0) &&
00581 SystemParametersInfo(SPI_GETMOUSESPEED, 0, oldSpeed + 3, 0);
00582
00583
00584 if (accelChanged) {
00585 int newSpeed[4] = { 0, 0, 0, 1 };
00586 accelChanged =
00587 SystemParametersInfo(SPI_SETMOUSE, 0, newSpeed, 0) ||
00588 SystemParametersInfo(SPI_SETMOUSESPEED, 0, newSpeed + 3, 0);
00589 }
00590
00591
00592 mouse_event(MOUSEEVENTF_MOVE, dx, dy, 0, 0);
00593
00594
00595 if (accelChanged) {
00596 SystemParametersInfo(SPI_SETMOUSE, 0, oldSpeed, 0);
00597 SystemParametersInfo(SPI_SETMOUSESPEED, 0, oldSpeed + 3, 0);
00598 }
00599 }
00600
00601 void
00602 CMSWindowsDesks::deskEnter(CDesk* desk)
00603 {
00604 if (!m_isPrimary) {
00605 ReleaseCapture();
00606 }
00607 ShowCursor(TRUE);
00608 SetWindowPos(desk->m_window, HWND_BOTTOM, 0, 0, 0, 0,
00609 SWP_NOMOVE | SWP_NOSIZE |
00610 SWP_NOACTIVATE | SWP_HIDEWINDOW);
00611
00612
00613
00614
00615
00616
00617
00618 DWORD thisThread =
00619 GetWindowThreadProcessId(desk->m_window, NULL);
00620 DWORD thatThread =
00621 GetWindowThreadProcessId(desk->m_foregroundWindow, NULL);
00622 AttachThreadInput(thatThread, thisThread, TRUE);
00623 SetForegroundWindow(desk->m_foregroundWindow);
00624 AttachThreadInput(thatThread, thisThread, FALSE);
00625 EnableWindow(desk->m_window, desk->m_lowLevel ? FALSE : TRUE);
00626 desk->m_foregroundWindow = NULL;
00627 }
00628
00629 void
00630 CMSWindowsDesks::deskLeave(CDesk* desk, HKL keyLayout)
00631 {
00632 ShowCursor(FALSE);
00633 if (m_isPrimary) {
00634
00635
00636
00637 int x, y, w, h;
00638 if (desk->m_lowLevel) {
00639
00640
00641 x = m_xCenter;
00642 y = m_yCenter;
00643 w = 1;
00644 h = 1;
00645 }
00646 else {
00647
00648
00649
00650 x = m_x;
00651 y = m_y;
00652 w = m_w;
00653 h = m_h;
00654 }
00655 SetWindowPos(desk->m_window, HWND_TOPMOST, x, y, w, h,
00656 SWP_NOACTIVATE | SWP_SHOWWINDOW);
00657
00658
00659
00660
00661
00662 if (!desk->m_lowLevel) {
00663 SetActiveWindow(desk->m_window);
00664 }
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674 else {
00675 desk->m_foregroundWindow = getForegroundWindow();
00676 if (desk->m_foregroundWindow != NULL) {
00677 EnableWindow(desk->m_window, TRUE);
00678 SetActiveWindow(desk->m_window);
00679 DWORD thisThread =
00680 GetWindowThreadProcessId(desk->m_window, NULL);
00681 DWORD thatThread =
00682 GetWindowThreadProcessId(desk->m_foregroundWindow, NULL);
00683 AttachThreadInput(thatThread, thisThread, TRUE);
00684 SetForegroundWindow(desk->m_window);
00685 AttachThreadInput(thatThread, thisThread, FALSE);
00686 }
00687 }
00688
00689
00690 ActivateKeyboardLayout(keyLayout, 0);
00691 }
00692 else {
00693
00694 SetWindowPos(desk->m_window, HWND_TOPMOST,
00695 m_xCenter, m_yCenter, 1, 1,
00696 SWP_NOACTIVATE | SWP_SHOWWINDOW);
00697
00698
00699
00700
00701
00702 SetCapture(desk->m_window);
00703
00704
00705 LOG((CLOG_DEBUG2 "warping cursor to center: %+d,%+d", m_xCenter, m_yCenter));
00706 deskMouseMove(m_xCenter, m_yCenter);
00707 }
00708 }
00709
00710 void
00711 CMSWindowsDesks::deskThread(void* vdesk)
00712 {
00713 MSG msg;
00714
00715
00716 CDesk* desk = reinterpret_cast<CDesk*>(vdesk);
00717 desk->m_threadID = GetCurrentThreadId();
00718 desk->m_window = NULL;
00719 desk->m_foregroundWindow = NULL;
00720 if (desk->m_desk != NULL && SetThreadDesktop(desk->m_desk) != 0) {
00721
00722 PeekMessage(&msg, NULL, 0,0, PM_NOREMOVE);
00723
00724
00725 try {
00726 desk->m_window = createWindow(m_deskClass, "SynergyDesk");
00727 LOG((CLOG_DEBUG "desk %s window is 0x%08x", desk->m_name.c_str(), desk->m_window));
00728 }
00729 catch (...) {
00730
00731 LOG((CLOG_DEBUG "can't create desk window for %s", desk->m_name.c_str()));
00732 }
00733 }
00734
00735
00736 {
00737 CLock lock(&m_mutex);
00738 m_deskReady = true;
00739 m_deskReady.broadcast();
00740 }
00741
00742 while (GetMessage(&msg, NULL, 0, 0)) {
00743 switch (msg.message) {
00744 default:
00745 TranslateMessage(&msg);
00746 DispatchMessage(&msg);
00747 continue;
00748
00749 case SYNERGY_MSG_SWITCH:
00750 if (m_isPrimary && !m_noHooks) {
00751 m_uninstall();
00752 if (m_screensaverNotify) {
00753 m_uninstallScreensaver();
00754 m_installScreensaver();
00755 }
00756 switch (m_install()) {
00757 case kHOOK_FAILED:
00758
00759 desk->m_lowLevel = false;
00760 break;
00761
00762 case kHOOK_OKAY:
00763 desk->m_lowLevel = false;
00764 break;
00765
00766 case kHOOK_OKAY_LL:
00767 desk->m_lowLevel = true;
00768 break;
00769 }
00770
00771
00772
00773 if (desk->m_window)
00774 EnableWindow(desk->m_window, desk->m_lowLevel ? FALSE : TRUE);
00775 }
00776 break;
00777
00778 case SYNERGY_MSG_ENTER:
00779 m_isOnScreen = true;
00780 deskEnter(desk);
00781 break;
00782
00783 case SYNERGY_MSG_LEAVE:
00784 m_isOnScreen = false;
00785 m_keyLayout = (HKL)msg.wParam;
00786 deskLeave(desk, m_keyLayout);
00787 break;
00788
00789 case SYNERGY_MSG_FAKE_KEY:
00790 keybd_event(HIBYTE(msg.lParam), LOBYTE(msg.lParam), (DWORD)msg.wParam, 0);
00791 break;
00792
00793 case SYNERGY_MSG_FAKE_BUTTON:
00794 if (msg.wParam != 0) {
00795 mouse_event((DWORD)msg.wParam, 0, 0, (DWORD)msg.lParam, 0);
00796 }
00797 break;
00798
00799 case SYNERGY_MSG_FAKE_MOVE:
00800 deskMouseMove(static_cast<SInt32>(msg.wParam),
00801 static_cast<SInt32>(msg.lParam));
00802 break;
00803
00804 case SYNERGY_MSG_FAKE_REL_MOVE:
00805 deskMouseRelativeMove(static_cast<SInt32>(msg.wParam),
00806 static_cast<SInt32>(msg.lParam));
00807 break;
00808
00809 case SYNERGY_MSG_FAKE_WHEEL:
00810
00811 if (msg.lParam != 0) {
00812 mouse_event(MOUSEEVENTF_WHEEL, 0, 0, (DWORD)msg.lParam, 0);
00813 }
00814 break;
00815
00816 case SYNERGY_MSG_CURSOR_POS: {
00817 POINT* pos = reinterpret_cast<POINT*>(msg.wParam);
00818 if (!GetCursorPos(pos)) {
00819 pos->x = m_xCenter;
00820 pos->y = m_yCenter;
00821 }
00822 break;
00823 }
00824
00825 case SYNERGY_MSG_SYNC_KEYS:
00826 m_updateKeys->run();
00827 break;
00828
00829 case SYNERGY_MSG_SCREENSAVER:
00830 if (!m_noHooks) {
00831 if (msg.wParam != 0) {
00832 m_installScreensaver();
00833 }
00834 else {
00835 m_uninstallScreensaver();
00836 }
00837 }
00838 break;
00839
00840 case SYNERGY_MSG_FAKE_INPUT:
00841 keybd_event(SYNERGY_HOOK_FAKE_INPUT_VIRTUAL_KEY,
00842 SYNERGY_HOOK_FAKE_INPUT_SCANCODE,
00843 msg.wParam ? 0 : KEYEVENTF_KEYUP, 0);
00844 break;
00845 }
00846
00847
00848 CLock lock(&m_mutex);
00849 m_deskReady = true;
00850 m_deskReady.broadcast();
00851 }
00852
00853
00854 deskEnter(desk);
00855 if (desk->m_window != NULL) {
00856 DestroyWindow(desk->m_window);
00857 }
00858 if (desk->m_desk != NULL) {
00859 closeDesktop(desk->m_desk);
00860 }
00861 }
00862
00863 CMSWindowsDesks::CDesk*
00864 CMSWindowsDesks::addDesk(const CString& name, HDESK hdesk)
00865 {
00866 CDesk* desk = new CDesk;
00867 desk->m_name = name;
00868 desk->m_desk = hdesk;
00869 desk->m_targetID = GetCurrentThreadId();
00870 desk->m_thread = new CThread(new TMethodJob<CMSWindowsDesks>(
00871 this, &CMSWindowsDesks::deskThread, desk));
00872 waitForDesk();
00873 m_desks.insert(std::make_pair(name, desk));
00874 return desk;
00875 }
00876
00877 void
00878 CMSWindowsDesks::removeDesks()
00879 {
00880 for (CDesks::iterator index = m_desks.begin();
00881 index != m_desks.end(); ++index) {
00882 CDesk* desk = index->second;
00883 PostThreadMessage(desk->m_threadID, WM_QUIT, 0, 0);
00884 desk->m_thread->wait();
00885 delete desk->m_thread;
00886 delete desk;
00887 }
00888 m_desks.clear();
00889 m_activeDesk = NULL;
00890 m_activeDeskName = "";
00891 }
00892
00893 void
00894 CMSWindowsDesks::checkDesk()
00895 {
00896
00897 CDesk* desk;
00898 HDESK hdesk = openInputDesktop();
00899 CString name = getDesktopName(hdesk);
00900 CDesks::const_iterator index = m_desks.find(name);
00901 if (index == m_desks.end()) {
00902 desk = addDesk(name, hdesk);
00903
00904
00905 }
00906 else {
00907 closeDesktop(hdesk);
00908 desk = index->second;
00909 }
00910
00911
00912
00913 if (m_stopOnDeskSwitch && m_activeDesk != NULL && name != m_activeDeskName) {
00914 LOG((CLOG_DEBUG "shutting down because of desk switch to \"%s\"", name.c_str()));
00915 EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
00916 return;
00917 }
00918
00919
00920
00921
00922
00923
00924 if (name != m_activeDeskName && !m_screensaver->isActive()) {
00925
00926 bool wasOnScreen = m_isOnScreen;
00927 if (!wasOnScreen) {
00928 sendMessage(SYNERGY_MSG_ENTER, 0, 0);
00929 }
00930
00931
00932
00933
00934
00935 LOG((CLOG_DEBUG "switched to desk \"%s\"", name.c_str()));
00936 bool syncKeys = false;
00937 bool isAccessible = isDeskAccessible(desk);
00938 if (isDeskAccessible(m_activeDesk) != isAccessible) {
00939 if (isAccessible) {
00940 LOG((CLOG_DEBUG "desktop is now accessible"));
00941 syncKeys = true;
00942 }
00943 else {
00944 LOG((CLOG_DEBUG "desktop is now inaccessible"));
00945 }
00946 }
00947
00948
00949 m_activeDesk = desk;
00950 m_activeDeskName = name;
00951 sendMessage(SYNERGY_MSG_SWITCH, 0, 0);
00952
00953
00954 if (!wasOnScreen) {
00955 sendMessage(SYNERGY_MSG_LEAVE, (WPARAM)m_keyLayout, 0);
00956 }
00957
00958
00959 if (syncKeys) {
00960 updateKeys();
00961 }
00962 }
00963 else if (name != m_activeDeskName) {
00964
00965 PostThreadMessage(m_threadID, SYNERGY_MSG_SCREEN_SAVER, TRUE, 0);
00966 }
00967 }
00968
00969 bool
00970 CMSWindowsDesks::isDeskAccessible(const CDesk* desk) const
00971 {
00972 return (desk != NULL && desk->m_desk != NULL);
00973 }
00974
00975 void
00976 CMSWindowsDesks::waitForDesk() const
00977 {
00978 CMSWindowsDesks* self = const_cast<CMSWindowsDesks*>(this);
00979
00980 CLock lock(&m_mutex);
00981 while (!(bool)m_deskReady) {
00982 m_deskReady.wait();
00983 }
00984 self->m_deskReady = false;
00985 }
00986
00987 void
00988 CMSWindowsDesks::handleCheckDesk(const CEvent&, void*)
00989 {
00990 checkDesk();
00991
00992
00993
00994 if (m_isPrimary && m_isModernFamily) {
00995 BOOL running;
00996 SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &running, FALSE);
00997 PostThreadMessage(m_threadID, SYNERGY_MSG_SCREEN_SAVER, running, 0);
00998 }
00999 }
01000
01001 HDESK
01002 CMSWindowsDesks::openInputDesktop()
01003 {
01004 if (m_is95Family) {
01005
01006 return GetThreadDesktop(GetCurrentThreadId());
01007 }
01008 else {
01009 return OpenInputDesktop(DF_ALLOWOTHERACCOUNTHOOK, TRUE,
01010 DESKTOP_CREATEWINDOW |
01011 DESKTOP_HOOKCONTROL |
01012 GENERIC_WRITE);
01013 }
01014 }
01015
01016 void
01017 CMSWindowsDesks::closeDesktop(HDESK desk)
01018 {
01019
01020
01021 if (desk != NULL && !m_is95Family) {
01022 CloseDesktop(desk);
01023 }
01024 }
01025
01026 CString
01027 CMSWindowsDesks::getDesktopName(HDESK desk)
01028 {
01029 if (desk == NULL) {
01030 return CString();
01031 }
01032 else if (m_is95Family) {
01033 return "desktop";
01034 }
01035 else {
01036 DWORD size;
01037 GetUserObjectInformation(desk, UOI_NAME, NULL, 0, &size);
01038 TCHAR* name = (TCHAR*)alloca(size + sizeof(TCHAR));
01039 GetUserObjectInformation(desk, UOI_NAME, name, size, &size);
01040 CString result(name);
01041 return result;
01042 }
01043 }
01044
01045 HWND
01046 CMSWindowsDesks::getForegroundWindow() const
01047 {
01048
01049
01050
01051
01052 if (m_leaveForegroundOption) {
01053 return NULL;
01054 }
01055 return GetForegroundWindow();
01056 }