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